diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index e0a2d40344..1cd0e596d5 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -778,7 +778,7 @@ where if self.settings.rules.any_enabled(&[ Rule::MutableDataclassDefault, Rule::FunctionCallInDataclassDefaultArgument, - ]) && ruff::rules::is_dataclass(self, decorator_list) + ]) && ruff::rules::is_dataclass(&self.model, decorator_list) { if self.settings.rules.enabled(Rule::MutableDataclassDefault) { ruff::rules::mutable_dataclass_default(self, body); @@ -5729,7 +5729,7 @@ impl<'a> Checker<'a> { // classes, etc.). if !overloaded_name.map_or(false, |overloaded_name| { flake8_annotations::helpers::is_overload_impl( - self, + &self.model, definition, &overloaded_name, ) @@ -5741,7 +5741,8 @@ impl<'a> Checker<'a> { *visibility, )); } - overloaded_name = flake8_annotations::helpers::overloaded_name(self, definition); + overloaded_name = + flake8_annotations::helpers::overloaded_name(&self.model, definition); } // flake8-pyi @@ -5756,7 +5757,7 @@ impl<'a> Checker<'a> { // pydocstyle if enforce_docstrings { if pydocstyle::helpers::should_ignore_definition( - self, + &self.model, definition, &self.settings.pydocstyle.ignore_decorators, ) { diff --git a/crates/ruff/src/rules/flake8_2020/rules.rs b/crates/ruff/src/rules/flake8_2020/rules.rs index 7f4a92b881..3c94f342d2 100644 --- a/crates/ruff/src/rules/flake8_2020/rules.rs +++ b/crates/ruff/src/rules/flake8_2020/rules.rs @@ -3,6 +3,7 @@ use rustpython_parser::ast::{self, Cmpop, Constant, Expr, Ranged}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; use crate::registry::Rule; @@ -113,16 +114,15 @@ impl Violation for SysVersionSlice1 { } } -fn is_sys(checker: &Checker, expr: &Expr, target: &str) -> bool { - checker - .model +fn is_sys(model: &SemanticModel, expr: &Expr, target: &str) -> bool { + model .resolve_call_path(expr) .map_or(false, |call_path| call_path.as_slice() == ["sys", target]) } /// YTT101, YTT102, YTT301, YTT303 pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) { - if is_sys(checker, value, "version") { + if is_sys(&checker.model, value, "version") { match slice { Expr::Slice(ast::ExprSlice { lower: None, @@ -176,7 +176,7 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) { pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &[Expr]) { match left { Expr::Subscript(ast::ExprSubscript { value, slice, .. }) - if is_sys(checker, value, "version_info") => + if is_sys(&checker.model, value, "version_info") => { if let Expr::Constant(ast::ExprConstant { value: Constant::Int(i), @@ -220,7 +220,7 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara } Expr::Attribute(ast::ExprAttribute { value, attr, .. }) - if is_sys(checker, value, "version_info") && attr == "minor" => + if is_sys(&checker.model, value, "version_info") && attr == "minor" => { if let ( [Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE], @@ -245,7 +245,7 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara _ => {} } - if is_sys(checker, left, "version") { + if is_sys(&checker.model, left, "version") { if let ( [Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE], [Expr::Constant(ast::ExprConstant { diff --git a/crates/ruff/src/rules/flake8_annotations/helpers.rs b/crates/ruff/src/rules/flake8_annotations/helpers.rs index 93c0c8e146..6813af9581 100644 --- a/crates/ruff/src/rules/flake8_annotations/helpers.rs +++ b/crates/ruff/src/rules/flake8_annotations/helpers.rs @@ -3,8 +3,7 @@ use rustpython_parser::ast::{self, Arguments, Expr, Stmt}; use ruff_python_ast::cast; use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::definition::{Definition, Member, MemberKind}; - -use crate::checkers::ast::Checker; +use ruff_python_semantic::model::SemanticModel; pub(super) fn match_function_def( stmt: &Stmt, @@ -37,14 +36,14 @@ pub(super) fn match_function_def( } /// Return the name of the function, if it's overloaded. -pub(crate) fn overloaded_name(checker: &Checker, definition: &Definition) -> Option { +pub(crate) fn overloaded_name(model: &SemanticModel, definition: &Definition) -> Option { if let Definition::Member(Member { kind: MemberKind::Function | MemberKind::NestedFunction | MemberKind::Method, stmt, .. }) = definition { - if visibility::is_overload(&checker.model, cast::decorator_list(stmt)) { + if visibility::is_overload(model, cast::decorator_list(stmt)) { let (name, ..) = match_function_def(stmt); Some(name.to_string()) } else { @@ -58,7 +57,7 @@ pub(crate) fn overloaded_name(checker: &Checker, definition: &Definition) -> Opt /// Return `true` if the definition is the implementation for an overloaded /// function. pub(crate) fn is_overload_impl( - checker: &Checker, + model: &SemanticModel, definition: &Definition, overloaded_name: &str, ) -> bool { @@ -68,7 +67,7 @@ pub(crate) fn is_overload_impl( .. }) = definition { - if visibility::is_overload(&checker.model, cast::decorator_list(stmt)) { + if visibility::is_overload(model, cast::decorator_list(stmt)) { false } else { let (name, ..) = match_function_def(stmt); diff --git a/crates/ruff/src/rules/flake8_annotations/rules.rs b/crates/ruff/src/rules/flake8_annotations/rules.rs index 132cfae00c..0f2612e7e2 100644 --- a/crates/ruff/src/rules/flake8_annotations/rules.rs +++ b/crates/ruff/src/rules/flake8_annotations/rules.rs @@ -8,6 +8,7 @@ use ruff_python_ast::{cast, helpers}; use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::analyze::visibility::Visibility; use ruff_python_semantic::definition::{Definition, Member, MemberKind}; +use ruff_python_semantic::model::SemanticModel; use ruff_python_stdlib::typing::SIMPLE_MAGIC_RETURN_TYPES; use crate::checkers::ast::Checker; @@ -430,7 +431,7 @@ fn is_none_returning(body: &[Stmt]) -> bool { /// ANN401 fn check_dynamically_typed( - checker: &Checker, + model: &SemanticModel, annotation: &Expr, func: F, diagnostics: &mut Vec, @@ -438,7 +439,7 @@ fn check_dynamically_typed( ) where F: FnOnce() -> String, { - if !is_overridden && checker.model.match_typing_expr(annotation, "Any") { + if !is_overridden && model.match_typing_expr(annotation, "Any") { diagnostics.push(Diagnostic::new( AnyType { name: func() }, annotation.range(), @@ -500,7 +501,7 @@ pub(crate) fn definition( has_any_typed_arg = true; if checker.settings.rules.enabled(Rule::AnyType) { check_dynamically_typed( - checker, + &checker.model, annotation, || arg.arg.to_string(), &mut diagnostics, @@ -535,7 +536,7 @@ pub(crate) fn definition( if checker.settings.rules.enabled(Rule::AnyType) { let name = &arg.arg; check_dynamically_typed( - checker, + &checker.model, expr, || format!("*{name}"), &mut diagnostics, @@ -567,7 +568,7 @@ pub(crate) fn definition( if checker.settings.rules.enabled(Rule::AnyType) { let name = &arg.arg; check_dynamically_typed( - checker, + &checker.model, expr, || format!("**{name}"), &mut diagnostics, @@ -625,7 +626,7 @@ pub(crate) fn definition( has_typed_return = true; if checker.settings.rules.enabled(Rule::AnyType) { check_dynamically_typed( - checker, + &checker.model, expr, || name.to_string(), &mut diagnostics, diff --git a/crates/ruff/src/rules/flake8_bandit/helpers.rs b/crates/ruff/src/rules/flake8_bandit/helpers.rs index ee7a4b46ae..1de1cc92e1 100644 --- a/crates/ruff/src/rules/flake8_bandit/helpers.rs +++ b/crates/ruff/src/rules/flake8_bandit/helpers.rs @@ -2,7 +2,7 @@ use once_cell::sync::Lazy; use regex::Regex; use rustpython_parser::ast::{self, Constant, Expr}; -use crate::checkers::ast::Checker; +use ruff_python_semantic::model::SemanticModel; static PASSWORD_CANDIDATE_REGEX: Lazy = Lazy::new(|| { Regex::new(r"(^|_)(?i)(pas+wo?r?d|pass(phrase)?|pwd|token|secrete?)($|_)").unwrap() @@ -22,26 +22,20 @@ pub(crate) fn matches_password_name(string: &str) -> bool { PASSWORD_CANDIDATE_REGEX.is_match(string) } -pub(crate) fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> bool { +pub(crate) fn is_untyped_exception(type_: Option<&Expr>, model: &SemanticModel) -> bool { type_.map_or(true, |type_| { if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &type_ { elts.iter().any(|type_| { - checker - .model - .resolve_call_path(type_) - .map_or(false, |call_path| { - call_path.as_slice() == ["", "Exception"] - || call_path.as_slice() == ["", "BaseException"] - }) - }) - } else { - checker - .model - .resolve_call_path(type_) - .map_or(false, |call_path| { + model.resolve_call_path(type_).map_or(false, |call_path| { call_path.as_slice() == ["", "Exception"] || call_path.as_slice() == ["", "BaseException"] }) + }) + } else { + model.resolve_call_path(type_).map_or(false, |call_path| { + call_path.as_slice() == ["", "Exception"] + || call_path.as_slice() == ["", "BaseException"] + }) } }) } diff --git a/crates/ruff/src/rules/flake8_bandit/rules/try_except_continue.rs b/crates/ruff/src/rules/flake8_bandit/rules/try_except_continue.rs index 4dd0c0b4a7..924e227c13 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/try_except_continue.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/try_except_continue.rs @@ -27,7 +27,7 @@ pub(crate) fn try_except_continue( ) { if body.len() == 1 && body[0].is_continue_stmt() - && (check_typed_exception || is_untyped_exception(type_, checker)) + && (check_typed_exception || is_untyped_exception(type_, &checker.model)) { checker .diagnostics diff --git a/crates/ruff/src/rules/flake8_bandit/rules/try_except_pass.rs b/crates/ruff/src/rules/flake8_bandit/rules/try_except_pass.rs index 429f363858..a104d27cdf 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/try_except_pass.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/try_except_pass.rs @@ -27,7 +27,7 @@ pub(crate) fn try_except_pass( ) { if body.len() == 1 && body[0].is_pass_stmt() - && (check_typed_exception || is_untyped_exception(type_, checker)) + && (check_typed_exception || is_untyped_exception(type_, &checker.model)) { checker .diagnostics diff --git a/crates/ruff/src/rules/flake8_blind_except/rules.rs b/crates/ruff/src/rules/flake8_blind_except/rules.rs index 28680567c6..a561ac1475 100644 --- a/crates/ruff/src/rules/flake8_blind_except/rules.rs +++ b/crates/ruff/src/rules/flake8_blind_except/rules.rs @@ -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.model, func) { + if logging::is_logger_candidate(func, &checker.model) { 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_bugbear/rules/cached_instance_method.rs b/crates/ruff/src/rules/flake8_bugbear/rules/cached_instance_method.rs index 39e7f54772..6da3d29736 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 @@ -2,6 +2,7 @@ use rustpython_parser::ast::{self, Expr, Ranged}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_semantic::model::SemanticModel; use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; @@ -18,14 +19,11 @@ impl Violation for CachedInstanceMethod { } } -fn is_cache_func(checker: &Checker, expr: &Expr) -> bool { - checker - .model - .resolve_call_path(expr) - .map_or(false, |call_path| { - call_path.as_slice() == ["functools", "lru_cache"] - || call_path.as_slice() == ["functools", "cache"] - }) +fn is_cache_func(model: &SemanticModel, expr: &Expr) -> bool { + model.resolve_call_path(expr).map_or(false, |call_path| { + call_path.as_slice() == ["functools", "lru_cache"] + || call_path.as_slice() == ["functools", "cache"] + }) } /// B019 @@ -44,7 +42,7 @@ pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Ex } for decorator in decorator_list { if is_cache_func( - checker, + &checker.model, match decorator { Expr::Call(ast::ExprCall { func, .. }) => func, _ => decorator, 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 8f1890ae88..ebb78dc9b8 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 @@ -4,11 +4,11 @@ use rustpython_parser::ast::{self, Arguments, Constant, Expr, Ranged}; use ruff_diagnostics::Violation; use ruff_diagnostics::{Diagnostic, DiagnosticKind}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::call_path::from_qualified_name; -use ruff_python_ast::call_path::{compose_call_path, CallPath}; +use ruff_python_ast::call_path::{compose_call_path, from_qualified_name, CallPath}; use ruff_python_ast::visitor; use ruff_python_ast::visitor::Visitor; use ruff_python_semantic::analyze::typing::is_immutable_func; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; use crate::rules::flake8_bugbear::rules::mutable_argument_default::is_mutable_func; @@ -73,9 +73,19 @@ impl Violation for FunctionCallInDefaultArgument { } struct ArgumentDefaultVisitor<'a> { - checker: &'a Checker<'a>, - diagnostics: Vec<(DiagnosticKind, TextRange)>, + model: &'a SemanticModel<'a>, extend_immutable_calls: Vec>, + diagnostics: Vec<(DiagnosticKind, TextRange)>, +} + +impl<'a> ArgumentDefaultVisitor<'a> { + fn new(model: &'a SemanticModel<'a>, extend_immutable_calls: Vec>) -> Self { + Self { + model, + extend_immutable_calls, + diagnostics: Vec::new(), + } + } } impl<'a, 'b> Visitor<'b> for ArgumentDefaultVisitor<'b> @@ -85,8 +95,8 @@ where fn visit_expr(&mut self, expr: &'b Expr) { match expr { Expr::Call(ast::ExprCall { func, args, .. }) => { - if !is_mutable_func(self.checker, func) - && !is_immutable_func(&self.checker.model, func, &self.extend_immutable_calls) + if !is_mutable_func(self.model, func) + && !is_immutable_func(self.model, func, &self.extend_immutable_calls) && !is_nan_or_infinity(func, args) { self.diagnostics.push(( @@ -139,11 +149,7 @@ pub(crate) fn function_call_argument_default(checker: &mut Checker, arguments: & .map(|target| from_qualified_name(target)) .collect(); let diagnostics = { - let mut visitor = ArgumentDefaultVisitor { - checker, - diagnostics: vec![], - extend_immutable_calls, - }; + let mut visitor = ArgumentDefaultVisitor::new(&checker.model, extend_immutable_calls); for expr in arguments .defaults .iter() 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 c80b673c70..3b8f0cdab1 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 @@ -3,6 +3,7 @@ use rustpython_parser::ast::{self, Arguments, Expr, Ranged}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_semantic::analyze::typing::is_immutable_annotation; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; @@ -25,18 +26,15 @@ const MUTABLE_FUNCS: &[&[&str]] = &[ &["collections", "deque"], ]; -pub(crate) fn is_mutable_func(checker: &Checker, func: &Expr) -> bool { - checker - .model - .resolve_call_path(func) - .map_or(false, |call_path| { - MUTABLE_FUNCS - .iter() - .any(|target| call_path.as_slice() == *target) - }) +pub(crate) fn is_mutable_func(model: &SemanticModel, func: &Expr) -> bool { + model.resolve_call_path(func).map_or(false, |call_path| { + MUTABLE_FUNCS + .iter() + .any(|target| call_path.as_slice() == *target) + }) } -fn is_mutable_expr(checker: &Checker, expr: &Expr) -> bool { +fn is_mutable_expr(model: &SemanticModel, expr: &Expr) -> bool { match expr { Expr::List(_) | Expr::Dict(_) @@ -44,7 +42,7 @@ fn is_mutable_expr(checker: &Checker, expr: &Expr) -> bool { | Expr::ListComp(_) | Expr::DictComp(_) | Expr::SetComp(_) => true, - Expr::Call(ast::ExprCall { func, .. }) => is_mutable_func(checker, func), + Expr::Call(ast::ExprCall { func, .. }) => is_mutable_func(model, func), _ => false, } } @@ -66,7 +64,7 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, arguments: &Argume .zip(arguments.defaults.iter().rev()), ) { - if is_mutable_expr(checker, default) + if is_mutable_expr(&checker.model, default) && !arg .annotation .as_ref() 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 0526ce7bf4..cdbabecb59 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 @@ -2,6 +2,7 @@ use rustpython_parser::ast::{self, Expr, Keyword, Ranged}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; @@ -60,7 +61,7 @@ pub(crate) fn locals_in_render_function( } let locals = if args.len() >= 3 { - if !is_locals_call(checker, &args[2]) { + if !is_locals_call(&checker.model, &args[2]) { return; } &args[2] @@ -68,7 +69,7 @@ pub(crate) fn locals_in_render_function( .iter() .find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "context")) { - if !is_locals_call(checker, &keyword.value) { + if !is_locals_call(&checker.model, &keyword.value) { return; } &keyword.value @@ -82,12 +83,11 @@ pub(crate) fn locals_in_render_function( )); } -fn is_locals_call(checker: &Checker, expr: &Expr) -> bool { +fn is_locals_call(model: &SemanticModel, expr: &Expr) -> bool { let Expr::Call(ast::ExprCall { func, .. }) = expr else { return false }; - checker - .model + 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 6d93b662ef..ec7f79ff47 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 @@ -2,6 +2,7 @@ use rustpython_parser::ast::{self, Constant, Expr, Ranged, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; @@ -55,7 +56,7 @@ pub(crate) fn model_without_dunder_str( body: &[Stmt], class_location: &Stmt, ) -> Option { - if !checker_applies(checker, bases, body) { + if !checker_applies(&checker.model, bases, body) { return None; } if !has_dunder_method(body) { @@ -79,12 +80,12 @@ fn has_dunder_method(body: &[Stmt]) -> bool { }) } -fn checker_applies(checker: &Checker, bases: &[Expr], body: &[Stmt]) -> bool { +fn checker_applies(model: &SemanticModel, bases: &[Expr], body: &[Stmt]) -> bool { for base in bases.iter() { if is_model_abstract(body) { continue; } - if helpers::is_model(&checker.model, base) { + if helpers::is_model(model, base) { return true; } } 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 7906f6514f..fcddec99d0 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 @@ -4,6 +4,7 @@ use rustpython_parser::ast::{self, Expr, Ranged, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; @@ -99,11 +100,11 @@ impl fmt::Display for ContentType { } } -fn get_element_type(checker: &Checker, element: &Stmt) -> Option { +fn get_element_type(model: &SemanticModel, 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.model, func) { + if helpers::is_model_field(model, func) { return Some(ContentType::FieldDeclaration); } } @@ -150,7 +151,7 @@ pub(crate) fn unordered_body_content_in_model( } let mut elements_type_found = Vec::new(); for element in body.iter() { - let Some(current_element_type) = get_element_type(checker, element) else { + let Some(current_element_type) = get_element_type(&checker.model, element) else { continue; }; let Some(&element_type) = elements_type_found diff --git a/crates/ruff/src/rules/flake8_logging_format/rules.rs b/crates/ruff/src/rules/flake8_logging_format/rules.rs index aa505f96ce..05d7db16f4 100644 --- a/crates/ruff/src/rules/flake8_logging_format/rules.rs +++ b/crates/ruff/src/rules/flake8_logging_format/rules.rs @@ -151,7 +151,7 @@ pub(crate) fn logging_call( args: &[Expr], keywords: &[Keyword], ) { - if !logging::is_logger_candidate(&checker.model, func) { + if !logging::is_logger_candidate(func, &checker.model) { return; } 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 b62d7045c2..e9e5103a10 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs @@ -2,6 +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_ast::source_code::Locator; use ruff_python_semantic::model::SemanticModel; use ruff_python_semantic::scope::{ClassDef, ScopeKind}; @@ -90,8 +91,9 @@ const ALLOWED_ATTRIBUTES_IN_DEFAULTS: &[&[&str]] = &[ fn is_valid_default_value_with_annotation( default: &Expr, - checker: &Checker, allow_container: bool, + locator: &Locator, + model: &SemanticModel, ) -> bool { match default { Expr::List(ast::ExprList { elts, .. }) @@ -101,7 +103,7 @@ fn is_valid_default_value_with_annotation( && elts.len() <= 10 && elts .iter() - .all(|e| is_valid_default_value_with_annotation(e, checker, false)); + .all(|e| is_valid_default_value_with_annotation(e, false, locator, model)); } Expr::Dict(ast::ExprDict { keys, @@ -112,8 +114,8 @@ fn is_valid_default_value_with_annotation( && keys.len() <= 10 && keys.iter().zip(values).all(|(k, v)| { k.as_ref().map_or(false, |k| { - is_valid_default_value_with_annotation(k, checker, false) - }) && is_valid_default_value_with_annotation(v, checker, false) + is_valid_default_value_with_annotation(k, false, locator, model) + }) && is_valid_default_value_with_annotation(v, false, locator, model) }); } Expr::Constant(ast::ExprConstant { @@ -125,17 +127,17 @@ fn is_valid_default_value_with_annotation( Expr::Constant(ast::ExprConstant { value: Constant::Str(..), .. - }) => return checker.locator.slice(default.range()).len() <= 50, + }) => return locator.slice(default.range()).len() <= 50, Expr::Constant(ast::ExprConstant { value: Constant::Bytes(..), .. - }) => return checker.locator.slice(default.range()).len() <= 50, + }) => return locator.slice(default.range()).len() <= 50, // Ex) `123`, `True`, `False`, `3.14` Expr::Constant(ast::ExprConstant { value: Constant::Int(..) | Constant::Bool(..) | Constant::Float(..), .. }) => { - return checker.locator.slice(default.range()).len() <= 10; + return locator.slice(default.range()).len() <= 10; } // Ex) `2j` Expr::Constant(ast::ExprConstant { @@ -143,7 +145,7 @@ fn is_valid_default_value_with_annotation( .. }) => { if *real == 0.0 { - return checker.locator.slice(default.range()).len() <= 10; + return locator.slice(default.range()).len() <= 10; } } Expr::UnaryOp(ast::ExprUnaryOp { @@ -157,7 +159,7 @@ fn is_valid_default_value_with_annotation( .. }) = operand.as_ref() { - return checker.locator.slice(operand.range()).len() <= 10; + return locator.slice(operand.range()).len() <= 10; } // Ex) `-2j` if let Expr::Constant(ast::ExprConstant { @@ -166,21 +168,17 @@ fn is_valid_default_value_with_annotation( }) = operand.as_ref() { if *real == 0.0 { - return checker.locator.slice(operand.range()).len() <= 10; + return locator.slice(operand.range()).len() <= 10; } } // Ex) `-math.inf`, `-math.pi`, etc. if let Expr::Attribute(_) = operand.as_ref() { - if checker - .model - .resolve_call_path(operand) - .map_or(false, |call_path| { - ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS.iter().any(|target| { - // reject `-math.nan` - call_path.as_slice() == *target && *target != ["math", "nan"] - }) + if model.resolve_call_path(operand).map_or(false, |call_path| { + ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS.iter().any(|target| { + // reject `-math.nan` + call_path.as_slice() == *target && *target != ["math", "nan"] }) - { + }) { return true; } } @@ -203,7 +201,7 @@ fn is_valid_default_value_with_annotation( .. }) = left.as_ref() { - return checker.locator.slice(left.range()).len() <= 10; + return locator.slice(left.range()).len() <= 10; } else if let Expr::UnaryOp(ast::ExprUnaryOp { op: Unaryop::USub, operand, @@ -216,23 +214,19 @@ fn is_valid_default_value_with_annotation( .. }) = operand.as_ref() { - return checker.locator.slice(operand.range()).len() <= 10; + return locator.slice(operand.range()).len() <= 10; } } } } // Ex) `math.inf`, `sys.stdin`, etc. Expr::Attribute(_) => { - if checker - .model - .resolve_call_path(default) - .map_or(false, |call_path| { - ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS - .iter() - .chain(ALLOWED_ATTRIBUTES_IN_DEFAULTS.iter()) - .any(|target| call_path.as_slice() == *target) - }) - { + if model.resolve_call_path(default).map_or(false, |call_path| { + ALLOWED_MATH_ATTRIBUTES_IN_DEFAULTS + .iter() + .chain(ALLOWED_ATTRIBUTES_IN_DEFAULTS.iter()) + .any(|target| call_path.as_slice() == *target) + }) { return true; } } @@ -332,7 +326,12 @@ pub(crate) fn typed_argument_simple_defaults(checker: &mut Checker, args: &Argum .and_then(|i| args.defaults.get(i)) { if arg.annotation.is_some() { - if !is_valid_default_value_with_annotation(default, checker, true) { + if !is_valid_default_value_with_annotation( + default, + true, + checker.locator, + &checker.model, + ) { let mut diagnostic = Diagnostic::new(TypedArgumentDefaultInStub, default.range()); @@ -359,7 +358,12 @@ pub(crate) fn typed_argument_simple_defaults(checker: &mut Checker, args: &Argum .and_then(|i| args.kw_defaults.get(i)) { if kwarg.annotation.is_some() { - if !is_valid_default_value_with_annotation(default, checker, true) { + if !is_valid_default_value_with_annotation( + default, + true, + checker.locator, + &checker.model, + ) { let mut diagnostic = Diagnostic::new(TypedArgumentDefaultInStub, default.range()); @@ -389,7 +393,12 @@ pub(crate) fn argument_simple_defaults(checker: &mut Checker, args: &Arguments) .and_then(|i| args.defaults.get(i)) { if arg.annotation.is_none() { - if !is_valid_default_value_with_annotation(default, checker, true) { + if !is_valid_default_value_with_annotation( + default, + true, + checker.locator, + &checker.model, + ) { let mut diagnostic = Diagnostic::new(ArgumentDefaultInStub, default.range()); @@ -416,7 +425,12 @@ pub(crate) fn argument_simple_defaults(checker: &mut Checker, args: &Arguments) .and_then(|i| args.kw_defaults.get(i)) { if kwarg.annotation.is_none() { - if !is_valid_default_value_with_annotation(default, checker, true) { + if !is_valid_default_value_with_annotation( + default, + true, + checker.locator, + &checker.model, + ) { let mut diagnostic = Diagnostic::new(ArgumentDefaultInStub, default.range()); @@ -454,7 +468,7 @@ pub(crate) fn assignment_default_in_stub(checker: &mut Checker, targets: &[Expr] if is_valid_default_value_without_annotation(value) { return; } - if is_valid_default_value_with_annotation(value, checker, true) { + if is_valid_default_value_with_annotation(value, true, checker.locator, &checker.model) { return; } @@ -485,7 +499,7 @@ pub(crate) fn annotated_assignment_default_in_stub( if is_type_var_like_call(&checker.model, value) { return; } - if is_valid_default_value_with_annotation(value, checker, true) { + if is_valid_default_value_with_annotation(value, true, checker.locator, &checker.model) { return; } @@ -522,7 +536,7 @@ pub(crate) fn unannotated_assignment_in_stub( if is_valid_default_value_without_annotation(value) { return; } - if !is_valid_default_value_with_annotation(value, checker, true) { + if !is_valid_default_value_with_annotation(value, true, checker.locator, &checker.model) { return; } 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 19096edf9d..dfda3bc625 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/parametrize.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/parametrize.rs @@ -4,6 +4,7 @@ use rustpython_parser::{lexer, Mode, Tok}; use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::source_code::{Generator, Locator}; use crate::checkers::ast::Checker; use crate::registry::{AsRule, Rule}; @@ -45,7 +46,7 @@ impl Violation for PytestParametrizeValuesWrongType { } } -fn elts_to_csv(elts: &[Expr], checker: &Checker) -> Option { +fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option { let all_literals = elts.iter().all(|e| { matches!( e, @@ -77,7 +78,7 @@ fn elts_to_csv(elts: &[Expr], checker: &Checker) -> Option { kind: None, range: TextRange::default(), }); - Some(checker.generator().expr(&node)) + Some(generator.expr(&node)) } /// Returns the range of the `name` argument of `@pytest.mark.parametrize`. @@ -93,14 +94,14 @@ fn elts_to_csv(elts: &[Expr], checker: &Checker) -> Option { /// ``` /// /// This method assumes that the first argument is a string. -fn get_parametrize_name_range(checker: &Checker, decorator: &Expr, expr: &Expr) -> TextRange { +fn get_parametrize_name_range(decorator: &Expr, expr: &Expr, locator: &Locator) -> TextRange { let mut locations = Vec::new(); let mut implicit_concat = None; // The parenthesis are not part of the AST, so we need to tokenize the // decorator to find them. for (tok, range) in lexer::lex_starts_at( - checker.locator.slice(decorator.range()), + locator.slice(decorator.range()), Mode::Module, decorator.start(), ) @@ -139,7 +140,8 @@ fn check_names(checker: &mut Checker, decorator: &Expr, expr: &Expr) { if names.len() > 1 { match names_type { types::ParametrizeNameType::Tuple => { - let name_range = get_parametrize_name_range(checker, decorator, expr); + let name_range = + get_parametrize_name_range(decorator, expr, checker.locator); let mut diagnostic = Diagnostic::new( PytestParametrizeNamesWrongType { expected: names_type, @@ -170,7 +172,8 @@ fn check_names(checker: &mut Checker, decorator: &Expr, expr: &Expr) { checker.diagnostics.push(diagnostic); } types::ParametrizeNameType::List => { - let name_range = get_parametrize_name_range(checker, decorator, expr); + let name_range = + get_parametrize_name_range(decorator, expr, checker.locator); let mut diagnostic = Diagnostic::new( PytestParametrizeNamesWrongType { expected: names_type, @@ -241,7 +244,7 @@ fn check_names(checker: &mut Checker, decorator: &Expr, expr: &Expr) { expr.range(), ); if checker.patch(diagnostic.kind.rule()) { - if let Some(content) = elts_to_csv(elts, checker) { + if let Some(content) = elts_to_csv(elts, checker.generator()) { #[allow(deprecated)] diagnostic.set_fix(Fix::unspecified(Edit::range_replacement( content, @@ -291,7 +294,7 @@ fn check_names(checker: &mut Checker, decorator: &Expr, expr: &Expr) { expr.range(), ); if checker.patch(diagnostic.kind.rule()) { - if let Some(content) = elts_to_csv(elts, checker) { + if let Some(content) = elts_to_csv(elts, checker.generator()) { #[allow(deprecated)] diagnostic.set_fix(Fix::unspecified(Edit::range_replacement( content, 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 ca1e3aaf4d..11fe6c56dc 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/raises.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/raises.rs @@ -4,6 +4,7 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::format_call_path; use ruff_python_ast::call_path::from_qualified_name; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; use crate::registry::Rule; @@ -46,13 +47,10 @@ impl Violation for PytestRaisesWithoutException { } } -fn is_pytest_raises(checker: &Checker, func: &Expr) -> bool { - checker - .model - .resolve_call_path(func) - .map_or(false, |call_path| { - call_path.as_slice() == ["pytest", "raises"] - }) +fn is_pytest_raises(func: &Expr, model: &SemanticModel) -> bool { + model.resolve_call_path(func).map_or(false, |call_path| { + call_path.as_slice() == ["pytest", "raises"] + }) } const fn is_non_trivial_with_body(body: &[Stmt]) -> bool { @@ -66,7 +64,7 @@ const fn is_non_trivial_with_body(body: &[Stmt]) -> bool { } pub(crate) fn raises_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) { - if is_pytest_raises(checker, func) { + if is_pytest_raises(func, &checker.model) { if checker .settings .rules @@ -106,7 +104,7 @@ pub(crate) fn complex_raises( let mut is_too_complex = false; let raises_called = items.iter().any(|item| match &item.context_expr { - Expr::Call(ast::ExprCall { func, .. }) => is_pytest_raises(checker, func), + Expr::Call(ast::ExprCall { func, .. }) => is_pytest_raises(func, &checker.model), _ => false, }); 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 f57a9f69a5..99f632fd41 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 @@ -2,6 +2,7 @@ use rustpython_parser::ast::{self, Expr, Ranged, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; @@ -41,8 +42,8 @@ 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.model.expr_grandparent() else { +fn match_async_exit_stack(model: &SemanticModel) -> bool { + let Some(expr) = model.expr_grandparent() else { return false; }; let Expr::Await(ast::ExprAwait { value, range: _ }) = expr else { @@ -57,17 +58,13 @@ fn match_async_exit_stack(checker: &Checker) -> bool { if attr != "enter_async_context" { return false; } - for parent in checker.model.parents() { + for parent in 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 - .model - .resolve_call_path(func) - .map_or(false, |call_path| { - call_path.as_slice() == ["contextlib", "AsyncExitStack"] - }) - { + if model.resolve_call_path(func).map_or(false, |call_path| { + call_path.as_slice() == ["contextlib", "AsyncExitStack"] + }) { return true; } } @@ -79,8 +76,8 @@ 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.model.expr_parent() else { +fn match_exit_stack(model: &SemanticModel) -> bool { + let Some(expr) = model.expr_parent() else { return false; }; let Expr::Call(ast::ExprCall { func, .. }) = expr else { @@ -92,17 +89,13 @@ fn match_exit_stack(checker: &Checker) -> bool { if attr != "enter_context" { return false; } - for parent in checker.model.parents() { + for parent in 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 - .model - .resolve_call_path(func) - .map_or(false, |call_path| { - call_path.as_slice() == ["contextlib", "ExitStack"] - }) - { + if model.resolve_call_path(func).map_or(false, |call_path| { + call_path.as_slice() == ["contextlib", "ExitStack"] + }) { return true; } } @@ -126,12 +119,12 @@ pub(crate) fn open_file_with_context_handler(checker: &mut Checker, func: &Expr) } // Ex) `with contextlib.ExitStack() as exit_stack: ...` - if match_exit_stack(checker) { + if match_exit_stack(&checker.model) { return; } // Ex) `with contextlib.AsyncExitStack() as exit_stack: ...` - if match_async_exit_stack(checker) { + if match_async_exit_stack(&checker.model) { return; } diff --git a/crates/ruff/src/rules/pydocstyle/helpers.rs b/crates/ruff/src/rules/pydocstyle/helpers.rs index 4be0b193e9..3925b0680a 100644 --- a/crates/ruff/src/rules/pydocstyle/helpers.rs +++ b/crates/ruff/src/rules/pydocstyle/helpers.rs @@ -6,8 +6,7 @@ use ruff_python_ast::helpers::map_callable; use ruff_python_ast::newlines::StrExt; use ruff_python_ast::str::is_implicit_concatenation; use ruff_python_semantic::definition::{Definition, Member, MemberKind}; - -use crate::checkers::ast::Checker; +use ruff_python_semantic::model::SemanticModel; /// Return the index of the first logical line in a string. pub(crate) fn logical_line(content: &str) -> Option { @@ -37,7 +36,7 @@ pub(crate) fn normalize_word(first_word: &str) -> String { /// Check decorator list to see if function should be ignored. pub(crate) fn should_ignore_definition( - checker: &Checker, + model: &SemanticModel, definition: &Definition, ignore_decorators: &BTreeSet, ) -> bool { @@ -52,7 +51,7 @@ pub(crate) fn should_ignore_definition( }) = definition { for decorator in cast::decorator_list(stmt) { - if let Some(call_path) = checker.model.resolve_call_path(map_callable(decorator)) { + if let Some(call_path) = 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/pylint/helpers.rs b/crates/ruff/src/rules/pylint/helpers.rs index 017f125423..f459370461 100644 --- a/crates/ruff/src/rules/pylint/helpers.rs +++ b/crates/ruff/src/rules/pylint/helpers.rs @@ -1,11 +1,12 @@ use ruff_python_semantic::analyze::function_type; use ruff_python_semantic::analyze::function_type::FunctionType; +use ruff_python_semantic::model::SemanticModel; use ruff_python_semantic::scope::{FunctionDef, ScopeKind}; -use crate::checkers::ast::Checker; +use crate::settings::Settings; -pub(crate) fn in_dunder_init(checker: &Checker) -> bool { - let scope = checker.model.scope(); +pub(crate) fn in_dunder_init(model: &SemanticModel, settings: &Settings) -> bool { + let scope = model.scope(); let ScopeKind::Function(FunctionDef { name, decorator_list, @@ -16,18 +17,18 @@ pub(crate) fn in_dunder_init(checker: &Checker) -> bool { if name != "__init__" { return false; } - let Some(parent) = scope.parent.map(|scope_id| &checker.model.scopes[scope_id]) else { + let Some(parent) = scope.parent.map(|scope_id| &model.scopes[scope_id]) else { return false; }; if !matches!( function_type::classify( - &checker.model, + model, parent, name, decorator_list, - &checker.settings.pep8_naming.classmethod_decorators, - &checker.settings.pep8_naming.staticmethod_decorators, + &settings.pep8_naming.classmethod_decorators, + &settings.pep8_naming.staticmethod_decorators, ), FunctionType::Method ) { diff --git a/crates/ruff/src/rules/pylint/rules/logging.rs b/crates/ruff/src/rules/pylint/rules/logging.rs index 4f7cf80624..102f5f55f4 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.model, func) { + if !logging::is_logger_candidate(func, &checker.model) { return; } diff --git a/crates/ruff/src/rules/pylint/rules/return_in_init.rs b/crates/ruff/src/rules/pylint/rules/return_in_init.rs index d5f981b545..3ab08833f9 100644 --- a/crates/ruff/src/rules/pylint/rules/return_in_init.rs +++ b/crates/ruff/src/rules/pylint/rules/return_in_init.rs @@ -62,7 +62,7 @@ pub(crate) fn return_in_init(checker: &mut Checker, stmt: &Stmt) { } } - if in_dunder_init(checker) { + if in_dunder_init(&checker.model, checker.settings) { checker .diagnostics .push(Diagnostic::new(ReturnInInit, stmt.range())); diff --git a/crates/ruff/src/rules/pylint/rules/yield_in_init.rs b/crates/ruff/src/rules/pylint/rules/yield_in_init.rs index f9f08650d4..d81d7a929e 100644 --- a/crates/ruff/src/rules/pylint/rules/yield_in_init.rs +++ b/crates/ruff/src/rules/pylint/rules/yield_in_init.rs @@ -39,7 +39,7 @@ impl Violation for YieldInInit { /// PLE0100 pub(crate) fn yield_in_init(checker: &mut Checker, expr: &Expr) { - if in_dunder_init(checker) { + if in_dunder_init(&checker.model, checker.settings) { checker .diagnostics .push(Diagnostic::new(YieldInInit, expr.range())); 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 c9e67e4edb..d15629c816 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 @@ -6,6 +6,7 @@ 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_semantic::model::SemanticModel; use ruff_python_stdlib::identifiers::is_identifier; use crate::checkers::ast::Checker; @@ -34,7 +35,7 @@ impl Violation for ConvertNamedTupleFunctionalToClass { /// Return the typename, args, keywords, and base class. fn match_named_tuple_assign<'a>( - checker: &Checker, + model: &SemanticModel, targets: &'a [Expr], value: &'a Expr, ) -> Option<(&'a str, &'a [Expr], &'a [Keyword], &'a Expr)> { @@ -50,13 +51,9 @@ fn match_named_tuple_assign<'a>( }) = value else { return None; }; - if !checker - .model - .resolve_call_path(func) - .map_or(false, |call_path| { - call_path.as_slice() == ["typing", "NamedTuple"] - }) - { + if !model.resolve_call_path(func).map_or(false, |call_path| { + call_path.as_slice() == ["typing", "NamedTuple"] + }) { return None; } Some((typename, args, keywords, func)) @@ -187,7 +184,7 @@ pub(crate) fn convert_named_tuple_functional_to_class( value: &Expr, ) { let Some((typename, args, keywords, base_class)) = - match_named_tuple_assign(checker, targets, value) else + match_named_tuple_assign(&checker.model, targets, value) else { return; }; 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 fa2b0646d2..6af560dcf9 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 @@ -6,6 +6,7 @@ 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_semantic::model::SemanticModel; use ruff_python_stdlib::identifiers::is_identifier; use crate::checkers::ast::Checker; @@ -35,7 +36,7 @@ impl Violation for ConvertTypedDictFunctionalToClass { /// Return the class name, arguments, keywords and base class for a `TypedDict` /// assignment. fn match_typed_dict_assign<'a>( - checker: &Checker, + model: &SemanticModel, targets: &'a [Expr], value: &'a Expr, ) -> Option<(&'a str, &'a [Expr], &'a [Keyword], &'a Expr)> { @@ -51,13 +52,9 @@ fn match_typed_dict_assign<'a>( }) = value else { return None; }; - if !checker - .model - .resolve_call_path(func) - .map_or(false, |call_path| { - call_path.as_slice() == ["typing", "TypedDict"] - }) - { + if !model.resolve_call_path(func).map_or(false, |call_path| { + call_path.as_slice() == ["typing", "TypedDict"] + }) { return None; } Some((class_name, args, keywords, func)) @@ -243,7 +240,7 @@ pub(crate) fn convert_typed_dict_functional_to_class( value: &Expr, ) { let Some((class_name, args, keywords, base_class)) = - match_typed_dict_assign(checker, targets, value) else + match_typed_dict_assign(&checker.model, targets, value) else { return; }; 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 eb1291209f..69fa2875e4 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 @@ -244,10 +244,9 @@ pub(crate) fn mutable_dataclass_default(checker: &mut Checker, body: &[Stmt]) { } } -pub(crate) fn is_dataclass(checker: &Checker, decorator_list: &[Expr]) -> bool { +pub(crate) fn is_dataclass(model: &SemanticModel, decorator_list: &[Expr]) -> bool { decorator_list.iter().any(|decorator| { - checker - .model + 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/tryceratops/helpers.rs b/crates/ruff/src/rules/tryceratops/helpers.rs index be685f3e62..7e94ca4c9a 100644 --- a/crates/ruff/src/rules/tryceratops/helpers.rs +++ b/crates/ruff/src/rules/tryceratops/helpers.rs @@ -26,7 +26,7 @@ where { fn visit_expr(&mut self, expr: &'b Expr) { if let Expr::Call(ast::ExprCall { func, .. }) = expr { - if logging::is_logger_candidate(self.context, func) { + if logging::is_logger_candidate(func, self.context) { self.calls.push((expr, func)); } } diff --git a/crates/ruff_python_semantic/src/analyze/logging.rs b/crates/ruff_python_semantic/src/analyze/logging.rs index 1033cc07ad..d16ed0425d 100644 --- a/crates/ruff_python_semantic/src/analyze/logging.rs +++ b/crates/ruff_python_semantic/src/analyze/logging.rs @@ -16,7 +16,7 @@ use crate::model::SemanticModel; /// # This is detected to be a logger candidate /// bar.error() /// ``` -pub fn is_logger_candidate(model: &SemanticModel, func: &Expr) -> bool { +pub fn is_logger_candidate(func: &Expr, model: &SemanticModel) -> bool { if let Expr::Attribute(ast::ExprAttribute { value, .. }) = func { 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"] {