diff --git a/crates/ruff/src/autofix/actions.rs b/crates/ruff/src/autofix/actions.rs index fc6231bda9..7b72337de7 100644 --- a/crates/ruff/src/autofix/actions.rs +++ b/crates/ruff/src/autofix/actions.rs @@ -13,7 +13,7 @@ use ruff_python_ast::helpers; use ruff_python_ast::imports::{AnyImport, Import}; use ruff_python_ast::newlines::NewlineWithTrailingNewline; use ruff_python_ast::source_code::{Indexer, Locator, Stylist}; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::cst::helpers::compose_module_path; use crate::cst::matchers::match_module; @@ -435,11 +435,11 @@ pub(crate) fn get_or_import_symbol( module: &str, member: &str, at: TextSize, - context: &Context, + model: &SemanticModel, importer: &Importer, locator: &Locator, ) -> Result<(Edit, String)> { - if let Some((source, binding)) = context.resolve_qualified_import_name(module, member) { + if let Some((source, binding)) = model.resolve_qualified_import_name(module, member) { // If the symbol is already available in the current scope, use it. // The exception: the symbol source (i.e., the import statement) comes after the current @@ -477,7 +477,7 @@ pub(crate) fn get_or_import_symbol( // Case 1: `from functools import lru_cache` is in scope, and we're trying to reference // `functools.cache`; thus, we add `cache` to the import, and return `"cache"` as the // bound name. - if context + if model .find_binding(member) .map_or(true, |binding| binding.kind.is_builtin()) { @@ -489,7 +489,7 @@ pub(crate) fn get_or_import_symbol( } else { // Case 2: No `functools` import is in scope; thus, we add `import functools`, and // return `"functools.cache"` as the bound name. - if context + if model .find_binding(module) .map_or(true, |binding| binding.kind.is_builtin()) { diff --git a/crates/ruff/src/checkers/ast/deferred.rs b/crates/ruff/src/checkers/ast/deferred.rs index 62a1719af1..ab74d51234 100644 --- a/crates/ruff/src/checkers/ast/deferred.rs +++ b/crates/ruff/src/checkers/ast/deferred.rs @@ -1,7 +1,7 @@ use ruff_text_size::TextRange; use rustpython_parser::ast::Expr; -use ruff_python_semantic::context::Snapshot; +use ruff_python_semantic::model::Snapshot; /// A collection of AST nodes that are deferred for later analysis. /// Used to, e.g., store functions, whose bodies shouldn't be analyzed until all diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 2ed17be534..e0a2d40344 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -27,8 +27,8 @@ use ruff_python_semantic::binding::{ Binding, BindingId, BindingKind, Exceptions, ExecutionContext, Export, FromImportation, Importation, StarImportation, SubmoduleImportation, }; -use ruff_python_semantic::context::{Context, ContextFlags, ResolvedReference}; use ruff_python_semantic::definition::{ContextualizedDefinition, Module, ModuleKind}; +use ruff_python_semantic::model::{ContextFlags, ResolvedReference, SemanticModel}; use ruff_python_semantic::node::NodeId; use ruff_python_semantic::scope::{ClassDef, FunctionDef, Lambda, Scope, ScopeId, ScopeKind}; use ruff_python_stdlib::builtins::{BUILTINS, MAGIC_GLOBALS}; @@ -71,7 +71,7 @@ pub(crate) struct Checker<'a> { pub(crate) indexer: &'a Indexer, pub(crate) importer: Importer<'a>, // Stateful fields. - pub(crate) ctx: Context<'a>, + pub(crate) model: SemanticModel<'a>, pub(crate) diagnostics: Vec, pub(crate) deletions: FxHashSet>, deferred: Deferred<'a>, @@ -105,7 +105,7 @@ impl<'a> Checker<'a> { stylist, indexer, importer, - ctx: Context::new(&settings.typing_modules, path, module), + model: SemanticModel::new(&settings.typing_modules, path, module), deferred: Deferred::default(), diagnostics: Vec::default(), deletions: FxHashSet::default(), @@ -138,13 +138,17 @@ impl<'a> Checker<'a> { /// Create a [`Generator`] to generate source code based on the current AST state. pub(crate) fn generator(&self) -> Generator { - fn quote_style(context: &Context, locator: &Locator, indexer: &Indexer) -> Option { - if !context.in_f_string() { + fn quote_style( + model: &SemanticModel, + locator: &Locator, + indexer: &Indexer, + ) -> Option { + if !model.in_f_string() { return None; } // Find the quote character used to start the containing f-string. - let expr = context.expr()?; + let expr = model.expr()?; let string_range = indexer.f_string_range(expr.start())?; let trailing_quote = trailing_quote(locator.slice(string_range))?; @@ -158,7 +162,7 @@ impl<'a> Checker<'a> { Generator::new( self.stylist.indentation(), - quote_style(&self.ctx, self.locator, self.indexer).unwrap_or(self.stylist.quote()), + quote_style(&self.model, self.locator, self.indexer).unwrap_or(self.stylist.quote()), self.stylist.line_ending(), ) } @@ -169,7 +173,7 @@ where 'b: 'a, { fn visit_stmt(&mut self, stmt: &'b Stmt) { - self.ctx.push_stmt(stmt); + self.model.push_stmt(stmt); // Track whether we've seen docstrings, non-imports, etc. match stmt { @@ -180,55 +184,55 @@ where .iter() .any(|alias| alias.name.as_str() == "annotations") { - self.ctx.flags |= ContextFlags::FUTURE_ANNOTATIONS; + self.model.flags |= ContextFlags::FUTURE_ANNOTATIONS; } } else { - self.ctx.flags |= ContextFlags::FUTURES_BOUNDARY; + self.model.flags |= ContextFlags::FUTURES_BOUNDARY; } } Stmt::Import(_) => { - self.ctx.flags |= ContextFlags::FUTURES_BOUNDARY; + self.model.flags |= ContextFlags::FUTURES_BOUNDARY; } _ => { - self.ctx.flags |= ContextFlags::FUTURES_BOUNDARY; - if !self.ctx.seen_import_boundary() + self.model.flags |= ContextFlags::FUTURES_BOUNDARY; + if !self.model.seen_import_boundary() && !helpers::is_assignment_to_a_dunder(stmt) - && !helpers::in_nested_block(self.ctx.parents()) + && !helpers::in_nested_block(self.model.parents()) { - self.ctx.flags |= ContextFlags::IMPORT_BOUNDARY; + self.model.flags |= ContextFlags::IMPORT_BOUNDARY; } } } // Track each top-level import, to guide import insertions. if matches!(stmt, Stmt::Import(_) | Stmt::ImportFrom(_)) { - if self.ctx.at_top_level() { + if self.model.at_top_level() { self.importer.visit_import(stmt); } } // Store the flags prior to any further descent, so that we can restore them after visiting // the node. - let flags_snapshot = self.ctx.flags; + let flags_snapshot = self.model.flags; // Pre-visit. match stmt { Stmt::Global(ast::StmtGlobal { names, range: _ }) => { let ranges: Vec = helpers::find_names(stmt, self.locator).collect(); - if !self.ctx.scope_id.is_global() { + if !self.model.scope_id.is_global() { // Add the binding to the current scope. - let context = self.ctx.execution_context(); - let exceptions = self.ctx.exceptions(); - let scope = &mut self.ctx.scopes[self.ctx.scope_id]; - let usage = Some((self.ctx.scope_id, stmt.range())); + let context = self.model.execution_context(); + let exceptions = self.model.exceptions(); + let scope = &mut self.model.scopes[self.model.scope_id]; + let usage = Some((self.model.scope_id, stmt.range())); for (name, range) in names.iter().zip(ranges.iter()) { - let id = self.ctx.bindings.push(Binding { + let id = self.model.bindings.push(Binding { kind: BindingKind::Global, runtime_usage: None, synthetic_usage: usage, typing_usage: None, range: *range, - source: self.ctx.stmt_id, + source: self.model.stmt_id, context, exceptions, }); @@ -245,20 +249,20 @@ where } Stmt::Nonlocal(ast::StmtNonlocal { names, range: _ }) => { let ranges: Vec = helpers::find_names(stmt, self.locator).collect(); - if !self.ctx.scope_id.is_global() { - let context = self.ctx.execution_context(); - let exceptions = self.ctx.exceptions(); - let scope = &mut self.ctx.scopes[self.ctx.scope_id]; - let usage = Some((self.ctx.scope_id, stmt.range())); + if !self.model.scope_id.is_global() { + let context = self.model.execution_context(); + let exceptions = self.model.exceptions(); + let scope = &mut self.model.scopes[self.model.scope_id]; + let usage = Some((self.model.scope_id, stmt.range())); for (name, range) in names.iter().zip(ranges.iter()) { // Add a binding to the current scope. - let id = self.ctx.bindings.push(Binding { + let id = self.model.bindings.push(Binding { kind: BindingKind::Nonlocal, runtime_usage: None, synthetic_usage: usage, typing_usage: None, range: *range, - source: self.ctx.stmt_id, + source: self.model.stmt_id, context, exceptions, }); @@ -269,15 +273,15 @@ where // and the current scope.) for (name, range) in names.iter().zip(ranges.iter()) { let binding_id = self - .ctx + .model .scopes - .ancestors(self.ctx.scope_id) + .ancestors(self.model.scope_id) .skip(1) .take_while(|scope| !scope.kind.is_module()) .find_map(|scope| scope.get(name.as_str())); if let Some(binding_id) = binding_id { - self.ctx.bindings[*binding_id].runtime_usage = usage; + self.model.bindings[*binding_id].runtime_usage = usage; } else { // Ensure that every nonlocal has an existing binding from a parent scope. if self.settings.rules.enabled(Rule::NonlocalWithoutBinding) { @@ -302,7 +306,7 @@ where Stmt::Break(_) => { if self.settings.rules.enabled(Rule::BreakOutsideLoop) { if let Some(diagnostic) = - pyflakes::rules::break_outside_loop(stmt, &mut self.ctx.parents().skip(1)) + pyflakes::rules::break_outside_loop(stmt, &mut self.model.parents().skip(1)) { self.diagnostics.push(diagnostic); } @@ -312,7 +316,7 @@ where if self.settings.rules.enabled(Rule::ContinueOutsideLoop) { if let Some(diagnostic) = pyflakes::rules::continue_outside_loop( stmt, - &mut self.ctx.parents().skip(1), + &mut self.model.parents().skip(1), ) { self.diagnostics.push(diagnostic); } @@ -342,7 +346,7 @@ where self.diagnostics .extend(flake8_django::rules::non_leading_receiver_decorator( decorator_list, - |expr| self.ctx.resolve_call_path(expr), + |expr| self.model.resolve_call_path(expr), )); } @@ -362,7 +366,7 @@ where name, decorator_list, &self.settings.pep8_naming.ignore_names, - &self.ctx, + &self.model, self.locator, ) { self.diagnostics.push(diagnostic); @@ -377,7 +381,7 @@ where if let Some(diagnostic) = pep8_naming::rules::invalid_first_argument_name_for_class_method( self, - self.ctx.scope(), + self.model.scope(), name, decorator_list, args, @@ -395,7 +399,7 @@ where if let Some(diagnostic) = pep8_naming::rules::invalid_first_argument_name_for_method( self, - self.ctx.scope(), + self.model.scope(), name, decorator_list, args, @@ -416,7 +420,7 @@ where if self.settings.rules.enabled(Rule::DunderFunctionName) { if let Some(diagnostic) = pep8_naming::rules::dunder_function_name( - self.ctx.scope(), + self.model.scope(), stmt, name, self.locator, @@ -614,7 +618,7 @@ where pyupgrade::rules::yield_in_for_loop(self, stmt); } - if self.ctx.scope().kind.is_class() { + if self.model.scope().kind.is_class() { if self.settings.rules.enabled(Rule::BuiltinAttributeShadowing) { flake8_builtins::rules::builtin_attribute_shadowing(self, name, stmt); } @@ -839,17 +843,17 @@ where kind: BindingKind::FutureImportation, runtime_usage: None, // Always mark `__future__` imports as used. - synthetic_usage: Some((self.ctx.scope_id, alias.range())), + synthetic_usage: Some((self.model.scope_id, alias.range())), typing_usage: None, range: alias.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); if self.settings.rules.enabled(Rule::LateFutureImport) { - if self.ctx.seen_futures_boundary() { + if self.model.seen_futures_boundary() { self.diagnostics.push(Diagnostic::new( pyflakes::rules::LateFutureImport, stmt.range(), @@ -872,9 +876,9 @@ where synthetic_usage: None, typing_usage: None, range: alias.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); } else { @@ -893,15 +897,15 @@ where kind: BindingKind::Importation(Importation { name, full_name }), runtime_usage: None, synthetic_usage: if is_explicit_reexport { - Some((self.ctx.scope_id, alias.range())) + Some((self.model.scope_id, alias.range())) } else { None }, typing_usage: None, range: alias.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); @@ -1154,12 +1158,12 @@ where kind: BindingKind::FutureImportation, runtime_usage: None, // Always mark `__future__` imports as used. - synthetic_usage: Some((self.ctx.scope_id, alias.range())), + synthetic_usage: Some((self.model.scope_id, alias.range())), typing_usage: None, range: alias.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); @@ -1168,7 +1172,7 @@ where } if self.settings.rules.enabled(Rule::LateFutureImport) { - if self.ctx.seen_futures_boundary() { + if self.model.seen_futures_boundary() { self.diagnostics.push(Diagnostic::new( pyflakes::rules::LateFutureImport, stmt.range(), @@ -1176,7 +1180,7 @@ where } } } else if &alias.name == "*" { - self.ctx + self.model .scope_mut() .add_star_import(StarImportation { level, module }); @@ -1185,7 +1189,7 @@ where .rules .enabled(Rule::UndefinedLocalWithNestedImportStarUsage) { - let scope = self.ctx.scope(); + let scope = self.model.scope(); if !matches!(scope.kind, ScopeKind::Module) { self.diagnostics.push(Diagnostic::new( pyflakes::rules::UndefinedLocalWithNestedImportStarUsage { @@ -1239,15 +1243,15 @@ where }), runtime_usage: None, synthetic_usage: if is_explicit_reexport { - Some((self.ctx.scope_id, alias.range())) + Some((self.model.scope_id, alias.range())) } else { None }, typing_usage: None, range: alias.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); } @@ -1491,11 +1495,11 @@ where test, body, orelse, - self.ctx.stmt_parent(), + self.model.stmt_parent(), ); } if self.settings.rules.enabled(Rule::IfWithSameArms) { - flake8_simplify::rules::if_with_same_arms(self, stmt, self.ctx.stmt_parent()); + flake8_simplify::rules::if_with_same_arms(self, stmt, self.model.stmt_parent()); } if self.settings.rules.enabled(Rule::NeedlessBool) { flake8_simplify::rules::needless_bool(self, stmt); @@ -1511,14 +1515,14 @@ where test, body, orelse, - self.ctx.stmt_parent(), + self.model.stmt_parent(), ); } if self.settings.rules.enabled(Rule::IfElseBlockInsteadOfIfExp) { flake8_simplify::rules::use_ternary_operator( self, stmt, - self.ctx.stmt_parent(), + self.model.stmt_parent(), ); } if self @@ -1532,7 +1536,7 @@ where test, body, orelse, - self.ctx.stmt_parent(), + self.model.stmt_parent(), ); } if self.settings.rules.enabled(Rule::TypeCheckWithoutTypeError) { @@ -1541,7 +1545,7 @@ where body, test, orelse, - self.ctx.stmt_parent(), + self.model.stmt_parent(), ); } if self.settings.rules.enabled(Rule::OutdatedVersionBlock) { @@ -1560,7 +1564,7 @@ where msg, range: _, }) => { - if !self.ctx.in_type_checking_block() { + if !self.model.in_type_checking_block() { if self.settings.rules.enabled(Rule::Assert) { self.diagnostics .push(flake8_bandit::rules::assert_used(stmt)); @@ -1606,7 +1610,7 @@ where self, stmt, body, - self.ctx.stmt_parent(), + self.model.stmt_parent(), ); } if self.settings.rules.enabled(Rule::RedefinedLoopName) { @@ -1636,7 +1640,7 @@ where .. }) => { if self.settings.rules.enabled(Rule::UnusedLoopControlVariable) { - self.deferred.for_loops.push(self.ctx.snapshot()); + self.deferred.for_loops.push(self.model.snapshot()); } if self .settings @@ -1662,7 +1666,7 @@ where flake8_simplify::rules::convert_for_loop_to_any_all( self, stmt, - self.ctx.sibling_stmt(), + self.model.sibling_stmt(), ); } if self.settings.rules.enabled(Rule::InDictKeys) { @@ -1806,7 +1810,7 @@ where Rule::UnannotatedAssignmentInStub, ]) { // Ignore assignments in function bodies; those are covered by other rules. - if !self.ctx.scopes().any(|scope| scope.kind.is_function()) { + if !self.model.scopes().any(|scope| scope.kind.is_function()) { if self.settings.rules.enabled(Rule::UnprefixedTypeParam) { flake8_pyi::rules::prefix_type_params(self, value, targets); } @@ -1859,14 +1863,14 @@ where if let Some(value) = value { if self.settings.rules.enabled(Rule::AssignmentDefaultInStub) { // Ignore assignments in function bodies; those are covered by other rules. - if !self.ctx.scopes().any(|scope| scope.kind.is_function()) { + if !self.model.scopes().any(|scope| scope.kind.is_function()) { flake8_pyi::rules::annotated_assignment_default_in_stub( self, target, value, annotation, ); } } } - if self.ctx.match_typing_expr(annotation, "TypeAlias") { + if self.model.match_typing_expr(annotation, "TypeAlias") { if self.settings.rules.enabled(Rule::SnakeCaseTypeAlias) { flake8_pyi::rules::snake_case_type_alias(self, target); } @@ -1900,7 +1904,7 @@ where } if self.settings.rules.enabled(Rule::AsyncioDanglingTask) { if let Some(diagnostic) = ruff::rules::asyncio_dangling_task(value, |expr| { - self.ctx.resolve_call_path(expr) + self.model.resolve_call_path(expr) }) { self.diagnostics.push(diagnostic); } @@ -1935,7 +1939,7 @@ where // Function annotations are always evaluated at runtime, unless future annotations // are enabled. - let runtime_annotation = !self.ctx.future_annotations(); + let runtime_annotation = !self.model.future_annotations(); for arg in &args.posonlyargs { if let Some(expr) = &arg.annotation { @@ -2004,44 +2008,41 @@ where synthetic_usage: None, typing_usage: None, range: stmt.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); // If any global bindings don't already exist in the global scope, add it. let globals = helpers::extract_globals(body); for (name, stmt) in helpers::extract_globals(body) { - if self - .ctx - .global_scope() - .get(name) - .map_or(true, |index| self.ctx.bindings[*index].kind.is_annotation()) - { - let id = self.ctx.bindings.push(Binding { + if self.model.global_scope().get(name).map_or(true, |index| { + self.model.bindings[*index].kind.is_annotation() + }) { + let id = self.model.bindings.push(Binding { kind: BindingKind::Assignment, runtime_usage: None, synthetic_usage: None, typing_usage: None, range: stmt.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }); - self.ctx.global_scope_mut().add(name, id); + self.model.global_scope_mut().add(name, id); } } let definition = docstrings::extraction::extract_definition( ExtractionTarget::Function, stmt, - self.ctx.definition_id, - &self.ctx.definitions, + self.model.definition_id, + &self.model.definitions, ); - self.ctx.push_definition(definition); + self.model.push_definition(definition); - self.ctx.push_scope(ScopeKind::Function(FunctionDef { + self.model.push_scope(ScopeKind::Function(FunctionDef { name, body, args, @@ -2050,7 +2051,7 @@ where globals, })); - self.deferred.functions.push(self.ctx.snapshot()); + self.deferred.functions.push(self.model.snapshot()); } Stmt::ClassDef(ast::StmtClassDef { body, @@ -2073,35 +2074,32 @@ where // If any global bindings don't already exist in the global scope, add it. let globals = helpers::extract_globals(body); for (name, stmt) in &globals { - if self - .ctx - .global_scope() - .get(name) - .map_or(true, |index| self.ctx.bindings[*index].kind.is_annotation()) - { - let id = self.ctx.bindings.push(Binding { + if self.model.global_scope().get(name).map_or(true, |index| { + self.model.bindings[*index].kind.is_annotation() + }) { + let id = self.model.bindings.push(Binding { kind: BindingKind::Assignment, runtime_usage: None, synthetic_usage: None, typing_usage: None, range: stmt.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }); - self.ctx.global_scope_mut().add(name, id); + self.model.global_scope_mut().add(name, id); } } let definition = docstrings::extraction::extract_definition( ExtractionTarget::Class, stmt, - self.ctx.definition_id, - &self.ctx.definitions, + self.model.definition_id, + &self.model.definitions, ); - self.ctx.push_definition(definition); + self.model.push_definition(definition); - self.ctx.push_scope(ScopeKind::Class(ClassDef { + self.model.push_scope(ScopeKind::Class(ClassDef { name, bases, keywords, @@ -2127,7 +2125,7 @@ where }) => { let mut handled_exceptions = Exceptions::empty(); for type_ in extract_handled_exceptions(handlers) { - if let Some(call_path) = self.ctx.resolve_call_path(type_) { + if let Some(call_path) = self.model.resolve_call_path(type_) { if call_path.as_slice() == ["", "NameError"] { handled_exceptions |= Exceptions::NAME_ERROR; } else if call_path.as_slice() == ["", "ModuleNotFoundError"] { @@ -2136,7 +2134,7 @@ where } } - self.ctx.handled_exceptions.push(handled_exceptions); + self.model.handled_exceptions.push(handled_exceptions); if self.settings.rules.enabled(Rule::JumpStatementInFinally) { flake8_bugbear::rules::jump_statement_in_finally(self, finalbody); @@ -2149,9 +2147,9 @@ where } self.visit_body(body); - self.ctx.handled_exceptions.pop(); + self.model.handled_exceptions.pop(); - self.ctx.flags |= ContextFlags::EXCEPTION_HANDLER; + self.model.flags |= ContextFlags::EXCEPTION_HANDLER; for excepthandler in handlers { self.visit_excepthandler(excepthandler); } @@ -2168,8 +2166,8 @@ where // If we're in a class or module scope, then the annotation needs to be // available at runtime. // See: https://docs.python.org/3/reference/simple_stmts.html#annotated-assignment-statements - let runtime_annotation = if self.ctx.future_annotations() { - if matches!(self.ctx.scope().kind, ScopeKind::Class(..)) { + let runtime_annotation = if self.model.future_annotations() { + if matches!(self.model.scope().kind, ScopeKind::Class(..)) { let baseclasses = &self .settings .flake8_type_checking @@ -2179,7 +2177,7 @@ where .flake8_type_checking .runtime_evaluated_decorators; flake8_type_checking::helpers::runtime_evaluated( - &self.ctx, + &self.model, baseclasses, decorators, ) @@ -2188,7 +2186,7 @@ where } } else { matches!( - self.ctx.scope().kind, + self.model.scope().kind, ScopeKind::Class(..) | ScopeKind::Module ) }; @@ -2199,7 +2197,7 @@ where self.visit_annotation(annotation); } if let Some(expr) = value { - if self.ctx.match_typing_expr(annotation, "TypeAlias") { + if self.model.match_typing_expr(annotation, "TypeAlias") { self.visit_type_definition(expr); } else { self.visit_expr(expr); @@ -2235,7 +2233,7 @@ where }) => { self.visit_boolean_test(test); - if flake8_type_checking::helpers::is_type_checking_block(&self.ctx, test) { + if flake8_type_checking::helpers::is_type_checking_block(&self.model, test) { if self.settings.rules.enabled(Rule::EmptyTypeCheckingBlock) { flake8_type_checking::rules::empty_type_checking_block(self, stmt, body); } @@ -2253,12 +2251,12 @@ where // Post-visit. match stmt { Stmt::FunctionDef(_) | Stmt::AsyncFunctionDef(_) => { - self.ctx.pop_scope(); - self.ctx.pop_definition(); + self.model.pop_scope(); + self.model.pop_definition(); } Stmt::ClassDef(ast::StmtClassDef { name, .. }) => { - self.ctx.pop_scope(); - self.ctx.pop_definition(); + self.model.pop_scope(); + self.model.pop_definition(); self.add_binding( name, Binding { @@ -2267,31 +2265,31 @@ where synthetic_usage: None, typing_usage: None, range: stmt.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); } _ => {} } - self.ctx.flags = flags_snapshot; - self.ctx.pop_stmt(); + self.model.flags = flags_snapshot; + self.model.pop_stmt(); } fn visit_annotation(&mut self, expr: &'b Expr) { - let flags_snapshot = self.ctx.flags; - self.ctx.flags |= ContextFlags::ANNOTATION; + let flags_snapshot = self.model.flags; + self.model.flags |= ContextFlags::ANNOTATION; self.visit_type_definition(expr); - self.ctx.flags = flags_snapshot; + self.model.flags = flags_snapshot; } fn visit_expr(&mut self, expr: &'b Expr) { - if !self.ctx.in_f_string() - && !self.ctx.in_deferred_type_definition() - && self.ctx.in_type_definition() - && self.ctx.future_annotations() + if !self.model.in_f_string() + && !self.model.in_deferred_type_definition() + && self.model.in_type_definition() + && self.model.future_annotations() { if let Expr::Constant(ast::ExprConstant { value: Constant::Str(value), @@ -2301,21 +2299,21 @@ where self.deferred.string_type_definitions.push(( expr.range(), value, - self.ctx.snapshot(), + self.model.snapshot(), )); } else { self.deferred .future_type_definitions - .push((expr, self.ctx.snapshot())); + .push((expr, self.model.snapshot())); } return; } - self.ctx.push_expr(expr); + self.model.push_expr(expr); // Store the flags prior to any further descent, so that we can restore them after visiting // the node. - let flags_snapshot = self.ctx.flags; + let flags_snapshot = self.model.flags; // If we're in a boolean test (e.g., the `test` of a `Stmt::If`), but now within a // subexpression (e.g., `a` in `f(a)`), then we're no longer in a boolean test. @@ -2327,7 +2325,7 @@ where .. }) ) { - self.ctx.flags -= ContextFlags::BOOLEAN_TEST; + self.model.flags -= ContextFlags::BOOLEAN_TEST; } // Pre-visit. @@ -2339,7 +2337,7 @@ where Rule::NonPEP604Annotation, ]) { if let Some(operator) = - analyze::typing::to_pep604_operator(value, slice, &self.ctx) + analyze::typing::to_pep604_operator(value, slice, &self.model) { if self .settings @@ -2348,8 +2346,8 @@ where { if self.settings.target_version < PythonVersion::Py310 && self.settings.target_version >= PythonVersion::Py37 - && !self.ctx.future_annotations() - && self.ctx.in_annotation() + && !self.model.future_annotations() + && self.model.in_annotation() { flake8_future_annotations::rules::missing_future_annotations( self, value, @@ -2359,8 +2357,8 @@ where if self.settings.rules.enabled(Rule::NonPEP604Annotation) { if self.settings.target_version >= PythonVersion::Py310 || (self.settings.target_version >= PythonVersion::Py37 - && self.ctx.future_annotations() - && self.ctx.in_annotation()) + && self.model.future_annotations() + && self.model.in_annotation()) { pyupgrade::rules::use_pep604_annotation( self, expr, slice, operator, @@ -2370,8 +2368,8 @@ where } } - if self.ctx.match_typing_expr(value, "Literal") { - self.ctx.flags |= ContextFlags::LITERAL; + if self.model.match_typing_expr(value, "Literal") { + self.model.flags |= ContextFlags::LITERAL; } if self.settings.rules.any_enabled(&[ @@ -2438,7 +2436,7 @@ where Rule::NonPEP585Annotation, ]) { if let Some(replacement) = - analyze::typing::to_pep585_generic(expr, &self.ctx) + analyze::typing::to_pep585_generic(expr, &self.model) { if self .settings @@ -2447,8 +2445,8 @@ where { if self.settings.target_version < PythonVersion::Py39 && self.settings.target_version >= PythonVersion::Py37 - && !self.ctx.future_annotations() - && self.ctx.in_annotation() + && !self.model.future_annotations() + && self.model.in_annotation() { flake8_future_annotations::rules::missing_future_annotations( self, expr, @@ -2458,8 +2456,8 @@ where if self.settings.rules.enabled(Rule::NonPEP585Annotation) { if self.settings.target_version >= PythonVersion::Py39 || (self.settings.target_version >= PythonVersion::Py37 - && self.ctx.future_annotations() - && self.ctx.in_annotation()) + && self.model.future_annotations() + && self.model.in_annotation()) { pyupgrade::rules::use_pep585_annotation( self, @@ -2482,7 +2480,7 @@ where } } - if self.ctx.scope().kind.is_class() { + if self.model.scope().kind.is_class() { if self.settings.rules.enabled(Rule::BuiltinAttributeShadowing) { flake8_builtins::rules::builtin_attribute_shadowing(self, id, expr); } @@ -2515,7 +2513,8 @@ where Rule::MissingFutureAnnotationsImport, Rule::NonPEP585Annotation, ]) { - if let Some(replacement) = analyze::typing::to_pep585_generic(expr, &self.ctx) { + if let Some(replacement) = analyze::typing::to_pep585_generic(expr, &self.model) + { if self .settings .rules @@ -2523,8 +2522,8 @@ where { if self.settings.target_version < PythonVersion::Py39 && self.settings.target_version >= PythonVersion::Py37 - && !self.ctx.future_annotations() - && self.ctx.in_annotation() + && !self.model.future_annotations() + && self.model.in_annotation() { flake8_future_annotations::rules::missing_future_annotations( self, expr, @@ -2534,8 +2533,8 @@ where if self.settings.rules.enabled(Rule::NonPEP585Annotation) { if self.settings.target_version >= PythonVersion::Py39 || (self.settings.target_version >= PythonVersion::Py37 - && self.ctx.future_annotations() - && self.ctx.in_annotation()) + && self.model.future_annotations() + && self.model.in_annotation()) { pyupgrade::rules::use_pep585_annotation(self, expr, &replacement); } @@ -2889,7 +2888,7 @@ where flake8_comprehensions::rules::unnecessary_generator_set( self, expr, - self.ctx.expr_parent(), + self.model.expr_parent(), func, args, keywords, @@ -2899,7 +2898,7 @@ where flake8_comprehensions::rules::unnecessary_generator_dict( self, expr, - self.ctx.expr_parent(), + self.model.expr_parent(), func, args, keywords, @@ -3004,7 +3003,7 @@ where flake8_comprehensions::rules::unnecessary_map( self, expr, - self.ctx.expr_parent(), + self.model.expr_parent(), func, args, ); @@ -3031,7 +3030,7 @@ where } if let Expr::Name(ast::ExprName { id, ctx, range: _ }) = func.as_ref() { if id == "locals" && matches!(ctx, ExprContext::Load) { - let scope = self.ctx.scope_mut(); + let scope = self.model.scope_mut(); scope.uses_locals = true; } } @@ -3540,8 +3539,8 @@ where }) => { if self.is_stub { if self.settings.rules.enabled(Rule::DuplicateUnionMember) - && self.ctx.in_type_definition() - && self.ctx.expr_parent().map_or(true, |parent| { + && self.model.in_type_definition() + && self.model.expr_parent().map_or(true, |parent| { !matches!( parent, Expr::BinOp(ast::ExprBinOp { @@ -3691,14 +3690,14 @@ where kind, range: _, }) => { - if self.ctx.in_type_definition() - && !self.ctx.in_literal() - && !self.ctx.in_f_string() + if self.model.in_type_definition() + && !self.model.in_literal() + && !self.model.in_f_string() { self.deferred.string_type_definitions.push(( expr.range(), value, - self.ctx.snapshot(), + self.model.snapshot(), )); } if self @@ -3743,7 +3742,7 @@ where for expr in &args.defaults { self.visit_expr(expr); } - self.ctx + self.model .push_scope(ScopeKind::Lambda(Lambda { args, body })); } Expr::IfExp(ast::ExprIfExp { @@ -3900,7 +3899,7 @@ where self.visit_expr(value); } Expr::Lambda(_) => { - self.deferred.lambdas.push((expr, self.ctx.snapshot())); + self.deferred.lambdas.push((expr, self.model.snapshot())); } Expr::IfExp(ast::ExprIfExp { test, @@ -3918,16 +3917,16 @@ where keywords, range: _, }) => { - let callable = self.ctx.resolve_call_path(func).and_then(|call_path| { - if self.ctx.match_typing_call_path(&call_path, "cast") { + let callable = self.model.resolve_call_path(func).and_then(|call_path| { + if self.model.match_typing_call_path(&call_path, "cast") { Some(Callable::Cast) - } else if self.ctx.match_typing_call_path(&call_path, "NewType") { + } else if self.model.match_typing_call_path(&call_path, "NewType") { Some(Callable::NewType) - } else if self.ctx.match_typing_call_path(&call_path, "TypeVar") { + } else if self.model.match_typing_call_path(&call_path, "TypeVar") { Some(Callable::TypeVar) - } else if self.ctx.match_typing_call_path(&call_path, "NamedTuple") { + } else if self.model.match_typing_call_path(&call_path, "NamedTuple") { Some(Callable::NamedTuple) - } else if self.ctx.match_typing_call_path(&call_path, "TypedDict") { + } else if self.model.match_typing_call_path(&call_path, "TypedDict") { Some(Callable::TypedDict) } else if [ "Arg", @@ -4104,15 +4103,15 @@ where // `obj["foo"]["bar"]`, we need to avoid treating the `obj["foo"]` // portion as an annotation, despite having `ExprContext::Load`. Thus, we track // the `ExprContext` at the top-level. - if self.ctx.in_subscript() { + if self.model.in_subscript() { visitor::walk_expr(self, expr); } else if matches!(ctx, ExprContext::Store | ExprContext::Del) { - self.ctx.flags |= ContextFlags::SUBSCRIPT; + self.model.flags |= ContextFlags::SUBSCRIPT; visitor::walk_expr(self, expr); } else { match analyze::typing::match_annotated_subscript( value, - &self.ctx, + &self.model, self.settings.typing_modules.iter().map(String::as_str), ) { Some(subscript) => { @@ -4155,7 +4154,7 @@ where } } Expr::JoinedStr(_) => { - self.ctx.flags |= ContextFlags::F_STRING; + self.model.flags |= ContextFlags::F_STRING; visitor::walk_expr(self, expr); } _ => visitor::walk_expr(self, expr), @@ -4168,13 +4167,13 @@ where | Expr::ListComp(_) | Expr::DictComp(_) | Expr::SetComp(_) => { - self.ctx.pop_scope(); + self.model.pop_scope(); } _ => {} }; - self.ctx.flags = flags_snapshot; - self.ctx.pop_expr(); + self.model.flags = flags_snapshot; + self.model.pop_expr(); } fn visit_excepthandler(&mut self, excepthandler: &'b Excepthandler) { @@ -4266,7 +4265,7 @@ where let name_range = helpers::excepthandler_name_range(excepthandler, self.locator).unwrap(); - if self.ctx.scope().defines(name) { + if self.model.scope().defines(name) { self.handle_node_store( name, &Expr::Name(ast::ExprName { @@ -4277,7 +4276,7 @@ where ); } - let definition = self.ctx.scope().get(name).copied(); + let definition = self.model.scope().get(name).copied(); self.handle_node_store( name, &Expr::Name(ast::ExprName { @@ -4290,10 +4289,10 @@ where walk_excepthandler(self, excepthandler); if let Some(index) = { - let scope = self.ctx.scope_mut(); + let scope = self.model.scope_mut(); &scope.remove(name) } { - if !self.ctx.bindings[*index].used() { + if !self.model.bindings[*index].used() { if self.settings.rules.enabled(Rule::UnusedVariable) { let mut diagnostic = Diagnostic::new( pyflakes::rules::UnusedVariable { name: name.into() }, @@ -4314,7 +4313,7 @@ where } if let Some(index) = definition { - let scope = self.ctx.scope_mut(); + let scope = self.model.scope_mut(); scope.add(name, index); } } @@ -4392,9 +4391,9 @@ where synthetic_usage: None, typing_usage: None, range: arg.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); @@ -4441,9 +4440,9 @@ where synthetic_usage: None, typing_usage: None, range: pattern.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); } @@ -4456,18 +4455,18 @@ where flake8_pie::rules::no_unnecessary_pass(self, body); } - let prev_body = self.ctx.body; - let prev_body_index = self.ctx.body_index; - self.ctx.body = body; - self.ctx.body_index = 0; + let prev_body = self.model.body; + let prev_body_index = self.model.body_index; + self.model.body = body; + self.model.body_index = 0; for stmt in body { self.visit_stmt(stmt); - self.ctx.body_index += 1; + self.model.body_index += 1; } - self.ctx.body = prev_body; - self.ctx.body_index = prev_body_index; + self.model.body = prev_body; + self.model.body_index = prev_body_index; } } @@ -4518,7 +4517,7 @@ impl<'a> Checker<'a> { // while all subsequent reads and writes are evaluated in the inner scope. In particular, // `x` is local to `foo`, and the `T` in `y=T` skips the class scope when resolving. self.visit_expr(&generator.iter); - self.ctx.push_scope(ScopeKind::Generator); + self.model.push_scope(ScopeKind::Generator); self.visit_expr(&generator.target); for expr in &generator.ifs { self.visit_boolean_test(expr); @@ -4535,56 +4534,56 @@ impl<'a> Checker<'a> { /// Visit an body of [`Stmt`] nodes within a type-checking block. fn visit_type_checking_block(&mut self, body: &'a [Stmt]) { - let snapshot = self.ctx.flags; - self.ctx.flags |= ContextFlags::TYPE_CHECKING_BLOCK; + let snapshot = self.model.flags; + self.model.flags |= ContextFlags::TYPE_CHECKING_BLOCK; self.visit_body(body); - self.ctx.flags = snapshot; + self.model.flags = snapshot; } /// Visit an [`Expr`], and treat it as a type definition. pub(crate) fn visit_type_definition(&mut self, expr: &'a Expr) { - let snapshot = self.ctx.flags; - self.ctx.flags |= ContextFlags::TYPE_DEFINITION; + let snapshot = self.model.flags; + self.model.flags |= ContextFlags::TYPE_DEFINITION; self.visit_expr(expr); - self.ctx.flags = snapshot; + self.model.flags = snapshot; } /// Visit an [`Expr`], and treat it as _not_ a type definition. pub(crate) fn visit_non_type_definition(&mut self, expr: &'a Expr) { - let snapshot = self.ctx.flags; - self.ctx.flags -= ContextFlags::TYPE_DEFINITION; + let snapshot = self.model.flags; + self.model.flags -= ContextFlags::TYPE_DEFINITION; self.visit_expr(expr); - self.ctx.flags = snapshot; + self.model.flags = snapshot; } /// Visit an [`Expr`], and treat it as a boolean test. This is useful for detecting whether an /// expressions return value is significant, or whether the calling context only relies on /// its truthiness. pub(crate) fn visit_boolean_test(&mut self, expr: &'a Expr) { - let snapshot = self.ctx.flags; - self.ctx.flags |= ContextFlags::BOOLEAN_TEST; + let snapshot = self.model.flags; + self.model.flags |= ContextFlags::BOOLEAN_TEST; self.visit_expr(expr); - self.ctx.flags = snapshot; + self.model.flags = snapshot; } /// Add a [`Binding`] to the current scope, bound to the given name. fn add_binding(&mut self, name: &'a str, binding: Binding<'a>) { - let binding_id = self.ctx.bindings.next_id(); + let binding_id = self.model.bindings.next_id(); if let Some((stack_index, existing_binding_id)) = self - .ctx + .model .scopes - .ancestors(self.ctx.scope_id) + .ancestors(self.model.scope_id) .enumerate() .find_map(|(stack_index, scope)| { scope.get(name).map(|binding_id| (stack_index, *binding_id)) }) { - let existing = &self.ctx.bindings[existing_binding_id]; + let existing = &self.model.bindings[existing_binding_id]; let in_current_scope = stack_index == 0; if !existing.kind.is_builtin() && existing.source.map_or(true, |left| { binding.source.map_or(true, |right| { - !branch_detection::different_forks(left, right, &self.ctx.stmts) + !branch_detection::different_forks(left, right, &self.model.stmts) }) }) { @@ -4614,8 +4613,8 @@ impl<'a> Checker<'a> { && (!self.settings.dummy_variable_rgx.is_match(name) || existing_is_import) && !(existing.kind.is_function_definition() && analyze::visibility::is_overload( - &self.ctx, - cast::decorator_list(self.ctx.stmts[existing.source.unwrap()]), + &self.model, + cast::decorator_list(self.model.stmts[existing.source.unwrap()]), )) { if self.settings.rules.enabled(Rule::RedefinedWhileUnused) { @@ -4634,7 +4633,7 @@ impl<'a> Checker<'a> { .then(|| { binding.source.map_or(binding.range, |source| { helpers::identifier_range( - self.ctx.stmts[source], + self.model.stmts[source], self.locator, ) }) @@ -4642,7 +4641,7 @@ impl<'a> Checker<'a> { .unwrap_or(binding.range), ); if let Some(parent) = binding.source { - let parent = self.ctx.stmts[parent]; + let parent = self.model.stmts[parent]; if matches!(parent, Stmt::ImportFrom(_)) && parent.range().contains_range(binding.range) { @@ -4653,7 +4652,7 @@ impl<'a> Checker<'a> { } } } else if existing_is_import && binding.redefines(existing) { - self.ctx + self.model .shadowed_bindings .entry(existing_binding_id) .or_insert_with(Vec::new) @@ -4666,18 +4665,18 @@ impl<'a> Checker<'a> { // expressions in generators and comprehensions bind to the scope that contains the // outermost comprehension. let scope_id = if binding.kind.is_named_expr_assignment() { - self.ctx + self.model .scopes - .ancestor_ids(self.ctx.scope_id) - .find_or_last(|scope_id| !self.ctx.scopes[*scope_id].kind.is_generator()) - .unwrap_or(self.ctx.scope_id) + .ancestor_ids(self.model.scope_id) + .find_or_last(|scope_id| !self.model.scopes[*scope_id].kind.is_generator()) + .unwrap_or(self.model.scope_id) } else { - self.ctx.scope_id + self.model.scope_id }; - let scope = &mut self.ctx.scopes[scope_id]; + let scope = &mut self.model.scopes[scope_id]; let binding = if let Some(index) = scope.get(name) { - let existing = &self.ctx.bindings[*index]; + let existing = &self.model.bindings[*index]; match &existing.kind { BindingKind::Builtin => { // Avoid overriding builtins. @@ -4708,7 +4707,7 @@ impl<'a> Checker<'a> { // Don't treat annotations as assignments if there is an existing value // in scope. if binding.kind.is_annotation() && scope.defines(name) { - self.ctx.bindings.push(binding); + self.model.bindings.push(binding); return; } @@ -4716,11 +4715,11 @@ impl<'a> Checker<'a> { scope.add(name, binding_id); // Add the binding to the arena. - self.ctx.bindings.push(binding); + self.model.bindings.push(binding); } fn bind_builtins(&mut self) { - let scope = &mut self.ctx.scopes[self.ctx.scope_id]; + let scope = &mut self.model.scopes[self.model.scope_id]; for builtin in BUILTINS .iter() @@ -4728,7 +4727,7 @@ impl<'a> Checker<'a> { .copied() .chain(self.settings.builtins.iter().map(String::as_str)) { - let id = self.ctx.bindings.push(Binding { + let id = self.model.bindings.push(Binding { kind: BindingKind::Builtin, range: TextRange::default(), runtime_usage: None, @@ -4746,7 +4745,7 @@ impl<'a> Checker<'a> { let Expr::Name(ast::ExprName { id, .. } )= expr else { return; }; - match self.ctx.resolve_reference(id, expr.range()) { + match self.model.resolve_reference(id, expr.range()) { ResolvedReference::Resolved(..) | ResolvedReference::ImplicitGlobal => { // Nothing to do. } @@ -4758,7 +4757,7 @@ impl<'a> Checker<'a> { .enabled(Rule::UndefinedLocalWithImportStarUsage) { let sources: Vec = self - .ctx + .model .scopes .iter() .flat_map(Scope::star_imports) @@ -4787,7 +4786,7 @@ impl<'a> Checker<'a> { // Avoid flagging if `NameError` is handled. if self - .ctx + .model .handled_exceptions .iter() .any(|handler_names| handler_names.contains(Exceptions::NAME_ERROR)) @@ -4807,7 +4806,7 @@ impl<'a> Checker<'a> { } fn handle_node_store(&mut self, id: &'a str, expr: &Expr) { - let parent = self.ctx.stmt(); + let parent = self.model.stmt(); if self.settings.rules.enabled(Rule::UndefinedLocal) { pyflakes::rules::undefined_local(self, id); @@ -4818,13 +4817,13 @@ impl<'a> Checker<'a> { .rules .enabled(Rule::NonLowercaseVariableInFunction) { - if matches!(self.ctx.scope().kind, ScopeKind::Function(..)) { + if matches!(self.model.scope().kind, ScopeKind::Function(..)) { // Ignore globals. if !self - .ctx + .model .scope() .get(id) - .map_or(false, |index| self.ctx.bindings[*index].kind.is_global()) + .map_or(false, |index| self.model.bindings[*index].kind.is_global()) { pep8_naming::rules::non_lowercase_variable_in_function(self, expr, parent, id); } @@ -4836,7 +4835,7 @@ impl<'a> Checker<'a> { .rules .enabled(Rule::MixedCaseVariableInClassScope) { - if let ScopeKind::Class(class) = &self.ctx.scope().kind { + if let ScopeKind::Class(class) = &self.model.scope().kind { pep8_naming::rules::mixed_case_variable_in_class_scope( self, expr, @@ -4852,7 +4851,7 @@ impl<'a> Checker<'a> { .rules .enabled(Rule::MixedCaseVariableInGlobalScope) { - if matches!(self.ctx.scope().kind, ScopeKind::Module) { + if matches!(self.model.scope().kind, ScopeKind::Module) { pep8_naming::rules::mixed_case_variable_in_global_scope(self, expr, parent, id); } } @@ -4869,9 +4868,9 @@ impl<'a> Checker<'a> { synthetic_usage: None, typing_usage: None, range: expr.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); return; @@ -4886,9 +4885,9 @@ impl<'a> Checker<'a> { synthetic_usage: None, typing_usage: None, range: expr.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); return; @@ -4903,15 +4902,15 @@ impl<'a> Checker<'a> { synthetic_usage: None, typing_usage: None, range: expr.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); return; } - let scope = self.ctx.scope(); + let scope = self.model.scope(); if id == "__all__" && scope.kind.is_module() @@ -4946,13 +4945,13 @@ impl<'a> Checker<'a> { } { let (all_names, all_names_flags) = { let (mut names, flags) = - extract_all_names(parent, |name| self.ctx.is_builtin(name)); + extract_all_names(parent, |name| self.model.is_builtin(name)); // Grab the existing bound __all__ values. if let Stmt::AugAssign(_) = parent { if let Some(index) = scope.get("__all__") { if let BindingKind::Export(Export { names: existing }) = - &self.ctx.bindings[*index].kind + &self.model.bindings[*index].kind { names.extend_from_slice(existing); } @@ -4984,9 +4983,9 @@ impl<'a> Checker<'a> { synthetic_usage: None, typing_usage: None, range: expr.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); return; @@ -4994,7 +4993,7 @@ impl<'a> Checker<'a> { } if self - .ctx + .model .expr_ancestors() .any(|expr| matches!(expr, Expr::NamedExpr(_))) { @@ -5006,9 +5005,9 @@ impl<'a> Checker<'a> { synthetic_usage: None, typing_usage: None, range: expr.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); return; @@ -5022,9 +5021,9 @@ impl<'a> Checker<'a> { synthetic_usage: None, typing_usage: None, range: expr.range(), - source: self.ctx.stmt_id, - context: self.ctx.execution_context(), - exceptions: self.ctx.exceptions(), + source: self.model.stmt_id, + context: self.model.execution_context(), + exceptions: self.model.exceptions(), }, ); } @@ -5033,11 +5032,11 @@ impl<'a> Checker<'a> { let Expr::Name(ast::ExprName { id, .. } )= expr else { return; }; - if helpers::on_conditional_branch(&mut self.ctx.parents()) { + if helpers::on_conditional_branch(&mut self.model.parents()) { return; } - let scope = self.ctx.scope_mut(); + let scope = self.model.scope_mut(); if scope.remove(id.as_str()).is_some() { return; } @@ -5057,9 +5056,9 @@ impl<'a> Checker<'a> { while !self.deferred.future_type_definitions.is_empty() { let type_definitions = std::mem::take(&mut self.deferred.future_type_definitions); for (expr, snapshot) in type_definitions { - self.ctx.restore(snapshot); + self.model.restore(snapshot); - self.ctx.flags |= + self.model.flags |= ContextFlags::TYPE_DEFINITION | ContextFlags::FUTURE_TYPE_DEFINITION; self.visit_expr(expr); } @@ -5073,9 +5072,9 @@ impl<'a> Checker<'a> { if let Ok((expr, kind)) = parse_type_annotation(value, range, self.locator) { let expr = allocator.alloc(expr); - self.ctx.restore(snapshot); + self.model.restore(snapshot); - if self.ctx.in_annotation() && self.ctx.future_annotations() { + if self.model.in_annotation() && self.model.future_annotations() { if self.settings.rules.enabled(Rule::QuotedAnnotation) { pyupgrade::rules::quoted_annotation(self, value, range); } @@ -5091,7 +5090,7 @@ impl<'a> Checker<'a> { AnnotationKind::Complex => ContextFlags::COMPLEX_STRING_TYPE_DEFINITION, }; - self.ctx.flags |= ContextFlags::TYPE_DEFINITION | type_definition_flag; + self.model.flags |= ContextFlags::TYPE_DEFINITION | type_definition_flag; self.visit_expr(expr); } else { if self @@ -5115,9 +5114,9 @@ impl<'a> Checker<'a> { while !self.deferred.functions.is_empty() { let deferred_functions = std::mem::take(&mut self.deferred.functions); for snapshot in deferred_functions { - self.ctx.restore(snapshot); + self.model.restore(snapshot); - match &self.ctx.stmt() { + match &self.model.stmt() { Stmt::FunctionDef(ast::StmtFunctionDef { body, args, .. }) | Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef { body, args, .. }) => { self.visit_arguments(args); @@ -5137,7 +5136,7 @@ impl<'a> Checker<'a> { while !self.deferred.lambdas.is_empty() { let lambdas = std::mem::take(&mut self.deferred.lambdas); for (expr, snapshot) in lambdas { - self.ctx.restore(snapshot); + self.model.restore(snapshot); if let Expr::Lambda(ast::ExprLambda { args, @@ -5160,14 +5159,14 @@ impl<'a> Checker<'a> { while !self.deferred.assignments.is_empty() { let assignments = std::mem::take(&mut self.deferred.assignments); for snapshot in assignments { - self.ctx.restore(snapshot); + self.model.restore(snapshot); // pyflakes if self.settings.rules.enabled(Rule::UnusedVariable) { - pyflakes::rules::unused_variable(self, self.ctx.scope_id); + pyflakes::rules::unused_variable(self, self.model.scope_id); } if self.settings.rules.enabled(Rule::UnusedAnnotation) { - pyflakes::rules::unused_annotation(self, self.ctx.scope_id); + pyflakes::rules::unused_annotation(self, self.model.scope_id); } if !self.is_stub { @@ -5179,14 +5178,14 @@ impl<'a> Checker<'a> { Rule::UnusedStaticMethodArgument, Rule::UnusedLambdaArgument, ]) { - let scope = &self.ctx.scopes[self.ctx.scope_id]; - let parent = &self.ctx.scopes[scope.parent.unwrap()]; + let scope = &self.model.scopes[self.model.scope_id]; + let parent = &self.model.scopes[scope.parent.unwrap()]; self.diagnostics .extend(flake8_unused_arguments::rules::unused_arguments( self, parent, scope, - &self.ctx.bindings, + &self.model.bindings, )); } } @@ -5199,10 +5198,10 @@ impl<'a> Checker<'a> { let for_loops = std::mem::take(&mut self.deferred.for_loops); for snapshot in for_loops { - self.ctx.restore(snapshot); + self.model.restore(snapshot); if let Stmt::For(ast::StmtFor { target, body, .. }) - | Stmt::AsyncFor(ast::StmtAsyncFor { target, body, .. }) = &self.ctx.stmt() + | Stmt::AsyncFor(ast::StmtAsyncFor { target, body, .. }) = &self.model.stmt() { if self.settings.rules.enabled(Rule::UnusedLoopControlVariable) { flake8_bugbear::rules::unused_loop_control_variable(self, target, body); @@ -5237,10 +5236,10 @@ impl<'a> Checker<'a> { // Mark anything referenced in `__all__` as used. let all_bindings: Option<(Vec, TextRange)> = { - let global_scope = self.ctx.global_scope(); + let global_scope = self.model.global_scope(); let all_names: Option<(&[&str], TextRange)> = global_scope .get("__all__") - .map(|index| &self.ctx.bindings[*index]) + .map(|index| &self.model.bindings[*index]) .and_then(|binding| match &binding.kind { BindingKind::Export(Export { names }) => { Some((names.as_slice(), binding.range)) @@ -5261,7 +5260,7 @@ impl<'a> Checker<'a> { if let Some((bindings, range)) = all_bindings { for index in bindings { - self.ctx.bindings[index].mark_used( + self.model.bindings[index].mark_used( ScopeId::global(), range, ExecutionContext::Runtime, @@ -5271,10 +5270,10 @@ impl<'a> Checker<'a> { // Extract `__all__` names from the global scope. let all_names: Option<(&[&str], TextRange)> = self - .ctx + .model .global_scope() .get("__all__") - .map(|index| &self.ctx.bindings[*index]) + .map(|index| &self.model.bindings[*index]) .and_then(|binding| match &binding.kind { BindingKind::Export(Export { names }) => Some((names.as_slice(), binding.range)), _ => None, @@ -5287,13 +5286,13 @@ impl<'a> Checker<'a> { if self.settings.flake8_type_checking.strict { vec![] } else { - self.ctx + self.model .scopes .iter() .map(|scope| { scope .binding_ids() - .map(|index| &self.ctx.bindings[*index]) + .map(|index| &self.model.bindings[*index]) .filter(|binding| { flake8_type_checking::helpers::is_valid_runtime_import(binding) }) @@ -5306,8 +5305,8 @@ impl<'a> Checker<'a> { }; let mut diagnostics: Vec = vec![]; - for scope_id in self.ctx.dead_scopes.iter().rev() { - let scope = &self.ctx.scopes[*scope_id]; + for scope_id in self.model.dead_scopes.iter().rev() { + let scope = &self.model.scopes[*scope_id]; if scope.kind.is_module() { // F822 @@ -5355,10 +5354,10 @@ impl<'a> Checker<'a> { // PLW0602 if self.settings.rules.enabled(Rule::GlobalVariableNotAssigned) { for (name, index) in scope.bindings() { - let binding = &self.ctx.bindings[*index]; + let binding = &self.model.bindings[*index]; if binding.kind.is_global() { if let Some(source) = binding.source { - let stmt = &self.ctx.stmts[source]; + let stmt = &self.model.stmts[source]; if matches!(stmt, Stmt::Global(_)) { diagnostics.push(Diagnostic::new( pylint::rules::GlobalVariableNotAssigned { @@ -5382,7 +5381,7 @@ impl<'a> Checker<'a> { // the bindings are in different scopes. if self.settings.rules.enabled(Rule::RedefinedWhileUnused) { for (name, index) in scope.bindings() { - let binding = &self.ctx.bindings[*index]; + let binding = &self.model.bindings[*index]; if matches!( binding.kind, @@ -5395,9 +5394,9 @@ impl<'a> Checker<'a> { continue; } - if let Some(indices) = self.ctx.shadowed_bindings.get(index) { + if let Some(indices) = self.model.shadowed_bindings.get(index) { for index in indices { - let rebound = &self.ctx.bindings[*index]; + let rebound = &self.model.bindings[*index]; #[allow(deprecated)] let line = self.locator.compute_line_index(binding.range.start()); @@ -5414,7 +5413,7 @@ impl<'a> Checker<'a> { .then(|| { rebound.source.map_or(rebound.range, |source| { helpers::identifier_range( - self.ctx.stmts[source], + self.model.stmts[source], self.locator, ) }) @@ -5422,7 +5421,7 @@ impl<'a> Checker<'a> { .unwrap_or(rebound.range), ); if let Some(source) = rebound.source { - let parent = &self.ctx.stmts[source]; + let parent = &self.model.stmts[source]; if matches!(parent, Stmt::ImportFrom(_)) && parent.range().contains_range(rebound.range) { @@ -5440,7 +5439,7 @@ impl<'a> Checker<'a> { let runtime_imports: Vec<&Binding> = if self.settings.flake8_type_checking.strict { vec![] } else { - self.ctx + self.model .scopes .ancestor_ids(*scope_id) .flat_map(|scope_id| runtime_imports[usize::from(scope_id)].iter()) @@ -5448,7 +5447,7 @@ impl<'a> Checker<'a> { .collect() }; for index in scope.binding_ids() { - let binding = &self.ctx.bindings[*index]; + let binding = &self.model.bindings[*index]; if let Some(diagnostic) = flake8_type_checking::rules::runtime_import_in_type_checking_block(binding) @@ -5483,7 +5482,7 @@ impl<'a> Checker<'a> { FxHashMap::default(); for index in scope.binding_ids() { - let binding = &self.ctx.bindings[*index]; + let binding = &self.model.bindings[*index]; let full_name = match &binding.kind { BindingKind::Importation(Importation { full_name, .. }) => full_name, @@ -5502,11 +5501,11 @@ impl<'a> Checker<'a> { } let child_id = binding.source.unwrap(); - let parent_id = self.ctx.stmts.parent_id(child_id); + let parent_id = self.model.stmts.parent_id(child_id); let exceptions = binding.exceptions; let diagnostic_offset = binding.range.start(); - let child = &self.ctx.stmts[child_id]; + let child = &self.model.stmts[child_id]; let parent_offset = if matches!(child, Stmt::ImportFrom(_)) { Some(child.start()) } else { @@ -5536,8 +5535,8 @@ impl<'a> Checker<'a> { .into_iter() .sorted_by_key(|((defined_by, ..), ..)| *defined_by) { - let child = self.ctx.stmts[defined_by]; - let parent = defined_in.map(|defined_in| self.ctx.stmts[defined_in]); + let child = self.model.stmts[defined_by]; + let parent = defined_in.map(|defined_in| self.model.stmts[defined_in]); let multiple = unused_imports.len() > 1; let in_except_handler = exceptions .intersects(Exceptions::MODULE_NOT_FOUND_ERROR | Exceptions::IMPORT_ERROR); @@ -5598,7 +5597,7 @@ impl<'a> Checker<'a> { .into_iter() .sorted_by_key(|((defined_by, ..), ..)| *defined_by) { - let child = self.ctx.stmts[child]; + let child = self.model.stmts[child]; let multiple = unused_imports.len() > 1; let in_except_handler = exceptions .intersects(Exceptions::MODULE_NOT_FOUND_ERROR | Exceptions::IMPORT_ERROR); @@ -5703,15 +5702,15 @@ impl<'a> Checker<'a> { } // Compute visibility of all definitions. - let global_scope = self.ctx.global_scope(); + let global_scope = self.model.global_scope(); let exports: Option<&[&str]> = global_scope .get("__all__") - .map(|index| &self.ctx.bindings[*index]) + .map(|index| &self.model.bindings[*index]) .and_then(|binding| match &binding.kind { BindingKind::Export(Export { names }) => Some(names.as_slice()), _ => None, }); - let definitions = std::mem::take(&mut self.ctx.definitions); + let definitions = std::mem::take(&mut self.model.definitions); let mut overloaded_name: Option = None; for ContextualizedDefinition { @@ -5964,8 +5963,8 @@ pub(crate) fn check_ast( checker.check_definitions(); // Reset the scope to module-level, and check all consumed scopes. - checker.ctx.scope_id = ScopeId::global(); - checker.ctx.dead_scopes.push(ScopeId::global()); + checker.model.scope_id = ScopeId::global(); + checker.model.dead_scopes.push(ScopeId::global()); checker.check_dead_scopes(); checker.diagnostics diff --git a/crates/ruff/src/docstrings/sections.rs b/crates/ruff/src/docstrings/sections.rs index 46ad1962a6..5c67e8e9de 100644 --- a/crates/ruff/src/docstrings/sections.rs +++ b/crates/ruff/src/docstrings/sections.rs @@ -1,12 +1,14 @@ -use ruff_python_ast::newlines::{StrExt, UniversalNewlineIterator}; -use ruff_text_size::{TextLen, TextRange, TextSize}; use std::fmt::{Debug, Formatter}; use std::iter::FusedIterator; + +use ruff_text_size::{TextLen, TextRange, TextSize}; use strum_macros::EnumIter; +use ruff_python_ast::newlines::{StrExt, UniversalNewlineIterator}; +use ruff_python_ast::whitespace; + use crate::docstrings::styles::SectionStyle; use crate::docstrings::{Docstring, DocstringBody}; -use ruff_python_ast::whitespace; #[derive(EnumIter, PartialEq, Eq, Debug, Clone, Copy)] pub enum SectionKind { diff --git a/crates/ruff/src/flake8_to_ruff/converter.rs b/crates/ruff/src/flake8_to_ruff/converter.rs index 8e54ae57bc..af6d53d680 100644 --- a/crates/ruff/src/flake8_to_ruff/converter.rs +++ b/crates/ruff/src/flake8_to_ruff/converter.rs @@ -3,9 +3,6 @@ use std::collections::{HashMap, HashSet}; use anyhow::Result; use itertools::Itertools; -use super::external_config::ExternalConfig; -use super::plugin::Plugin; -use super::{parser, plugin}; use crate::registry::Linter; use crate::rule_selector::RuleSelector; use crate::rules::flake8_pytest_style::types::{ @@ -23,6 +20,10 @@ use crate::settings::pyproject::Pyproject; use crate::settings::types::PythonVersion; use crate::warn_user; +use super::external_config::ExternalConfig; +use super::plugin::Plugin; +use super::{parser, plugin}; + const DEFAULT_SELECTORS: &[RuleSelector] = &[ RuleSelector::Linter(Linter::Pyflakes), RuleSelector::Linter(Linter::Pycodestyle), @@ -456,8 +457,6 @@ mod tests { use pep440_rs::VersionSpecifiers; use pretty_assertions::assert_eq; - use super::super::plugin::Plugin; - use super::convert; use crate::flake8_to_ruff::converter::DEFAULT_SELECTORS; use crate::flake8_to_ruff::pep621::Project; use crate::flake8_to_ruff::ExternalConfig; @@ -469,6 +468,9 @@ mod tests { use crate::settings::pyproject::Pyproject; use crate::settings::types::PythonVersion; + use super::super::plugin::Plugin; + use super::convert; + fn default_options(plugins: impl IntoIterator) -> Options { Options { ignore: Some(vec![]), diff --git a/crates/ruff/src/flake8_to_ruff/mod.rs b/crates/ruff/src/flake8_to_ruff/mod.rs index 629b4831c2..1b847b97d4 100644 --- a/crates/ruff/src/flake8_to_ruff/mod.rs +++ b/crates/ruff/src/flake8_to_ruff/mod.rs @@ -1,3 +1,8 @@ +pub use converter::convert; +pub use external_config::ExternalConfig; +pub use plugin::Plugin; +pub use pyproject::parse; + mod black; mod converter; mod external_config; @@ -6,8 +11,3 @@ mod parser; pub mod pep621; mod plugin; mod pyproject; - -pub use converter::convert; -pub use external_config::ExternalConfig; -pub use plugin::Plugin; -pub use pyproject::parse; diff --git a/crates/ruff/src/flake8_to_ruff/parser.rs b/crates/ruff/src/flake8_to_ruff/parser.rs index 8e71b8e2ab..5c305aafcd 100644 --- a/crates/ruff/src/flake8_to_ruff/parser.rs +++ b/crates/ruff/src/flake8_to_ruff/parser.rs @@ -195,12 +195,13 @@ pub(crate) fn collect_per_file_ignores( mod tests { use anyhow::Result; - use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings}; use crate::codes; use crate::registry::Linter; use crate::rule_selector::RuleSelector; use crate::settings::types::PatternPrefixPair; + use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings}; + #[test] fn it_parses_prefix_codes() { let actual = parse_prefix_codes(""); diff --git a/crates/ruff/src/importer/insertion.rs b/crates/ruff/src/importer/insertion.rs index 7b3258d6bf..ca715a1d0d 100644 --- a/crates/ruff/src/importer/insertion.rs +++ b/crates/ruff/src/importer/insertion.rs @@ -1,8 +1,8 @@ -use ruff_diagnostics::Edit; use ruff_text_size::TextSize; use rustpython_parser::ast::{Ranged, Stmt}; use rustpython_parser::{lexer, Mode, Tok}; +use ruff_diagnostics::Edit; use ruff_python_ast::helpers::is_docstring_stmt; use ruff_python_ast::source_code::{Locator, Stylist}; diff --git a/crates/ruff/src/jupyter/mod.rs b/crates/ruff/src/jupyter/mod.rs index 92ee1e8a03..ce6b9ef3bc 100644 --- a/crates/ruff/src/jupyter/mod.rs +++ b/crates/ruff/src/jupyter/mod.rs @@ -1,7 +1,7 @@ //! Utils for reading and writing jupyter notebooks -mod notebook; -mod schema; - pub use notebook::*; pub use schema::*; + +mod notebook; +mod schema; diff --git a/crates/ruff/src/jupyter/notebook.rs b/crates/ruff/src/jupyter/notebook.rs index 85a97dd6e6..81a75805d1 100644 --- a/crates/ruff/src/jupyter/notebook.rs +++ b/crates/ruff/src/jupyter/notebook.rs @@ -1,9 +1,9 @@ -use ruff_text_size::TextRange; use std::fs::File; use std::io::{BufReader, BufWriter}; use std::iter; use std::path::Path; +use ruff_text_size::TextRange; use serde::Serialize; use serde_json::error::Category; diff --git a/crates/ruff/src/logging.rs b/crates/ruff/src/logging.rs index dbf719aa80..ede7c8f43b 100644 --- a/crates/ruff/src/logging.rs +++ b/crates/ruff/src/logging.rs @@ -2,15 +2,17 @@ use std::fmt::{Display, Formatter, Write}; use std::path::Path; use std::sync::Mutex; -use crate::fs; use anyhow::Result; use colored::Colorize; use fern; use log::Level; use once_cell::sync::Lazy; -use ruff_python_ast::source_code::SourceCode; use rustpython_parser::{ParseError, ParseErrorType}; +use ruff_python_ast::source_code::SourceCode; + +use crate::fs; + pub(crate) static WARNINGS: Lazy>> = Lazy::new(Mutex::default); /// Warn a user once, with uniqueness determined by the given ID. diff --git a/crates/ruff/src/message/azure.rs b/crates/ruff/src/message/azure.rs index 2f2fd019db..d5119faca0 100644 --- a/crates/ruff/src/message/azure.rs +++ b/crates/ruff/src/message/azure.rs @@ -1,7 +1,9 @@ +use std::io::Write; + +use ruff_python_ast::source_code::SourceLocation; + use crate::message::{Emitter, EmitterContext, Message}; use crate::registry::AsRule; -use ruff_python_ast::source_code::SourceLocation; -use std::io::Write; /// Generate error logging commands for Azure Pipelines format. /// See [documentation](https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#logissue-log-an-error-or-warning) @@ -42,9 +44,10 @@ impl Emitter for AzureEmitter { #[cfg(test)] mod tests { + use insta::assert_snapshot; + use crate::message::tests::{capture_emitter_output, create_messages}; use crate::message::AzureEmitter; - use insta::assert_snapshot; #[test] fn output() { diff --git a/crates/ruff/src/message/diff.rs b/crates/ruff/src/message/diff.rs index d3c56d7d24..9676e20089 100644 --- a/crates/ruff/src/message/diff.rs +++ b/crates/ruff/src/message/diff.rs @@ -1,12 +1,15 @@ -use crate::message::Message; -use colored::{Color, ColoredString, Colorize, Styles}; -use ruff_diagnostics::{Applicability, Fix}; -use ruff_python_ast::source_code::{OneIndexed, SourceFile}; -use ruff_text_size::{TextRange, TextSize}; -use similar::{ChangeTag, TextDiff}; use std::fmt::{Display, Formatter}; use std::num::NonZeroUsize; +use colored::{Color, ColoredString, Colorize, Styles}; +use ruff_text_size::{TextRange, TextSize}; +use similar::{ChangeTag, TextDiff}; + +use ruff_diagnostics::{Applicability, Fix}; +use ruff_python_ast::source_code::{OneIndexed, SourceFile}; + +use crate::message::Message; + /// Renders a diff that shows the code fixes. /// /// The implementation isn't fully fledged out and only used by tests. Before using in production, try diff --git a/crates/ruff/src/message/github.rs b/crates/ruff/src/message/github.rs index ad7b064f27..23ddae5d67 100644 --- a/crates/ruff/src/message/github.rs +++ b/crates/ruff/src/message/github.rs @@ -1,8 +1,10 @@ +use std::io::Write; + +use ruff_python_ast::source_code::SourceLocation; + use crate::fs::relativize_path; use crate::message::{Emitter, EmitterContext, Message}; use crate::registry::AsRule; -use ruff_python_ast::source_code::SourceLocation; -use std::io::Write; /// Generate error workflow command in GitHub Actions format. /// See: [GitHub documentation](https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message) @@ -57,9 +59,10 @@ impl Emitter for GithubEmitter { #[cfg(test)] mod tests { + use insta::assert_snapshot; + use crate::message::tests::{capture_emitter_output, create_messages}; use crate::message::GithubEmitter; - use insta::assert_snapshot; #[test] fn output() { diff --git a/crates/ruff/src/message/gitlab.rs b/crates/ruff/src/message/gitlab.rs index 355bdf0dbd..8538245b39 100644 --- a/crates/ruff/src/message/gitlab.rs +++ b/crates/ruff/src/message/gitlab.rs @@ -1,14 +1,17 @@ -use crate::fs::{relativize_path, relativize_path_to}; -use crate::message::{Emitter, EmitterContext, Message}; -use crate::registry::AsRule; -use ruff_python_ast::source_code::SourceLocation; -use serde::ser::SerializeSeq; -use serde::{Serialize, Serializer}; -use serde_json::json; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::io::Write; +use serde::ser::SerializeSeq; +use serde::{Serialize, Serializer}; +use serde_json::json; + +use ruff_python_ast::source_code::SourceLocation; + +use crate::fs::{relativize_path, relativize_path_to}; +use crate::message::{Emitter, EmitterContext, Message}; +use crate::registry::AsRule; + /// Generate JSON with violations in GitLab CI format // https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool pub struct GitlabEmitter { @@ -122,9 +125,10 @@ fn fingerprint( #[cfg(test)] mod tests { + use insta::assert_snapshot; + use crate::message::tests::{capture_emitter_output, create_messages}; use crate::message::GitlabEmitter; - use insta::assert_snapshot; #[test] fn output() { diff --git a/crates/ruff/src/message/grouped.rs b/crates/ruff/src/message/grouped.rs index 444fd5563a..44dc4b39c6 100644 --- a/crates/ruff/src/message/grouped.rs +++ b/crates/ruff/src/message/grouped.rs @@ -1,3 +1,11 @@ +use std::fmt::{Display, Formatter}; +use std::io::Write; +use std::num::NonZeroUsize; + +use colored::Colorize; + +use ruff_python_ast::source_code::OneIndexed; + use crate::fs::relativize_path; use crate::jupyter::JupyterIndex; use crate::message::diff::calculate_print_width; @@ -5,11 +13,6 @@ use crate::message::text::{MessageCodeFrame, RuleCodeAndBody}; use crate::message::{ group_messages_by_filename, Emitter, EmitterContext, Message, MessageWithLocation, }; -use colored::Colorize; -use ruff_python_ast::source_code::OneIndexed; -use std::fmt::{Display, Formatter}; -use std::io::Write; -use std::num::NonZeroUsize; #[derive(Default)] pub struct GroupedEmitter { @@ -175,9 +178,10 @@ impl std::fmt::Write for PadAdapter<'_> { #[cfg(test)] mod tests { + use insta::assert_snapshot; + use crate::message::tests::{capture_emitter_output, create_messages}; use crate::message::GroupedEmitter; - use insta::assert_snapshot; #[test] fn default() { diff --git a/crates/ruff/src/message/json.rs b/crates/ruff/src/message/json.rs index 623501bf23..c3adda51ba 100644 --- a/crates/ruff/src/message/json.rs +++ b/crates/ruff/src/message/json.rs @@ -1,11 +1,14 @@ -use crate::message::{Emitter, EmitterContext, Message}; -use crate::registry::AsRule; -use ruff_diagnostics::Edit; -use ruff_python_ast::source_code::SourceCode; +use std::io::Write; + use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; use serde_json::json; -use std::io::Write; + +use ruff_diagnostics::Edit; +use ruff_python_ast::source_code::SourceCode; + +use crate::message::{Emitter, EmitterContext, Message}; +use crate::registry::AsRule; #[derive(Default)] pub struct JsonEmitter; @@ -94,9 +97,10 @@ impl Serialize for ExpandedEdits<'_> { #[cfg(test)] mod tests { + use insta::assert_snapshot; + use crate::message::tests::{capture_emitter_output, create_messages}; use crate::message::JsonEmitter; - use insta::assert_snapshot; #[test] fn output() { diff --git a/crates/ruff/src/message/junit.rs b/crates/ruff/src/message/junit.rs index acef3344f8..f910b7e6ed 100644 --- a/crates/ruff/src/message/junit.rs +++ b/crates/ruff/src/message/junit.rs @@ -1,11 +1,14 @@ +use std::io::Write; +use std::path::Path; + +use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite}; + +use ruff_python_ast::source_code::SourceLocation; + use crate::message::{ group_messages_by_filename, Emitter, EmitterContext, Message, MessageWithLocation, }; use crate::registry::AsRule; -use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite}; -use ruff_python_ast::source_code::SourceLocation; -use std::io::Write; -use std::path::Path; #[derive(Default)] pub struct JunitEmitter; @@ -83,9 +86,10 @@ impl Emitter for JunitEmitter { #[cfg(test)] mod tests { + use insta::assert_snapshot; + use crate::message::tests::{capture_emitter_output, create_messages}; use crate::message::JunitEmitter; - use insta::assert_snapshot; #[test] fn output() { diff --git a/crates/ruff/src/message/mod.rs b/crates/ruff/src/message/mod.rs index 82f063ad6c..5b28212741 100644 --- a/crates/ruff/src/message/mod.rs +++ b/crates/ruff/src/message/mod.rs @@ -1,3 +1,25 @@ +use std::cmp::Ordering; +use std::collections::BTreeMap; +use std::io::Write; +use std::ops::Deref; + +use ruff_text_size::{TextRange, TextSize}; +use rustc_hash::FxHashMap; + +pub use azure::AzureEmitter; +pub use github::GithubEmitter; +pub use gitlab::GitlabEmitter; +pub use grouped::GroupedEmitter; +pub use json::JsonEmitter; +pub use junit::JunitEmitter; +pub use pylint::PylintEmitter; +use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix}; +use ruff_python_ast::source_code::{SourceFile, SourceLocation}; +pub use text::TextEmitter; + +use crate::jupyter::JupyterIndex; +use crate::registry::AsRule; + mod azure; mod diff; mod github; @@ -8,27 +30,6 @@ mod junit; mod pylint; mod text; -use ruff_text_size::{TextRange, TextSize}; -use rustc_hash::FxHashMap; -use std::cmp::Ordering; -use std::collections::BTreeMap; -use std::io::Write; -use std::ops::Deref; - -pub use azure::AzureEmitter; -pub use github::GithubEmitter; -pub use gitlab::GitlabEmitter; -pub use grouped::GroupedEmitter; -pub use json::JsonEmitter; -pub use junit::JunitEmitter; -pub use pylint::PylintEmitter; -pub use text::TextEmitter; - -use crate::jupyter::JupyterIndex; -use crate::registry::AsRule; -use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix}; -use ruff_python_ast::source_code::{SourceFile, SourceLocation}; - #[derive(Debug, PartialEq, Eq)] pub struct Message { pub kind: DiagnosticKind, @@ -152,13 +153,15 @@ impl<'a> EmitterContext<'a> { #[cfg(test)] mod tests { - use crate::message::{Emitter, EmitterContext, Message}; - use crate::rules::pyflakes::rules::{UndefinedName, UnusedImport, UnusedVariable}; - use ruff_diagnostics::{Diagnostic, Edit, Fix}; - use ruff_python_ast::source_code::SourceFileBuilder; use ruff_text_size::{TextRange, TextSize}; use rustc_hash::FxHashMap; + use ruff_diagnostics::{Diagnostic, Edit, Fix}; + use ruff_python_ast::source_code::SourceFileBuilder; + + use crate::message::{Emitter, EmitterContext, Message}; + use crate::rules::pyflakes::rules::{UndefinedName, UnusedImport, UnusedVariable}; + pub(super) fn create_messages() -> Vec { let fib = r#"import os diff --git a/crates/ruff/src/message/pylint.rs b/crates/ruff/src/message/pylint.rs index d456fa6e10..edede90422 100644 --- a/crates/ruff/src/message/pylint.rs +++ b/crates/ruff/src/message/pylint.rs @@ -1,8 +1,10 @@ +use std::io::Write; + +use ruff_python_ast::source_code::OneIndexed; + use crate::fs::relativize_path; use crate::message::{Emitter, EmitterContext, Message}; use crate::registry::AsRule; -use ruff_python_ast::source_code::OneIndexed; -use std::io::Write; /// Generate violations in Pylint format. /// See: [Flake8 documentation](https://flake8.pycqa.org/en/latest/internal/formatters.html#pylint-formatter) @@ -40,9 +42,10 @@ impl Emitter for PylintEmitter { #[cfg(test)] mod tests { + use insta::assert_snapshot; + use crate::message::tests::{capture_emitter_output, create_messages}; use crate::message::PylintEmitter; - use insta::assert_snapshot; #[test] fn output() { diff --git a/crates/ruff/src/message/text.rs b/crates/ruff/src/message/text.rs index 23249499ed..f19b0f03ea 100644 --- a/crates/ruff/src/message/text.rs +++ b/crates/ruff/src/message/text.rs @@ -1,16 +1,19 @@ -use crate::fs::relativize_path; -use crate::message::diff::Diff; -use crate::message::{Emitter, EmitterContext, Message}; -use crate::registry::AsRule; +use std::borrow::Cow; +use std::fmt::{Display, Formatter}; +use std::io::Write; + use annotate_snippets::display_list::{DisplayList, FormatOptions}; use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; use bitflags::bitflags; use colored::Colorize; -use ruff_python_ast::source_code::{OneIndexed, SourceLocation}; use ruff_text_size::{TextRange, TextSize}; -use std::borrow::Cow; -use std::fmt::{Display, Formatter}; -use std::io::Write; + +use ruff_python_ast::source_code::{OneIndexed, SourceLocation}; + +use crate::fs::relativize_path; +use crate::message::diff::Diff; +use crate::message::{Emitter, EmitterContext, Message}; +use crate::registry::AsRule; bitflags! { #[derive(Default)] @@ -292,9 +295,10 @@ struct SourceCode<'a> { #[cfg(test)] mod tests { + use insta::assert_snapshot; + use crate::message::tests::{capture_emitter_output, create_messages}; use crate::message::TextEmitter; - use insta::assert_snapshot; #[test] fn default() { diff --git a/crates/ruff/src/registry.rs b/crates/ruff/src/registry.rs index 803157879a..315d66ec66 100644 --- a/crates/ruff/src/registry.rs +++ b/crates/ruff/src/registry.rs @@ -1,15 +1,15 @@ //! Registry of all [`Rule`] implementations. -mod rule_set; - use strum_macros::{AsRefStr, EnumIter}; use ruff_diagnostics::Violation; use ruff_macros::RuleNamespace; +pub use rule_set::{RuleSet, RuleSetIterator}; use crate::codes::{self, RuleCodePrefix}; use crate::rules; -pub use rule_set::{RuleSet, RuleSetIterator}; + +mod rule_set; ruff_macros::register_rules!( // pycodestyle errors @@ -1003,6 +1003,7 @@ pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str); 2] = &[ #[cfg(test)] mod tests { use std::mem::size_of; + use strum::IntoEnumIterator; use super::{Linter, Rule, RuleNamespace}; diff --git a/crates/ruff/src/rules/eradicate/mod.rs b/crates/ruff/src/rules/eradicate/mod.rs index b355e2bda3..3f26ac808e 100644 --- a/crates/ruff/src/rules/eradicate/mod.rs +++ b/crates/ruff/src/rules/eradicate/mod.rs @@ -7,7 +7,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_2020/mod.rs b/crates/ruff/src/rules/flake8_2020/mod.rs index b34b124e70..3bf933c433 100644 --- a/crates/ruff/src/rules/flake8_2020/mod.rs +++ b/crates/ruff/src/rules/flake8_2020/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_2020/rules.rs b/crates/ruff/src/rules/flake8_2020/rules.rs index bd19cccd91..7f4a92b881 100644 --- a/crates/ruff/src/rules/flake8_2020/rules.rs +++ b/crates/ruff/src/rules/flake8_2020/rules.rs @@ -115,7 +115,7 @@ impl Violation for SysVersionSlice1 { fn is_sys(checker: &Checker, expr: &Expr, target: &str) -> bool { checker - .ctx + .model .resolve_call_path(expr) .map_or(false, |call_path| call_path.as_slice() == ["sys", target]) } @@ -272,7 +272,7 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara /// YTT202 pub(crate) fn name_or_attribute(checker: &mut Checker, expr: &Expr) { if checker - .ctx + .model .resolve_call_path(expr) .map_or(false, |call_path| call_path.as_slice() == ["six", "PY3"]) { diff --git a/crates/ruff/src/rules/flake8_annotations/helpers.rs b/crates/ruff/src/rules/flake8_annotations/helpers.rs index 6abc9efd4c..93c0c8e146 100644 --- a/crates/ruff/src/rules/flake8_annotations/helpers.rs +++ b/crates/ruff/src/rules/flake8_annotations/helpers.rs @@ -44,7 +44,7 @@ pub(crate) fn overloaded_name(checker: &Checker, definition: &Definition) -> Opt .. }) = definition { - if visibility::is_overload(&checker.ctx, cast::decorator_list(stmt)) { + if visibility::is_overload(&checker.model, cast::decorator_list(stmt)) { let (name, ..) = match_function_def(stmt); Some(name.to_string()) } else { @@ -68,7 +68,7 @@ pub(crate) fn is_overload_impl( .. }) = definition { - if visibility::is_overload(&checker.ctx, cast::decorator_list(stmt)) { + if visibility::is_overload(&checker.model, cast::decorator_list(stmt)) { false } else { let (name, ..) = match_function_def(stmt); diff --git a/crates/ruff/src/rules/flake8_annotations/mod.rs b/crates/ruff/src/rules/flake8_annotations/mod.rs index ecfab2d4be..9928a48fb1 100644 --- a/crates/ruff/src/rules/flake8_annotations/mod.rs +++ b/crates/ruff/src/rules/flake8_annotations/mod.rs @@ -8,9 +8,9 @@ pub mod settings; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::test_path; diff --git a/crates/ruff/src/rules/flake8_annotations/rules.rs b/crates/ruff/src/rules/flake8_annotations/rules.rs index 93a43f858e..132cfae00c 100644 --- a/crates/ruff/src/rules/flake8_annotations/rules.rs +++ b/crates/ruff/src/rules/flake8_annotations/rules.rs @@ -438,7 +438,7 @@ fn check_dynamically_typed( ) where F: FnOnce() -> String, { - if !is_overridden && checker.ctx.match_typing_expr(annotation, "Any") { + if !is_overridden && checker.model.match_typing_expr(annotation, "Any") { diagnostics.push(Diagnostic::new( AnyType { name: func() }, annotation.range(), @@ -479,7 +479,7 @@ pub(crate) fn definition( // unless configured to suppress ANN* for declarations that are fully untyped. let mut diagnostics = Vec::new(); - let is_overridden = visibility::is_override(&checker.ctx, decorator_list); + let is_overridden = visibility::is_override(&checker.model, decorator_list); // ANN001, ANN401 for arg in args @@ -490,7 +490,8 @@ pub(crate) fn definition( .skip( // If this is a non-static method, skip `cls` or `self`. usize::from( - is_method && !visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt)), + is_method + && !visibility::is_staticmethod(&checker.model, cast::decorator_list(stmt)), ), ) { @@ -591,10 +592,10 @@ pub(crate) fn definition( } // ANN101, ANN102 - if is_method && !visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt)) { + if is_method && !visibility::is_staticmethod(&checker.model, cast::decorator_list(stmt)) { if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) { if arg.annotation.is_none() { - if visibility::is_classmethod(&checker.ctx, cast::decorator_list(stmt)) { + if visibility::is_classmethod(&checker.model, cast::decorator_list(stmt)) { if checker.settings.rules.enabled(Rule::MissingTypeCls) { diagnostics.push(Diagnostic::new( MissingTypeCls { @@ -636,7 +637,7 @@ pub(crate) fn definition( // (explicitly or implicitly). checker.settings.flake8_annotations.suppress_none_returning && is_none_returning(body) ) { - if is_method && visibility::is_classmethod(&checker.ctx, cast::decorator_list(stmt)) { + if is_method && visibility::is_classmethod(&checker.model, cast::decorator_list(stmt)) { if checker .settings .rules @@ -649,7 +650,8 @@ pub(crate) fn definition( helpers::identifier_range(stmt, checker.locator), )); } - } else if is_method && visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt)) + } else if is_method + && visibility::is_staticmethod(&checker.model, cast::decorator_list(stmt)) { if checker .settings diff --git a/crates/ruff/src/rules/flake8_async/rules.rs b/crates/ruff/src/rules/flake8_async/rules.rs index 69abff7291..9622d35f35 100644 --- a/crates/ruff/src/rules/flake8_async/rules.rs +++ b/crates/ruff/src/rules/flake8_async/rules.rs @@ -3,7 +3,7 @@ use rustpython_parser::ast::{Expr, Ranged}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use ruff_python_semantic::scope::{FunctionDef, ScopeKind}; use crate::checkers::ast::Checker; @@ -66,9 +66,9 @@ const BLOCKING_HTTP_CALLS: &[&[&str]] = &[ /// ASYNC100 pub(crate) fn blocking_http_call(checker: &mut Checker, expr: &Expr) { - if in_async_function(&checker.ctx) { + if in_async_function(&checker.model) { if let Expr::Call(ast::ExprCall { func, .. }) = expr { - if let Some(call_path) = checker.ctx.resolve_call_path(func) { + if let Some(call_path) = checker.model.resolve_call_path(func) { if BLOCKING_HTTP_CALLS.contains(&call_path.as_slice()) { checker.diagnostics.push(Diagnostic::new( BlockingHttpCallInAsyncFunction, @@ -133,9 +133,9 @@ const OPEN_SLEEP_OR_SUBPROCESS_CALL: &[&[&str]] = &[ /// ASYNC101 pub(crate) fn open_sleep_or_subprocess_call(checker: &mut Checker, expr: &Expr) { - if in_async_function(&checker.ctx) { + if in_async_function(&checker.model) { if let Expr::Call(ast::ExprCall { func, .. }) = expr { - if let Some(call_path) = checker.ctx.resolve_call_path(func) { + if let Some(call_path) = checker.model.resolve_call_path(func) { if OPEN_SLEEP_OR_SUBPROCESS_CALL.contains(&call_path.as_slice()) { checker.diagnostics.push(Diagnostic::new( OpenSleepOrSubprocessInAsyncFunction, @@ -197,9 +197,9 @@ const UNSAFE_OS_METHODS: &[&[&str]] = &[ /// ASYNC102 pub(crate) fn blocking_os_call(checker: &mut Checker, expr: &Expr) { - if in_async_function(&checker.ctx) { + if in_async_function(&checker.model) { if let Expr::Call(ast::ExprCall { func, .. }) = expr { - if let Some(call_path) = checker.ctx.resolve_call_path(func) { + if let Some(call_path) = checker.model.resolve_call_path(func) { if UNSAFE_OS_METHODS.contains(&call_path.as_slice()) { checker .diagnostics @@ -210,9 +210,9 @@ pub(crate) fn blocking_os_call(checker: &mut Checker, expr: &Expr) { } } -/// Return `true` if the [`Context`] is inside an async function definition. -fn in_async_function(context: &Context) -> bool { - context +/// Return `true` if the [`SemanticModel`] is inside an async function definition. +fn in_async_function(model: &SemanticModel) -> bool { + model .scopes() .find_map(|scope| { if let ScopeKind::Function(FunctionDef { async_, .. }) = &scope.kind { diff --git a/crates/ruff/src/rules/flake8_bandit/helpers.rs b/crates/ruff/src/rules/flake8_bandit/helpers.rs index 3158586e6b..ee7a4b46ae 100644 --- a/crates/ruff/src/rules/flake8_bandit/helpers.rs +++ b/crates/ruff/src/rules/flake8_bandit/helpers.rs @@ -27,7 +27,7 @@ pub(crate) fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> b if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &type_ { elts.iter().any(|type_| { checker - .ctx + .model .resolve_call_path(type_) .map_or(false, |call_path| { call_path.as_slice() == ["", "Exception"] @@ -36,7 +36,7 @@ pub(crate) fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> b }) } else { checker - .ctx + .model .resolve_call_path(type_) .map_or(false, |call_path| { call_path.as_slice() == ["", "Exception"] diff --git a/crates/ruff/src/rules/flake8_bandit/mod.rs b/crates/ruff/src/rules/flake8_bandit/mod.rs index 6cfa043884..fc7e2b6e28 100644 --- a/crates/ruff/src/rules/flake8_bandit/mod.rs +++ b/crates/ruff/src/rules/flake8_bandit/mod.rs @@ -7,11 +7,10 @@ pub mod settings; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; - use test_case::test_case; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::test_path; diff --git a/crates/ruff/src/rules/flake8_bandit/rules/bad_file_permissions.rs b/crates/ruff/src/rules/flake8_bandit/rules/bad_file_permissions.rs index 95e0d89807..2b5463dcae 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/bad_file_permissions.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/bad_file_permissions.rs @@ -108,7 +108,7 @@ pub(crate) fn bad_file_permissions( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["os", "chmod"]) { diff --git a/crates/ruff/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs b/crates/ruff/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs index 47057ee468..86f68e10b8 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs @@ -1,6 +1,7 @@ +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::TextRange; #[violation] pub struct HardcodedBindAllInterfaces; diff --git a/crates/ruff/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs b/crates/ruff/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs index b0b6e60c22..1b7cabb0ba 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs @@ -60,7 +60,7 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio op: Operator::Add | Operator::Mod, .. }) => { - let Some(parent) = checker.ctx.expr_parent() else { + let Some(parent) = checker.model.expr_parent() else { if any_over_expr(expr, &has_string_literal) { return Some(checker.generator().expr(expr)); } diff --git a/crates/ruff/src/rules/flake8_bandit/rules/hashlib_insecure_hash_functions.rs b/crates/ruff/src/rules/flake8_bandit/rules/hashlib_insecure_hash_functions.rs index ff6dcd88a9..9edb3fb423 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/hashlib_insecure_hash_functions.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/hashlib_insecure_hash_functions.rs @@ -48,7 +48,7 @@ pub(crate) fn hashlib_insecure_hash_functions( args: &[Expr], keywords: &[Keyword], ) { - if let Some(hashlib_call) = checker.ctx.resolve_call_path(func).and_then(|call_path| { + if let Some(hashlib_call) = checker.model.resolve_call_path(func).and_then(|call_path| { if call_path.as_slice() == ["hashlib", "new"] { Some(HashlibCall::New) } else { diff --git a/crates/ruff/src/rules/flake8_bandit/rules/jinja2_autoescape_false.rs b/crates/ruff/src/rules/flake8_bandit/rules/jinja2_autoescape_false.rs index 2855cd5022..43a1c41ed8 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/jinja2_autoescape_false.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/jinja2_autoescape_false.rs @@ -37,7 +37,7 @@ pub(crate) fn jinja2_autoescape_false( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["jinja2", "Environment"] diff --git a/crates/ruff/src/rules/flake8_bandit/rules/logging_config_insecure_listen.rs b/crates/ruff/src/rules/flake8_bandit/rules/logging_config_insecure_listen.rs index 762e6093f9..d2a6c408c3 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/logging_config_insecure_listen.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/logging_config_insecure_listen.rs @@ -24,7 +24,7 @@ pub(crate) fn logging_config_insecure_listen( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["logging", "config", "listen"] diff --git a/crates/ruff/src/rules/flake8_bandit/rules/paramiko_calls.rs b/crates/ruff/src/rules/flake8_bandit/rules/paramiko_calls.rs index 09995a400a..28520da8d6 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/paramiko_calls.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/paramiko_calls.rs @@ -18,7 +18,7 @@ impl Violation for ParamikoCall { /// S601 pub(crate) fn paramiko_call(checker: &mut Checker, func: &Expr) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["paramiko", "exec_command"] diff --git a/crates/ruff/src/rules/flake8_bandit/rules/request_with_no_cert_validation.rs b/crates/ruff/src/rules/flake8_bandit/rules/request_with_no_cert_validation.rs index 9870928984..4fab850708 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/request_with_no_cert_validation.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/request_with_no_cert_validation.rs @@ -43,7 +43,7 @@ pub(crate) fn request_with_no_cert_validation( args: &[Expr], keywords: &[Keyword], ) { - if let Some(target) = checker.ctx.resolve_call_path(func).and_then(|call_path| { + if let Some(target) = checker.model.resolve_call_path(func).and_then(|call_path| { if call_path.len() == 2 { if call_path[0] == "requests" && REQUESTS_HTTP_VERBS.contains(&call_path[1]) { return Some("requests"); diff --git a/crates/ruff/src/rules/flake8_bandit/rules/request_without_timeout.rs b/crates/ruff/src/rules/flake8_bandit/rules/request_without_timeout.rs index fee08cd188..dff91da386 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/request_without_timeout.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/request_without_timeout.rs @@ -34,7 +34,7 @@ pub(crate) fn request_without_timeout( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { HTTP_VERBS diff --git a/crates/ruff/src/rules/flake8_bandit/rules/shell_injection.rs b/crates/ruff/src/rules/flake8_bandit/rules/shell_injection.rs index b571173c19..a4d12ba1e6 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/shell_injection.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/shell_injection.rs @@ -7,7 +7,7 @@ use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::Truthiness; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::{ checkers::ast::Checker, registry::Rule, rules::flake8_bandit::helpers::string_literal, @@ -97,8 +97,8 @@ enum CallKind { } /// Return the [`CallKind`] of the given function call. -fn get_call_kind(func: &Expr, context: &Context) -> Option { - context +fn get_call_kind(func: &Expr, model: &SemanticModel) -> Option { + model .resolve_call_path(func) .and_then(|call_path| match call_path.as_slice() { &[module, submodule] => match module { @@ -138,12 +138,15 @@ struct ShellKeyword<'a> { } /// Return the `shell` keyword argument to the given function call, if any. -fn find_shell_keyword<'a>(ctx: &Context, keywords: &'a [Keyword]) -> Option> { +fn find_shell_keyword<'a>( + model: &SemanticModel, + keywords: &'a [Keyword], +) -> Option> { keywords .iter() .find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "shell")) .map(|keyword| ShellKeyword { - truthiness: Truthiness::from_expr(&keyword.value, |id| ctx.is_builtin(id)), + truthiness: Truthiness::from_expr(&keyword.value, |id| model.is_builtin(id)), keyword, }) } @@ -181,11 +184,11 @@ pub(crate) fn shell_injection( args: &[Expr], keywords: &[Keyword], ) { - let call_kind = get_call_kind(func, &checker.ctx); + let call_kind = get_call_kind(func, &checker.model); if matches!(call_kind, Some(CallKind::Subprocess)) { if let Some(arg) = args.first() { - match find_shell_keyword(&checker.ctx, keywords) { + match find_shell_keyword(&checker.model, keywords) { // S602 Some(ShellKeyword { truthiness: Truthiness::Truthy, @@ -238,7 +241,7 @@ pub(crate) fn shell_injection( } else if let Some(ShellKeyword { truthiness: Truthiness::Truthy, keyword, - }) = find_shell_keyword(&checker.ctx, keywords) + }) = find_shell_keyword(&checker.model, keywords) { // S604 if checker diff --git a/crates/ruff/src/rules/flake8_bandit/rules/snmp_insecure_version.rs b/crates/ruff/src/rules/flake8_bandit/rules/snmp_insecure_version.rs index 2add3b236f..dc3897459c 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/snmp_insecure_version.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/snmp_insecure_version.rs @@ -25,7 +25,7 @@ pub(crate) fn snmp_insecure_version( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["pysnmp", "hlapi", "CommunityData"] diff --git a/crates/ruff/src/rules/flake8_bandit/rules/snmp_weak_cryptography.rs b/crates/ruff/src/rules/flake8_bandit/rules/snmp_weak_cryptography.rs index 68d6e09d1a..03ab93e936 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/snmp_weak_cryptography.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/snmp_weak_cryptography.rs @@ -27,7 +27,7 @@ pub(crate) fn snmp_weak_cryptography( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["pysnmp", "hlapi", "UsmUserData"] diff --git a/crates/ruff/src/rules/flake8_bandit/rules/suspicious_function_call.rs b/crates/ruff/src/rules/flake8_bandit/rules/suspicious_function_call.rs index c0eb38e09a..b139a4f80e 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/suspicious_function_call.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/suspicious_function_call.rs @@ -470,7 +470,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, expr: &Expr) { return; }; - let Some(reason) = checker.ctx.resolve_call_path(func).and_then(|call_path| { + let Some(reason) = checker.model.resolve_call_path(func).and_then(|call_path| { for module in SUSPICIOUS_MEMBERS { for member in module.members { if call_path.as_slice() == *member { diff --git a/crates/ruff/src/rules/flake8_bandit/rules/unsafe_yaml_load.rs b/crates/ruff/src/rules/flake8_bandit/rules/unsafe_yaml_load.rs index f25b242026..34b90467be 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/unsafe_yaml_load.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/unsafe_yaml_load.rs @@ -38,14 +38,14 @@ pub(crate) fn unsafe_yaml_load( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["yaml", "load"]) { let call_args = SimpleCallArgs::new(args, keywords); if let Some(loader_arg) = call_args.argument("Loader", 1) { if !checker - .ctx + .model .resolve_call_path(loader_arg) .map_or(false, |call_path| { call_path.as_slice() == ["yaml", "SafeLoader"] diff --git a/crates/ruff/src/rules/flake8_blind_except/mod.rs b/crates/ruff/src/rules/flake8_blind_except/mod.rs index ba972c8471..1ade0f4092 100644 --- a/crates/ruff/src/rules/flake8_blind_except/mod.rs +++ b/crates/ruff/src/rules/flake8_blind_except/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_blind_except/rules.rs b/crates/ruff/src/rules/flake8_blind_except/rules.rs index 6837e1d3c5..28680567c6 100644 --- a/crates/ruff/src/rules/flake8_blind_except/rules.rs +++ b/crates/ruff/src/rules/flake8_blind_except/rules.rs @@ -34,7 +34,7 @@ pub(crate) fn blind_except( return; }; for exception in ["BaseException", "Exception"] { - if id == exception && checker.ctx.is_builtin(exception) { + if id == exception && checker.model.is_builtin(exception) { // If the exception is re-raised, don't flag an error. if body.iter().any(|stmt| { if let Stmt::Raise(ast::StmtRaise { exc, .. }) = stmt { @@ -58,7 +58,7 @@ pub(crate) fn blind_except( if body.iter().any(|stmt| { if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt { if let Expr::Call(ast::ExprCall { func, keywords, .. }) = value.as_ref() { - if logging::is_logger_candidate(&checker.ctx, func) { + if logging::is_logger_candidate(&checker.model, func) { if let Some(attribute) = func.as_attribute_expr() { let attr = attribute.attr.as_str(); if attr == "exception" { diff --git a/crates/ruff/src/rules/flake8_boolean_trap/mod.rs b/crates/ruff/src/rules/flake8_boolean_trap/mod.rs index a90031bcee..84ad7a7caf 100644 --- a/crates/ruff/src/rules/flake8_boolean_trap/mod.rs +++ b/crates/ruff/src/rules/flake8_boolean_trap/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_bugbear/mod.rs b/crates/ruff/src/rules/flake8_bugbear/mod.rs index a25369f284..386b591a8f 100644 --- a/crates/ruff/src/rules/flake8_bugbear/mod.rs +++ b/crates/ruff/src/rules/flake8_bugbear/mod.rs @@ -6,11 +6,10 @@ pub mod settings; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; - use test_case::test_case; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::test_path; diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs b/crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs index fcc849b2b6..305685722b 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs @@ -3,7 +3,7 @@ use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_semantic::analyze::visibility::{is_abstract, is_overload}; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; use crate::registry::Rule; @@ -35,16 +35,16 @@ impl Violation for EmptyMethodWithoutAbstractDecorator { } } -fn is_abc_class(context: &Context, bases: &[Expr], keywords: &[Keyword]) -> bool { +fn is_abc_class(model: &SemanticModel, bases: &[Expr], keywords: &[Keyword]) -> bool { keywords.iter().any(|keyword| { keyword.arg.as_ref().map_or(false, |arg| arg == "metaclass") - && context + && model .resolve_call_path(&keyword.value) .map_or(false, |call_path| { call_path.as_slice() == ["abc", "ABCMeta"] }) }) || bases.iter().any(|base| { - context + model .resolve_call_path(base) .map_or(false, |call_path| call_path.as_slice() == ["abc", "ABC"]) }) @@ -79,7 +79,7 @@ pub(crate) fn abstract_base_class( if bases.len() + keywords.len() != 1 { return; } - if !is_abc_class(&checker.ctx, bases, keywords) { + if !is_abc_class(&checker.model, bases, keywords) { return; } @@ -108,7 +108,7 @@ pub(crate) fn abstract_base_class( continue; }; - let has_abstract_decorator = is_abstract(&checker.ctx, decorator_list); + let has_abstract_decorator = is_abstract(&checker.model, decorator_list); has_abstract_method |= has_abstract_decorator; if !checker @@ -121,7 +121,7 @@ pub(crate) fn abstract_base_class( if !has_abstract_decorator && is_empty_body(body) - && !is_overload(&checker.ctx, decorator_list) + && !is_overload(&checker.model, decorator_list) { checker.diagnostics.push(Diagnostic::new( EmptyMethodWithoutAbstractDecorator { diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/assert_raises_exception.rs b/crates/ruff/src/rules/flake8_bugbear/rules/assert_raises_exception.rs index 04c6255c78..7eca579ab6 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/assert_raises_exception.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/assert_raises_exception.rs @@ -66,7 +66,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: } if !checker - .ctx + .model .resolve_call_path(args.first().unwrap()) .map_or(false, |call_path| call_path.as_slice() == ["", "Exception"]) { @@ -78,7 +78,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: { AssertionKind::AssertRaises } else if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["pytest", "raises"] diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs b/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs index 3d438f01c0..39e7f54772 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs @@ -20,7 +20,7 @@ impl Violation for CachedInstanceMethod { fn is_cache_func(checker: &Checker, expr: &Expr) -> bool { checker - .ctx + .model .resolve_call_path(expr) .map_or(false, |call_path| { call_path.as_slice() == ["functools", "lru_cache"] @@ -30,7 +30,7 @@ fn is_cache_func(checker: &Checker, expr: &Expr) -> bool { /// B019 pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Expr]) { - if !matches!(checker.ctx.scope().kind, ScopeKind::Class(_)) { + if !matches!(checker.model.scope().kind, ScopeKind::Class(_)) { return; } for decorator in decorator_list { diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/function_call_argument_default.rs b/crates/ruff/src/rules/flake8_bugbear/rules/function_call_argument_default.rs index 2dd097d3f7..8f1890ae88 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/function_call_argument_default.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/function_call_argument_default.rs @@ -86,7 +86,7 @@ where match expr { Expr::Call(ast::ExprCall { func, args, .. }) => { if !is_mutable_func(self.checker, func) - && !is_immutable_func(&self.checker.ctx, func, &self.extend_immutable_calls) + && !is_immutable_func(&self.checker.model, func, &self.extend_immutable_calls) && !is_nan_or_infinity(func, args) { self.diagnostics.push(( diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/getattr_with_constant.rs b/crates/ruff/src/rules/flake8_bugbear/rules/getattr_with_constant.rs index 0c150609af..2cfd46603b 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/getattr_with_constant.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/getattr_with_constant.rs @@ -3,7 +3,6 @@ use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private}; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/mutable_argument_default.rs b/crates/ruff/src/rules/flake8_bugbear/rules/mutable_argument_default.rs index 6c680ed630..c80b673c70 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/mutable_argument_default.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/mutable_argument_default.rs @@ -27,7 +27,7 @@ const MUTABLE_FUNCS: &[&[&str]] = &[ pub(crate) fn is_mutable_func(checker: &Checker, func: &Expr) -> bool { checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { MUTABLE_FUNCS @@ -70,7 +70,7 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, arguments: &Argume && !arg .annotation .as_ref() - .map_or(false, |expr| is_immutable_annotation(&checker.ctx, expr)) + .map_or(false, |expr| is_immutable_annotation(&checker.model, expr)) { checker .diagnostics diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/no_explicit_stacklevel.rs b/crates/ruff/src/rules/flake8_bugbear/rules/no_explicit_stacklevel.rs index e76c085cbc..6616abe659 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/no_explicit_stacklevel.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/no_explicit_stacklevel.rs @@ -45,7 +45,7 @@ pub(crate) fn no_explicit_stacklevel( keywords: &[Keyword], ) { if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["warnings", "warn"] diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs b/crates/ruff/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs index 93c0d3c9b8..c949d23de9 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs @@ -342,7 +342,7 @@ pub(crate) fn reuse_of_groupby_generator( }; // Check if the function call is `itertools.groupby` if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["itertools", "groupby"] diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/setattr_with_constant.rs b/crates/ruff/src/rules/flake8_bugbear/rules/setattr_with_constant.rs index e68d2db100..8a320aa122 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/setattr_with_constant.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/setattr_with_constant.rs @@ -3,7 +3,6 @@ use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged, Stmt}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_ast::source_code::Generator; use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private}; @@ -76,7 +75,7 @@ pub(crate) fn setattr_with_constant( if let Stmt::Expr(ast::StmtExpr { value: child, range: _, - }) = &checker.ctx.stmt() + }) = &checker.model.stmt() { if expr == child.as_ref() { let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range()); diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs b/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs index 42638a1b78..0fd7e3b4cf 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs @@ -129,7 +129,7 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, target: &Expr, // Avoid fixing any variables that _may_ be used, but undetectably so. let certainty = Certainty::from(!helpers::uses_magic_variable_access(body, |id| { - checker.ctx.is_builtin(id) + checker.model.is_builtin(id) })); // Attempt to rename the variable by prepending an underscore, but avoid @@ -153,12 +153,12 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, target: &Expr, if let Some(rename) = rename { if certainty.into() && checker.patch(diagnostic.kind.rule()) { // Find the `BindingKind::LoopVar` corresponding to the name. - let scope = checker.ctx.scope(); + let scope = checker.model.scope(); let binding = scope.bindings_for_name(name).find_map(|index| { - let binding = &checker.ctx.bindings[*index]; - binding - .source - .and_then(|source| (Some(source) == checker.ctx.stmt_id).then_some(binding)) + let binding = &checker.model.bindings[*index]; + binding.source.and_then(|source| { + (Some(source) == checker.model.stmt_id).then_some(binding) + }) }); if let Some(binding) = binding { if binding.kind.is_loop_var() { diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/useless_contextlib_suppress.rs b/crates/ruff/src/rules/flake8_bugbear/rules/useless_contextlib_suppress.rs index ad2061ba7f..4bd6de3a69 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/useless_contextlib_suppress.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/useless_contextlib_suppress.rs @@ -1,9 +1,10 @@ use rustpython_parser::ast::{Expr, Ranged}; -use crate::checkers::ast::Checker; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use crate::checkers::ast::Checker; + #[violation] pub struct UselessContextlibSuppress; @@ -26,7 +27,7 @@ pub(crate) fn useless_contextlib_suppress( ) { if args.is_empty() && checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["contextlib", "suppress"] diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/useless_expression.rs b/crates/ruff/src/rules/flake8_bugbear/rules/useless_expression.rs index eb845b78eb..44f8b1b107 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/useless_expression.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/useless_expression.rs @@ -53,7 +53,7 @@ pub(crate) fn useless_expression(checker: &mut Checker, value: &Expr) { } // Ignore statements that have side effects. - if contains_effect(value, |id| checker.ctx.is_builtin(id)) { + if contains_effect(value, |id| checker.model.is_builtin(id)) { // Flag attributes as useless expressions, even if they're attached to calls or other // expressions. if matches!(value, Expr::Attribute(_)) { diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/zip_without_explicit_strict.rs b/crates/ruff/src/rules/flake8_bugbear/rules/zip_without_explicit_strict.rs index 5db77e2d38..d7b02e6581 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/zip_without_explicit_strict.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/zip_without_explicit_strict.rs @@ -1,9 +1,10 @@ use rustpython_parser::ast::{self, Expr, Keyword, Ranged}; -use crate::checkers::ast::Checker; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use crate::checkers::ast::Checker; + #[violation] pub struct ZipWithoutExplicitStrict; @@ -23,7 +24,7 @@ pub(crate) fn zip_without_explicit_strict( ) { if let Expr::Name(ast::ExprName { id, .. }) = func { if id == "zip" - && checker.ctx.is_builtin("zip") + && checker.model.is_builtin("zip") && !kwargs .iter() .any(|keyword| keyword.arg.as_ref().map_or(false, |name| name == "strict")) diff --git a/crates/ruff/src/rules/flake8_builtins/rules.rs b/crates/ruff/src/rules/flake8_builtins/rules.rs index 46193c1e37..52da75ceea 100644 --- a/crates/ruff/src/rules/flake8_builtins/rules.rs +++ b/crates/ruff/src/rules/flake8_builtins/rules.rs @@ -1,8 +1,9 @@ +use rustpython_parser::ast::Ranged; + use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_stdlib::builtins::BUILTINS; -use rustpython_parser::ast::Ranged; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/flake8_commas/mod.rs b/crates/ruff/src/rules/flake8_commas/mod.rs index 9736b33f84..675c70a8cc 100644 --- a/crates/ruff/src/rules/flake8_commas/mod.rs +++ b/crates/ruff/src/rules/flake8_commas/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_comprehensions/mod.rs b/crates/ruff/src/rules/flake8_comprehensions/mod.rs index 02bd63ddb2..9806e41659 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/mod.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/mod.rs @@ -7,11 +7,10 @@ pub mod settings; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; - use test_case::test_case; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::test_path; diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_call_around_sorted.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_call_around_sorted.rs index 4d1514cf9e..f647d227c0 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_call_around_sorted.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_call_around_sorted.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{self, Expr, Ranged}; +use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; +use ruff_macros::{derive_message_formats, violation}; + use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_comprehensions::fixes; -use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; -use ruff_macros::{derive_message_formats, violation}; use super::helpers; @@ -74,7 +75,7 @@ pub(crate) fn unnecessary_call_around_sorted( if inner != "sorted" { return; } - if !checker.ctx.is_builtin(inner) || !checker.ctx.is_builtin(outer) { + if !checker.model.is_builtin(inner) || !checker.model.is_builtin(outer) { return; } let mut diagnostic = Diagnostic::new( diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs index 1789608900..0d049983c0 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs @@ -79,7 +79,7 @@ pub(crate) fn unnecessary_collection_call( } _ => return, }; - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; } let mut diagnostic = Diagnostic::new( diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_comprehension.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_comprehension.rs index 24dbdcfbf5..d3459ee274 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_comprehension.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_comprehension.rs @@ -56,7 +56,7 @@ fn add_diagnostic(checker: &mut Checker, expr: &Expr) { Expr::DictComp(_) => "dict", _ => return, }; - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; } let mut diagnostic = Diagnostic::new( diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_comprehension_any_all.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_comprehension_any_all.rs index 0eb7b10d43..4a55a0600d 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_comprehension_any_all.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_comprehension_any_all.rs @@ -76,7 +76,7 @@ pub(crate) fn unnecessary_comprehension_any_all( if is_async_generator(elt) { return; } - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; } let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, args[0].range()); diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_double_cast_or_process.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_double_cast_or_process.rs index ee0767b056..0c7bcea021 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_double_cast_or_process.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_double_cast_or_process.rs @@ -90,7 +90,7 @@ pub(crate) fn unnecessary_double_cast_or_process( let Some(inner) = helpers::expr_name(func) else { return; }; - if !checker.ctx.is_builtin(inner) || !checker.ctx.is_builtin(outer) { + if !checker.model.is_builtin(inner) || !checker.model.is_builtin(outer) { return; } diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_list.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_list.rs index db6a5bcf9f..bf44696dd7 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_list.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_list.rs @@ -52,7 +52,7 @@ pub(crate) fn unnecessary_generator_list( let Some(argument) = helpers::exactly_one_argument_with_matching_function("list", func, args, keywords) else { return; }; - if !checker.ctx.is_builtin("list") { + if !checker.model.is_builtin("list") { return; } if let Expr::GeneratorExp(_) = argument { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs index eb80f2b5fc..2633b1f786 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs @@ -53,7 +53,7 @@ pub(crate) fn unnecessary_generator_set( let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else { return; }; - if !checker.ctx.is_builtin("set") { + if !checker.model.is_builtin("set") { return; } if let Expr::GeneratorExp(_) = argument { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_call.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_call.rs index dd3a7c3cc5..ad6d08fff6 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_call.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_call.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{Expr, Ranged}; +use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; +use ruff_macros::{derive_message_formats, violation}; + use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_comprehensions::fixes; -use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; -use ruff_macros::{derive_message_formats, violation}; use super::helpers; @@ -47,7 +48,7 @@ pub(crate) fn unnecessary_list_call( let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else { return; }; - if !checker.ctx.is_builtin("list") { + if !checker.model.is_builtin("list") { return; } if !argument.is_list_comp_expr() { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs index 12e9ee790c..6e4b62b1bf 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{self, Expr, Keyword, Ranged}; +use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; +use ruff_macros::{derive_message_formats, violation}; + use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_comprehensions::fixes; -use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; -use ruff_macros::{derive_message_formats, violation}; use super::helpers; @@ -49,7 +50,7 @@ pub(crate) fn unnecessary_list_comprehension_dict( let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else { return; }; - if !checker.ctx.is_builtin("dict") { + if !checker.model.is_builtin("dict") { return; } let Expr::ListComp(ast::ExprListComp { elt, .. }) = argument else { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs index 49076501f4..06c2300936 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs @@ -50,7 +50,7 @@ pub(crate) fn unnecessary_list_comprehension_set( let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else { return; }; - if !checker.ctx.is_builtin("set") { + if !checker.model.is_builtin("set") { return; } if argument.is_list_comp_expr() { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs index 0d1890a502..b539f72696 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{self, Expr, Keyword, Ranged}; +use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; +use ruff_macros::{derive_message_formats, violation}; + use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_comprehensions::fixes; -use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; -use ruff_macros::{derive_message_formats, violation}; use super::helpers; @@ -56,7 +57,7 @@ pub(crate) fn unnecessary_literal_dict( let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else { return; }; - if !checker.ctx.is_builtin("dict") { + if !checker.model.is_builtin("dict") { return; } let (kind, elts) = match argument { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs index 2d58455da0..65090e6513 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{Expr, Keyword, Ranged}; +use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; +use ruff_macros::{derive_message_formats, violation}; + use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_comprehensions::fixes; -use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; -use ruff_macros::{derive_message_formats, violation}; use super::helpers; @@ -57,7 +58,7 @@ pub(crate) fn unnecessary_literal_set( let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else { return; }; - if !checker.ctx.is_builtin("set") { + if !checker.model.is_builtin("set") { return; } let kind = match argument { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_dict_call.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_dict_call.rs index f48ec9c9fb..c34819eee3 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_dict_call.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_dict_call.rs @@ -1,6 +1,7 @@ -use rustpython_parser::ast::{Expr, Keyword, Ranged}; use std::fmt; +use rustpython_parser::ast::{Expr, Keyword, Ranged}; + use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; use ruff_macros::{derive_message_formats, violation}; @@ -75,7 +76,7 @@ pub(crate) fn unnecessary_literal_within_dict_call( let Some(argument) = helpers::first_argument_with_matching_function("dict", func, args) else { return; }; - if !checker.ctx.is_builtin("dict") { + if !checker.model.is_builtin("dict") { return; } let argument_kind = match argument { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_list_call.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_list_call.rs index b4f99d7191..95d9699dce 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_list_call.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_list_call.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{Expr, Keyword, Ranged}; +use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; +use ruff_macros::{derive_message_formats, violation}; + use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_comprehensions::fixes; -use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; -use ruff_macros::{derive_message_formats, violation}; use super::helpers; @@ -78,7 +79,7 @@ pub(crate) fn unnecessary_literal_within_list_call( let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else { return; }; - if !checker.ctx.is_builtin("list") { + if !checker.model.is_builtin("list") { return; } let argument_kind = match argument { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_tuple_call.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_tuple_call.rs index f569a34e00..12ad9a6174 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_tuple_call.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_tuple_call.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{Expr, Keyword, Ranged}; +use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; +use ruff_macros::{derive_message_formats, violation}; + use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_comprehensions::fixes; -use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; -use ruff_macros::{derive_message_formats, violation}; use super::helpers; @@ -79,7 +80,7 @@ pub(crate) fn unnecessary_literal_within_tuple_call( let Some(argument) = helpers::first_argument_with_matching_function("tuple", func, args) else { return; }; - if !checker.ctx.is_builtin("tuple") { + if !checker.model.is_builtin("tuple") { return; } let argument_kind = match argument { diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_map.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_map.rs index e6cf53f68d..8b9a708f69 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_map.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_map.rs @@ -88,7 +88,7 @@ pub(crate) fn unnecessary_map( }; match id { "map" => { - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; } @@ -119,7 +119,7 @@ pub(crate) fn unnecessary_map( } } "list" | "set" => { - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; } @@ -149,7 +149,7 @@ pub(crate) fn unnecessary_map( } } "dict" => { - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; } diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_subscript_reversal.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_subscript_reversal.rs index a27628d774..819a9797b0 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_subscript_reversal.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_subscript_reversal.rs @@ -1,10 +1,11 @@ use num_bigint::BigInt; use rustpython_parser::ast::{self, Constant, Expr, Ranged, Unaryop}; -use crate::checkers::ast::Checker; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use crate::checkers::ast::Checker; + use super::helpers; /// ## What it does @@ -57,7 +58,7 @@ pub(crate) fn unnecessary_subscript_reversal( if !(id == "set" || id == "sorted" || id == "reversed") { return; } - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; } let Expr::Subscript(ast::ExprSubscript { slice, .. }) = first_arg else { diff --git a/crates/ruff/src/rules/flake8_datetimez/mod.rs b/crates/ruff/src/rules/flake8_datetimez/mod.rs index d2d22010eb..b4d19816da 100644 --- a/crates/ruff/src/rules/flake8_datetimez/mod.rs +++ b/crates/ruff/src/rules/flake8_datetimez/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_datetimez/rules.rs b/crates/ruff/src/rules/flake8_datetimez/rules.rs index de3faa826d..04a177a181 100644 --- a/crates/ruff/src/rules/flake8_datetimez/rules.rs +++ b/crates/ruff/src/rules/flake8_datetimez/rules.rs @@ -125,7 +125,7 @@ pub(crate) fn call_datetime_without_tzinfo( location: TextRange, ) { if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "datetime"] @@ -158,7 +158,7 @@ pub(crate) fn call_datetime_without_tzinfo( /// Use `datetime.datetime.now(tz=)` instead. pub(crate) fn call_datetime_today(checker: &mut Checker, func: &Expr, location: TextRange) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "datetime", "today"] @@ -180,7 +180,7 @@ pub(crate) fn call_datetime_today(checker: &mut Checker, func: &Expr, location: /// current time in UTC is by calling `datetime.now(timezone.utc)`. pub(crate) fn call_datetime_utcnow(checker: &mut Checker, func: &Expr, location: TextRange) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "datetime", "utcnow"] @@ -207,7 +207,7 @@ pub(crate) fn call_datetime_utcfromtimestamp( location: TextRange, ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "datetime", "utcfromtimestamp"] @@ -228,7 +228,7 @@ pub(crate) fn call_datetime_now_without_tzinfo( location: TextRange, ) { if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "datetime", "now"] @@ -270,7 +270,7 @@ pub(crate) fn call_datetime_fromtimestamp( location: TextRange, ) { if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "datetime", "fromtimestamp"] @@ -311,7 +311,7 @@ pub(crate) fn call_datetime_strptime_without_zone( location: TextRange, ) { if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "datetime", "strptime"] @@ -332,7 +332,7 @@ pub(crate) fn call_datetime_strptime_without_zone( } }; - let (Some(grandparent), Some(parent)) = (checker.ctx.expr_grandparent(), checker.ctx.expr_parent()) else { + let (Some(grandparent), Some(parent)) = (checker.model.expr_grandparent(), checker.model.expr_parent()) else { checker.diagnostics.push(Diagnostic::new( CallDatetimeStrptimeWithoutZone, location, @@ -370,7 +370,7 @@ pub(crate) fn call_datetime_strptime_without_zone( /// Use `datetime.datetime.now(tz=).date()` instead. pub(crate) fn call_date_today(checker: &mut Checker, func: &Expr, location: TextRange) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "date", "today"] @@ -390,7 +390,7 @@ pub(crate) fn call_date_today(checker: &mut Checker, func: &Expr, location: Text /// Use `datetime.datetime.fromtimestamp(, tz=).date()` instead. pub(crate) fn call_date_fromtimestamp(checker: &mut Checker, func: &Expr, location: TextRange) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "date", "fromtimestamp"] diff --git a/crates/ruff/src/rules/flake8_debugger/mod.rs b/crates/ruff/src/rules/flake8_debugger/mod.rs index 799d434b6c..29a40913ca 100644 --- a/crates/ruff/src/rules/flake8_debugger/mod.rs +++ b/crates/ruff/src/rules/flake8_debugger/mod.rs @@ -7,7 +7,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_debugger/rules.rs b/crates/ruff/src/rules/flake8_debugger/rules.rs index 22036b1942..6258033775 100644 --- a/crates/ruff/src/rules/flake8_debugger/rules.rs +++ b/crates/ruff/src/rules/flake8_debugger/rules.rs @@ -1,11 +1,12 @@ use rustpython_parser::ast::{Expr, Ranged, Stmt}; -use crate::checkers::ast::Checker; -use crate::rules::flake8_debugger::types::DebuggerUsingType; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::{format_call_path, from_unqualified_name, CallPath}; +use crate::checkers::ast::Checker; +use crate::rules::flake8_debugger::types::DebuggerUsingType; + #[violation] pub struct Debugger { using_type: DebuggerUsingType, @@ -42,7 +43,7 @@ const DEBUGGERS: &[&[&str]] = &[ /// Checks for the presence of a debugger call. pub(crate) fn debugger_call(checker: &mut Checker, expr: &Expr, func: &Expr) { - if let Some(target) = checker.ctx.resolve_call_path(func).and_then(|call_path| { + if let Some(target) = checker.model.resolve_call_path(func).and_then(|call_path| { DEBUGGERS .iter() .find(|target| call_path.as_slice() == **target) diff --git a/crates/ruff/src/rules/flake8_django/mod.rs b/crates/ruff/src/rules/flake8_django/mod.rs index 321373db80..ec6ad0f098 100644 --- a/crates/ruff/src/rules/flake8_django/mod.rs +++ b/crates/ruff/src/rules/flake8_django/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_django/rules/all_with_model_form.rs b/crates/ruff/src/rules/flake8_django/rules/all_with_model_form.rs index 410f83fbfa..cd24d27af9 100644 --- a/crates/ruff/src/rules/flake8_django/rules/all_with_model_form.rs +++ b/crates/ruff/src/rules/flake8_django/rules/all_with_model_form.rs @@ -52,7 +52,7 @@ pub(crate) fn all_with_model_form( bases: &[Expr], body: &[Stmt], ) -> Option { - if !bases.iter().any(|base| is_model_form(&checker.ctx, base)) { + if !bases.iter().any(|base| is_model_form(&checker.model, base)) { return None; } for element in body.iter() { diff --git a/crates/ruff/src/rules/flake8_django/rules/exclude_with_model_form.rs b/crates/ruff/src/rules/flake8_django/rules/exclude_with_model_form.rs index bc3ae08909..6b107756aa 100644 --- a/crates/ruff/src/rules/flake8_django/rules/exclude_with_model_form.rs +++ b/crates/ruff/src/rules/flake8_django/rules/exclude_with_model_form.rs @@ -50,7 +50,7 @@ pub(crate) fn exclude_with_model_form( bases: &[Expr], body: &[Stmt], ) -> Option { - if !bases.iter().any(|base| is_model_form(&checker.ctx, base)) { + if !bases.iter().any(|base| is_model_form(&checker.model, base)) { return None; } for element in body.iter() { diff --git a/crates/ruff/src/rules/flake8_django/rules/helpers.rs b/crates/ruff/src/rules/flake8_django/rules/helpers.rs index ac73f2143f..3d0f72e10e 100644 --- a/crates/ruff/src/rules/flake8_django/rules/helpers.rs +++ b/crates/ruff/src/rules/flake8_django/rules/helpers.rs @@ -1,25 +1,25 @@ use rustpython_parser::ast::Expr; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; /// Return `true` if a Python class appears to be a Django model, based on its base classes. -pub(crate) fn is_model(context: &Context, base: &Expr) -> bool { - context.resolve_call_path(base).map_or(false, |call_path| { +pub(crate) fn is_model(model: &SemanticModel, base: &Expr) -> bool { + model.resolve_call_path(base).map_or(false, |call_path| { call_path.as_slice() == ["django", "db", "models", "Model"] }) } /// Return `true` if a Python class appears to be a Django model form, based on its base classes. -pub(crate) fn is_model_form(context: &Context, base: &Expr) -> bool { - context.resolve_call_path(base).map_or(false, |call_path| { +pub(crate) fn is_model_form(model: &SemanticModel, base: &Expr) -> bool { + model.resolve_call_path(base).map_or(false, |call_path| { call_path.as_slice() == ["django", "forms", "ModelForm"] || call_path.as_slice() == ["django", "forms", "models", "ModelForm"] }) } /// Return `true` if the expression is constructor for a Django model field. -pub(crate) fn is_model_field(context: &Context, expr: &Expr) -> bool { - context.resolve_call_path(expr).map_or(false, |call_path| { +pub(crate) fn is_model_field(model: &SemanticModel, expr: &Expr) -> bool { + model.resolve_call_path(expr).map_or(false, |call_path| { call_path .as_slice() .starts_with(&["django", "db", "models"]) @@ -27,8 +27,11 @@ pub(crate) fn is_model_field(context: &Context, expr: &Expr) -> bool { } /// Return the name of the field type, if the expression is constructor for a Django model field. -pub(crate) fn get_model_field_name<'a>(context: &'a Context, expr: &'a Expr) -> Option<&'a str> { - context.resolve_call_path(expr).and_then(|call_path| { +pub(crate) fn get_model_field_name<'a>( + model: &'a SemanticModel, + expr: &'a Expr, +) -> Option<&'a str> { + model.resolve_call_path(expr).and_then(|call_path| { let call_path = call_path.as_slice(); if !call_path.starts_with(&["django", "db", "models"]) { return None; diff --git a/crates/ruff/src/rules/flake8_django/rules/locals_in_render_function.rs b/crates/ruff/src/rules/flake8_django/rules/locals_in_render_function.rs index 5e3aa9a309..0526ce7bf4 100644 --- a/crates/ruff/src/rules/flake8_django/rules/locals_in_render_function.rs +++ b/crates/ruff/src/rules/flake8_django/rules/locals_in_render_function.rs @@ -50,7 +50,7 @@ pub(crate) fn locals_in_render_function( keywords: &[Keyword], ) { if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["django", "shortcuts", "render"] @@ -87,7 +87,7 @@ fn is_locals_call(checker: &Checker, expr: &Expr) -> bool { return false }; checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["", "locals"]) } diff --git a/crates/ruff/src/rules/flake8_django/rules/model_without_dunder_str.rs b/crates/ruff/src/rules/flake8_django/rules/model_without_dunder_str.rs index 69853ac571..6d93b662ef 100644 --- a/crates/ruff/src/rules/flake8_django/rules/model_without_dunder_str.rs +++ b/crates/ruff/src/rules/flake8_django/rules/model_without_dunder_str.rs @@ -84,7 +84,7 @@ fn checker_applies(checker: &Checker, bases: &[Expr], body: &[Stmt]) -> bool { if is_model_abstract(body) { continue; } - if helpers::is_model(&checker.ctx, base) { + if helpers::is_model(&checker.model, base) { return true; } } diff --git a/crates/ruff/src/rules/flake8_django/rules/nullable_model_string_field.rs b/crates/ruff/src/rules/flake8_django/rules/nullable_model_string_field.rs index e73d323785..2a10a8059b 100644 --- a/crates/ruff/src/rules/flake8_django/rules/nullable_model_string_field.rs +++ b/crates/ruff/src/rules/flake8_django/rules/nullable_model_string_field.rs @@ -84,7 +84,7 @@ fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a st return None; }; - let Some(valid_field_name) = helpers::get_model_field_name(&checker.ctx, func) else { + let Some(valid_field_name) = helpers::get_model_field_name(&checker.model, func) else { return None; }; diff --git a/crates/ruff/src/rules/flake8_django/rules/unordered_body_content_in_model.rs b/crates/ruff/src/rules/flake8_django/rules/unordered_body_content_in_model.rs index e8a18c27cb..7906f6514f 100644 --- a/crates/ruff/src/rules/flake8_django/rules/unordered_body_content_in_model.rs +++ b/crates/ruff/src/rules/flake8_django/rules/unordered_body_content_in_model.rs @@ -103,7 +103,7 @@ fn get_element_type(checker: &Checker, element: &Stmt) -> Option { match element { Stmt::Assign(ast::StmtAssign { targets, value, .. }) => { if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() { - if helpers::is_model_field(&checker.ctx, func) { + if helpers::is_model_field(&checker.model, func) { return Some(ContentType::FieldDeclaration); } } @@ -144,7 +144,7 @@ pub(crate) fn unordered_body_content_in_model( ) { if !bases .iter() - .any(|base| helpers::is_model(&checker.ctx, base)) + .any(|base| helpers::is_model(&checker.model, base)) { return; } diff --git a/crates/ruff/src/rules/flake8_errmsg/rules.rs b/crates/ruff/src/rules/flake8_errmsg/rules.rs index 4d749806b6..d81365423e 100644 --- a/crates/ruff/src/rules/flake8_errmsg/rules.rs +++ b/crates/ruff/src/rules/flake8_errmsg/rules.rs @@ -3,7 +3,6 @@ use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged, Stmt}; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_ast::source_code::{Generator, Stylist}; use ruff_python_ast::whitespace; @@ -234,7 +233,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr if string.len() > checker.settings.flake8_errmsg.max_string_length { let indentation = whitespace::indentation(checker.locator, stmt) .and_then(|indentation| { - if checker.ctx.find_binding("msg").is_none() { + if checker.model.find_binding("msg").is_none() { Some(indentation) } else { None @@ -262,7 +261,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr if checker.settings.rules.enabled(Rule::FStringInException) { let indentation = whitespace::indentation(checker.locator, stmt).and_then( |indentation| { - if checker.ctx.find_binding("msg").is_none() { + if checker.model.find_binding("msg").is_none() { Some(indentation) } else { None @@ -293,7 +292,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr if attr == "format" && value.is_constant_expr() { let indentation = whitespace::indentation(checker.locator, stmt) .and_then(|indentation| { - if checker.ctx.find_binding("msg").is_none() { + if checker.model.find_binding("msg").is_none() { Some(indentation) } else { None diff --git a/crates/ruff/src/rules/flake8_executable/helpers.rs b/crates/ruff/src/rules/flake8_executable/helpers.rs index 70592af16e..f52e746bd0 100644 --- a/crates/ruff/src/rules/flake8_executable/helpers.rs +++ b/crates/ruff/src/rules/flake8_executable/helpers.rs @@ -51,12 +51,12 @@ pub(crate) fn is_executable(filepath: &Path) -> Result { #[cfg(test)] mod tests { + use ruff_text_size::TextSize; + use crate::rules::flake8_executable::helpers::{ extract_shebang, ShebangDirective, SHEBANG_REGEX, }; - use ruff_text_size::TextSize; - #[test] fn shebang_regex() { // Positive cases diff --git a/crates/ruff/src/rules/flake8_executable/mod.rs b/crates/ruff/src/rules/flake8_executable/mod.rs index f37d8f7993..a38ffbac24 100644 --- a/crates/ruff/src/rules/flake8_executable/mod.rs +++ b/crates/ruff/src/rules/flake8_executable/mod.rs @@ -8,7 +8,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_executable/rules/shebang_missing.rs b/crates/ruff/src/rules/flake8_executable/rules/shebang_missing.rs index 4466127f9c..ea33e57d0c 100644 --- a/crates/ruff/src/rules/flake8_executable/rules/shebang_missing.rs +++ b/crates/ruff/src/rules/flake8_executable/rules/shebang_missing.rs @@ -1,8 +1,9 @@ #![allow(unused_imports)] -use ruff_text_size::TextRange; use std::path::Path; +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; diff --git a/crates/ruff/src/rules/flake8_executable/rules/shebang_not_executable.rs b/crates/ruff/src/rules/flake8_executable/rules/shebang_not_executable.rs index f68ffa5aaf..6cfcc13887 100644 --- a/crates/ruff/src/rules/flake8_executable/rules/shebang_not_executable.rs +++ b/crates/ruff/src/rules/flake8_executable/rules/shebang_not_executable.rs @@ -1,8 +1,9 @@ #![allow(unused_imports)] -use ruff_text_size::{TextLen, TextRange, TextSize}; use std::path::Path; +use ruff_text_size::{TextLen, TextRange, TextSize}; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; diff --git a/crates/ruff/src/rules/flake8_future_annotations/rules.rs b/crates/ruff/src/rules/flake8_future_annotations/rules.rs index 4828164b3a..5d79780229 100644 --- a/crates/ruff/src/rules/flake8_future_annotations/rules.rs +++ b/crates/ruff/src/rules/flake8_future_annotations/rules.rs @@ -67,7 +67,7 @@ impl Violation for MissingFutureAnnotationsImport { /// FA100 pub(crate) fn missing_future_annotations(checker: &mut Checker, expr: &Expr) { - if let Some(binding) = checker.ctx.resolve_call_path(expr) { + if let Some(binding) = checker.model.resolve_call_path(expr) { checker.diagnostics.push(Diagnostic::new( MissingFutureAnnotationsImport { name: format_call_path(&binding), diff --git a/crates/ruff/src/rules/flake8_gettext/mod.rs b/crates/ruff/src/rules/flake8_gettext/mod.rs index bc15074290..f7d7145107 100644 --- a/crates/ruff/src/rules/flake8_gettext/mod.rs +++ b/crates/ruff/src/rules/flake8_gettext/mod.rs @@ -7,7 +7,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_implicit_str_concat/mod.rs b/crates/ruff/src/rules/flake8_implicit_str_concat/mod.rs index 4dd5497135..d5ddd4b37d 100644 --- a/crates/ruff/src/rules/flake8_implicit_str_concat/mod.rs +++ b/crates/ruff/src/rules/flake8_implicit_str_concat/mod.rs @@ -7,7 +7,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_import_conventions/mod.rs b/crates/ruff/src/rules/flake8_import_conventions/mod.rs index bd07037e43..3df13cbea4 100644 --- a/crates/ruff/src/rules/flake8_import_conventions/mod.rs +++ b/crates/ruff/src/rules/flake8_import_conventions/mod.rs @@ -6,11 +6,10 @@ pub mod settings; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; - use rustc_hash::{FxHashMap, FxHashSet}; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::test_path; diff --git a/crates/ruff/src/rules/flake8_logging_format/rules.rs b/crates/ruff/src/rules/flake8_logging_format/rules.rs index b30870b3e3..aa505f96ce 100644 --- a/crates/ruff/src/rules/flake8_logging_format/rules.rs +++ b/crates/ruff/src/rules/flake8_logging_format/rules.rs @@ -106,7 +106,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) { } Expr::Call(ast::ExprCall { func, keywords, .. }) => { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["", "dict"]) { @@ -151,7 +151,7 @@ pub(crate) fn logging_call( args: &[Expr], keywords: &[Keyword], ) { - if !logging::is_logger_candidate(&checker.ctx, func) { + if !logging::is_logger_candidate(&checker.model, func) { return; } @@ -198,7 +198,7 @@ pub(crate) fn logging_call( .rules .enabled(Rule::LoggingRedundantExcInfo) { - if !checker.ctx.in_exception_handler() { + if !checker.model.in_exception_handler() { return; } if let Some(exc_info) = find_keyword(keywords, "exc_info") { @@ -212,7 +212,7 @@ pub(crate) fn logging_call( }) ) || if let Expr::Call(ast::ExprCall { func, .. }) = &exc_info.value { checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["sys", "exc_info"] diff --git a/crates/ruff/src/rules/flake8_no_pep420/mod.rs b/crates/ruff/src/rules/flake8_no_pep420/mod.rs index 623cf89c69..c6dbdbe605 100644 --- a/crates/ruff/src/rules/flake8_no_pep420/mod.rs +++ b/crates/ruff/src/rules/flake8_no_pep420/mod.rs @@ -5,11 +5,10 @@ pub(crate) mod rules; mod tests { use std::path::{Path, PathBuf}; - use crate::assert_messages; use anyhow::Result; - use test_case::test_case; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::{test_path, test_resource_path}; diff --git a/crates/ruff/src/rules/flake8_no_pep420/rules.rs b/crates/ruff/src/rules/flake8_no_pep420/rules.rs index 406446bdaf..5c2a8ae4f8 100644 --- a/crates/ruff/src/rules/flake8_no_pep420/rules.rs +++ b/crates/ruff/src/rules/flake8_no_pep420/rules.rs @@ -1,6 +1,7 @@ -use ruff_text_size::TextRange; use std::path::{Path, PathBuf}; +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; diff --git a/crates/ruff/src/rules/flake8_pie/mod.rs b/crates/ruff/src/rules/flake8_pie/mod.rs index 67925fca2d..ed9b8730ab 100644 --- a/crates/ruff/src/rules/flake8_pie/mod.rs +++ b/crates/ruff/src/rules/flake8_pie/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_pie/rules.rs b/crates/ruff/src/rules/flake8_pie/rules.rs index 77c04131d8..82d28ad37d 100644 --- a/crates/ruff/src/rules/flake8_pie/rules.rs +++ b/crates/ruff/src/rules/flake8_pie/rules.rs @@ -417,7 +417,7 @@ pub(crate) fn non_unique_enums<'a, 'b>( if !bases.iter().any(|expr| { checker - .ctx + .model .resolve_call_path(expr) .map_or(false, |call_path| call_path.as_slice() == ["enum", "Enum"]) }) { @@ -432,7 +432,7 @@ pub(crate) fn non_unique_enums<'a, 'b>( if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["enum", "auto"]) { diff --git a/crates/ruff/src/rules/flake8_print/mod.rs b/crates/ruff/src/rules/flake8_print/mod.rs index bb0e532615..4c5087bf0a 100644 --- a/crates/ruff/src/rules/flake8_print/mod.rs +++ b/crates/ruff/src/rules/flake8_print/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_print/rules/print_call.rs b/crates/ruff/src/rules/flake8_print/rules/print_call.rs index 366ce93962..ce11b9e589 100644 --- a/crates/ruff/src/rules/flake8_print/rules/print_call.rs +++ b/crates/ruff/src/rules/flake8_print/rules/print_call.rs @@ -78,7 +78,7 @@ impl Violation for PPrint { /// T201, T203 pub(crate) fn print_call(checker: &mut Checker, func: &Expr, keywords: &[Keyword]) { let diagnostic = { - let call_path = checker.ctx.resolve_call_path(func); + let call_path = checker.model.resolve_call_path(func); if call_path .as_ref() .map_or(false, |call_path| *call_path.as_slice() == ["", "print"]) @@ -91,7 +91,7 @@ pub(crate) fn print_call(checker: &mut Checker, func: &Expr, keywords: &[Keyword { if !is_const_none(&keyword.value) { if checker - .ctx + .model .resolve_call_path(&keyword.value) .map_or(true, |call_path| { call_path.as_slice() != ["sys", "stdout"] diff --git a/crates/ruff/src/rules/flake8_pyi/mod.rs b/crates/ruff/src/rules/flake8_pyi/mod.rs index 9b42ec42b8..436c370369 100644 --- a/crates/ruff/src/rules/flake8_pyi/mod.rs +++ b/crates/ruff/src/rules/flake8_pyi/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_pyi/rules/bad_version_info_comparison.rs b/crates/ruff/src/rules/flake8_pyi/rules/bad_version_info_comparison.rs index c1afc2f305..482da48776 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/bad_version_info_comparison.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/bad_version_info_comparison.rs @@ -1,9 +1,10 @@ use rustpython_parser::ast::{Cmpop, Expr, Ranged}; -use crate::checkers::ast::Checker; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use crate::checkers::ast::Checker; + /// ## What it does /// Checks for usages of comparators other than `<` and `>=` for /// `sys.version_info` checks in `.pyi` files. All other comparators, such @@ -68,7 +69,7 @@ pub(crate) fn bad_version_info_comparison( }; if !checker - .ctx + .model .resolve_call_path(left) .map_or(false, |call_path| { call_path.as_slice() == ["sys", "version_info"] diff --git a/crates/ruff/src/rules/flake8_pyi/rules/pass_in_class_body.rs b/crates/ruff/src/rules/flake8_pyi/rules/pass_in_class_body.rs index 4518708979..5e73f9e7f4 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/pass_in_class_body.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/pass_in_class_body.rs @@ -1,13 +1,13 @@ -use crate::autofix::actions::delete_stmt; use log::error; +use rustpython_parser::ast::{Ranged, Stmt}; + use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::types::RefEquality; +use crate::autofix::actions::delete_stmt; use crate::checkers::ast::Checker; - use crate::registry::AsRule; -use rustpython_parser::ast::{Ranged, Stmt}; #[violation] pub struct PassInClassBody; diff --git a/crates/ruff/src/rules/flake8_pyi/rules/prefix_type_params.rs b/crates/ruff/src/rules/flake8_pyi/rules/prefix_type_params.rs index 358ea50626..e1b2699f47 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/prefix_type_params.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/prefix_type_params.rs @@ -70,12 +70,12 @@ pub(crate) fn prefix_type_params(checker: &mut Checker, value: &Expr, targets: & }; if let Expr::Call(ast::ExprCall { func, .. }) = value { - let Some(kind) = checker.ctx.resolve_call_path(func).and_then(|call_path| { - if checker.ctx.match_typing_call_path(&call_path, "ParamSpec") { + let Some(kind) = checker.model.resolve_call_path(func).and_then(|call_path| { + if checker.model.match_typing_call_path(&call_path, "ParamSpec") { Some(VarKind::ParamSpec) - } else if checker.ctx.match_typing_call_path(&call_path, "TypeVar") { + } else if checker.model.match_typing_call_path(&call_path, "TypeVar") { Some(VarKind::TypeVar) - } else if checker.ctx.match_typing_call_path(&call_path, "TypeVarTuple") { + } else if checker.model.match_typing_call_path(&call_path, "TypeVarTuple") { Some(VarKind::TypeVarTuple) } else { None diff --git a/crates/ruff/src/rules/flake8_pyi/rules/quoted_annotation_in_stub.rs b/crates/ruff/src/rules/flake8_pyi/rules/quoted_annotation_in_stub.rs index 8ba8d3fbf3..6041af59d2 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/quoted_annotation_in_stub.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/quoted_annotation_in_stub.rs @@ -1,6 +1,7 @@ +use ruff_text_size::TextRange; + use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::TextRange; use crate::checkers::ast::Checker; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs b/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs index d1e5313797..b62d7045c2 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs @@ -2,7 +2,7 @@ use rustpython_parser::ast::{self, Arguments, Constant, Expr, Operator, Ranged, use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use ruff_python_semantic::scope::{ClassDef, ScopeKind}; use crate::checkers::ast::Checker; @@ -172,7 +172,7 @@ fn is_valid_default_value_with_annotation( // Ex) `-math.inf`, `-math.pi`, etc. if let Expr::Attribute(_) = operand.as_ref() { if checker - .ctx + .model .resolve_call_path(operand) .map_or(false, |call_path| { ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS.iter().any(|target| { @@ -224,7 +224,7 @@ fn is_valid_default_value_with_annotation( // Ex) `math.inf`, `sys.stdin`, etc. Expr::Attribute(_) => { if checker - .ctx + .model .resolve_call_path(default) .map_or(false, |call_path| { ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS @@ -278,11 +278,11 @@ fn is_valid_default_value_without_annotation(default: &Expr) -> bool { /// Returns `true` if an [`Expr`] appears to be `TypeVar`, `TypeVarTuple`, `NewType`, or `ParamSpec` /// call. -fn is_type_var_like_call(context: &Context, expr: &Expr) -> bool { +fn is_type_var_like_call(model: &SemanticModel, expr: &Expr) -> bool { let Expr::Call(ast::ExprCall { func, .. } )= expr else { return false; }; - context.resolve_call_path(func).map_or(false, |call_path| { + model.resolve_call_path(func).map_or(false, |call_path| { matches!( call_path.as_slice(), [ @@ -295,11 +295,11 @@ fn is_type_var_like_call(context: &Context, expr: &Expr) -> bool { /// Returns `true` if this is a "special" assignment which must have a value (e.g., an assignment to /// `__all__`). -fn is_special_assignment(context: &Context, target: &Expr) -> bool { +fn is_special_assignment(model: &SemanticModel, target: &Expr) -> bool { if let Expr::Name(ast::ExprName { id, .. }) = target { match id.as_str() { - "__all__" => context.scope().kind.is_module(), - "__match_args__" | "__slots__" => context.scope().kind.is_class(), + "__all__" => model.scope().kind.is_module(), + "__match_args__" | "__slots__" => model.scope().kind.is_class(), _ => false, } } else { @@ -308,9 +308,9 @@ fn is_special_assignment(context: &Context, target: &Expr) -> bool { } /// Returns `true` if the a class is an enum, based on its base classes. -fn is_enum(context: &Context, bases: &[Expr]) -> bool { +fn is_enum(model: &SemanticModel, bases: &[Expr]) -> bool { return bases.iter().any(|expr| { - context.resolve_call_path(expr).map_or(false, |call_path| { + model.resolve_call_path(expr).map_or(false, |call_path| { matches!( call_path.as_slice(), [ @@ -445,10 +445,10 @@ pub(crate) fn assignment_default_in_stub(checker: &mut Checker, targets: &[Expr] if !target.is_name_expr() { return; } - if is_special_assignment(&checker.ctx, target) { + if is_special_assignment(&checker.model, target) { return; } - if is_type_var_like_call(&checker.ctx, value) { + if is_type_var_like_call(&checker.model, value) { return; } if is_valid_default_value_without_annotation(value) { @@ -476,13 +476,13 @@ pub(crate) fn annotated_assignment_default_in_stub( value: &Expr, annotation: &Expr, ) { - if checker.ctx.match_typing_expr(annotation, "TypeAlias") { + if checker.model.match_typing_expr(annotation, "TypeAlias") { return; } - if is_special_assignment(&checker.ctx, target) { + if is_special_assignment(&checker.model, target) { return; } - if is_type_var_like_call(&checker.ctx, value) { + if is_type_var_like_call(&checker.model, value) { return; } if is_valid_default_value_with_annotation(value, checker, true) { @@ -513,10 +513,10 @@ pub(crate) fn unannotated_assignment_in_stub( let Expr::Name(ast::ExprName { id, .. }) = target else { return; }; - if is_special_assignment(&checker.ctx, target) { + if is_special_assignment(&checker.model, target) { return; } - if is_type_var_like_call(&checker.ctx, value) { + if is_type_var_like_call(&checker.model, value) { return; } if is_valid_default_value_without_annotation(value) { @@ -526,8 +526,8 @@ pub(crate) fn unannotated_assignment_in_stub( return; } - if let ScopeKind::Class(ClassDef { bases, .. }) = &checker.ctx.scope().kind { - if is_enum(&checker.ctx, bases) { + if let ScopeKind::Class(ClassDef { bases, .. }) = &checker.model.scope().kind { + if is_enum(&checker.model, bases) { return; } } diff --git a/crates/ruff/src/rules/flake8_pyi/rules/unrecognized_platform.rs b/crates/ruff/src/rules/flake8_pyi/rules/unrecognized_platform.rs index 20f4cb0815..3515073867 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/unrecognized_platform.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/unrecognized_platform.rs @@ -103,7 +103,7 @@ pub(crate) fn unrecognized_platform( let diagnostic_unrecognized_platform_check = Diagnostic::new(UnrecognizedPlatformCheck, expr.range()); if !checker - .ctx + .model .resolve_call_path(left) .map_or(false, |call_path| { call_path.as_slice() == ["sys", "platform"] diff --git a/crates/ruff/src/rules/flake8_pytest_style/mod.rs b/crates/ruff/src/rules/flake8_pytest_style/mod.rs index 1ef7da6cf0..1c116551a2 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/mod.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/mod.rs @@ -8,7 +8,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_pytest_style/rules/assertion.rs b/crates/ruff/src/rules/flake8_pytest_style/rules/assertion.rs index d59faa9d43..3b20cd73d8 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/assertion.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/assertion.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use anyhow::bail; use anyhow::Result; use libcst_native::{ @@ -6,7 +8,6 @@ use libcst_native::{ SmallStatement, Statement, Suite, TrailingWhitespace, UnaryOp, UnaryOperation, }; use rustpython_parser::ast::{self, Boolop, Excepthandler, Expr, Keyword, Ranged, Stmt, Unaryop}; -use std::borrow::Cow; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; @@ -184,9 +185,9 @@ pub(crate) fn unittest_assertion( if let Ok(unittest_assert) = UnittestAssert::try_from(attr.as_str()) { // We're converting an expression to a statement, so avoid applying the fix if // the assertion is part of a larger expression. - let fixable = checker.ctx.stmt().is_expr_stmt() - && checker.ctx.expr_parent().is_none() - && !checker.ctx.scope().kind.is_lambda() + let fixable = checker.model.stmt().is_expr_stmt() + && checker.model.expr_parent().is_none() + && !checker.model.scope().kind.is_lambda() && !has_comments_in(expr.range(), checker.locator); let mut diagnostic = Diagnostic::new( PytestUnittestAssertion { @@ -214,7 +215,7 @@ pub(crate) fn unittest_assertion( /// PT015 pub(crate) fn assert_falsy(checker: &mut Checker, stmt: &Stmt, test: &Expr) { - if Truthiness::from_expr(test, |id| checker.ctx.is_builtin(id)).is_falsey() { + if Truthiness::from_expr(test, |id| checker.model.is_builtin(id)).is_falsey() { checker .diagnostics .push(Diagnostic::new(PytestAssertAlwaysFalse, stmt.range())); diff --git a/crates/ruff/src/rules/flake8_pytest_style/rules/fail.rs b/crates/ruff/src/rules/flake8_pytest_style/rules/fail.rs index f634e3be48..d4ce8c6518 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/fail.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/fail.rs @@ -19,7 +19,7 @@ impl Violation for PytestFailWithoutMessage { } pub(crate) fn fail_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) { - if is_pytest_fail(&checker.ctx, func) { + if is_pytest_fail(&checker.model, func) { let call_args = SimpleCallArgs::new(args, keywords); let msg = call_args.argument("msg", 0); diff --git a/crates/ruff/src/rules/flake8_pytest_style/rules/fixture.rs b/crates/ruff/src/rules/flake8_pytest_style/rules/fixture.rs index 7df5b1bd08..22e5725d43 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/fixture.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/fixture.rs @@ -1,7 +1,8 @@ +use std::fmt; + use anyhow::Result; use ruff_text_size::{TextLen, TextRange, TextSize}; use rustpython_parser::ast::{self, Arguments, Expr, Keyword, Ranged, Stmt}; -use std::fmt; use ruff_diagnostics::{AlwaysAutofixableViolation, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix}; @@ -12,7 +13,7 @@ use ruff_python_ast::source_code::Locator; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::{helpers, visitor}; use ruff_python_semantic::analyze::visibility::is_abstract; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::autofix::actions::remove_argument; use crate::checkers::ast::Checker; @@ -242,9 +243,9 @@ where } } -fn get_fixture_decorator<'a>(context: &Context, decorators: &'a [Expr]) -> Option<&'a Expr> { +fn get_fixture_decorator<'a>(model: &SemanticModel, decorators: &'a [Expr]) -> Option<&'a Expr> { decorators.iter().find(|decorator| { - is_pytest_fixture(context, decorator) || is_pytest_yield_fixture(context, decorator) + is_pytest_fixture(model, decorator) || is_pytest_yield_fixture(model, decorator) }) } @@ -456,7 +457,7 @@ fn check_test_function_args(checker: &mut Checker, args: &Arguments) { /// PT020 fn check_fixture_decorator_name(checker: &mut Checker, decorator: &Expr) { - if is_pytest_yield_fixture(&checker.ctx, decorator) { + if is_pytest_yield_fixture(&checker.model, decorator) { checker.diagnostics.push(Diagnostic::new( PytestDeprecatedYieldFixture, decorator.range(), @@ -532,7 +533,7 @@ pub(crate) fn fixture( decorators: &[Expr], body: &[Stmt], ) { - let decorator = get_fixture_decorator(&checker.ctx, decorators); + let decorator = get_fixture_decorator(&checker.model, decorators); if let Some(decorator) = decorator { if checker .settings @@ -571,7 +572,7 @@ pub(crate) fn fixture( .settings .rules .enabled(Rule::PytestUselessYieldFixture)) - && !is_abstract(&checker.ctx, decorators) + && !is_abstract(&checker.model, decorators) { check_fixture_returns(checker, stmt, name, body); } diff --git a/crates/ruff/src/rules/flake8_pytest_style/rules/helpers.rs b/crates/ruff/src/rules/flake8_pytest_style/rules/helpers.rs index cd6ea32b81..36beb36f79 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/helpers.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/helpers.rs @@ -2,7 +2,7 @@ use rustpython_parser::ast::{self, Constant, Expr, Keyword}; use ruff_python_ast::call_path::{collect_call_path, CallPath}; use ruff_python_ast::helpers::map_callable; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; pub(super) fn get_mark_decorators(decorators: &[Expr]) -> impl Iterator { decorators.iter().filter_map(|decorator| { @@ -17,30 +17,30 @@ pub(super) fn get_mark_decorators(decorators: &[Expr]) -> impl Iterator bool { - context.resolve_call_path(call).map_or(false, |call_path| { +pub(super) fn is_pytest_fail(model: &SemanticModel, call: &Expr) -> bool { + model.resolve_call_path(call).map_or(false, |call_path| { call_path.as_slice() == ["pytest", "fail"] }) } -pub(super) fn is_pytest_fixture(context: &Context, decorator: &Expr) -> bool { - context +pub(super) fn is_pytest_fixture(model: &SemanticModel, decorator: &Expr) -> bool { + model .resolve_call_path(map_callable(decorator)) .map_or(false, |call_path| { call_path.as_slice() == ["pytest", "fixture"] }) } -pub(super) fn is_pytest_yield_fixture(context: &Context, decorator: &Expr) -> bool { - context +pub(super) fn is_pytest_yield_fixture(model: &SemanticModel, decorator: &Expr) -> bool { + model .resolve_call_path(map_callable(decorator)) .map_or(false, |call_path| { call_path.as_slice() == ["pytest", "yield_fixture"] }) } -pub(super) fn is_pytest_parametrize(context: &Context, decorator: &Expr) -> bool { - context +pub(super) fn is_pytest_parametrize(model: &SemanticModel, decorator: &Expr) -> bool { + model .resolve_call_path(map_callable(decorator)) .map_or(false, |call_path| { call_path.as_slice() == ["pytest", "mark", "parametrize"] diff --git a/crates/ruff/src/rules/flake8_pytest_style/rules/parametrize.rs b/crates/ruff/src/rules/flake8_pytest_style/rules/parametrize.rs index 4d225f422b..19096edf9d 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/parametrize.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/parametrize.rs @@ -416,7 +416,7 @@ fn handle_value_rows( pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Expr]) { for decorator in decorators { - if is_pytest_parametrize(&checker.ctx, decorator) { + if is_pytest_parametrize(&checker.model, decorator) { if let Expr::Call(ast::ExprCall { args, .. }) = decorator { if checker .settings diff --git a/crates/ruff/src/rules/flake8_pytest_style/rules/raises.rs b/crates/ruff/src/rules/flake8_pytest_style/rules/raises.rs index dd541156ae..ca1e3aaf4d 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/raises.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/raises.rs @@ -48,7 +48,7 @@ impl Violation for PytestRaisesWithoutException { fn is_pytest_raises(checker: &Checker, func: &Expr) -> bool { checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["pytest", "raises"] @@ -147,7 +147,7 @@ pub(crate) fn complex_raises( /// PT011 fn exception_needs_match(checker: &mut Checker, exception: &Expr) { if let Some(call_path) = checker - .ctx + .model .resolve_call_path(exception) .and_then(|call_path| { let is_broad_exception = checker diff --git a/crates/ruff/src/rules/flake8_pytest_style/types.rs b/crates/ruff/src/rules/flake8_pytest_style/types.rs index e1c4314726..f666a8a909 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/types.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/types.rs @@ -1,7 +1,9 @@ -use ruff_macros::CacheKey; -use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; +use serde::{Deserialize, Serialize}; + +use ruff_macros::CacheKey; + #[derive(Clone, Copy, Debug, CacheKey, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum ParametrizeNameType { diff --git a/crates/ruff/src/rules/flake8_quotes/mod.rs b/crates/ruff/src/rules/flake8_quotes/mod.rs index e542478e93..ee9648bcb3 100644 --- a/crates/ruff/src/rules/flake8_quotes/mod.rs +++ b/crates/ruff/src/rules/flake8_quotes/mod.rs @@ -6,11 +6,10 @@ pub mod settings; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; - use test_case::test_case; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::test_path; diff --git a/crates/ruff/src/rules/flake8_raise/mod.rs b/crates/ruff/src/rules/flake8_raise/mod.rs index 8ab2d26a74..d5233d1bd4 100644 --- a/crates/ruff/src/rules/flake8_raise/mod.rs +++ b/crates/ruff/src/rules/flake8_raise/mod.rs @@ -7,7 +7,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_return/mod.rs b/crates/ruff/src/rules/flake8_return/mod.rs index 21763cb570..cdde36ef05 100644 --- a/crates/ruff/src/rules/flake8_return/mod.rs +++ b/crates/ruff/src/rules/flake8_return/mod.rs @@ -8,11 +8,10 @@ mod visitor; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; - use test_case::test_case; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::test_path; diff --git a/crates/ruff/src/rules/flake8_return/rules.rs b/crates/ruff/src/rules/flake8_return/rules.rs index c293df8396..a2094e74db 100644 --- a/crates/ruff/src/rules/flake8_return/rules.rs +++ b/crates/ruff/src/rules/flake8_return/rules.rs @@ -9,7 +9,7 @@ use ruff_python_ast::helpers::elif_else_range; use ruff_python_ast::helpers::is_const_none; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::whitespace::indentation; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; use crate::registry::{AsRule, Rule}; @@ -391,12 +391,12 @@ const NORETURN_FUNCS: &[&[&str]] = &[ ]; /// Return `true` if the `func` is a known function that never returns. -fn is_noreturn_func(context: &Context, func: &Expr) -> bool { - context.resolve_call_path(func).map_or(false, |call_path| { +fn is_noreturn_func(model: &SemanticModel, func: &Expr) -> bool { + model.resolve_call_path(func).map_or(false, |call_path| { NORETURN_FUNCS .iter() .any(|target| call_path.as_slice() == *target) - || context.match_typing_call_path(&call_path, "assert_never") + || model.match_typing_call_path(&call_path, "assert_never") }) } @@ -484,7 +484,7 @@ fn implicit_return(checker: &mut Checker, stmt: &Stmt) { if matches!( value.as_ref(), Expr::Call(ast::ExprCall { func, .. }) - if is_noreturn_func(&checker.ctx, func) + if is_noreturn_func(&checker.model, func) ) => {} _ => { let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range()); diff --git a/crates/ruff/src/rules/flake8_self/mod.rs b/crates/ruff/src/rules/flake8_self/mod.rs index 1d75aeef63..debfc7d5e5 100644 --- a/crates/ruff/src/rules/flake8_self/mod.rs +++ b/crates/ruff/src/rules/flake8_self/mod.rs @@ -8,7 +8,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs b/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs index da01985e1c..10117e1393 100644 --- a/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs +++ b/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs @@ -94,7 +94,7 @@ pub(crate) fn private_member_access(checker: &mut Checker, expr: &Expr) { // Ignore accesses on class members from _within_ the class. if checker - .ctx + .model .scopes .iter() .rev() @@ -104,14 +104,14 @@ pub(crate) fn private_member_access(checker: &mut Checker, expr: &Expr) { }) .map_or(false, |class_def| { if call_path.as_slice() == [class_def.name] { - checker - .ctx - .find_binding(class_def.name) - .map_or(false, |binding| { + checker.model.find_binding(class_def.name).map_or( + false, + |binding| { // TODO(charlie): Could the name ever be bound to a // _different_ class here? binding.kind.is_class_definition() - }) + }, + ) } else { false } diff --git a/crates/ruff/src/rules/flake8_simplify/mod.rs b/crates/ruff/src/rules/flake8_simplify/mod.rs index 027d9ddb91..45937fdff0 100644 --- a/crates/ruff/src/rules/flake8_simplify/mod.rs +++ b/crates/ruff/src/rules/flake8_simplify/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_bool_op.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_bool_op.rs index 76cc3db4cb..44b8f4480e 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_bool_op.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_bool_op.rs @@ -271,7 +271,7 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) { if func_name != "isinstance" { continue; } - if !checker.ctx.is_builtin("isinstance") { + if !checker.model.is_builtin("isinstance") { continue; } @@ -293,7 +293,7 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) { } else { unreachable!("Indices should only contain `isinstance` calls") }; - let fixable = !contains_effect(target, |id| checker.ctx.is_builtin(id)); + let fixable = !contains_effect(target, |id| checker.model.is_builtin(id)); let mut diagnostic = Diagnostic::new( DuplicateIsinstanceCall { name: if let Expr::Name(ast::ExprName { id, .. }) = target { @@ -425,7 +425,7 @@ pub(crate) fn compare_with_tuple(checker: &mut Checker, expr: &Expr) { // Avoid rewriting (e.g.) `a == "foo" or a == f()`. if comparators .iter() - .any(|expr| contains_effect(expr, |id| checker.ctx.is_builtin(id))) + .any(|expr| contains_effect(expr, |id| checker.model.is_builtin(id))) { continue; } @@ -516,7 +516,7 @@ pub(crate) fn expr_and_not_expr(checker: &mut Checker, expr: &Expr) { return; } - if contains_effect(expr, |id| checker.ctx.is_builtin(id)) { + if contains_effect(expr, |id| checker.model.is_builtin(id)) { return; } @@ -571,7 +571,7 @@ pub(crate) fn expr_or_not_expr(checker: &mut Checker, expr: &Expr) { return; } - if contains_effect(expr, |id| checker.ctx.is_builtin(id)) { + if contains_effect(expr, |id| checker.model.is_builtin(id)) { return; } @@ -640,14 +640,14 @@ fn is_short_circuit( for (index, (value, next_value)) in values.iter().tuple_windows().enumerate() { // Keep track of the location of the furthest-right, truthy or falsey expression. - let value_truthiness = Truthiness::from_expr(value, |id| checker.ctx.is_builtin(id)); + let value_truthiness = Truthiness::from_expr(value, |id| checker.model.is_builtin(id)); let next_value_truthiness = - Truthiness::from_expr(next_value, |id| checker.ctx.is_builtin(id)); + Truthiness::from_expr(next_value, |id| checker.model.is_builtin(id)); // Keep track of the location of the furthest-right, non-effectful expression. if value_truthiness.is_unknown() - && (!checker.ctx.in_boolean_test() - || contains_effect(value, |id| checker.ctx.is_builtin(id))) + && (!checker.model.in_boolean_test() + || contains_effect(value, |id| checker.model.is_builtin(id))) { location = next_value.start(); continue; @@ -667,7 +667,7 @@ fn is_short_circuit( value, TextRange::new(location, expr.end()), short_circuit_truthiness, - checker.ctx.in_boolean_test(), + checker.model.in_boolean_test(), checker, )); break; @@ -685,7 +685,7 @@ fn is_short_circuit( next_value, TextRange::new(location, expr.end()), short_circuit_truthiness, - checker.ctx.in_boolean_test(), + checker.model.in_boolean_test(), checker, )); break; diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_expr.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_expr.rs index c9ba60dc20..56e347ecbe 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_expr.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_expr.rs @@ -87,7 +87,7 @@ pub(crate) fn use_capital_environment_variables(checker: &mut Checker, expr: &Ex return; }; if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["os", "environ", "get"] diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs index 1449957c80..43cdf718b4 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs @@ -11,7 +11,7 @@ use ruff_python_ast::helpers::{ any_over_expr, contains_effect, first_colon_range, has_comments, has_comments_in, }; use ruff_python_ast::newlines::StrExt; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; use crate::registry::AsRule; @@ -351,7 +351,7 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt: &Stmt) { let fixable = matches!(if_return, Bool::True) && matches!(else_return, Bool::False) && !has_comments(stmt, checker.locator) - && (test.is_compare_expr() || checker.ctx.is_builtin("bool")); + && (test.is_compare_expr() || checker.model.is_builtin("bool")); let mut diagnostic = Diagnostic::new(NeedlessBool { condition }, stmt.range()); if fixable && checker.patch(diagnostic.kind.rule()) { @@ -411,9 +411,10 @@ fn ternary(target_var: &Expr, body_value: &Expr, test: &Expr, orelse_value: &Exp } /// Return `true` if the `Expr` contains a reference to `${module}.${target}`. -fn contains_call_path(ctx: &Context, expr: &Expr, target: &[&str]) -> bool { +fn contains_call_path(model: &SemanticModel, expr: &Expr, target: &[&str]) -> bool { any_over_expr(expr, &|expr| { - ctx.resolve_call_path(expr) + model + .resolve_call_path(expr) .map_or(false, |call_path| call_path.as_slice() == target) }) } @@ -446,13 +447,13 @@ pub(crate) fn use_ternary_operator(checker: &mut Checker, stmt: &Stmt, parent: O } // Avoid suggesting ternary for `if sys.version_info >= ...`-style checks. - if contains_call_path(&checker.ctx, test, &["sys", "version_info"]) { + if contains_call_path(&checker.model, test, &["sys", "version_info"]) { return; } // Avoid suggesting ternary for `if sys.platform.startswith("...")`-style // checks. - if contains_call_path(&checker.ctx, test, &["sys", "platform"]) { + if contains_call_path(&checker.model, test, &["sys", "platform"]) { return; } @@ -647,7 +648,7 @@ pub(crate) fn manual_dict_lookup( return; }; if value.as_ref().map_or(false, |value| { - contains_effect(value, |id| checker.ctx.is_builtin(id)) + contains_effect(value, |id| checker.model.is_builtin(id)) }) { return; } @@ -720,7 +721,7 @@ pub(crate) fn manual_dict_lookup( return; }; if value.as_ref().map_or(false, |value| { - contains_effect(value, |id| checker.ctx.is_builtin(id)) + contains_effect(value, |id| checker.model.is_builtin(id)) }) { return; }; @@ -803,7 +804,7 @@ pub(crate) fn use_dict_get_with_default( } // Check that the default value is not "complex". - if contains_effect(default_value, |id| checker.ctx.is_builtin(id)) { + if contains_effect(default_value, |id| checker.model.is_builtin(id)) { return; } diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_ifexp.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_ifexp.rs index 2879fb5798..7e62cb8477 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_ifexp.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_ifexp.rs @@ -107,7 +107,7 @@ pub(crate) fn explicit_true_false_in_ifexpr( checker.generator().expr(&test.clone()), expr.range(), ))); - } else if checker.ctx.is_builtin("bool") { + } else if checker.model.is_builtin("bool") { let node = ast::ExprName { id: "bool".into(), ctx: ExprContext::Load, diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_unary_op.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_unary_op.rs index 39128b5f9c..ba647bfb1f 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_unary_op.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_unary_op.rs @@ -3,7 +3,6 @@ use rustpython_parser::ast::{self, Cmpop, Expr, ExprContext, Ranged, Stmt, Unary use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; @@ -94,12 +93,12 @@ pub(crate) fn negation_with_equal_op( if !matches!(&ops[..], [Cmpop::Eq]) { return; } - if is_exception_check(checker.ctx.stmt()) { + if is_exception_check(checker.model.stmt()) { return; } // Avoid flagging issues in dunder implementations. - if let ScopeKind::Function(def) = &checker.ctx.scope().kind { + if let ScopeKind::Function(def) = &checker.model.scope().kind { if DUNDER_METHODS.contains(&def.name) { return; } @@ -144,12 +143,12 @@ pub(crate) fn negation_with_not_equal_op( if !matches!(&ops[..], [Cmpop::NotEq]) { return; } - if is_exception_check(checker.ctx.stmt()) { + if is_exception_check(checker.model.stmt()) { return; } // Avoid flagging issues in dunder implementations. - if let ScopeKind::Function(def) = &checker.ctx.scope().kind { + if let ScopeKind::Function(def) = &checker.model.scope().kind { if DUNDER_METHODS.contains(&def.name) { return; } @@ -197,13 +196,13 @@ pub(crate) fn double_negation(checker: &mut Checker, expr: &Expr, op: Unaryop, o expr.range(), ); if checker.patch(diagnostic.kind.rule()) { - if checker.ctx.in_boolean_test() { + if checker.model.in_boolean_test() { #[allow(deprecated)] diagnostic.set_fix(Fix::unspecified(Edit::range_replacement( checker.generator().expr(operand), expr.range(), ))); - } else if checker.ctx.is_builtin("bool") { + } else if checker.model.is_builtin("bool") { let node = ast::ExprName { id: "bool".into(), ctx: ExprContext::Load, diff --git a/crates/ruff/src/rules/flake8_simplify/rules/fix_if.rs b/crates/ruff/src/rules/flake8_simplify/rules/fix_if.rs index b94839db61..7081dc69be 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/fix_if.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/fix_if.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use anyhow::{bail, Result}; use libcst_native::{ BooleanOp, BooleanOperation, Codegen, CodegenState, CompoundStatement, Expression, If, @@ -5,7 +7,6 @@ use libcst_native::{ Statement, Suite, }; use rustpython_parser::ast::Ranged; -use std::borrow::Cow; use ruff_diagnostics::Edit; use ruff_python_ast::source_code::{Locator, Stylist}; diff --git a/crates/ruff/src/rules/flake8_simplify/rules/open_file_with_context_handler.rs b/crates/ruff/src/rules/flake8_simplify/rules/open_file_with_context_handler.rs index 9713fac9a2..f57a9f69a5 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/open_file_with_context_handler.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/open_file_with_context_handler.rs @@ -42,7 +42,7 @@ impl Violation for OpenFileWithContextHandler { /// Return `true` if the current expression is nested in an `await /// exit_stack.enter_async_context` call. fn match_async_exit_stack(checker: &Checker) -> bool { - let Some(expr) = checker.ctx.expr_grandparent() else { + let Some(expr) = checker.model.expr_grandparent() else { return false; }; let Expr::Await(ast::ExprAwait { value, range: _ }) = expr else { @@ -57,12 +57,12 @@ fn match_async_exit_stack(checker: &Checker) -> bool { if attr != "enter_async_context" { return false; } - for parent in checker.ctx.parents() { + for parent in checker.model.parents() { if let Stmt::With(ast::StmtWith { items, .. }) = parent { for item in items { if let Expr::Call(ast::ExprCall { func, .. }) = &item.context_expr { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["contextlib", "AsyncExitStack"] @@ -80,7 +80,7 @@ fn match_async_exit_stack(checker: &Checker) -> bool { /// Return `true` if the current expression is nested in an /// `exit_stack.enter_context` call. fn match_exit_stack(checker: &Checker) -> bool { - let Some(expr) = checker.ctx.expr_parent() else { + let Some(expr) = checker.model.expr_parent() else { return false; }; let Expr::Call(ast::ExprCall { func, .. }) = expr else { @@ -92,12 +92,12 @@ fn match_exit_stack(checker: &Checker) -> bool { if attr != "enter_context" { return false; } - for parent in checker.ctx.parents() { + for parent in checker.model.parents() { if let Stmt::With(ast::StmtWith { items, .. }) = parent { for item in items { if let Expr::Call(ast::ExprCall { func, .. }) = &item.context_expr { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["contextlib", "ExitStack"] @@ -115,13 +115,13 @@ fn match_exit_stack(checker: &Checker) -> bool { /// SIM115 pub(crate) fn open_file_with_context_handler(checker: &mut Checker, func: &Expr) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["", "open"]) { - if checker.ctx.is_builtin("open") { + if checker.model.is_builtin("open") { // Ex) `with open("foo.txt") as f: ...` - if matches!(checker.ctx.stmt(), Stmt::With(_)) { + if matches!(checker.model.stmt(), Stmt::With(_)) { return; } diff --git a/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs b/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs index 3f654ebc4b..cc6ec382e8 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs @@ -6,7 +6,6 @@ use unicode_width::UnicodeWidthStr; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_ast::source_code::Generator; use crate::checkers::ast::Checker; @@ -238,7 +237,7 @@ pub(crate) fn convert_for_loop_to_any_all( }, TextRange::new(stmt.start(), loop_info.terminal), ); - if checker.patch(diagnostic.kind.rule()) && checker.ctx.is_builtin("any") { + if checker.patch(diagnostic.kind.rule()) && checker.model.is_builtin("any") { #[allow(deprecated)] diagnostic.set_fix(Fix::unspecified(Edit::replacement( contents, @@ -328,7 +327,7 @@ pub(crate) fn convert_for_loop_to_any_all( }, TextRange::new(stmt.start(), loop_info.terminal), ); - if checker.patch(diagnostic.kind.rule()) && checker.ctx.is_builtin("all") { + if checker.patch(diagnostic.kind.rule()) && checker.model.is_builtin("all") { #[allow(deprecated)] diagnostic.set_fix(Fix::unspecified(Edit::replacement( contents, diff --git a/crates/ruff/src/rules/flake8_simplify/rules/suppressible_exception.rs b/crates/ruff/src/rules/flake8_simplify/rules/suppressible_exception.rs index 086fdb97c5..b4d5350bd8 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/suppressible_exception.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/suppressible_exception.rs @@ -93,7 +93,7 @@ pub(crate) fn suppressible_exception( "contextlib", "suppress", stmt.start(), - &checker.ctx, + &checker.model, &checker.importer, checker.locator, )?; diff --git a/crates/ruff/src/rules/flake8_tidy_imports/banned_api.rs b/crates/ruff/src/rules/flake8_tidy_imports/banned_api.rs index bcaf261967..78f7837fed 100644 --- a/crates/ruff/src/rules/flake8_tidy_imports/banned_api.rs +++ b/crates/ruff/src/rules/flake8_tidy_imports/banned_api.rs @@ -96,7 +96,7 @@ where /// TID251 pub(crate) fn banned_attribute_access(checker: &mut Checker, expr: &Expr) { let banned_api = &checker.settings.flake8_tidy_imports.banned_api; - if let Some((banned_path, ban)) = checker.ctx.resolve_call_path(expr).and_then(|call_path| { + if let Some((banned_path, ban)) = checker.model.resolve_call_path(expr).and_then(|call_path| { banned_api .iter() .find(|(banned_path, ..)| call_path == from_qualified_name(banned_path)) diff --git a/crates/ruff/src/rules/flake8_type_checking/helpers.rs b/crates/ruff/src/rules/flake8_type_checking/helpers.rs index 317ec2f044..2fda263bab 100644 --- a/crates/ruff/src/rules/flake8_type_checking/helpers.rs +++ b/crates/ruff/src/rules/flake8_type_checking/helpers.rs @@ -4,11 +4,11 @@ use rustpython_parser::ast::{self, Constant, Expr}; use ruff_python_ast::call_path::from_qualified_name; use ruff_python_ast::helpers::map_callable; use ruff_python_semantic::binding::{Binding, BindingKind, ExecutionContext}; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use ruff_python_semantic::scope::ScopeKind; /// Return `true` if [`Expr`] is a guard for a type-checking block. -pub(crate) fn is_type_checking_block(context: &Context, test: &Expr) -> bool { +pub(crate) fn is_type_checking_block(model: &SemanticModel, test: &Expr) -> bool { // Ex) `if False:` if matches!( test, @@ -32,7 +32,7 @@ pub(crate) fn is_type_checking_block(context: &Context, test: &Expr) -> bool { } // Ex) `if typing.TYPE_CHECKING:` - if context.resolve_call_path(test).map_or(false, |call_path| { + if model.resolve_call_path(test).map_or(false, |call_path| { call_path.as_slice() == ["typing", "TYPE_CHECKING"] }) { return true; @@ -55,27 +55,27 @@ pub(crate) const fn is_valid_runtime_import(binding: &Binding) -> bool { } pub(crate) fn runtime_evaluated( - context: &Context, + model: &SemanticModel, base_classes: &[String], decorators: &[String], ) -> bool { if !base_classes.is_empty() { - if runtime_evaluated_base_class(context, base_classes) { + if runtime_evaluated_base_class(model, base_classes) { return true; } } if !decorators.is_empty() { - if runtime_evaluated_decorators(context, decorators) { + if runtime_evaluated_decorators(model, decorators) { return true; } } false } -fn runtime_evaluated_base_class(context: &Context, base_classes: &[String]) -> bool { - if let ScopeKind::Class(class_def) = &context.scope().kind { +fn runtime_evaluated_base_class(model: &SemanticModel, base_classes: &[String]) -> bool { + if let ScopeKind::Class(class_def) = &model.scope().kind { for base in class_def.bases.iter() { - if let Some(call_path) = context.resolve_call_path(base) { + if let Some(call_path) = model.resolve_call_path(base) { if base_classes .iter() .any(|base_class| from_qualified_name(base_class) == call_path) @@ -88,10 +88,10 @@ fn runtime_evaluated_base_class(context: &Context, base_classes: &[String]) -> b false } -fn runtime_evaluated_decorators(context: &Context, decorators: &[String]) -> bool { - if let ScopeKind::Class(class_def) = &context.scope().kind { +fn runtime_evaluated_decorators(model: &SemanticModel, decorators: &[String]) -> bool { + if let ScopeKind::Class(class_def) = &model.scope().kind { for decorator in class_def.decorator_list.iter() { - if let Some(call_path) = context.resolve_call_path(map_callable(decorator)) { + if let Some(call_path) = model.resolve_call_path(map_callable(decorator)) { if decorators .iter() .any(|decorator| from_qualified_name(decorator) == call_path) diff --git a/crates/ruff/src/rules/flake8_type_checking/mod.rs b/crates/ruff/src/rules/flake8_type_checking/mod.rs index cec52d2f45..ff2b1c298c 100644 --- a/crates/ruff/src/rules/flake8_type_checking/mod.rs +++ b/crates/ruff/src/rules/flake8_type_checking/mod.rs @@ -9,7 +9,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_type_checking/rules/empty_type_checking_block.rs b/crates/ruff/src/rules/flake8_type_checking/rules/empty_type_checking_block.rs index f78759d651..42d16eecad 100644 --- a/crates/ruff/src/rules/flake8_type_checking/rules/empty_type_checking_block.rs +++ b/crates/ruff/src/rules/flake8_type_checking/rules/empty_type_checking_block.rs @@ -60,7 +60,7 @@ pub(crate) fn empty_type_checking_block<'a, 'b>( // Delete the entire type-checking block. if checker.patch(diagnostic.kind.rule()) { - let parent = checker.ctx.stmts.parent(stmt); + let parent = checker.model.stmts.parent(stmt); let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect(); match delete_stmt( stmt, diff --git a/crates/ruff/src/rules/flake8_unused_arguments/mod.rs b/crates/ruff/src/rules/flake8_unused_arguments/mod.rs index 1739430a9a..d2543b31d9 100644 --- a/crates/ruff/src/rules/flake8_unused_arguments/mod.rs +++ b/crates/ruff/src/rules/flake8_unused_arguments/mod.rs @@ -9,7 +9,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/flake8_unused_arguments/rules.rs b/crates/ruff/src/rules/flake8_unused_arguments/rules.rs index 65a94ebf51..d46421c8ad 100644 --- a/crates/ruff/src/rules/flake8_unused_arguments/rules.rs +++ b/crates/ruff/src/rules/flake8_unused_arguments/rules.rs @@ -289,7 +289,7 @@ pub(crate) fn unused_arguments( .. }) => { match function_type::classify( - &checker.ctx, + &checker.model, parent, name, decorator_list, @@ -301,7 +301,7 @@ pub(crate) fn unused_arguments( .settings .rules .enabled(Argumentable::Function.rule_code()) - && !visibility::is_overload(&checker.ctx, decorator_list) + && !visibility::is_overload(&checker.model, decorator_list) { function( Argumentable::Function, @@ -328,9 +328,9 @@ pub(crate) fn unused_arguments( || visibility::is_init(name) || visibility::is_new(name) || visibility::is_call(name)) - && !visibility::is_abstract(&checker.ctx, decorator_list) - && !visibility::is_override(&checker.ctx, decorator_list) - && !visibility::is_overload(&checker.ctx, decorator_list) + && !visibility::is_abstract(&checker.model, decorator_list) + && !visibility::is_override(&checker.model, decorator_list) + && !visibility::is_overload(&checker.model, decorator_list) { method( Argumentable::Method, @@ -357,9 +357,9 @@ pub(crate) fn unused_arguments( || visibility::is_init(name) || visibility::is_new(name) || visibility::is_call(name)) - && !visibility::is_abstract(&checker.ctx, decorator_list) - && !visibility::is_override(&checker.ctx, decorator_list) - && !visibility::is_overload(&checker.ctx, decorator_list) + && !visibility::is_abstract(&checker.model, decorator_list) + && !visibility::is_override(&checker.model, decorator_list) + && !visibility::is_overload(&checker.model, decorator_list) { method( Argumentable::ClassMethod, @@ -386,9 +386,9 @@ pub(crate) fn unused_arguments( || visibility::is_init(name) || visibility::is_new(name) || visibility::is_call(name)) - && !visibility::is_abstract(&checker.ctx, decorator_list) - && !visibility::is_override(&checker.ctx, decorator_list) - && !visibility::is_overload(&checker.ctx, decorator_list) + && !visibility::is_abstract(&checker.model, decorator_list) + && !visibility::is_override(&checker.model, decorator_list) + && !visibility::is_overload(&checker.model, decorator_list) { function( Argumentable::StaticMethod, diff --git a/crates/ruff/src/rules/flake8_use_pathlib/helpers.rs b/crates/ruff/src/rules/flake8_use_pathlib/helpers.rs index 5978d2dfc6..08dcc457ee 100644 --- a/crates/ruff/src/rules/flake8_use_pathlib/helpers.rs +++ b/crates/ruff/src/rules/flake8_use_pathlib/helpers.rs @@ -1,5 +1,7 @@ use rustpython_parser::ast::{Expr, Ranged}; +use ruff_diagnostics::{Diagnostic, DiagnosticKind}; + use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_use_pathlib::violations::{ @@ -9,12 +11,11 @@ use crate::rules::flake8_use_pathlib::violations::{ OsRmdir, OsStat, OsUnlink, PathlibReplace, PyPath, }; use crate::settings::types::PythonVersion; -use ruff_diagnostics::{Diagnostic, DiagnosticKind}; pub(crate) fn replaceable_by_pathlib(checker: &mut Checker, expr: &Expr) { if let Some(diagnostic_kind) = checker - .ctx + .model .resolve_call_path(expr) .and_then(|call_path| match call_path.as_slice() { ["os", "path", "abspath"] => Some(OsPathAbspath.into()), diff --git a/crates/ruff/src/rules/flynt/rules/mod.rs b/crates/ruff/src/rules/flynt/rules/mod.rs index d3bd2e2746..ce0b9462d8 100644 --- a/crates/ruff/src/rules/flynt/rules/mod.rs +++ b/crates/ruff/src/rules/flynt/rules/mod.rs @@ -1,3 +1,3 @@ -mod static_join_to_fstring; - pub(crate) use static_join_to_fstring::{static_join_to_fstring, StaticJoinToFString}; + +mod static_join_to_fstring; diff --git a/crates/ruff/src/rules/isort/comments.rs b/crates/ruff/src/rules/isort/comments.rs index 7b4d7417d8..8b2e001186 100644 --- a/crates/ruff/src/rules/isort/comments.rs +++ b/crates/ruff/src/rules/isort/comments.rs @@ -1,6 +1,6 @@ -use ruff_text_size::{TextRange, TextSize}; use std::borrow::Cow; +use ruff_text_size::{TextRange, TextSize}; use rustpython_parser::{lexer, Mode, Tok}; use ruff_python_ast::source_code::Locator; diff --git a/crates/ruff/src/rules/isort/format.rs b/crates/ruff/src/rules/isort/format.rs index 4304d86f5d..0194dc4fa1 100644 --- a/crates/ruff/src/rules/isort/format.rs +++ b/crates/ruff/src/rules/isort/format.rs @@ -1,6 +1,7 @@ -use ruff_python_ast::source_code::Stylist; use unicode_width::UnicodeWidthStr; +use ruff_python_ast::source_code::Stylist; + use super::types::{AliasData, CommentSet, ImportFromData, Importable}; // Guess a capacity to use for string allocation. diff --git a/crates/ruff/src/rules/isort/mod.rs b/crates/ruff/src/rules/isort/mod.rs index ad72fdbc2b..aba67b45f9 100644 --- a/crates/ruff/src/rules/isort/mod.rs +++ b/crates/ruff/src/rules/isort/mod.rs @@ -282,12 +282,11 @@ mod tests { use std::path::Path; use anyhow::Result; - - use crate::message::Message; use rustc_hash::FxHashMap; use test_case::test_case; use crate::assert_messages; + use crate::message::Message; use crate::registry::Rule; use crate::rules::isort::categorize::{ImportSection, KnownModules}; use crate::settings::Settings; diff --git a/crates/ruff/src/rules/isort/normalize.rs b/crates/ruff/src/rules/isort/normalize.rs index b626d03ede..1c0e4312ed 100644 --- a/crates/ruff/src/rules/isort/normalize.rs +++ b/crates/ruff/src/rules/isort/normalize.rs @@ -1,6 +1,7 @@ -use crate::rules::isort::types::TrailingComma; use std::collections::BTreeSet; +use crate::rules::isort::types::TrailingComma; + use super::types::{AliasData, ImportBlock, ImportFromData}; use super::AnnotatedImport; diff --git a/crates/ruff/src/rules/mccabe/mod.rs b/crates/ruff/src/rules/mccabe/mod.rs index ad21d2e16c..697859e26a 100644 --- a/crates/ruff/src/rules/mccabe/mod.rs +++ b/crates/ruff/src/rules/mccabe/mod.rs @@ -6,11 +6,10 @@ pub mod settings; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; - use test_case::test_case; + use crate::assert_messages; use crate::registry::Rule; use crate::settings::Settings; use crate::test::test_path; diff --git a/crates/ruff/src/rules/mccabe/settings.rs b/crates/ruff/src/rules/mccabe/settings.rs index 8f53f535e2..eb8daa8dcc 100644 --- a/crates/ruff/src/rules/mccabe/settings.rs +++ b/crates/ruff/src/rules/mccabe/settings.rs @@ -1,8 +1,9 @@ //! Settings for the `mccabe` plugin. -use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; use serde::{Deserialize, Serialize}; +use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; + #[derive( Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, CombineOptions, )] diff --git a/crates/ruff/src/rules/numpy/mod.rs b/crates/ruff/src/rules/numpy/mod.rs index 865b116cd9..97a25000e5 100644 --- a/crates/ruff/src/rules/numpy/mod.rs +++ b/crates/ruff/src/rules/numpy/mod.rs @@ -7,7 +7,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/numpy/rules/deprecated_type_alias.rs b/crates/ruff/src/rules/numpy/rules/deprecated_type_alias.rs index 8a136e292f..1ecd42c7e6 100644 --- a/crates/ruff/src/rules/numpy/rules/deprecated_type_alias.rs +++ b/crates/ruff/src/rules/numpy/rules/deprecated_type_alias.rs @@ -48,7 +48,7 @@ impl AlwaysAutofixableViolation for NumpyDeprecatedTypeAlias { /// NPY001 pub(crate) fn deprecated_type_alias(checker: &mut Checker, expr: &Expr) { - if let Some(type_name) = checker.ctx.resolve_call_path(expr).and_then(|call_path| { + if let Some(type_name) = checker.model.resolve_call_path(expr).and_then(|call_path| { if call_path.as_slice() == ["numpy", "bool"] || call_path.as_slice() == ["numpy", "int"] || call_path.as_slice() == ["numpy", "float"] diff --git a/crates/ruff/src/rules/numpy/rules/numpy_legacy_random.rs b/crates/ruff/src/rules/numpy/rules/numpy_legacy_random.rs index d1e5aa055b..c78ad8b201 100644 --- a/crates/ruff/src/rules/numpy/rules/numpy_legacy_random.rs +++ b/crates/ruff/src/rules/numpy/rules/numpy_legacy_random.rs @@ -1,9 +1,10 @@ use rustpython_parser::ast::{Expr, Ranged}; -use crate::checkers::ast::Checker; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use crate::checkers::ast::Checker; + /// ## What it does /// Checks for the use of legacy `np.random` function calls. /// @@ -57,7 +58,7 @@ impl Violation for NumpyLegacyRandom { /// NPY002 pub(crate) fn numpy_legacy_random(checker: &mut Checker, expr: &Expr) { - if let Some(method_name) = checker.ctx.resolve_call_path(expr).and_then(|call_path| { + if let Some(method_name) = checker.model.resolve_call_path(expr).and_then(|call_path| { // seeding state if call_path.as_slice() == ["numpy", "random", "seed"] || call_path.as_slice() == ["numpy", "random", "get_state"] diff --git a/crates/ruff/src/rules/pandas_vet/helpers.rs b/crates/ruff/src/rules/pandas_vet/helpers.rs index 45db1a5d0b..6783a960dd 100644 --- a/crates/ruff/src/rules/pandas_vet/helpers.rs +++ b/crates/ruff/src/rules/pandas_vet/helpers.rs @@ -1,8 +1,9 @@ -use ruff_python_semantic::binding::{BindingKind, Importation}; -use ruff_python_semantic::context::Context; use rustpython_parser::ast; use rustpython_parser::ast::Expr; +use ruff_python_semantic::binding::{BindingKind, Importation}; +use ruff_python_semantic::model::SemanticModel; + pub(crate) enum Resolution { /// The expression resolves to an irrelevant expression type (e.g., a constant). IrrelevantExpression, @@ -15,7 +16,7 @@ pub(crate) enum Resolution { } /// Test an [`Expr`] for relevance to Pandas-related operations. -pub(crate) fn test_expression(expr: &Expr, context: &Context) -> Resolution { +pub(crate) fn test_expression(expr: &Expr, model: &SemanticModel) -> Resolution { match expr { Expr::Constant(_) | Expr::Tuple(_) @@ -27,7 +28,7 @@ pub(crate) fn test_expression(expr: &Expr, context: &Context) -> Resolution { | Expr::DictComp(_) | Expr::GeneratorExp(_) => Resolution::IrrelevantExpression, Expr::Name(ast::ExprName { id, .. }) => { - context + model .find_binding(id) .map_or(Resolution::IrrelevantBinding, |binding| { match binding.kind { diff --git a/crates/ruff/src/rules/pandas_vet/mod.rs b/crates/ruff/src/rules/pandas_vet/mod.rs index cc610c5ad6..346caf8137 100644 --- a/crates/ruff/src/rules/pandas_vet/mod.rs +++ b/crates/ruff/src/rules/pandas_vet/mod.rs @@ -8,7 +8,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use rustpython_parser::lexer::LexResult; use test_case::test_case; use textwrap::dedent; diff --git a/crates/ruff/src/rules/pandas_vet/rules/attr.rs b/crates/ruff/src/rules/pandas_vet/rules/attr.rs index 67311ad8a0..f47a15926e 100644 --- a/crates/ruff/src/rules/pandas_vet/rules/attr.rs +++ b/crates/ruff/src/rules/pandas_vet/rules/attr.rs @@ -26,7 +26,7 @@ pub(crate) fn attr(checker: &mut Checker, attr: &str, value: &Expr, attr_expr: & }; // Avoid flagging on function calls (e.g., `df.values()`). - if let Some(parent) = checker.ctx.expr_parent() { + if let Some(parent) = checker.model.expr_parent() { if matches!(parent, Expr::Call(_)) { return; } @@ -35,7 +35,7 @@ pub(crate) fn attr(checker: &mut Checker, attr: &str, value: &Expr, attr_expr: & // Avoid flagging on non-DataFrames (e.g., `{"a": 1}.values`), and on irrelevant bindings // (like imports). if !matches!( - test_expression(value, &checker.ctx), + test_expression(value, &checker.model), Resolution::RelevantLocal ) { return; diff --git a/crates/ruff/src/rules/pandas_vet/rules/call.rs b/crates/ruff/src/rules/pandas_vet/rules/call.rs index 2d0396d1fc..28ef3bcec0 100644 --- a/crates/ruff/src/rules/pandas_vet/rules/call.rs +++ b/crates/ruff/src/rules/pandas_vet/rules/call.rs @@ -80,7 +80,7 @@ pub(crate) fn call(checker: &mut Checker, func: &Expr) { // Ignore irrelevant bindings (like imports). if !matches!( - test_expression(value, &checker.ctx), + test_expression(value, &checker.model), Resolution::RelevantLocal | Resolution::PandasModule ) { return; diff --git a/crates/ruff/src/rules/pandas_vet/rules/inplace_argument.rs b/crates/ruff/src/rules/pandas_vet/rules/inplace_argument.rs index 40421917bf..e0ab23bef8 100644 --- a/crates/ruff/src/rules/pandas_vet/rules/inplace_argument.rs +++ b/crates/ruff/src/rules/pandas_vet/rules/inplace_argument.rs @@ -1,8 +1,8 @@ -use ruff_python_semantic::binding::{BindingKind, Importation}; use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged}; use ruff_diagnostics::{AutofixKind, Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_semantic::binding::{BindingKind, Importation}; use crate::checkers::ast::Checker; use crate::registry::AsRule; @@ -60,11 +60,11 @@ pub(crate) fn inplace_argument( let mut is_checkable = false; let mut is_pandas = false; - if let Some(call_path) = checker.ctx.resolve_call_path(func) { + if let Some(call_path) = checker.model.resolve_call_path(func) { is_checkable = true; let module = call_path[0]; - is_pandas = checker.ctx.find_binding(module).map_or(false, |binding| { + is_pandas = checker.model.find_binding(module).map_or(false, |binding| { matches!( binding.kind, BindingKind::Importation(Importation { @@ -99,9 +99,9 @@ pub(crate) fn inplace_argument( // but we don't currently restore expression stacks when parsing deferred nodes, // and so the parent is lost. let fixable = !seen_star - && checker.ctx.stmt().is_expr_stmt() - && checker.ctx.expr_parent().is_none() - && !checker.ctx.scope().kind.is_lambda(); + && checker.model.stmt().is_expr_stmt() + && checker.model.expr_parent().is_none() + && !checker.model.scope().kind.is_lambda(); let mut diagnostic = Diagnostic::new(PandasUseOfInplaceArgument, keyword.range()); if fixable && checker.patch(diagnostic.kind.rule()) { if let Some(fix) = convert_inplace_argument_to_assignment( diff --git a/crates/ruff/src/rules/pandas_vet/rules/subscript.rs b/crates/ruff/src/rules/pandas_vet/rules/subscript.rs index 1ee7147a0b..394dfde43a 100644 --- a/crates/ruff/src/rules/pandas_vet/rules/subscript.rs +++ b/crates/ruff/src/rules/pandas_vet/rules/subscript.rs @@ -54,7 +54,7 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, expr: &Expr) { // Avoid flagging on non-DataFrames (e.g., `{"a": 1}.at[0]`), and on irrelevant bindings // (like imports). if !matches!( - test_expression(value, &checker.ctx), + test_expression(value, &checker.model), Resolution::RelevantLocal ) { return; diff --git a/crates/ruff/src/rules/pep8_naming/helpers.rs b/crates/ruff/src/rules/pep8_naming/helpers.rs index 29b0a803f1..11e96981ca 100644 --- a/crates/ruff/src/rules/pep8_naming/helpers.rs +++ b/crates/ruff/src/rules/pep8_naming/helpers.rs @@ -1,7 +1,7 @@ use itertools::Itertools; -use ruff_python_semantic::context::Context; use rustpython_parser::ast::{self, Expr, Stmt}; +use ruff_python_semantic::model::SemanticModel; use ruff_python_stdlib::str::{is_lower, is_upper}; pub(crate) fn is_camelcase(name: &str) -> bool { @@ -22,14 +22,14 @@ pub(crate) fn is_acronym(name: &str, asname: &str) -> bool { name.chars().filter(|c| c.is_uppercase()).join("") == asname } -pub(crate) fn is_named_tuple_assignment(context: &Context, stmt: &Stmt) -> bool { +pub(crate) fn is_named_tuple_assignment(model: &SemanticModel, stmt: &Stmt) -> bool { let Stmt::Assign(ast::StmtAssign { value, .. }) = stmt else { return false; }; let Expr::Call(ast::ExprCall {func, ..}) = value.as_ref() else { return false; }; - context.resolve_call_path(func).map_or(false, |call_path| { + model.resolve_call_path(func).map_or(false, |call_path| { matches!( call_path.as_slice(), ["collections", "namedtuple"] | ["typing", "NamedTuple"] @@ -37,35 +37,35 @@ pub(crate) fn is_named_tuple_assignment(context: &Context, stmt: &Stmt) -> bool }) } -pub(crate) fn is_typed_dict_assignment(context: &Context, stmt: &Stmt) -> bool { +pub(crate) fn is_typed_dict_assignment(model: &SemanticModel, stmt: &Stmt) -> bool { let Stmt::Assign(ast::StmtAssign { value, .. }) = stmt else { return false; }; let Expr::Call(ast::ExprCall {func, ..}) = value.as_ref() else { return false; }; - context.resolve_call_path(func).map_or(false, |call_path| { + model.resolve_call_path(func).map_or(false, |call_path| { call_path.as_slice() == ["typing", "TypedDict"] }) } -pub(crate) fn is_type_var_assignment(context: &Context, stmt: &Stmt) -> bool { +pub(crate) fn is_type_var_assignment(model: &SemanticModel, stmt: &Stmt) -> bool { let Stmt::Assign(ast::StmtAssign { value, .. }) = stmt else { return false; }; let Expr::Call(ast::ExprCall {func, ..}) = value.as_ref() else { return false; }; - context.resolve_call_path(func).map_or(false, |call_path| { + model.resolve_call_path(func).map_or(false, |call_path| { call_path.as_slice() == ["typing", "TypeVar"] || call_path.as_slice() == ["typing", "NewType"] }) } -pub(crate) fn is_typed_dict_class(context: &Context, bases: &[Expr]) -> bool { +pub(crate) fn is_typed_dict_class(model: &SemanticModel, bases: &[Expr]) -> bool { bases .iter() - .any(|base| context.match_typing_expr(base, "TypedDict")) + .any(|base| model.match_typing_expr(base, "TypedDict")) } #[cfg(test)] diff --git a/crates/ruff/src/rules/pep8_naming/mod.rs b/crates/ruff/src/rules/pep8_naming/mod.rs index 989376efd0..8c4f53b04f 100644 --- a/crates/ruff/src/rules/pep8_naming/mod.rs +++ b/crates/ruff/src/rules/pep8_naming/mod.rs @@ -8,7 +8,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs index 010d69dfb4..9d5709ba95 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs @@ -64,7 +64,7 @@ pub(crate) fn invalid_first_argument_name_for_class_method( ) -> Option { if !matches!( function_type::classify( - &checker.ctx, + &checker.model, scope, name, decorator_list, diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs index 6a6c786035..b206a396f1 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs @@ -61,7 +61,7 @@ pub(crate) fn invalid_first_argument_name_for_method( ) -> Option { if !matches!( function_type::classify( - &checker.ctx, + &checker.model, scope, name, decorator_list, diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs index e8843a7a3f..1b908c2256 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs @@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::identifier_range; use ruff_python_ast::source_code::Locator; use ruff_python_semantic::analyze::visibility; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; /// ## What it does /// Checks for functions names that do not follow the `snake_case` naming @@ -53,7 +53,7 @@ pub(crate) fn invalid_function_name( name: &str, decorator_list: &[Expr], ignore_names: &[String], - ctx: &Context, + model: &SemanticModel, locator: &Locator, ) -> Option { // Ignore any explicitly-ignored function names. @@ -68,7 +68,7 @@ pub(crate) fn invalid_function_name( // Ignore any functions that are explicitly `@override`. These are defined elsewhere, // so if they're first-party, we'll flag them at the definition site. - if visibility::is_override(ctx, decorator_list) { + if visibility::is_override(model, decorator_list) { return None; } diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_module_name.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_module_name.rs index 165f3036e0..aa42ba8a89 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_module_name.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_module_name.rs @@ -1,7 +1,8 @@ -use ruff_text_size::TextRange; use std::ffi::OsStr; use std::path::Path; +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_stdlib::identifiers::{is_migration_name, is_module_name}; diff --git a/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_class_scope.rs b/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_class_scope.rs index 6834f0a093..bd471058f5 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_class_scope.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_class_scope.rs @@ -67,8 +67,8 @@ pub(crate) fn mixed_case_variable_in_class_scope( return; } if helpers::is_mixed_case(name) - && !helpers::is_named_tuple_assignment(&checker.ctx, stmt) - && !helpers::is_typed_dict_class(&checker.ctx, bases) + && !helpers::is_named_tuple_assignment(&checker.model, stmt) + && !helpers::is_typed_dict_class(&checker.model, bases) { checker.diagnostics.push(Diagnostic::new( MixedCaseVariableInClassScope { diff --git a/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_global_scope.rs b/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_global_scope.rs index fcad8aa628..0b14ea5d93 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_global_scope.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_global_scope.rs @@ -75,7 +75,7 @@ pub(crate) fn mixed_case_variable_in_global_scope( { return; } - if helpers::is_mixed_case(name) && !helpers::is_named_tuple_assignment(&checker.ctx, stmt) { + if helpers::is_mixed_case(name) && !helpers::is_named_tuple_assignment(&checker.model, stmt) { checker.diagnostics.push(Diagnostic::new( MixedCaseVariableInGlobalScope { name: name.to_string(), diff --git a/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs b/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs index 2b7e45286d..ea774aa24d 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs @@ -66,9 +66,9 @@ pub(crate) fn non_lowercase_variable_in_function( } if name.to_lowercase() != name - && !helpers::is_named_tuple_assignment(&checker.ctx, stmt) - && !helpers::is_typed_dict_assignment(&checker.ctx, stmt) - && !helpers::is_type_var_assignment(&checker.ctx, stmt) + && !helpers::is_named_tuple_assignment(&checker.model, stmt) + && !helpers::is_typed_dict_assignment(&checker.model, stmt) + && !helpers::is_type_var_assignment(&checker.model, stmt) { checker.diagnostics.push(Diagnostic::new( NonLowercaseVariableInFunction { diff --git a/crates/ruff/src/rules/pep8_naming/settings.rs b/crates/ruff/src/rules/pep8_naming/settings.rs index ffc77699fc..cfacb63632 100644 --- a/crates/ruff/src/rules/pep8_naming/settings.rs +++ b/crates/ruff/src/rules/pep8_naming/settings.rs @@ -1,8 +1,9 @@ //! Settings for the `pep8-naming` plugin. -use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; use serde::{Deserialize, Serialize}; +use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; + const IGNORE_NAMES: [&str; 12] = [ "setUp", "tearDown", diff --git a/crates/ruff/src/rules/pycodestyle/mod.rs b/crates/ruff/src/rules/pycodestyle/mod.rs index 7b7f492426..85999ec70e 100644 --- a/crates/ruff/src/rules/pycodestyle/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/mod.rs @@ -9,7 +9,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/pycodestyle/rules/ambiguous_class_name.rs b/crates/ruff/src/rules/pycodestyle/rules/ambiguous_class_name.rs index d03b69ac62..c5159f0119 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/ambiguous_class_name.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/ambiguous_class_name.rs @@ -1,6 +1,7 @@ +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::TextRange; use crate::rules::pycodestyle::helpers::is_ambiguous_name; diff --git a/crates/ruff/src/rules/pycodestyle/rules/ambiguous_function_name.rs b/crates/ruff/src/rules/pycodestyle/rules/ambiguous_function_name.rs index c45bfda3a0..653814af77 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/ambiguous_function_name.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/ambiguous_function_name.rs @@ -1,6 +1,7 @@ +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::TextRange; use crate::rules::pycodestyle::helpers::is_ambiguous_name; diff --git a/crates/ruff/src/rules/pycodestyle/rules/ambiguous_variable_name.rs b/crates/ruff/src/rules/pycodestyle/rules/ambiguous_variable_name.rs index 4aa2ecdbe4..4abeb9444e 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/ambiguous_variable_name.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/ambiguous_variable_name.rs @@ -1,6 +1,7 @@ +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::TextRange; use crate::rules::pycodestyle::helpers::is_ambiguous_name; diff --git a/crates/ruff/src/rules/pycodestyle/rules/errors.rs b/crates/ruff/src/rules/pycodestyle/rules/errors.rs index ad6c56caaf..4b81bf466c 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/errors.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/errors.rs @@ -1,11 +1,12 @@ use ruff_text_size::{TextLen, TextRange, TextSize}; use rustpython_parser::ParseError; -use crate::logging::DisplayParseErrorType; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::source_code::Locator; +use crate::logging::DisplayParseErrorType; + #[violation] pub struct IOError { pub message: String, diff --git a/crates/ruff/src/rules/pycodestyle/rules/imports.rs b/crates/ruff/src/rules/pycodestyle/rules/imports.rs index 09cc5fb600..15ce7e5658 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/imports.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/imports.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{Alias, Ranged, Stmt}; -use crate::checkers::ast::Checker; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::source_code::Locator; +use crate::checkers::ast::Checker; + /// ## What it does /// Check for multiple imports on one line. /// @@ -87,7 +88,7 @@ pub(crate) fn module_import_not_at_top_of_file( stmt: &Stmt, locator: &Locator, ) { - if checker.ctx.seen_import_boundary() && locator.is_at_start_of_line(stmt.start()) { + if checker.model.seen_import_boundary() && locator.is_at_start_of_line(stmt.start()) { checker .diagnostics .push(Diagnostic::new(ModuleImportNotAtTopOfFile, stmt.range())); diff --git a/crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs b/crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs index 3defc9b456..af96e9c7c3 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs @@ -7,7 +7,7 @@ use ruff_python_ast::helpers::{has_leading_content, has_trailing_content}; use ruff_python_ast::newlines::StrExt; use ruff_python_ast::source_code::Generator; use ruff_python_ast::whitespace::leading_space; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; @@ -72,7 +72,7 @@ pub(crate) fn lambda_assignment( // package like dataclasses, which wouldn't consider the // rewritten function definition to be equivalent. // See https://github.com/charliermarsh/ruff/issues/3046 - let fixable = !matches!(checker.ctx.scope().kind, ScopeKind::Class(_)); + let fixable = !matches!(checker.model.scope().kind, ScopeKind::Class(_)); let mut diagnostic = Diagnostic::new( LambdaAssignment { @@ -90,7 +90,7 @@ pub(crate) fn lambda_assignment( let indentation = &leading_space(first_line); let mut indented = String::new(); for (idx, line) in function( - &checker.ctx, + &checker.model, id, args, body, @@ -124,7 +124,7 @@ pub(crate) fn lambda_assignment( /// The `Callable` import can be from either `collections.abc` or `typing`. /// If an ellipsis is used for the argument types, an empty list is returned. /// The returned values are cloned, so they can be used as-is. -fn extract_types(ctx: &Context, annotation: &Expr) -> Option<(Vec, Expr)> { +fn extract_types(model: &SemanticModel, annotation: &Expr) -> Option<(Vec, Expr)> { let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = &annotation else { return None; }; @@ -135,9 +135,9 @@ fn extract_types(ctx: &Context, annotation: &Expr) -> Option<(Vec, Expr)> return None; } - if !ctx.resolve_call_path(value).map_or(false, |call_path| { + if !model.resolve_call_path(value).map_or(false, |call_path| { call_path.as_slice() == ["collections", "abc", "Callable"] - || ctx.match_typing_call_path(&call_path, "Callable") + || model.match_typing_call_path(&call_path, "Callable") }) { return None; } @@ -160,7 +160,7 @@ fn extract_types(ctx: &Context, annotation: &Expr) -> Option<(Vec, Expr)> } fn function( - ctx: &Context, + model: &SemanticModel, name: &str, args: &Arguments, body: &Expr, @@ -172,7 +172,7 @@ fn function( range: TextRange::default(), }); if let Some(annotation) = annotation { - if let Some((arg_types, return_type)) = extract_types(ctx, annotation) { + if let Some((arg_types, return_type)) = extract_types(model, annotation) { // A `lambda` expression can only have positional and positional-only // arguments. The order is always positional-only first, then positional. let new_posonlyargs = args diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs index ab289a7863..b10e1b79fa 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs @@ -1,10 +1,13 @@ -use super::LogicalLine; -use crate::checkers::logical_lines::LogicalLinesContext; +use ruff_text_size::TextSize; + use ruff_diagnostics::Edit; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; -use ruff_text_size::TextSize; + +use crate::checkers::logical_lines::LogicalLinesContext; + +use super::LogicalLine; #[violation] pub struct MissingWhitespace { diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_after_keyword.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_after_keyword.rs index cb249accbc..19ee6a1e4e 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_after_keyword.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_after_keyword.rs @@ -1,9 +1,10 @@ -use crate::checkers::logical_lines::LogicalLinesContext; -use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; +use crate::checkers::logical_lines::LogicalLinesContext; +use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; + #[violation] pub struct MissingWhitespaceAfterKeyword; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/space_around_operator.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/space_around_operator.rs index beb2e9552e..5c111773de 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/space_around_operator.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/space_around_operator.rs @@ -1,11 +1,13 @@ use ruff_text_size::TextRange; -use super::{LogicalLine, Whitespace}; -use crate::checkers::logical_lines::LogicalLinesContext; use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; +use crate::checkers::logical_lines::LogicalLinesContext; + +use super::{LogicalLine, Whitespace}; + /// ## What it does /// Checks for extraneous tabs before an operator. /// diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs index a181c925a8..d65d1a1693 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs @@ -1,8 +1,11 @@ -use super::{LogicalLine, Whitespace}; -use crate::checkers::logical_lines::LogicalLinesContext; +use ruff_text_size::TextRange; + use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::TextRange; + +use crate::checkers::logical_lines::LogicalLinesContext; + +use super::{LogicalLine, Whitespace}; /// ## What it does /// Checks for extraneous whitespace after keywords. diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs index 935373c726..080afb2d32 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs @@ -1,9 +1,11 @@ -use crate::checkers::logical_lines::LogicalLinesContext; -use crate::rules::pycodestyle::rules::logical_lines::{LogicalLine, LogicalLineToken}; +use ruff_text_size::{TextRange, TextSize}; + use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; -use ruff_text_size::{TextRange, TextSize}; + +use crate::checkers::logical_lines::LogicalLinesContext; +use crate::rules::pycodestyle::rules::logical_lines::{LogicalLine, LogicalLineToken}; #[violation] pub struct UnexpectedSpacesAroundKeywordParameterEquals; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs index 30cf2a149c..455bd5f0f3 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs @@ -1,10 +1,12 @@ -use crate::checkers::logical_lines::LogicalLinesContext; -use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; +use ruff_text_size::{TextLen, TextRange, TextSize}; + use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::source_code::Locator; use ruff_python_ast::token_kind::TokenKind; -use ruff_text_size::{TextLen, TextRange, TextSize}; + +use crate::checkers::logical_lines::LogicalLinesContext; +use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; /// ## What it does /// Checks if inline comments are separated by at least two spaces. diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_parameters.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_parameters.rs index 0c5434509c..a65220fa74 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_parameters.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_parameters.rs @@ -1,9 +1,11 @@ -use crate::checkers::logical_lines::LogicalLinesContext; -use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; +use ruff_text_size::{TextRange, TextSize}; + use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; -use ruff_text_size::{TextRange, TextSize}; + +use crate::checkers::logical_lines::LogicalLinesContext; +use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; #[violation] pub struct WhitespaceBeforeParameters { diff --git a/crates/ruff/src/rules/pycodestyle/rules/mixed_spaces_and_tabs.rs b/crates/ruff/src/rules/pycodestyle/rules/mixed_spaces_and_tabs.rs index c296adeb89..a2a7966a40 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/mixed_spaces_and_tabs.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/mixed_spaces_and_tabs.rs @@ -1,8 +1,9 @@ +use ruff_text_size::{TextLen, TextRange}; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::newlines::Line; use ruff_python_ast::whitespace::leading_space; -use ruff_text_size::{TextLen, TextRange}; /// ## What it does /// Checks for mixed tabs and spaces in indentation. diff --git a/crates/ruff/src/rules/pycodestyle/rules/type_comparison.rs b/crates/ruff/src/rules/pycodestyle/rules/type_comparison.rs index e4d93a02b3..b49b65b5d9 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/type_comparison.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/type_comparison.rs @@ -1,10 +1,11 @@ use itertools::izip; use rustpython_parser::ast::{self, Cmpop, Constant, Expr, Ranged}; -use crate::checkers::ast::Checker; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use crate::checkers::ast::Checker; + /// ## What it does /// Checks for object type comparisons without using isinstance(). /// @@ -51,7 +52,7 @@ pub(crate) fn type_comparison( Expr::Call(ast::ExprCall { func, args, .. }) => { if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() { // Ex) `type(False)` - if id == "type" && checker.ctx.is_builtin("type") { + if id == "type" && checker.model.is_builtin("type") { if let Some(arg) = args.first() { // Allow comparison for types which are not obvious. if !matches!( @@ -76,7 +77,7 @@ pub(crate) fn type_comparison( // Ex) `types.NoneType` if id == "types" && checker - .ctx + .model .resolve_call_path(value) .map_or(false, |call_path| { call_path.first().map_or(false, |module| *module == "types") diff --git a/crates/ruff/src/rules/pycodestyle/settings.rs b/crates/ruff/src/rules/pycodestyle/settings.rs index 06204f29bb..9f6897a62a 100644 --- a/crates/ruff/src/rules/pycodestyle/settings.rs +++ b/crates/ruff/src/rules/pycodestyle/settings.rs @@ -1,8 +1,9 @@ //! Settings for the `pycodestyle` plugin. -use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; use serde::{Deserialize, Serialize}; +use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; + #[derive( Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, CombineOptions, )] diff --git a/crates/ruff/src/rules/pydocstyle/helpers.rs b/crates/ruff/src/rules/pydocstyle/helpers.rs index c63964ba19..4be0b193e9 100644 --- a/crates/ruff/src/rules/pydocstyle/helpers.rs +++ b/crates/ruff/src/rules/pydocstyle/helpers.rs @@ -52,7 +52,7 @@ pub(crate) fn should_ignore_definition( }) = definition { for decorator in cast::decorator_list(stmt) { - if let Some(call_path) = checker.ctx.resolve_call_path(map_callable(decorator)) { + if let Some(call_path) = checker.model.resolve_call_path(map_callable(decorator)) { if ignore_decorators .iter() .any(|decorator| from_qualified_name(decorator) == call_path) diff --git a/crates/ruff/src/rules/pydocstyle/mod.rs b/crates/ruff/src/rules/pydocstyle/mod.rs index 80ddf076f5..86206741d3 100644 --- a/crates/ruff/src/rules/pydocstyle/mod.rs +++ b/crates/ruff/src/rules/pydocstyle/mod.rs @@ -9,7 +9,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/pydocstyle/rules/blank_before_after_class.rs b/crates/ruff/src/rules/pydocstyle/rules/blank_before_after_class.rs index a07bf56ff8..77661d2e3f 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/blank_before_after_class.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/blank_before_after_class.rs @@ -1,9 +1,10 @@ +use ruff_text_size::{TextLen, TextRange}; +use rustpython_parser::ast::Ranged; + use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::newlines::{StrExt, UniversalNewlineIterator}; use ruff_python_semantic::definition::{Definition, Member, MemberKind}; -use ruff_text_size::{TextLen, TextRange}; -use rustpython_parser::ast::Ranged; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/if_needed.rs b/crates/ruff/src/rules/pydocstyle/rules/if_needed.rs index 87cf83fee4..43211c6fae 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/if_needed.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/if_needed.rs @@ -27,7 +27,7 @@ pub(crate) fn if_needed(checker: &mut Checker, docstring: &Docstring) { }) = docstring.definition else { return; }; - if !is_overload(&checker.ctx, cast::decorator_list(stmt)) { + if !is_overload(&checker.model, cast::decorator_list(stmt)) { return; } checker.diagnostics.push(Diagnostic::new( diff --git a/crates/ruff/src/rules/pydocstyle/rules/indent.rs b/crates/ruff/src/rules/pydocstyle/rules/indent.rs index e76c3bf420..c37d89d470 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/indent.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/indent.rs @@ -1,9 +1,10 @@ +use ruff_text_size::{TextLen, TextRange}; + use ruff_diagnostics::{AlwaysAutofixableViolation, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::newlines::NewlineWithTrailingNewline; use ruff_python_ast::whitespace; -use ruff_text_size::{TextLen, TextRange}; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/newline_after_last_paragraph.rs b/crates/ruff/src/rules/pydocstyle/rules/newline_after_last_paragraph.rs index 34f3cf1047..2461d4df89 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/newline_after_last_paragraph.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/newline_after_last_paragraph.rs @@ -1,9 +1,10 @@ +use ruff_text_size::{TextLen, TextSize}; +use rustpython_parser::ast::Ranged; + use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::newlines::{NewlineWithTrailingNewline, StrExt}; use ruff_python_ast::whitespace; -use ruff_text_size::{TextLen, TextSize}; -use rustpython_parser::ast::Ranged; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/no_surrounding_whitespace.rs b/crates/ruff/src/rules/pydocstyle/rules/no_surrounding_whitespace.rs index ea2e61a8b4..8bd1682ffc 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/no_surrounding_whitespace.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/no_surrounding_whitespace.rs @@ -1,7 +1,8 @@ +use ruff_text_size::{TextLen, TextRange}; + use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::newlines::NewlineWithTrailingNewline; -use ruff_text_size::{TextLen, TextRange}; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs b/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs index 39ec77b9ec..f3be352592 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs @@ -41,7 +41,7 @@ pub(crate) fn non_imperative_mood( if is_test(cast::name(stmt)) || is_property( - &checker.ctx, + &checker.model, cast::decorator_list(stmt), &property_decorators, ) diff --git a/crates/ruff/src/rules/pydocstyle/rules/not_missing.rs b/crates/ruff/src/rules/pydocstyle/rules/not_missing.rs index 82d29685c4..2382a53a2e 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/not_missing.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/not_missing.rs @@ -1,3 +1,5 @@ +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::cast; @@ -6,10 +8,8 @@ use ruff_python_semantic::analyze::visibility::{ is_call, is_init, is_magic, is_new, is_overload, is_override, Visibility, }; use ruff_python_semantic::definition::{Definition, Member, MemberKind, Module, ModuleKind}; -use ruff_text_size::TextRange; use crate::checkers::ast::Checker; - use crate::registry::Rule; #[violation] @@ -174,7 +174,7 @@ pub(crate) fn not_missing( stmt, .. }) => { - if is_overload(&checker.ctx, cast::decorator_list(stmt)) { + if is_overload(&checker.model, cast::decorator_list(stmt)) { true } else { if checker @@ -195,8 +195,8 @@ pub(crate) fn not_missing( stmt, .. }) => { - if is_overload(&checker.ctx, cast::decorator_list(stmt)) - || is_override(&checker.ctx, cast::decorator_list(stmt)) + if is_overload(&checker.model, cast::decorator_list(stmt)) + || is_override(&checker.model, cast::decorator_list(stmt)) { true } else if is_init(cast::name(stmt)) { diff --git a/crates/ruff/src/rules/pydocstyle/rules/sections.rs b/crates/ruff/src/rules/pydocstyle/rules/sections.rs index 2f4b5adc5d..1a2a93661d 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/sections.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/sections.rs @@ -760,7 +760,7 @@ fn missing_args(checker: &mut Checker, docstring: &Docstring, docstrings_args: & // If this is a non-static method, skip `cls` or `self`. usize::from( docstring.definition.is_method() - && !is_staticmethod(&checker.ctx, cast::decorator_list(stmt)), + && !is_staticmethod(&checker.model, cast::decorator_list(stmt)), ), ) { diff --git a/crates/ruff/src/rules/pydocstyle/settings.rs b/crates/ruff/src/rules/pydocstyle/settings.rs index e3ce5bd399..1ec4a9a7fc 100644 --- a/crates/ruff/src/rules/pydocstyle/settings.rs +++ b/crates/ruff/src/rules/pydocstyle/settings.rs @@ -1,10 +1,13 @@ //! Settings for the `pydocstyle` plugin. -use crate::registry::Rule; -use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; -use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; +use serde::{Deserialize, Serialize}; + +use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; + +use crate::registry::Rule; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, CacheKey)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] diff --git a/crates/ruff/src/rules/pyflakes/fixes.rs b/crates/ruff/src/rules/pyflakes/fixes.rs index 904eba68e7..bc9ce26b33 100644 --- a/crates/ruff/src/rules/pyflakes/fixes.rs +++ b/crates/ruff/src/rules/pyflakes/fixes.rs @@ -1,15 +1,15 @@ use anyhow::{bail, Ok, Result}; use libcst_native::{Codegen, CodegenState, DictElement, Expression}; use ruff_text_size::TextRange; +use rustpython_format::{ + FieldName, FieldNamePart, FieldType, FormatPart, FormatString, FromTemplate, +}; use rustpython_parser::ast::{Excepthandler, Expr, Ranged}; use rustpython_parser::{lexer, Mode, Tok}; use ruff_diagnostics::Edit; use ruff_python_ast::source_code::{Locator, Stylist}; use ruff_python_ast::str::raw_contents; -use rustpython_format::{ - FieldName, FieldNamePart, FieldType, FormatPart, FormatString, FromTemplate, -}; use crate::cst::matchers::{ match_attribute, match_call, match_dict, match_expression, match_simple_string, diff --git a/crates/ruff/src/rules/pyflakes/mod.rs b/crates/ruff/src/rules/pyflakes/mod.rs index 8fe0e3ca19..2fd06eb44a 100644 --- a/crates/ruff/src/rules/pyflakes/mod.rs +++ b/crates/ruff/src/rules/pyflakes/mod.rs @@ -9,13 +9,12 @@ mod tests { use std::path::Path; use anyhow::Result; - use regex::Regex; - use ruff_diagnostics::Diagnostic; use rustpython_parser::lexer::LexResult; use test_case::test_case; use textwrap::dedent; + use ruff_diagnostics::Diagnostic; use ruff_python_ast::source_code::{Indexer, Locator, Stylist}; use crate::linter::{check_path, LinterResult}; diff --git a/crates/ruff/src/rules/pyflakes/rules/invalid_print_syntax.rs b/crates/ruff/src/rules/pyflakes/rules/invalid_print_syntax.rs index 7e47e176f6..4cbe42829b 100644 --- a/crates/ruff/src/rules/pyflakes/rules/invalid_print_syntax.rs +++ b/crates/ruff/src/rules/pyflakes/rules/invalid_print_syntax.rs @@ -23,7 +23,7 @@ pub(crate) fn invalid_print_syntax(checker: &mut Checker, left: &Expr) { if id != "print" { return; } - if !checker.ctx.is_builtin("print") { + if !checker.model.is_builtin("print") { return; }; checker diff --git a/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs b/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs index 41cecdc571..83021cfc5c 100644 --- a/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs +++ b/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs @@ -18,7 +18,7 @@ impl Violation for ReturnOutsideFunction { pub(crate) fn return_outside_function(checker: &mut Checker, stmt: &Stmt) { if matches!( - checker.ctx.scope().kind, + checker.model.scope().kind, ScopeKind::Class(_) | ScopeKind::Module ) { checker diff --git a/crates/ruff/src/rules/pyflakes/rules/strings.rs b/crates/ruff/src/rules/pyflakes/rules/strings.rs index 2324012937..34df8a937f 100644 --- a/crates/ruff/src/rules/pyflakes/rules/strings.rs +++ b/crates/ruff/src/rules/pyflakes/rules/strings.rs @@ -1,6 +1,6 @@ -use ruff_text_size::TextRange; use std::string::ToString; +use ruff_text_size::TextRange; use rustc_hash::FxHashSet; use rustpython_parser::ast::{self, Constant, Expr, Identifier, Keyword}; diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs index 1ad222cbf1..bce55367fc 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs @@ -1,7 +1,8 @@ +use ruff_text_size::TextRange; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_semantic::scope::Scope; -use ruff_text_size::TextRange; #[violation] pub struct UndefinedExport { diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs index 1d7a4b868f..1984c11257 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs @@ -21,7 +21,7 @@ impl Violation for UndefinedLocal { /// F823 pub(crate) fn undefined_local(checker: &mut Checker, name: &str) { // If the name hasn't already been defined in the current scope... - let current = checker.ctx.scope(); + let current = checker.model.scope(); if !current.kind.is_function() || current.defines(name) { return; } @@ -31,16 +31,16 @@ pub(crate) fn undefined_local(checker: &mut Checker, name: &str) { }; // For every function and module scope above us... - for scope in checker.ctx.scopes.ancestors(parent) { + for scope in checker.model.scopes.ancestors(parent) { if !(scope.kind.is_function() || scope.kind.is_module()) { continue; } // If the name was defined in that scope... - if let Some(binding) = scope.get(name).map(|index| &checker.ctx.bindings[*index]) { + if let Some(binding) = scope.get(name).map(|index| &checker.model.bindings[*index]) { // And has already been accessed in the current scope... if let Some((scope_id, location)) = binding.runtime_usage { - if scope_id == checker.ctx.scope_id { + if scope_id == checker.model.scope_id { // Then it's probably an error. checker.diagnostics.push(Diagnostic::new( UndefinedLocal { diff --git a/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs b/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs index b29e52bbcf..1be79d398b 100644 --- a/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs +++ b/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs @@ -19,10 +19,10 @@ impl Violation for UnusedAnnotation { /// F842 pub(crate) fn unused_annotation(checker: &mut Checker, scope: ScopeId) { - let scope = &checker.ctx.scopes[scope]; + let scope = &checker.model.scopes[scope]; for (name, binding) in scope .bindings() - .map(|(name, index)| (name, &checker.ctx.bindings[*index])) + .map(|(name, index)| (name, &checker.model.bindings[*index])) { if !binding.used() && binding.kind.is_annotation() diff --git a/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs b/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs index 29944b1186..d8ed8d5a82 100644 --- a/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs +++ b/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs @@ -204,7 +204,7 @@ fn remove_unused_variable( if let Some(target) = targets.iter().find(|target| range == target.range()) { if target.is_name_expr() { return if targets.len() > 1 - || contains_effect(value, |id| checker.ctx.is_builtin(id)) + || contains_effect(value, |id| checker.model.is_builtin(id)) { // If the expression is complex (`x = foo()`), remove the assignment, // but preserve the right-hand side. @@ -219,7 +219,7 @@ fn remove_unused_variable( )) } else { // If (e.g.) assigning to a constant (`x = 1`), delete the entire statement. - let parent = checker.ctx.stmts.parent(stmt); + let parent = checker.model.stmts.parent(stmt); let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect(); match delete_stmt( stmt, @@ -249,7 +249,7 @@ fn remove_unused_variable( }) = stmt { if target.is_name_expr() { - return if contains_effect(value, |id| checker.ctx.is_builtin(id)) { + return if contains_effect(value, |id| checker.model.is_builtin(id)) { // If the expression is complex (`x = foo()`), remove the assignment, // but preserve the right-hand side. #[allow(deprecated)] @@ -262,7 +262,7 @@ fn remove_unused_variable( )) } else { // If assigning to a constant (`x = 1`), delete the entire statement. - let parent = checker.ctx.stmts.parent(stmt); + let parent = checker.model.stmts.parent(stmt); let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect(); match delete_stmt( stmt, @@ -313,14 +313,14 @@ fn remove_unused_variable( /// F841 pub(crate) fn unused_variable(checker: &mut Checker, scope: ScopeId) { - let scope = &checker.ctx.scopes[scope]; + let scope = &checker.model.scopes[scope]; if scope.uses_locals && matches!(scope.kind, ScopeKind::Function(..)) { return; } for (name, binding) in scope .bindings() - .map(|(name, index)| (name, &checker.ctx.bindings[*index])) + .map(|(name, index)| (name, &checker.model.bindings[*index])) { if !binding.used() && (binding.kind.is_assignment() || binding.kind.is_named_expr_assignment()) @@ -338,7 +338,7 @@ pub(crate) fn unused_variable(checker: &mut Checker, scope: ScopeId) { ); if checker.patch(diagnostic.kind.rule()) { if let Some(source) = binding.source { - let stmt = checker.ctx.stmts[source]; + let stmt = checker.model.stmts[source]; if let Some((kind, fix)) = remove_unused_variable(stmt, binding.range, checker) { if matches!(kind, DeletionKind::Whole) { diff --git a/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs b/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs index 2fb4291551..25660a8523 100644 --- a/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs +++ b/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs @@ -40,7 +40,7 @@ impl Violation for YieldOutsideFunction { pub(crate) fn yield_outside_function(checker: &mut Checker, expr: &Expr) { if matches!( - checker.ctx.scope().kind, + checker.model.scope().kind, ScopeKind::Class(_) | ScopeKind::Module ) { let keyword = match expr { diff --git a/crates/ruff/src/rules/pygrep_hooks/mod.rs b/crates/ruff/src/rules/pygrep_hooks/mod.rs index a82a3e4285..38b9333b13 100644 --- a/crates/ruff/src/rules/pygrep_hooks/mod.rs +++ b/crates/ruff/src/rules/pygrep_hooks/mod.rs @@ -6,7 +6,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/pygrep_hooks/rules/deprecated_log_warn.rs b/crates/ruff/src/rules/pygrep_hooks/rules/deprecated_log_warn.rs index 4dfeed38aa..64413ea282 100644 --- a/crates/ruff/src/rules/pygrep_hooks/rules/deprecated_log_warn.rs +++ b/crates/ruff/src/rules/pygrep_hooks/rules/deprecated_log_warn.rs @@ -44,7 +44,7 @@ impl Violation for DeprecatedLogWarn { /// PGH002 pub(crate) fn deprecated_log_warn(checker: &mut Checker, func: &Expr) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["logging", "warn"] diff --git a/crates/ruff/src/rules/pygrep_hooks/rules/no_eval.rs b/crates/ruff/src/rules/pygrep_hooks/rules/no_eval.rs index 5eaccae08e..d4d34f007a 100644 --- a/crates/ruff/src/rules/pygrep_hooks/rules/no_eval.rs +++ b/crates/ruff/src/rules/pygrep_hooks/rules/no_eval.rs @@ -46,7 +46,7 @@ pub(crate) fn no_eval(checker: &mut Checker, func: &Expr) { if id != "eval" { return; } - if !checker.ctx.is_builtin("eval") { + if !checker.model.is_builtin("eval") { return; } checker diff --git a/crates/ruff/src/rules/pylint/helpers.rs b/crates/ruff/src/rules/pylint/helpers.rs index 1c51bef4b0..017f125423 100644 --- a/crates/ruff/src/rules/pylint/helpers.rs +++ b/crates/ruff/src/rules/pylint/helpers.rs @@ -5,7 +5,7 @@ use ruff_python_semantic::scope::{FunctionDef, ScopeKind}; use crate::checkers::ast::Checker; pub(crate) fn in_dunder_init(checker: &Checker) -> bool { - let scope = checker.ctx.scope(); + let scope = checker.model.scope(); let ScopeKind::Function(FunctionDef { name, decorator_list, @@ -16,13 +16,13 @@ pub(crate) fn in_dunder_init(checker: &Checker) -> bool { if name != "__init__" { return false; } - let Some(parent) = scope.parent.map(|scope_id| &checker.ctx.scopes[scope_id]) else { + let Some(parent) = scope.parent.map(|scope_id| &checker.model.scopes[scope_id]) else { return false; }; if !matches!( function_type::classify( - &checker.ctx, + &checker.model, parent, name, decorator_list, diff --git a/crates/ruff/src/rules/pylint/mod.rs b/crates/ruff/src/rules/pylint/mod.rs index b5cec179d9..0c0a4952a5 100644 --- a/crates/ruff/src/rules/pylint/mod.rs +++ b/crates/ruff/src/rules/pylint/mod.rs @@ -7,12 +7,11 @@ pub mod settings; mod tests { use std::path::Path; - use crate::assert_messages; use anyhow::Result; - use regex::Regex; use test_case::test_case; + use crate::assert_messages; use crate::registry::Rule; use crate::rules::pylint; use crate::settings::types::PythonVersion; diff --git a/crates/ruff/src/rules/pylint/rules/await_outside_async.rs b/crates/ruff/src/rules/pylint/rules/await_outside_async.rs index 6419e10a99..4c88b51137 100644 --- a/crates/ruff/src/rules/pylint/rules/await_outside_async.rs +++ b/crates/ruff/src/rules/pylint/rules/await_outside_async.rs @@ -46,7 +46,7 @@ impl Violation for AwaitOutsideAsync { /// PLE1142 pub(crate) fn await_outside_async(checker: &mut Checker, expr: &Expr) { if !checker - .ctx + .model .scopes() .find_map(|scope| { if let ScopeKind::Function(FunctionDef { async_, .. }) = &scope.kind { diff --git a/crates/ruff/src/rules/pylint/rules/bad_string_format_type.rs b/crates/ruff/src/rules/pylint/rules/bad_string_format_type.rs index d141286f0f..cbb8b10b4e 100644 --- a/crates/ruff/src/rules/pylint/rules/bad_string_format_type.rs +++ b/crates/ruff/src/rules/pylint/rules/bad_string_format_type.rs @@ -1,6 +1,6 @@ -use ruff_text_size::TextRange; use std::str::FromStr; +use ruff_text_size::TextRange; use rustc_hash::FxHashMap; use rustpython_format::cformat::{CFormatPart, CFormatSpec, CFormatStrOrBytes, CFormatString}; use rustpython_parser::ast::{self, Constant, Expr, Operator, Ranged}; diff --git a/crates/ruff/src/rules/pylint/rules/compare_to_empty_string.rs b/crates/ruff/src/rules/pylint/rules/compare_to_empty_string.rs index 1501c53253..9e79b90e72 100644 --- a/crates/ruff/src/rules/pylint/rules/compare_to_empty_string.rs +++ b/crates/ruff/src/rules/pylint/rules/compare_to_empty_string.rs @@ -98,7 +98,7 @@ pub(crate) fn compare_to_empty_string( ) { // Omit string comparison rules within subscripts. This is mostly commonly used within // DataFrame and np.ndarray indexing. - for parent in checker.ctx.expr_ancestors() { + for parent in checker.model.expr_ancestors() { if matches!(parent, Expr::Subscript(_)) { return; } diff --git a/crates/ruff/src/rules/pylint/rules/global_statement.rs b/crates/ruff/src/rules/pylint/rules/global_statement.rs index 9ec1147331..4841af9376 100644 --- a/crates/ruff/src/rules/pylint/rules/global_statement.rs +++ b/crates/ruff/src/rules/pylint/rules/global_statement.rs @@ -1,6 +1,7 @@ +use rustpython_parser::ast::Ranged; + use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use rustpython_parser::ast::Ranged; use crate::checkers::ast::Checker; @@ -54,11 +55,11 @@ impl Violation for GlobalStatement { /// PLW0603 pub(crate) fn global_statement(checker: &mut Checker, name: &str) { - let scope = checker.ctx.scope(); + let scope = checker.model.scope(); if let Some(index) = scope.get(name) { - let binding = &checker.ctx.bindings[*index]; + let binding = &checker.model.bindings[*index]; if binding.kind.is_global() { - let source = checker.ctx.stmts[binding + let source = checker.model.stmts[binding .source .expect("`global` bindings should always have a `source`")]; let diagnostic = Diagnostic::new( diff --git a/crates/ruff/src/rules/pylint/rules/invalid_envvar_default.rs b/crates/ruff/src/rules/pylint/rules/invalid_envvar_default.rs index d09d1b35f7..db1aa68d86 100644 --- a/crates/ruff/src/rules/pylint/rules/invalid_envvar_default.rs +++ b/crates/ruff/src/rules/pylint/rules/invalid_envvar_default.rs @@ -84,7 +84,7 @@ pub(crate) fn invalid_envvar_default( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["os", "getenv"]) { diff --git a/crates/ruff/src/rules/pylint/rules/invalid_envvar_value.rs b/crates/ruff/src/rules/pylint/rules/invalid_envvar_value.rs index a5f853e3bb..41dd47a6a6 100644 --- a/crates/ruff/src/rules/pylint/rules/invalid_envvar_value.rs +++ b/crates/ruff/src/rules/pylint/rules/invalid_envvar_value.rs @@ -81,7 +81,7 @@ pub(crate) fn invalid_envvar_value( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["os", "getenv"]) { diff --git a/crates/ruff/src/rules/pylint/rules/load_before_global_declaration.rs b/crates/ruff/src/rules/pylint/rules/load_before_global_declaration.rs index 025d6384f6..1778dee2ef 100644 --- a/crates/ruff/src/rules/pylint/rules/load_before_global_declaration.rs +++ b/crates/ruff/src/rules/pylint/rules/load_before_global_declaration.rs @@ -55,7 +55,7 @@ impl Violation for LoadBeforeGlobalDeclaration { } /// PLE0118 pub(crate) fn load_before_global_declaration(checker: &mut Checker, name: &str, expr: &Expr) { - let globals = match &checker.ctx.scope().kind { + let globals = match &checker.model.scope().kind { ScopeKind::Class(class_def) => &class_def.globals, ScopeKind::Function(function_def) => &function_def.globals, _ => return, diff --git a/crates/ruff/src/rules/pylint/rules/logging.rs b/crates/ruff/src/rules/pylint/rules/logging.rs index 65fcf9e64a..4f7cf80624 100644 --- a/crates/ruff/src/rules/pylint/rules/logging.rs +++ b/crates/ruff/src/rules/pylint/rules/logging.rs @@ -102,7 +102,7 @@ pub(crate) fn logging_call( return; } - if !logging::is_logger_candidate(&checker.ctx, func) { + if !logging::is_logger_candidate(&checker.model, func) { return; } diff --git a/crates/ruff/src/rules/pylint/rules/nested_min_max.rs b/crates/ruff/src/rules/pylint/rules/nested_min_max.rs index 7c34721325..dde8dcd30b 100644 --- a/crates/ruff/src/rules/pylint/rules/nested_min_max.rs +++ b/crates/ruff/src/rules/pylint/rules/nested_min_max.rs @@ -4,7 +4,7 @@ use rustpython_parser::ast::{self, Expr, Keyword, Ranged}; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::has_comments; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::{checkers::ast::Checker, registry::AsRule}; @@ -59,16 +59,16 @@ impl Violation for NestedMinMax { impl MinMax { /// Converts a function call [`Expr`] into a [`MinMax`] if it is a call to `min` or `max`. - fn try_from_call(func: &Expr, keywords: &[Keyword], context: &Context) -> Option { + fn try_from_call(func: &Expr, keywords: &[Keyword], model: &SemanticModel) -> Option { if !keywords.is_empty() { return None; } let Expr::Name(ast::ExprName { id, .. }) = func else { return None; }; - if id.as_str() == "min" && context.is_builtin("min") { + if id.as_str() == "min" && model.is_builtin("min") { Some(MinMax::Min) - } else if id.as_str() == "max" && context.is_builtin("max") { + } else if id.as_str() == "max" && model.is_builtin("max") { Some(MinMax::Max) } else { None @@ -87,8 +87,8 @@ impl std::fmt::Display for MinMax { /// Collect a new set of arguments to by either accepting existing args as-is or /// collecting child arguments, if it's a call to the same function. -fn collect_nested_args(context: &Context, min_max: MinMax, args: &[Expr]) -> Vec { - fn inner(context: &Context, min_max: MinMax, args: &[Expr], new_args: &mut Vec) { +fn collect_nested_args(model: &SemanticModel, min_max: MinMax, args: &[Expr]) -> Vec { + fn inner(model: &SemanticModel, min_max: MinMax, args: &[Expr], new_args: &mut Vec) { for arg in args { if let Expr::Call(ast::ExprCall { func, @@ -106,8 +106,8 @@ fn collect_nested_args(context: &Context, min_max: MinMax, args: &[Expr]) -> Vec new_args.push(new_arg); continue; } - if MinMax::try_from_call(func, keywords, context) == Some(min_max) { - inner(context, min_max, args, new_args); + if MinMax::try_from_call(func, keywords, model) == Some(min_max) { + inner(model, min_max, args, new_args); continue; } } @@ -116,7 +116,7 @@ fn collect_nested_args(context: &Context, min_max: MinMax, args: &[Expr]) -> Vec } let mut new_args = Vec::with_capacity(args.len()); - inner(context, min_max, args, &mut new_args); + inner(model, min_max, args, &mut new_args); new_args } @@ -128,7 +128,7 @@ pub(crate) fn nested_min_max( args: &[Expr], keywords: &[Keyword], ) { - let Some(min_max) = MinMax::try_from_call(func, keywords, &checker.ctx) else { + let Some(min_max) = MinMax::try_from_call(func, keywords, &checker.model) else { return; }; @@ -136,14 +136,14 @@ pub(crate) fn nested_min_max( let Expr::Call(ast::ExprCall { func, keywords, ..} )= arg else { return false; }; - MinMax::try_from_call(func.as_ref(), keywords.as_ref(), &checker.ctx) == Some(min_max) + MinMax::try_from_call(func.as_ref(), keywords.as_ref(), &checker.model) == Some(min_max) }) { let fixable = !has_comments(expr, checker.locator); let mut diagnostic = Diagnostic::new(NestedMinMax { func: min_max }, expr.range()); if fixable && checker.patch(diagnostic.kind.rule()) { let flattened_expr = Expr::Call(ast::ExprCall { func: Box::new(func.clone()), - args: collect_nested_args(&checker.ctx, min_max, args), + args: collect_nested_args(&checker.model, min_max, args), keywords: keywords.to_owned(), range: TextRange::default(), }); diff --git a/crates/ruff/src/rules/pylint/rules/property_with_parameters.rs b/crates/ruff/src/rules/pylint/rules/property_with_parameters.rs index 4471a4a73d..f91fc56211 100644 --- a/crates/ruff/src/rules/pylint/rules/property_with_parameters.rs +++ b/crates/ruff/src/rules/pylint/rules/property_with_parameters.rs @@ -59,7 +59,7 @@ pub(crate) fn property_with_parameters( { return; } - if checker.ctx.is_builtin("property") + if checker.model.is_builtin("property") && args .args .iter() diff --git a/crates/ruff/src/rules/pylint/rules/redefined_loop_name.rs b/crates/ruff/src/rules/pylint/rules/redefined_loop_name.rs index 6e89473b70..373c282ae3 100644 --- a/crates/ruff/src/rules/pylint/rules/redefined_loop_name.rs +++ b/crates/ruff/src/rules/pylint/rules/redefined_loop_name.rs @@ -6,10 +6,9 @@ use rustpython_parser::ast::{self, Expr, ExprContext, Ranged, Stmt, Withitem}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::comparable::ComparableExpr; - use ruff_python_ast::statement_visitor::{walk_stmt, StatementVisitor}; use ruff_python_ast::types::Node; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; @@ -140,7 +139,7 @@ struct ExprWithInnerBindingKind<'a> { } struct InnerForWithAssignTargetsVisitor<'a> { - context: &'a Context<'a>, + context: &'a SemanticModel<'a>, dummy_variable_rgx: &'a Regex, assignment_targets: Vec>, } @@ -240,7 +239,7 @@ where /// /// x = cast(int, x) /// ``` -fn assignment_is_cast_expr(context: &Context, value: &Expr, target: &Expr) -> bool { +fn assignment_is_cast_expr(model: &SemanticModel, value: &Expr, target: &Expr) -> bool { let Expr::Call(ast::ExprCall { func, args, .. }) = value else { return false; }; @@ -256,7 +255,7 @@ fn assignment_is_cast_expr(context: &Context, value: &Expr, target: &Expr) -> bo if arg_id != target_id { return false; } - context.match_typing_expr(func, "cast") + model.match_typing_expr(func, "cast") } fn assignment_targets_from_expr<'a, U>( @@ -349,7 +348,7 @@ pub(crate) fn redefined_loop_name<'a, 'b>(checker: &'a mut Checker<'b>, node: &N }) .collect(); let mut visitor = InnerForWithAssignTargetsVisitor { - context: &checker.ctx, + context: &checker.model, dummy_variable_rgx: &checker.settings.dummy_variable_rgx, assignment_targets: vec![], }; @@ -369,7 +368,7 @@ pub(crate) fn redefined_loop_name<'a, 'b>(checker: &'a mut Checker<'b>, node: &N }) .collect(); let mut visitor = InnerForWithAssignTargetsVisitor { - context: &checker.ctx, + context: &checker.model, dummy_variable_rgx: &checker.settings.dummy_variable_rgx, assignment_targets: vec![], }; diff --git a/crates/ruff/src/rules/pylint/rules/repeated_isinstance_calls.rs b/crates/ruff/src/rules/pylint/rules/repeated_isinstance_calls.rs index c3b5289b61..bced6188c7 100644 --- a/crates/ruff/src/rules/pylint/rules/repeated_isinstance_calls.rs +++ b/crates/ruff/src/rules/pylint/rules/repeated_isinstance_calls.rs @@ -58,7 +58,7 @@ pub(crate) fn repeated_isinstance_calls( op: Boolop, values: &[Expr], ) { - if !matches!(op, Boolop::Or) || !checker.ctx.is_builtin("isinstance") { + if !matches!(op, Boolop::Or) || !checker.model.is_builtin("isinstance") { return; } diff --git a/crates/ruff/src/rules/pylint/rules/sys_exit_alias.rs b/crates/ruff/src/rules/pylint/rules/sys_exit_alias.rs index 9bc28642ad..a1f4670711 100644 --- a/crates/ruff/src/rules/pylint/rules/sys_exit_alias.rs +++ b/crates/ruff/src/rules/pylint/rules/sys_exit_alias.rs @@ -65,7 +65,7 @@ pub(crate) fn sys_exit_alias(checker: &mut Checker, func: &Expr) { if id != name { continue; } - if !checker.ctx.is_builtin(name) { + if !checker.model.is_builtin(name) { continue; } let mut diagnostic = Diagnostic::new( @@ -80,7 +80,7 @@ pub(crate) fn sys_exit_alias(checker: &mut Checker, func: &Expr) { "sys", "exit", func.start(), - &checker.ctx, + &checker.model, &checker.importer, checker.locator, )?; diff --git a/crates/ruff/src/rules/pylint/rules/unexpected_special_method_signature.rs b/crates/ruff/src/rules/pylint/rules/unexpected_special_method_signature.rs index 8204f44afc..18d82d9093 100644 --- a/crates/ruff/src/rules/pylint/rules/unexpected_special_method_signature.rs +++ b/crates/ruff/src/rules/pylint/rules/unexpected_special_method_signature.rs @@ -145,7 +145,7 @@ pub(crate) fn unexpected_special_method_signature( args: &Arguments, locator: &Locator, ) { - if !checker.ctx.scope().kind.is_class() { + if !checker.model.scope().kind.is_class() { return; } @@ -163,7 +163,7 @@ pub(crate) fn unexpected_special_method_signature( let optional_params = args.defaults.len(); let mandatory_params = actual_params - optional_params; - let Some(expected_params) = ExpectedParams::from_method(name, is_staticmethod(&checker.ctx, decorator_list)) else { + let Some(expected_params) = ExpectedParams::from_method(name, is_staticmethod(&checker.model, decorator_list)) else { return; }; diff --git a/crates/ruff/src/rules/pylint/settings.rs b/crates/ruff/src/rules/pylint/settings.rs index 2525d2f564..bc40d7b6a4 100644 --- a/crates/ruff/src/rules/pylint/settings.rs +++ b/crates/ruff/src/rules/pylint/settings.rs @@ -1,10 +1,11 @@ //! Settings for the `pylint` plugin. use anyhow::anyhow; -use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; use rustpython_parser::ast::Constant; use serde::{Deserialize, Serialize}; +use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; + #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, CacheKey)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] diff --git a/crates/ruff/src/rules/pyupgrade/mod.rs b/crates/ruff/src/rules/pyupgrade/mod.rs index 9a5c07dc59..e702f75279 100644 --- a/crates/ruff/src/rules/pyupgrade/mod.rs +++ b/crates/ruff/src/rules/pyupgrade/mod.rs @@ -9,7 +9,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs b/crates/ruff/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs index 0143fa4a2e..c9e67e4edb 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs @@ -5,7 +5,6 @@ use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Keyword, Ranged, use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_ast::source_code::Generator; use ruff_python_stdlib::identifiers::is_identifier; @@ -52,7 +51,7 @@ fn match_named_tuple_assign<'a>( return None; }; if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["typing", "NamedTuple"] diff --git a/crates/ruff/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs b/crates/ruff/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs index 7992137612..fa2b0646d2 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs @@ -5,7 +5,6 @@ use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Keyword, Ranged, use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_ast::source_code::Generator; use ruff_python_stdlib::identifiers::is_identifier; @@ -53,7 +52,7 @@ fn match_typed_dict_assign<'a>( return None; }; if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["typing", "TypedDict"] diff --git a/crates/ruff/src/rules/pyupgrade/rules/datetime_utc_alias.rs b/crates/ruff/src/rules/pyupgrade/rules/datetime_utc_alias.rs index 01055b6ba0..b89ded1e4d 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/datetime_utc_alias.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/datetime_utc_alias.rs @@ -28,7 +28,7 @@ impl Violation for DatetimeTimezoneUTC { /// UP017 pub(crate) fn datetime_utc_alias(checker: &mut Checker, expr: &Expr) { if checker - .ctx + .model .resolve_call_path(expr) .map_or(false, |call_path| { call_path.as_slice() == ["datetime", "timezone", "utc"] diff --git a/crates/ruff/src/rules/pyupgrade/rules/f_strings.rs b/crates/ruff/src/rules/pyupgrade/rules/f_strings.rs index 9553acefff..2c23330d2d 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/f_strings.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/f_strings.rs @@ -1,10 +1,11 @@ +use std::borrow::Cow; + use ruff_text_size::TextRange; use rustc_hash::FxHashMap; use rustpython_format::{ FieldName, FieldNamePart, FieldType, FormatPart, FormatString, FromTemplate, }; use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged}; -use std::borrow::Cow; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; diff --git a/crates/ruff/src/rules/pyupgrade/rules/lru_cache_with_maxsize_none.rs b/crates/ruff/src/rules/pyupgrade/rules/lru_cache_with_maxsize_none.rs index 1eb96710d5..41733866b7 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/lru_cache_with_maxsize_none.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/lru_cache_with_maxsize_none.rs @@ -38,7 +38,7 @@ pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list: if args.is_empty() && keywords.len() == 1 && checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["functools", "lru_cache"] @@ -69,7 +69,7 @@ pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list: "functools", "cache", expr.start(), - &checker.ctx, + &checker.model, &checker.importer, checker.locator, )?; diff --git a/crates/ruff/src/rules/pyupgrade/rules/lru_cache_without_parameters.rs b/crates/ruff/src/rules/pyupgrade/rules/lru_cache_without_parameters.rs index 3675ecfc09..66e6ead4a7 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/lru_cache_without_parameters.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/lru_cache_without_parameters.rs @@ -37,7 +37,7 @@ pub(crate) fn lru_cache_without_parameters(checker: &mut Checker, decorator_list if args.is_empty() && keywords.is_empty() && checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["functools", "lru_cache"] diff --git a/crates/ruff/src/rules/pyupgrade/rules/native_literals.rs b/crates/ruff/src/rules/pyupgrade/rules/native_literals.rs index 4d154bb761..6580a2be11 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/native_literals.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/native_literals.rs @@ -4,7 +4,6 @@ use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_ast::str::is_implicit_concatenation; use crate::checkers::ast::Checker; @@ -57,7 +56,7 @@ pub(crate) fn native_literals( return; } - if (id == "str" || id == "bytes") && checker.ctx.is_builtin(id) { + if (id == "str" || id == "bytes") && checker.model.is_builtin(id) { let Some(arg) = args.get(0) else { let mut diagnostic = Diagnostic::new(NativeLiterals{literal_type:if id == "str" { LiteralType::Str diff --git a/crates/ruff/src/rules/pyupgrade/rules/open_alias.rs b/crates/ruff/src/rules/pyupgrade/rules/open_alias.rs index a7f8372a62..ffae0d601b 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/open_alias.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/open_alias.rs @@ -25,12 +25,12 @@ impl Violation for OpenAlias { /// UP020 pub(crate) fn open_alias(checker: &mut Checker, expr: &Expr, func: &Expr) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["io", "open"]) { let fixable = checker - .ctx + .model .find_binding("open") .map_or(true, |binding| binding.kind.is_builtin()); let mut diagnostic = Diagnostic::new(OpenAlias, expr.range()); diff --git a/crates/ruff/src/rules/pyupgrade/rules/os_error_alias.rs b/crates/ruff/src/rules/pyupgrade/rules/os_error_alias.rs index c269474b28..d767b5fe75 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/os_error_alias.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/os_error_alias.rs @@ -4,8 +4,7 @@ use rustpython_parser::ast::{self, Excepthandler, Expr, ExprContext, Ranged}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::compose_call_path; - -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; use crate::registry::AsRule; @@ -40,8 +39,8 @@ const ALIASES: &[(&str, &str)] = &[ ]; /// Return `true` if an [`Expr`] is an alias of `OSError`. -fn is_alias(context: &Context, expr: &Expr) -> bool { - context.resolve_call_path(expr).map_or(false, |call_path| { +fn is_alias(model: &SemanticModel, expr: &Expr) -> bool { + model.resolve_call_path(expr).map_or(false, |call_path| { ALIASES .iter() .any(|(module, member)| call_path.as_slice() == [*module, *member]) @@ -49,8 +48,8 @@ fn is_alias(context: &Context, expr: &Expr) -> bool { } /// Return `true` if an [`Expr`] is `OSError`. -fn is_os_error(context: &Context, expr: &Expr) -> bool { - context +fn is_os_error(model: &SemanticModel, expr: &Expr) -> bool { + model .resolve_call_path(expr) .map_or(false, |call_path| call_path.as_slice() == ["", "OSError"]) } @@ -94,7 +93,7 @@ fn tuple_diagnostic(checker: &mut Checker, target: &Expr, aliases: &[&Expr]) { .collect(); // If `OSError` itself isn't already in the tuple, add it. - if elts.iter().all(|elt| !is_os_error(&checker.ctx, elt)) { + if elts.iter().all(|elt| !is_os_error(&checker.model, elt)) { let node = ast::ExprName { id: "OSError".into(), ctx: ExprContext::Load, @@ -134,7 +133,7 @@ pub(crate) fn os_error_alias_handlers(checker: &mut Checker, handlers: &[Excepth }; match expr.as_ref() { Expr::Name(_) | Expr::Attribute(_) => { - if is_alias(&checker.ctx, expr) { + if is_alias(&checker.model, expr) { atom_diagnostic(checker, expr); } } @@ -142,7 +141,7 @@ pub(crate) fn os_error_alias_handlers(checker: &mut Checker, handlers: &[Excepth // List of aliases to replace with `OSError`. let mut aliases: Vec<&Expr> = vec![]; for elt in elts { - if is_alias(&checker.ctx, elt) { + if is_alias(&checker.model, elt) { aliases.push(elt); } } @@ -157,7 +156,7 @@ pub(crate) fn os_error_alias_handlers(checker: &mut Checker, handlers: &[Excepth /// UP024 pub(crate) fn os_error_alias_call(checker: &mut Checker, func: &Expr) { - if is_alias(&checker.ctx, func) { + if is_alias(&checker.model, func) { atom_diagnostic(checker, func); } } @@ -165,7 +164,7 @@ pub(crate) fn os_error_alias_call(checker: &mut Checker, func: &Expr) { /// UP024 pub(crate) fn os_error_alias_raise(checker: &mut Checker, expr: &Expr) { if matches!(expr, Expr::Name(_) | Expr::Attribute(_)) { - if is_alias(&checker.ctx, expr) { + if is_alias(&checker.model, expr) { atom_diagnostic(checker, expr); } } diff --git a/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs b/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs index 6419c73ed1..0e31033952 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs @@ -164,8 +164,8 @@ fn fix_py2_block( // of its parent, so avoid passing in the parent at all. Otherwise, // `delete_stmt` will erroneously include a `pass`. let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect(); - let defined_by = checker.ctx.stmt(); - let defined_in = checker.ctx.stmt_parent(); + let defined_by = checker.model.stmt(); + let defined_in = checker.model.stmt_parent(); return match delete_stmt( defined_by, if block.starter == Tok::If { @@ -323,7 +323,7 @@ pub(crate) fn outdated_version_block( }; if !checker - .ctx + .model .resolve_call_path(left) .map_or(false, |call_path| { call_path.as_slice() == ["sys", "version_info"] diff --git a/crates/ruff/src/rules/pyupgrade/rules/printf_string_formatting.rs b/crates/ruff/src/rules/pyupgrade/rules/printf_string_formatting.rs index 08aa5fda1e..5bcf6c764d 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/printf_string_formatting.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/printf_string_formatting.rs @@ -1,6 +1,6 @@ -use ruff_text_size::TextRange; use std::str::FromStr; +use ruff_text_size::TextRange; use rustpython_format::cformat::{ CConversionFlags, CFormatPart, CFormatPrecision, CFormatQuantity, CFormatString, }; diff --git a/crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs b/crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs index 967abefee0..1a8a29e0a6 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs @@ -1,6 +1,7 @@ +use ruff_text_size::TextRange; + use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::TextRange; use crate::checkers::ast::Checker; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/pyupgrade/rules/redundant_open_modes.rs b/crates/ruff/src/rules/pyupgrade/rules/redundant_open_modes.rs index b7afd6a51c..69c0772636 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/redundant_open_modes.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/redundant_open_modes.rs @@ -173,7 +173,7 @@ fn create_remove_param_fix(locator: &Locator, expr: &Expr, mode_param: &Expr) -> /// UP015 pub(crate) fn redundant_open_modes(checker: &mut Checker, expr: &Expr) { // If `open` has been rebound, skip this check entirely. - if !checker.ctx.is_builtin(OPEN_FUNC_NAME) { + if !checker.model.is_builtin(OPEN_FUNC_NAME) { return; } let (mode_param, keywords): (Option<&Expr>, Vec) = match_open(expr); diff --git a/crates/ruff/src/rules/pyupgrade/rules/replace_stdout_stderr.rs b/crates/ruff/src/rules/pyupgrade/rules/replace_stdout_stderr.rs index 2c0c42e956..34d72db948 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/replace_stdout_stderr.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/replace_stdout_stderr.rs @@ -61,7 +61,7 @@ pub(crate) fn replace_stdout_stderr( keywords: &[Keyword], ) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["subprocess", "run"] @@ -77,13 +77,13 @@ pub(crate) fn replace_stdout_stderr( // Verify that they're both set to `subprocess.PIPE`. if !checker - .ctx + .model .resolve_call_path(&stdout.value) .map_or(false, |call_path| { call_path.as_slice() == ["subprocess", "PIPE"] }) || !checker - .ctx + .model .resolve_call_path(&stderr.value) .map_or(false, |call_path| { call_path.as_slice() == ["subprocess", "PIPE"] diff --git a/crates/ruff/src/rules/pyupgrade/rules/replace_universal_newlines.rs b/crates/ruff/src/rules/pyupgrade/rules/replace_universal_newlines.rs index 7df30f8b62..9f11ce0009 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/replace_universal_newlines.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/replace_universal_newlines.rs @@ -25,7 +25,7 @@ impl AlwaysAutofixableViolation for ReplaceUniversalNewlines { /// UP021 pub(crate) fn replace_universal_newlines(checker: &mut Checker, func: &Expr, kwargs: &[Keyword]) { if checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| { call_path.as_slice() == ["subprocess", "run"] diff --git a/crates/ruff/src/rules/pyupgrade/rules/super_call_with_parameters.rs b/crates/ruff/src/rules/pyupgrade/rules/super_call_with_parameters.rs index 9d3fb07fb0..4f634ff949 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/super_call_with_parameters.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/super_call_with_parameters.rs @@ -43,14 +43,14 @@ pub(crate) fn super_call_with_parameters( if !is_super_call_with_arguments(func, args) { return; } - let scope = checker.ctx.scope(); + let scope = checker.model.scope(); // Check: are we in a Function scope? if !matches!(scope.kind, ScopeKind::Function(_)) { return; } - let mut parents = checker.ctx.parents(); + let mut parents = checker.model.parents(); // For a `super` invocation to be unnecessary, the first argument needs to match // the enclosing class, and the second argument needs to match the first diff --git a/crates/ruff/src/rules/pyupgrade/rules/type_of_primitive.rs b/crates/ruff/src/rules/pyupgrade/rules/type_of_primitive.rs index 9c80dd5579..4d148877de 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/type_of_primitive.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/type_of_primitive.rs @@ -32,7 +32,7 @@ pub(crate) fn type_of_primitive(checker: &mut Checker, expr: &Expr, func: &Expr, return; } if !checker - .ctx + .model .resolve_call_path(func) .map_or(false, |call_path| call_path.as_slice() == ["", "type"]) { diff --git a/crates/ruff/src/rules/pyupgrade/rules/typing_text_str_alias.rs b/crates/ruff/src/rules/pyupgrade/rules/typing_text_str_alias.rs index dd165ca1c6..c38161e68f 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/typing_text_str_alias.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/typing_text_str_alias.rs @@ -23,7 +23,7 @@ impl AlwaysAutofixableViolation for TypingTextStrAlias { /// UP019 pub(crate) fn typing_text_str_alias(checker: &mut Checker, expr: &Expr) { if checker - .ctx + .model .resolve_call_path(expr) .map_or(false, |call_path| { call_path.as_slice() == ["typing", "Text"] diff --git a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_builtin_import.rs b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_builtin_import.rs index 2f037a1116..4ee3401243 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_builtin_import.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_builtin_import.rs @@ -106,8 +106,8 @@ pub(crate) fn unnecessary_builtin_import( if checker.patch(diagnostic.kind.rule()) { let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect(); - let defined_by = checker.ctx.stmt(); - let defined_in = checker.ctx.stmt_parent(); + let defined_by = checker.model.stmt(); + let defined_in = checker.model.stmt_parent(); let unused_imports: Vec = unused_imports .iter() .map(|alias| format!("{module}.{}", alias.name)) diff --git a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_future_import.rs b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_future_import.rs index 7924b55b16..2028375c3f 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_future_import.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_future_import.rs @@ -86,8 +86,8 @@ pub(crate) fn unnecessary_future_import(checker: &mut Checker, stmt: &Stmt, name if checker.patch(diagnostic.kind.rule()) { let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect(); - let defined_by = checker.ctx.stmt(); - let defined_in = checker.ctx.stmt_parent(); + let defined_by = checker.model.stmt(); + let defined_in = checker.model.stmt_parent(); let unused_imports: Vec = unused_imports .iter() .map(|alias| format!("__future__.{}", alias.name)) diff --git a/crates/ruff/src/rules/pyupgrade/rules/use_pep585_annotation.rs b/crates/ruff/src/rules/pyupgrade/rules/use_pep585_annotation.rs index b216e11e1e..27a04c5975 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/use_pep585_annotation.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/use_pep585_annotation.rs @@ -46,12 +46,12 @@ pub(crate) fn use_pep585_annotation( }, expr.range(), ); - let fixable = !checker.ctx.in_complex_string_type_definition(); + let fixable = !checker.model.in_complex_string_type_definition(); if fixable && checker.patch(diagnostic.kind.rule()) { match replacement { ModuleMember::BuiltIn(name) => { // Built-in type, like `list`. - if checker.ctx.is_builtin(name) { + if checker.model.is_builtin(name) { diagnostic.set_fix(Fix::automatic(Edit::range_replacement( (*name).to_string(), expr.range(), @@ -65,7 +65,7 @@ pub(crate) fn use_pep585_annotation( module, member, expr.start(), - &checker.ctx, + &checker.model, &checker.importer, checker.locator, )?; diff --git a/crates/ruff/src/rules/pyupgrade/rules/use_pep604_annotation.rs b/crates/ruff/src/rules/pyupgrade/rules/use_pep604_annotation.rs index 75149e1349..e464262811 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/use_pep604_annotation.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/use_pep604_annotation.rs @@ -3,7 +3,6 @@ use rustpython_parser::ast::{self, Constant, Expr, Operator, Ranged}; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; - use ruff_python_semantic::analyze::typing::Pep604Operator; use crate::checkers::ast::Checker; @@ -60,7 +59,7 @@ pub(crate) fn use_pep604_annotation( ) { // Avoid fixing forward references, or types not in an annotation. let fixable = - checker.ctx.in_type_definition() && !checker.ctx.in_complex_string_type_definition(); + checker.model.in_type_definition() && !checker.model.in_complex_string_type_definition(); match operator { Pep604Operator::Optional => { let mut diagnostic = Diagnostic::new(NonPEP604Annotation, expr.range()); diff --git a/crates/ruff/src/rules/pyupgrade/rules/use_pep604_isinstance.rs b/crates/ruff/src/rules/pyupgrade/rules/use_pep604_isinstance.rs index 04c585aa0c..66d1b24c31 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/use_pep604_isinstance.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/use_pep604_isinstance.rs @@ -74,7 +74,7 @@ pub(crate) fn use_pep604_isinstance( let Some(kind) = CallKind::from_name(id) else { return; }; - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; }; if let Some(types) = args.get(1) { diff --git a/crates/ruff/src/rules/pyupgrade/rules/useless_metaclass_type.rs b/crates/ruff/src/rules/pyupgrade/rules/useless_metaclass_type.rs index 0bfdca15c6..10f738bd2a 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/useless_metaclass_type.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/useless_metaclass_type.rs @@ -56,8 +56,8 @@ pub(crate) fn useless_metaclass_type( }; if checker.patch(diagnostic.kind.rule()) { let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect(); - let defined_by = checker.ctx.stmt(); - let defined_in = checker.ctx.stmt_parent(); + let defined_by = checker.model.stmt(); + let defined_in = checker.model.stmt_parent(); match actions::delete_stmt( defined_by, defined_in, diff --git a/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs b/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs index 1397a4525f..5b48caeffa 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs @@ -62,7 +62,8 @@ pub(crate) fn useless_object_inheritance( bases: &[Expr], keywords: &[Keyword], ) { - if let Some(mut diagnostic) = rule(name, bases, checker.ctx.scope(), &checker.ctx.bindings) { + if let Some(mut diagnostic) = rule(name, bases, checker.model.scope(), &checker.model.bindings) + { if checker.patch(diagnostic.kind.rule()) { let expr_range = diagnostic.range(); #[allow(deprecated)] diff --git a/crates/ruff/src/rules/ruff/mod.rs b/crates/ruff/src/rules/ruff/mod.rs index 727711225f..7a8f38254b 100644 --- a/crates/ruff/src/rules/ruff/mod.rs +++ b/crates/ruff/src/rules/ruff/mod.rs @@ -7,7 +7,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use rustc_hash::FxHashSet; use test_case::test_case; diff --git a/crates/ruff/src/rules/ruff/rules/explicit_f_string_type_conversion.rs b/crates/ruff/src/rules/ruff/rules/explicit_f_string_type_conversion.rs index 4fd1be8b4b..ca7fefab4c 100644 --- a/crates/ruff/src/rules/ruff/rules/explicit_f_string_type_conversion.rs +++ b/crates/ruff/src/rules/ruff/rules/explicit_f_string_type_conversion.rs @@ -131,7 +131,7 @@ pub(crate) fn explicit_f_string_type_conversion( return; }; - if !checker.ctx.is_builtin(id) { + if !checker.model.is_builtin(id) { return; } diff --git a/crates/ruff/src/rules/ruff/rules/mod.rs b/crates/ruff/src/rules/ruff/rules/mod.rs index 61a9ff69a3..43543fe7ce 100644 --- a/crates/ruff/src/rules/ruff/rules/mod.rs +++ b/crates/ruff/src/rules/ruff/rules/mod.rs @@ -1,3 +1,21 @@ +pub(crate) use ambiguous_unicode_character::{ + ambiguous_unicode_character, AmbiguousUnicodeCharacterComment, + AmbiguousUnicodeCharacterDocstring, AmbiguousUnicodeCharacterString, +}; +pub(crate) use asyncio_dangling_task::{asyncio_dangling_task, AsyncioDanglingTask}; +pub(crate) use collection_literal_concatenation::{ + collection_literal_concatenation, CollectionLiteralConcatenation, +}; +pub(crate) use explicit_f_string_type_conversion::{ + explicit_f_string_type_conversion, ExplicitFStringTypeConversion, +}; +pub(crate) use mutable_defaults_in_dataclass_fields::{ + function_call_in_dataclass_defaults, is_dataclass, mutable_dataclass_default, + FunctionCallInDataclassDefaultArgument, MutableDataclassDefault, +}; +pub(crate) use pairwise_over_zipped::{pairwise_over_zipped, PairwiseOverZipped}; +pub(crate) use unused_noqa::{UnusedCodes, UnusedNOQA}; + mod ambiguous_unicode_character; mod asyncio_dangling_task; mod collection_literal_concatenation; @@ -7,25 +25,6 @@ mod mutable_defaults_in_dataclass_fields; mod pairwise_over_zipped; mod unused_noqa; -pub(crate) use ambiguous_unicode_character::{ - ambiguous_unicode_character, AmbiguousUnicodeCharacterComment, - AmbiguousUnicodeCharacterDocstring, AmbiguousUnicodeCharacterString, -}; -pub(crate) use asyncio_dangling_task::{asyncio_dangling_task, AsyncioDanglingTask}; -pub(crate) use collection_literal_concatenation::{ - collection_literal_concatenation, CollectionLiteralConcatenation, -}; -pub(crate) use mutable_defaults_in_dataclass_fields::{ - function_call_in_dataclass_defaults, is_dataclass, mutable_dataclass_default, - FunctionCallInDataclassDefaultArgument, MutableDataclassDefault, -}; -pub(crate) use pairwise_over_zipped::{pairwise_over_zipped, PairwiseOverZipped}; -pub(crate) use unused_noqa::{UnusedCodes, UnusedNOQA}; - -pub(crate) use explicit_f_string_type_conversion::{ - explicit_f_string_type_conversion, ExplicitFStringTypeConversion, -}; - #[derive(Clone, Copy)] pub(crate) enum Context { String, diff --git a/crates/ruff/src/rules/ruff/rules/mutable_defaults_in_dataclass_fields.rs b/crates/ruff/src/rules/ruff/rules/mutable_defaults_in_dataclass_fields.rs index f478b3e38e..eb1291209f 100644 --- a/crates/ruff/src/rules/ruff/rules/mutable_defaults_in_dataclass_fields.rs +++ b/crates/ruff/src/rules/ruff/rules/mutable_defaults_in_dataclass_fields.rs @@ -1,12 +1,12 @@ -use ruff_python_ast::call_path::{from_qualified_name, CallPath}; use rustpython_parser::ast::{self, Expr, Ranged, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::call_path::{from_qualified_name, CallPath}; use ruff_python_ast::{call_path::compose_call_path, helpers::map_callable}; use ruff_python_semantic::{ analyze::typing::{is_immutable_annotation, is_immutable_func}, - context::Context, + model::SemanticModel, }; use crate::checkers::ast::Checker; @@ -162,8 +162,8 @@ fn is_mutable_expr(expr: &Expr) -> bool { const ALLOWED_DATACLASS_SPECIFIC_FUNCTIONS: &[&[&str]] = &[&["dataclasses", "field"]]; -fn is_allowed_dataclass_function(context: &Context, func: &Expr) -> bool { - context.resolve_call_path(func).map_or(false, |call_path| { +fn is_allowed_dataclass_function(model: &SemanticModel, func: &Expr) -> bool { + model.resolve_call_path(func).map_or(false, |call_path| { ALLOWED_DATACLASS_SPECIFIC_FUNCTIONS .iter() .any(|target| call_path.as_slice() == *target) @@ -171,11 +171,11 @@ fn is_allowed_dataclass_function(context: &Context, func: &Expr) -> bool { } /// Returns `true` if the given [`Expr`] is a `typing.ClassVar` annotation. -fn is_class_var_annotation(context: &Context, annotation: &Expr) -> bool { +fn is_class_var_annotation(model: &SemanticModel, annotation: &Expr) -> bool { let Expr::Subscript(ast::ExprSubscript { value, .. }) = &annotation else { return false; }; - context.match_typing_expr(value, "ClassVar") + model.match_typing_expr(value, "ClassVar") } /// RUF009 @@ -195,12 +195,12 @@ pub(crate) fn function_call_in_dataclass_defaults(checker: &mut Checker, body: & .. }) = statement { - if is_class_var_annotation(&checker.ctx, annotation) { + if is_class_var_annotation(&checker.model, annotation) { continue; } if let Expr::Call(ast::ExprCall { func, .. }) = expr.as_ref() { - if !is_immutable_func(&checker.ctx, func, &extend_immutable_calls) - && !is_allowed_dataclass_function(&checker.ctx, func) + if !is_immutable_func(&checker.model, func, &extend_immutable_calls) + && !is_allowed_dataclass_function(&checker.model, func) { checker.diagnostics.push(Diagnostic::new( FunctionCallInDataclassDefaultArgument { @@ -223,8 +223,8 @@ pub(crate) fn mutable_dataclass_default(checker: &mut Checker, body: &[Stmt]) { value: Some(value), .. }) => { - if !is_class_var_annotation(&checker.ctx, annotation) - && !is_immutable_annotation(&checker.ctx, annotation) + if !is_class_var_annotation(&checker.model, annotation) + && !is_immutable_annotation(&checker.model, annotation) && is_mutable_expr(value) { checker @@ -247,7 +247,7 @@ pub(crate) fn mutable_dataclass_default(checker: &mut Checker, body: &[Stmt]) { pub(crate) fn is_dataclass(checker: &Checker, decorator_list: &[Expr]) -> bool { decorator_list.iter().any(|decorator| { checker - .ctx + .model .resolve_call_path(map_callable(decorator)) .map_or(false, |call_path| { call_path.as_slice() == ["dataclasses", "dataclass"] diff --git a/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs b/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs index e93a5d5a29..84d719ea70 100644 --- a/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs +++ b/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs @@ -99,7 +99,7 @@ pub(crate) fn pairwise_over_zipped(checker: &mut Checker, func: &Expr, args: &[E } // Require the function to be the builtin `zip`. - if !(id == "zip" && checker.ctx.is_builtin(id)) { + if !(id == "zip" && checker.model.is_builtin(id)) { return; } diff --git a/crates/ruff/src/rules/tryceratops/helpers.rs b/crates/ruff/src/rules/tryceratops/helpers.rs index adc856e1ec..be685f3e62 100644 --- a/crates/ruff/src/rules/tryceratops/helpers.rs +++ b/crates/ruff/src/rules/tryceratops/helpers.rs @@ -3,16 +3,16 @@ use rustpython_parser::ast::{self, Expr}; use ruff_python_ast::visitor; use ruff_python_ast::visitor::Visitor; use ruff_python_semantic::analyze::logging; -use ruff_python_semantic::context::Context; +use ruff_python_semantic::model::SemanticModel; /// Collect `logging`-like calls from an AST. pub(crate) struct LoggerCandidateVisitor<'a> { - context: &'a Context<'a>, + context: &'a SemanticModel<'a>, pub(crate) calls: Vec<(&'a Expr, &'a Expr)>, } impl<'a> LoggerCandidateVisitor<'a> { - pub(crate) fn new(context: &'a Context<'a>) -> Self { + pub(crate) fn new(context: &'a SemanticModel<'a>) -> Self { LoggerCandidateVisitor { context, calls: Vec::new(), diff --git a/crates/ruff/src/rules/tryceratops/mod.rs b/crates/ruff/src/rules/tryceratops/mod.rs index 36387df298..f4694b1d70 100644 --- a/crates/ruff/src/rules/tryceratops/mod.rs +++ b/crates/ruff/src/rules/tryceratops/mod.rs @@ -8,7 +8,6 @@ mod tests { use std::path::Path; use anyhow::Result; - use test_case::test_case; use crate::registry::Rule; diff --git a/crates/ruff/src/rules/tryceratops/rules/error_instead_of_exception.rs b/crates/ruff/src/rules/tryceratops/rules/error_instead_of_exception.rs index 646a35ffed..5f7f693ed4 100644 --- a/crates/ruff/src/rules/tryceratops/rules/error_instead_of_exception.rs +++ b/crates/ruff/src/rules/tryceratops/rules/error_instead_of_exception.rs @@ -57,7 +57,7 @@ pub(crate) fn error_instead_of_exception(checker: &mut Checker, handlers: &[Exce for handler in handlers { let Excepthandler::ExceptHandler(ast::ExcepthandlerExceptHandler { body, .. }) = handler; let calls = { - let mut visitor = LoggerCandidateVisitor::new(&checker.ctx); + let mut visitor = LoggerCandidateVisitor::new(&checker.model); visitor.visit_body(body); visitor.calls }; diff --git a/crates/ruff/src/rules/tryceratops/rules/raise_vanilla_class.rs b/crates/ruff/src/rules/tryceratops/rules/raise_vanilla_class.rs index 163bb03203..d81f1a0142 100644 --- a/crates/ruff/src/rules/tryceratops/rules/raise_vanilla_class.rs +++ b/crates/ruff/src/rules/tryceratops/rules/raise_vanilla_class.rs @@ -63,7 +63,7 @@ impl Violation for RaiseVanillaClass { /// TRY002 pub(crate) fn raise_vanilla_class(checker: &mut Checker, expr: &Expr) { if checker - .ctx + .model .resolve_call_path(if let Expr::Call(ast::ExprCall { func, .. }) = expr { func } else { diff --git a/crates/ruff/src/rules/tryceratops/rules/try_consider_else.rs b/crates/ruff/src/rules/tryceratops/rules/try_consider_else.rs index 77ab803bb5..700fd168b1 100644 --- a/crates/ruff/src/rules/tryceratops/rules/try_consider_else.rs +++ b/crates/ruff/src/rules/tryceratops/rules/try_consider_else.rs @@ -66,7 +66,7 @@ pub(crate) fn try_consider_else( if let Some(stmt) = body.last() { if let Stmt::Return(ast::StmtReturn { value, range: _ }) = stmt { if let Some(value) = value { - if contains_effect(value, |id| checker.ctx.is_builtin(id)) { + if contains_effect(value, |id| checker.model.is_builtin(id)) { return; } } diff --git a/crates/ruff/src/rules/tryceratops/rules/type_check_without_type_error.rs b/crates/ruff/src/rules/tryceratops/rules/type_check_without_type_error.rs index 5cc964c3a4..afe3e6408e 100644 --- a/crates/ruff/src/rules/tryceratops/rules/type_check_without_type_error.rs +++ b/crates/ruff/src/rules/tryceratops/rules/type_check_without_type_error.rs @@ -77,7 +77,7 @@ fn has_control_flow(stmt: &Stmt) -> bool { /// Returns `true` if an [`Expr`] is a call to check types. fn check_type_check_call(checker: &mut Checker, call: &Expr) -> bool { checker - .ctx + .model .resolve_call_path(call) .map_or(false, |call_path| { call_path.as_slice() == ["", "isinstance"] @@ -101,7 +101,7 @@ fn check_type_check_test(checker: &mut Checker, test: &Expr) -> bool { /// Returns `true` if `exc` is a reference to a builtin exception. fn is_builtin_exception(checker: &mut Checker, exc: &Expr) -> bool { return checker - .ctx + .model .resolve_call_path(exc) .map_or(false, |call_path| { [ diff --git a/crates/ruff/src/rules/tryceratops/rules/verbose_log_message.rs b/crates/ruff/src/rules/tryceratops/rules/verbose_log_message.rs index 660fd89f7b..411242b5e2 100644 --- a/crates/ruff/src/rules/tryceratops/rules/verbose_log_message.rs +++ b/crates/ruff/src/rules/tryceratops/rules/verbose_log_message.rs @@ -74,7 +74,7 @@ pub(crate) fn verbose_log_message(checker: &mut Checker, handlers: &[Excepthandl // Find all calls to `logging.exception`. let calls = { - let mut visitor = LoggerCandidateVisitor::new(&checker.ctx); + let mut visitor = LoggerCandidateVisitor::new(&checker.model); visitor.visit_body(body); visitor.calls }; diff --git a/crates/ruff/src/settings/types.rs b/crates/ruff/src/settings/types.rs index 7a0bd96ecd..49689d8948 100644 --- a/crates/ruff/src/settings/types.rs +++ b/crates/ruff/src/settings/types.rs @@ -1,12 +1,13 @@ -use anyhow::{bail, Result}; -use globset::{Glob, GlobSet, GlobSetBuilder}; -use pep440_rs::{Version as Pep440Version, VersionSpecifiers}; -use serde::{de, Deserialize, Deserializer, Serialize}; use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::string::ToString; + +use anyhow::{bail, Result}; +use globset::{Glob, GlobSet, GlobSetBuilder}; +use pep440_rs::{Version as Pep440Version, VersionSpecifiers}; +use serde::{de, Deserialize, Deserializer, Serialize}; use strum::IntoEnumIterator; use strum_macros::EnumIter; diff --git a/crates/ruff/src/test.rs b/crates/ruff/src/test.rs index 92b3ba25c9..9c6010965e 100644 --- a/crates/ruff/src/test.rs +++ b/crates/ruff/src/test.rs @@ -5,10 +5,10 @@ use std::path::Path; use anyhow::Result; use itertools::Itertools; -use ruff_diagnostics::{AutofixKind, Diagnostic}; use rustc_hash::FxHashMap; use rustpython_parser::lexer::LexResult; +use ruff_diagnostics::{AutofixKind, Diagnostic}; use ruff_python_ast::source_code::{Indexer, Locator, SourceFileBuilder, Stylist}; use crate::autofix::fix_file; diff --git a/crates/ruff_benchmark/benches/linter.rs b/crates/ruff_benchmark/benches/linter.rs index b07390edbb..98ea5c1bd3 100644 --- a/crates/ruff_benchmark/benches/linter.rs +++ b/crates/ruff_benchmark/benches/linter.rs @@ -1,12 +1,14 @@ +use std::time::Duration; + use criterion::measurement::WallTime; use criterion::{ criterion_group, criterion_main, BenchmarkGroup, BenchmarkId, Criterion, Throughput, }; + use ruff::linter::lint_only; use ruff::settings::{flags, Settings}; use ruff::RuleSelector; use ruff_benchmark::{TestCase, TestCaseSpeed, TestFile, TestFileDownloadError}; -use std::time::Duration; #[cfg(target_os = "windows")] #[global_allocator] diff --git a/crates/ruff_benchmark/benches/parser.rs b/crates/ruff_benchmark/benches/parser.rs index afdcc59832..1dbd95af42 100644 --- a/crates/ruff_benchmark/benches/parser.rs +++ b/crates/ruff_benchmark/benches/parser.rs @@ -1,9 +1,11 @@ +use std::time::Duration; + use criterion::measurement::WallTime; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; +use rustpython_parser::ast::Stmt; + use ruff_benchmark::{TestCase, TestCaseSpeed, TestFile, TestFileDownloadError}; use ruff_python_ast::statement_visitor::{walk_stmt, StatementVisitor}; -use rustpython_parser::ast::Stmt; -use std::time::Duration; #[cfg(target_os = "windows")] #[global_allocator] diff --git a/crates/ruff_benchmark/src/lib.rs b/crates/ruff_benchmark/src/lib.rs index 6ea1fcabe1..70d2e7a34f 100644 --- a/crates/ruff_benchmark/src/lib.rs +++ b/crates/ruff_benchmark/src/lib.rs @@ -1,6 +1,7 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::process::Command; + use url::Url; /// Relative size of a test case. Benchmarks can use it to configure the time for how long a benchmark should run to get stable results. diff --git a/crates/ruff_cache/src/cache_key.rs b/crates/ruff_cache/src/cache_key.rs index 999aa8861e..c05bf48ead 100644 --- a/crates/ruff_cache/src/cache_key.rs +++ b/crates/ruff_cache/src/cache_key.rs @@ -1,5 +1,3 @@ -use itertools::Itertools; -use regex::Regex; use std::borrow::Cow; use std::collections::hash_map::DefaultHasher; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; @@ -7,6 +5,9 @@ use std::hash::{Hash, Hasher}; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; +use itertools::Itertools; +use regex::Regex; + #[derive(Clone, Debug, Default)] pub struct CacheKeyHasher { inner: DefaultHasher, diff --git a/crates/ruff_cache/src/filetime.rs b/crates/ruff_cache/src/filetime.rs index 17e8eb551e..29c2d074a5 100644 --- a/crates/ruff_cache/src/filetime.rs +++ b/crates/ruff_cache/src/filetime.rs @@ -1,7 +1,9 @@ -use crate::{CacheKey, CacheKeyHasher}; -use filetime::FileTime; use std::hash::Hash; +use filetime::FileTime; + +use crate::{CacheKey, CacheKeyHasher}; + impl CacheKey for FileTime { fn cache_key(&self, state: &mut CacheKeyHasher) { self.hash(&mut **state); diff --git a/crates/ruff_cache/src/globset.rs b/crates/ruff_cache/src/globset.rs index fbaf79ca05..8011b7e055 100644 --- a/crates/ruff_cache/src/globset.rs +++ b/crates/ruff_cache/src/globset.rs @@ -1,6 +1,7 @@ -use crate::{CacheKey, CacheKeyHasher}; use globset::{Glob, GlobMatcher}; +use crate::{CacheKey, CacheKeyHasher}; + impl CacheKey for GlobMatcher { fn cache_key(&self, state: &mut CacheKeyHasher) { self.glob().cache_key(state); diff --git a/crates/ruff_cache/src/lib.rs b/crates/ruff_cache/src/lib.rs index ddde67db1f..3d17f88336 100644 --- a/crates/ruff_cache/src/lib.rs +++ b/crates/ruff_cache/src/lib.rs @@ -1,10 +1,10 @@ -mod cache_key; -pub mod filetime; -pub mod globset; +use std::path::{Path, PathBuf}; pub use cache_key::{CacheKey, CacheKeyHasher}; -use std::path::{Path, PathBuf}; +mod cache_key; +pub mod filetime; +pub mod globset; pub const CACHE_DIR_NAME: &str = ".ruff_cache"; diff --git a/crates/ruff_cache/tests/cache_key.rs b/crates/ruff_cache/tests/cache_key.rs index 0041afd253..43e8f09203 100644 --- a/crates/ruff_cache/tests/cache_key.rs +++ b/crates/ruff_cache/tests/cache_key.rs @@ -1,8 +1,9 @@ -use ruff_cache::{CacheKey, CacheKeyHasher}; -use ruff_macros::CacheKey; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; +use ruff_cache::{CacheKey, CacheKeyHasher}; +use ruff_macros::CacheKey; + #[derive(CacheKey, Hash)] struct UnitStruct; diff --git a/crates/ruff_cli/src/args.rs b/crates/ruff_cli/src/args.rs index b8548c33c9..8ef8e400d5 100644 --- a/crates/ruff_cli/src/args.rs +++ b/crates/ruff_cli/src/args.rs @@ -3,6 +3,8 @@ use std::str::FromStr; use clap::{command, Parser}; use regex::Regex; +use rustc_hash::FxHashMap; + use ruff::logging::LogLevel; use ruff::registry::Rule; use ruff::resolver::ConfigProcessor; @@ -11,7 +13,6 @@ use ruff::settings::types::{ FilePattern, PatternPrefixPair, PerFileIgnore, PythonVersion, SerializationFormat, }; use ruff::RuleSelector; -use rustc_hash::FxHashMap; #[derive(Debug, Parser)] #[command( diff --git a/crates/ruff_cli/src/cache.rs b/crates/ruff_cli/src/cache.rs index 757ef33805..0147d9ccb5 100644 --- a/crates/ruff_cli/src/cache.rs +++ b/crates/ruff_cli/src/cache.rs @@ -2,23 +2,24 @@ use std::cell::RefCell; use std::fs; use std::hash::Hasher; use std::io::Write; +#[cfg(unix)] +use std::os::unix::fs::PermissionsExt; use std::path::Path; use anyhow::Result; use filetime::FileTime; use log::error; use path_absolutize::Absolutize; +use ruff_text_size::{TextRange, TextSize}; +use serde::ser::{SerializeSeq, SerializeStruct}; +use serde::{Deserialize, Serialize, Serializer}; + use ruff::message::Message; use ruff::settings::{AllSettings, Settings}; use ruff_cache::{CacheKey, CacheKeyHasher}; use ruff_diagnostics::{DiagnosticKind, Fix}; use ruff_python_ast::imports::ImportMap; use ruff_python_ast::source_code::SourceFileBuilder; -use ruff_text_size::{TextRange, TextSize}; -use serde::ser::{SerializeSeq, SerializeStruct}; -use serde::{Deserialize, Serialize, Serializer}; -#[cfg(unix)] -use std::os::unix::fs::PermissionsExt; const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/crates/ruff_cli/src/commands/config.rs b/crates/ruff_cli/src/commands/config.rs index a2db72a85f..22c414a361 100644 --- a/crates/ruff_cli/src/commands/config.rs +++ b/crates/ruff_cli/src/commands/config.rs @@ -1,6 +1,7 @@ -use crate::ExitStatus; use ruff::settings::options::Options; +use crate::ExitStatus; + #[allow(clippy::print_stdout)] pub(crate) fn config(key: Option<&str>) -> ExitStatus { match key { diff --git a/crates/ruff_cli/src/lib.rs b/crates/ruff_cli/src/lib.rs index 1ff17a3c55..4bb05f9ab0 100644 --- a/crates/ruff_cli/src/lib.rs +++ b/crates/ruff_cli/src/lib.rs @@ -388,9 +388,10 @@ fn check(args: CheckArgs, log_level: LogLevel) -> Result { #[cfg(test)] mod test_file_change_detector { - use crate::{change_detected, ChangeKind}; use std::path::PathBuf; + use crate::{change_detected, ChangeKind}; + #[test] fn detect_correct_file_change() { assert_eq!( diff --git a/crates/ruff_cli/tests/black_compatibility_test.rs b/crates/ruff_cli/tests/black_compatibility_test.rs index afe3d174c7..39f5ba5497 100644 --- a/crates/ruff_cli/tests/black_compatibility_test.rs +++ b/crates/ruff_cli/tests/black_compatibility_test.rs @@ -11,9 +11,10 @@ use std::{fs, process, str}; use anyhow::{anyhow, Context, Result}; use assert_cmd::Command; use log::info; -use ruff::logging::{set_up_logging, LogLevel}; use walkdir::WalkDir; +use ruff::logging::{set_up_logging, LogLevel}; + /// Handles `blackd` process and allows submitting code to it for formatting. struct Blackd { address: SocketAddr, diff --git a/crates/ruff_dev/src/generate_cli_help.rs b/crates/ruff_dev/src/generate_cli_help.rs index 266cfe6f5e..25e2417467 100644 --- a/crates/ruff_dev/src/generate_cli_help.rs +++ b/crates/ruff_dev/src/generate_cli_help.rs @@ -7,6 +7,7 @@ use std::{fs, str}; use anyhow::{bail, Context, Result}; use clap::CommandFactory; use pretty_assertions::StrComparison; + use ruff_cli::args; use crate::generate_all::{Mode, REGENERATE_ALL_COMMAND}; @@ -119,10 +120,12 @@ fn check_help_text() -> String { #[cfg(test)] mod test { - use super::{main, Args}; - use crate::generate_all::Mode; use anyhow::Result; + use crate::generate_all::Mode; + + use super::{main, Args}; + #[test] fn test_generate_json_schema() -> Result<()> { main(&Args { mode: Mode::Check }) diff --git a/crates/ruff_dev/src/generate_json_schema.rs b/crates/ruff_dev/src/generate_json_schema.rs index 5d8139674b..147638dba6 100644 --- a/crates/ruff_dev/src/generate_json_schema.rs +++ b/crates/ruff_dev/src/generate_json_schema.rs @@ -3,12 +3,13 @@ use std::fs; use std::path::PathBuf; -use crate::generate_all::{Mode, REGENERATE_ALL_COMMAND}; use anyhow::{bail, Result}; use pretty_assertions::StrComparison; -use ruff::settings::options::Options; use schemars::schema_for; +use ruff::settings::options::Options; + +use crate::generate_all::{Mode, REGENERATE_ALL_COMMAND}; use crate::ROOT_DIR; #[derive(clap::Args)] @@ -48,10 +49,12 @@ pub(crate) fn main(args: &Args) -> Result<()> { #[cfg(test)] mod test { - use super::{main, Args}; - use crate::generate_all::Mode; use anyhow::Result; + use crate::generate_all::Mode; + + use super::{main, Args}; + #[test] fn test_generate_json_schema() -> Result<()> { main(&Args { mode: Mode::Check }) diff --git a/crates/ruff_dev/src/generate_options.rs b/crates/ruff_dev/src/generate_options.rs index 8e541eb192..cbea31d99f 100644 --- a/crates/ruff_dev/src/generate_options.rs +++ b/crates/ruff_dev/src/generate_options.rs @@ -1,5 +1,6 @@ //! Generate a Markdown-compatible listing of configuration options. use itertools::Itertools; + use ruff::settings::options::Options; use ruff::settings::options_base::{OptionEntry, OptionField}; diff --git a/crates/ruff_diagnostics/src/diagnostic.rs b/crates/ruff_diagnostics/src/diagnostic.rs index 32ddbbedbd..419f048674 100644 --- a/crates/ruff_diagnostics/src/diagnostic.rs +++ b/crates/ruff_diagnostics/src/diagnostic.rs @@ -1,7 +1,6 @@ use anyhow::Result; use log::error; use ruff_text_size::{TextRange, TextSize}; - #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; diff --git a/crates/ruff_diagnostics/src/edit.rs b/crates/ruff_diagnostics/src/edit.rs index 4eaf7ad3a7..5da2dc590a 100644 --- a/crates/ruff_diagnostics/src/edit.rs +++ b/crates/ruff_diagnostics/src/edit.rs @@ -1,8 +1,8 @@ -use ruff_text_size::{TextRange, TextSize}; +use std::cmp::Ordering; +use ruff_text_size::{TextRange, TextSize}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; /// A text edit to be applied to a source file. Inserts, deletes, or replaces /// content at a given location. diff --git a/crates/ruff_python_ast/src/imports.rs b/crates/ruff_python_ast/src/imports.rs index 3b92b8c067..b9d24d74dc 100644 --- a/crates/ruff_python_ast/src/imports.rs +++ b/crates/ruff_python_ast/src/imports.rs @@ -1,6 +1,5 @@ use ruff_text_size::TextRange; use rustc_hash::FxHashMap; - #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; diff --git a/crates/ruff_python_ast/src/newlines.rs b/crates/ruff_python_ast/src/newlines.rs index 5e3b97f85a..bba0343d0a 100644 --- a/crates/ruff_python_ast/src/newlines.rs +++ b/crates/ruff_python_ast/src/newlines.rs @@ -1,8 +1,9 @@ -use memchr::{memchr2, memrchr2}; -use ruff_text_size::{TextLen, TextRange, TextSize}; use std::iter::FusedIterator; use std::ops::Deref; +use memchr::{memchr2, memrchr2}; +use ruff_text_size::{TextLen, TextRange, TextSize}; + /// Extension trait for [`str`] that provides a [`UniversalNewlineIterator`]. pub trait StrExt { fn universal_newlines(&self) -> UniversalNewlineIterator<'_>; @@ -337,10 +338,12 @@ impl Deref for LineEnding { #[cfg(test)] mod tests { - use super::UniversalNewlineIterator; - use crate::newlines::Line; use ruff_text_size::TextSize; + use crate::newlines::Line; + + use super::UniversalNewlineIterator; + #[test] fn universal_newlines_empty_str() { let lines: Vec<_> = UniversalNewlineIterator::from("").collect(); diff --git a/crates/ruff_python_ast/src/source_code/generator.rs b/crates/ruff_python_ast/src/source_code/generator.rs index f7806335ef..af36d7eaa5 100644 --- a/crates/ruff_python_ast/src/source_code/generator.rs +++ b/crates/ruff_python_ast/src/source_code/generator.rs @@ -9,7 +9,6 @@ use rustpython_parser::ast::{ }; use crate::newlines::LineEnding; - use crate::source_code::stylist::{Indentation, Quote, Stylist}; mod precedence { @@ -1457,9 +1456,9 @@ impl<'a> Generator<'a> { #[cfg(test)] mod tests { - use crate::newlines::LineEnding; use rustpython_parser as parser; + use crate::newlines::LineEnding; use crate::source_code::stylist::{Indentation, Quote}; use crate::source_code::Generator; diff --git a/crates/ruff_python_ast/src/source_code/line_index.rs b/crates/ruff_python_ast/src/source_code/line_index.rs index 96916d3534..1096f1d1bf 100644 --- a/crates/ruff_python_ast/src/source_code/line_index.rs +++ b/crates/ruff_python_ast/src/source_code/line_index.rs @@ -1,13 +1,15 @@ -use crate::source_code::SourceLocation; -use ruff_text_size::{TextLen, TextRange, TextSize}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; use std::fmt; use std::fmt::{Debug, Formatter}; use std::num::NonZeroUsize; use std::ops::Deref; use std::sync::Arc; +use ruff_text_size::{TextLen, TextRange, TextSize}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +use crate::source_code::SourceLocation; + /// Index for fast [byte offset](TextSize) to [`SourceLocation`] conversions. /// /// Cloning a [`LineIndex`] is cheap because it only requires bumping a reference count. @@ -312,9 +314,10 @@ const fn unwrap(option: Option) -> T { #[cfg(test)] mod tests { + use ruff_text_size::TextSize; + use crate::source_code::line_index::LineIndex; use crate::source_code::{OneIndexed, SourceLocation}; - use ruff_text_size::TextSize; #[test] fn ascii_index() { diff --git a/crates/ruff_python_ast/src/source_code/locator.rs b/crates/ruff_python_ast/src/source_code/locator.rs index 6a56e75584..58dd92f233 100644 --- a/crates/ruff_python_ast/src/source_code/locator.rs +++ b/crates/ruff_python_ast/src/source_code/locator.rs @@ -1,11 +1,13 @@ //! Struct used to efficiently slice source code at (row, column) Locations. -use crate::newlines::find_newline; -use crate::source_code::{LineIndex, OneIndexed, SourceCode, SourceLocation}; +use std::ops::Add; + use memchr::{memchr2, memrchr2}; use once_cell::unsync::OnceCell; use ruff_text_size::{TextLen, TextRange, TextSize}; -use std::ops::Add; + +use crate::newlines::find_newline; +use crate::source_code::{LineIndex, OneIndexed, SourceCode, SourceLocation}; pub struct Locator<'a> { contents: &'a str, diff --git a/crates/ruff_python_ast/src/source_code/mod.rs b/crates/ruff_python_ast/src/source_code/mod.rs index 3a1764d3d0..c1f8222d4d 100644 --- a/crates/ruff_python_ast/src/source_code/mod.rs +++ b/crates/ruff_python_ast/src/source_code/mod.rs @@ -1,22 +1,25 @@ -mod generator; -mod indexer; -mod line_index; -mod locator; -mod stylist; +use std::fmt::{Debug, Formatter}; +use std::sync::Arc; -pub use crate::source_code::line_index::{LineIndex, OneIndexed}; -pub use generator::Generator; -pub use indexer::Indexer; -pub use locator::Locator; use ruff_text_size::{TextRange, TextSize}; use rustpython_parser as parser; use rustpython_parser::{lexer, Mode, ParseError}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use std::fmt::{Debug, Formatter}; -use std::sync::Arc; + +pub use generator::Generator; +pub use indexer::Indexer; +pub use locator::Locator; pub use stylist::{Quote, Stylist}; +pub use crate::source_code::line_index::{LineIndex, OneIndexed}; + +mod generator; +mod indexer; +mod line_index; +mod locator; +mod stylist; + /// Run round-trip source code generation on a given Python code. pub fn round_trip(code: &str, source_path: &str) -> Result { let locator = Locator::new(code); diff --git a/crates/ruff_python_ast/src/source_code/stylist.rs b/crates/ruff_python_ast/src/source_code/stylist.rs index 5074beb1a5..237b619b57 100644 --- a/crates/ruff_python_ast/src/source_code/stylist.rs +++ b/crates/ruff_python_ast/src/source_code/stylist.rs @@ -9,7 +9,6 @@ use rustpython_parser::lexer::LexResult; use rustpython_parser::Tok; use crate::newlines::{find_newline, LineEnding}; - use crate::source_code::Locator; use crate::str::leading_quote; @@ -164,10 +163,10 @@ impl Deref for Indentation { #[cfg(test)] mod tests { - use crate::newlines::{find_newline, LineEnding}; use rustpython_parser::lexer::lex; use rustpython_parser::Mode; + use crate::newlines::{find_newline, LineEnding}; use crate::source_code::stylist::{Indentation, Quote}; use crate::source_code::{Locator, Stylist}; diff --git a/crates/ruff_python_semantic/src/analyze/function_type.rs b/crates/ruff_python_semantic/src/analyze/function_type.rs index 1df2f34a07..8d90e1edd7 100644 --- a/crates/ruff_python_semantic/src/analyze/function_type.rs +++ b/crates/ruff_python_semantic/src/analyze/function_type.rs @@ -3,7 +3,7 @@ use rustpython_parser::ast::Expr; use ruff_python_ast::call_path::from_qualified_name; use ruff_python_ast::helpers::map_callable; -use crate::context::Context; +use crate::model::SemanticModel; use crate::scope::{Scope, ScopeKind}; const CLASS_METHODS: [&str; 3] = ["__new__", "__init_subclass__", "__class_getitem__"]; @@ -19,7 +19,7 @@ pub enum FunctionType { /// Classify a function based on its scope, name, and decorators. pub fn classify( - ctx: &Context, + model: &SemanticModel, scope: &Scope, name: &str, decorator_list: &[Expr], @@ -32,7 +32,8 @@ pub fn classify( if decorator_list.iter().any(|expr| { // The method is decorated with a static method decorator (like // `@staticmethod`). - ctx.resolve_call_path(map_callable(expr)) + model + .resolve_call_path(map_callable(expr)) .map_or(false, |call_path| { call_path.as_slice() == ["", "staticmethod"] || staticmethod_decorators @@ -45,7 +46,7 @@ pub fn classify( // Special-case class method, like `__new__`. || scope.bases.iter().any(|expr| { // The class itself extends a known metaclass, so all methods are class methods. - ctx.resolve_call_path(map_callable(expr)).map_or(false, |call_path| { + model.resolve_call_path(map_callable(expr)).map_or(false, |call_path| { METACLASS_BASES .iter() .any(|(module, member)| call_path.as_slice() == [*module, *member]) @@ -53,7 +54,7 @@ pub fn classify( }) || decorator_list.iter().any(|expr| { // The method is decorated with a class method decorator (like `@classmethod`). - ctx.resolve_call_path(map_callable(expr)).map_or(false, |call_path| { + model.resolve_call_path(map_callable(expr)).map_or(false, |call_path| { call_path.as_slice() == ["", "classmethod"] || classmethod_decorators .iter() diff --git a/crates/ruff_python_semantic/src/analyze/logging.rs b/crates/ruff_python_semantic/src/analyze/logging.rs index 036c8afb23..1033cc07ad 100644 --- a/crates/ruff_python_semantic/src/analyze/logging.rs +++ b/crates/ruff_python_semantic/src/analyze/logging.rs @@ -2,7 +2,7 @@ use rustpython_parser::ast::{self, Expr}; use ruff_python_ast::call_path::collect_call_path; -use crate::context::Context; +use crate::model::SemanticModel; /// Return `true` if the given `Expr` is a potential logging call. Matches /// `logging.error`, `logger.error`, `self.logger.error`, etc., but not @@ -16,9 +16,9 @@ use crate::context::Context; /// # This is detected to be a logger candidate /// bar.error() /// ``` -pub fn is_logger_candidate(context: &Context, func: &Expr) -> bool { +pub fn is_logger_candidate(model: &SemanticModel, func: &Expr) -> bool { if let Expr::Attribute(ast::ExprAttribute { value, .. }) = func { - let Some(call_path) = (if let Some(call_path) = context.resolve_call_path(value) { + let Some(call_path) = (if let Some(call_path) = model.resolve_call_path(value) { if call_path.first().map_or(false, |module| *module == "logging") || call_path.as_slice() == ["flask", "current_app", "logger"] { Some(call_path) } else { diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index 4b467de4aa..e9c6bf4a8f 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -5,7 +5,7 @@ use ruff_python_stdlib::typing::{ IMMUTABLE_GENERIC_TYPES, IMMUTABLE_TYPES, PEP_585_GENERICS, PEP_593_SUBSCRIPTS, SUBSCRIPTS, }; -use crate::context::Context; +use crate::model::SemanticModel; #[derive(Copy, Clone)] pub enum Callable { @@ -26,14 +26,14 @@ pub enum SubscriptKind { pub fn match_annotated_subscript<'a>( expr: &Expr, - context: &Context, + model: &SemanticModel, typing_modules: impl Iterator, ) -> Option { if !matches!(expr, Expr::Name(_) | Expr::Attribute(_)) { return None; } - context.resolve_call_path(expr).and_then(|call_path| { + model.resolve_call_path(expr).and_then(|call_path| { if SUBSCRIPTS.contains(&call_path.as_slice()) { return Some(SubscriptKind::AnnotatedSubscript); } @@ -80,8 +80,8 @@ impl std::fmt::Display for ModuleMember { /// Returns the PEP 585 standard library generic variant for a `typing` module reference, if such /// a variant exists. -pub fn to_pep585_generic(expr: &Expr, context: &Context) -> Option { - context.resolve_call_path(expr).and_then(|call_path| { +pub fn to_pep585_generic(expr: &Expr, model: &SemanticModel) -> Option { + model.resolve_call_path(expr).and_then(|call_path| { let [module, name] = call_path.as_slice() else { return None; }; @@ -110,7 +110,11 @@ pub enum Pep604Operator { } /// Return the PEP 604 operator variant to which the given subscript [`Expr`] corresponds, if any. -pub fn to_pep604_operator(value: &Expr, slice: &Expr, context: &Context) -> Option { +pub fn to_pep604_operator( + value: &Expr, + slice: &Expr, + model: &SemanticModel, +) -> Option { /// Returns `true` if any argument in the slice is a string. fn any_arg_is_str(slice: &Expr) -> bool { match slice { @@ -129,13 +133,13 @@ pub fn to_pep604_operator(value: &Expr, slice: &Expr, context: &Context) -> Opti return None; } - context + model .resolve_call_path(value) .as_ref() .and_then(|call_path| { - if context.match_typing_call_path(call_path, "Optional") { + if model.match_typing_call_path(call_path, "Optional") { Some(Pep604Operator::Optional) - } else if context.match_typing_call_path(call_path, "Union") { + } else if model.match_typing_call_path(call_path, "Union") { Some(Pep604Operator::Union) } else { None @@ -145,10 +149,10 @@ pub fn to_pep604_operator(value: &Expr, slice: &Expr, context: &Context) -> Opti /// Return `true` if `Expr` represents a reference to a type annotation that resolves to an /// immutable type. -pub fn is_immutable_annotation(context: &Context, expr: &Expr) -> bool { +pub fn is_immutable_annotation(model: &SemanticModel, expr: &Expr) -> bool { match expr { Expr::Name(_) | Expr::Attribute(_) => { - context.resolve_call_path(expr).map_or(false, |call_path| { + model.resolve_call_path(expr).map_or(false, |call_path| { IMMUTABLE_TYPES .iter() .chain(IMMUTABLE_GENERIC_TYPES) @@ -156,7 +160,7 @@ pub fn is_immutable_annotation(context: &Context, expr: &Expr) -> bool { }) } Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { - context.resolve_call_path(value).map_or(false, |call_path| { + model.resolve_call_path(value).map_or(false, |call_path| { if IMMUTABLE_GENERIC_TYPES .iter() .any(|target| call_path.as_slice() == *target) @@ -164,16 +168,16 @@ pub fn is_immutable_annotation(context: &Context, expr: &Expr) -> bool { true } else if call_path.as_slice() == ["typing", "Union"] { if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice.as_ref() { - elts.iter().all(|elt| is_immutable_annotation(context, elt)) + elts.iter().all(|elt| is_immutable_annotation(model, elt)) } else { false } } else if call_path.as_slice() == ["typing", "Optional"] { - is_immutable_annotation(context, slice) + is_immutable_annotation(model, slice) } else if call_path.as_slice() == ["typing", "Annotated"] { if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice.as_ref() { elts.first() - .map_or(false, |elt| is_immutable_annotation(context, elt)) + .map_or(false, |elt| is_immutable_annotation(model, elt)) } else { false } @@ -187,7 +191,7 @@ pub fn is_immutable_annotation(context: &Context, expr: &Expr) -> bool { op: Operator::BitOr, right, range: _range, - }) => is_immutable_annotation(context, left) && is_immutable_annotation(context, right), + }) => is_immutable_annotation(model, left) && is_immutable_annotation(model, right), Expr::Constant(ast::ExprConstant { value: Constant::None, .. @@ -213,11 +217,11 @@ const IMMUTABLE_FUNCS: &[&[&str]] = &[ /// Return `true` if `func` is a function that returns an immutable object. pub fn is_immutable_func( - context: &Context, + model: &SemanticModel, func: &Expr, extend_immutable_calls: &[CallPath], ) -> bool { - context.resolve_call_path(func).map_or(false, |call_path| { + model.resolve_call_path(func).map_or(false, |call_path| { IMMUTABLE_FUNCS .iter() .any(|target| call_path.as_slice() == *target) diff --git a/crates/ruff_python_semantic/src/analyze/visibility.rs b/crates/ruff_python_semantic/src/analyze/visibility.rs index 4c2bc6a4bc..b5e5ac9d25 100644 --- a/crates/ruff_python_semantic/src/analyze/visibility.rs +++ b/crates/ruff_python_semantic/src/analyze/visibility.rs @@ -5,7 +5,7 @@ use rustpython_parser::ast::{self, Expr, Stmt}; use ruff_python_ast::call_path::{collect_call_path, CallPath}; use ruff_python_ast::helpers::map_callable; -use crate::context::Context; +use crate::model::SemanticModel; #[derive(Debug, Clone, Copy, is_macro::Is)] pub enum Visibility { @@ -14,9 +14,10 @@ pub enum Visibility { } /// Returns `true` if a function is a "static method". -pub fn is_staticmethod(ctx: &Context, decorator_list: &[Expr]) -> bool { +pub fn is_staticmethod(model: &SemanticModel, decorator_list: &[Expr]) -> bool { decorator_list.iter().any(|expr| { - ctx.resolve_call_path(map_callable(expr)) + model + .resolve_call_path(map_callable(expr)) .map_or(false, |call_path| { call_path.as_slice() == ["", "staticmethod"] }) @@ -24,9 +25,10 @@ pub fn is_staticmethod(ctx: &Context, decorator_list: &[Expr]) -> bool { } /// Returns `true` if a function is a "class method". -pub fn is_classmethod(ctx: &Context, decorator_list: &[Expr]) -> bool { +pub fn is_classmethod(model: &SemanticModel, decorator_list: &[Expr]) -> bool { decorator_list.iter().any(|expr| { - ctx.resolve_call_path(map_callable(expr)) + model + .resolve_call_path(map_callable(expr)) .map_or(false, |call_path| { call_path.as_slice() == ["", "classmethod"] }) @@ -34,23 +36,24 @@ pub fn is_classmethod(ctx: &Context, decorator_list: &[Expr]) -> bool { } /// Returns `true` if a function definition is an `@overload`. -pub fn is_overload(ctx: &Context, decorator_list: &[Expr]) -> bool { +pub fn is_overload(model: &SemanticModel, decorator_list: &[Expr]) -> bool { decorator_list .iter() - .any(|expr| ctx.match_typing_expr(map_callable(expr), "overload")) + .any(|expr| model.match_typing_expr(map_callable(expr), "overload")) } /// Returns `true` if a function definition is an `@override` (PEP 698). -pub fn is_override(ctx: &Context, decorator_list: &[Expr]) -> bool { +pub fn is_override(model: &SemanticModel, decorator_list: &[Expr]) -> bool { decorator_list .iter() - .any(|expr| ctx.match_typing_expr(map_callable(expr), "override")) + .any(|expr| model.match_typing_expr(map_callable(expr), "override")) } /// Returns `true` if a function definition is an abstract method based on its decorators. -pub fn is_abstract(ctx: &Context, decorator_list: &[Expr]) -> bool { +pub fn is_abstract(model: &SemanticModel, decorator_list: &[Expr]) -> bool { decorator_list.iter().any(|expr| { - ctx.resolve_call_path(map_callable(expr)) + model + .resolve_call_path(map_callable(expr)) .map_or(false, |call_path| { matches!( call_path.as_slice(), @@ -69,9 +72,14 @@ pub fn is_abstract(ctx: &Context, decorator_list: &[Expr]) -> bool { /// Returns `true` if a function definition is a `@property`. /// `extra_properties` can be used to check additional non-standard /// `@property`-like decorators. -pub fn is_property(ctx: &Context, decorator_list: &[Expr], extra_properties: &[CallPath]) -> bool { +pub fn is_property( + model: &SemanticModel, + decorator_list: &[Expr], + extra_properties: &[CallPath], +) -> bool { decorator_list.iter().any(|expr| { - ctx.resolve_call_path(map_callable(expr)) + model + .resolve_call_path(map_callable(expr)) .map_or(false, |call_path| { call_path.as_slice() == ["", "property"] || call_path.as_slice() == ["functools", "cached_property"] diff --git a/crates/ruff_python_semantic/src/lib.rs b/crates/ruff_python_semantic/src/lib.rs index e5f72a625b..5270ccd5d1 100644 --- a/crates/ruff_python_semantic/src/lib.rs +++ b/crates/ruff_python_semantic/src/lib.rs @@ -1,6 +1,6 @@ pub mod analyze; pub mod binding; -pub mod context; pub mod definition; +pub mod model; pub mod node; pub mod scope; diff --git a/crates/ruff_python_semantic/src/context.rs b/crates/ruff_python_semantic/src/model.rs similarity index 99% rename from crates/ruff_python_semantic/src/context.rs rename to crates/ruff_python_semantic/src/model.rs index 1831b991c5..7c94dc642a 100644 --- a/crates/ruff_python_semantic/src/context.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -20,8 +20,8 @@ use crate::definition::{Definition, DefinitionId, Definitions, Member, Module}; use crate::node::{NodeId, Nodes}; use crate::scope::{Scope, ScopeId, ScopeKind, Scopes}; -#[allow(clippy::struct_excessive_bools)] -pub struct Context<'a> { +/// A semantic model for a Python module, to enable querying the module's semantic information. +pub struct SemanticModel<'a> { pub typing_modules: &'a [String], pub module_path: Option<&'a [String]>, // Stack of all visited statements, along with the identifier of the current statement. @@ -49,7 +49,7 @@ pub struct Context<'a> { pub handled_exceptions: Vec, } -impl<'a> Context<'a> { +impl<'a> SemanticModel<'a> { pub fn new(typing_modules: &'a [String], path: &'a Path, module: Module<'a>) -> Self { Self { typing_modules, @@ -836,7 +836,7 @@ impl ContextFlags { } } -/// A snapshot of the [`Context`] at a given point in the AST traversal. +/// A snapshot of the [`SemanticModel`] at a given point in the AST traversal. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Snapshot { scope_id: ScopeId, diff --git a/crates/ruff_testing_macros/src/lib.rs b/crates/ruff_testing_macros/src/lib.rs index 622da40057..23815540a1 100644 --- a/crates/ruff_testing_macros/src/lib.rs +++ b/crates/ruff_testing_macros/src/lib.rs @@ -1,11 +1,12 @@ -use glob::{glob, Pattern}; use proc_macro::TokenStream; -use proc_macro2::Span; -use quote::{format_ident, quote}; use std::borrow::Cow; use std::collections::BTreeMap; use std::env; use std::path::{Component, PathBuf}; + +use glob::{glob, Pattern}; +use proc_macro2::Span; +use quote::{format_ident, quote}; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned;