mirror of
https://github.com/astral-sh/ruff.git
synced 2025-12-15 21:45:30 +00:00
Use SemanticModel in lieu of Checker in more methods (#4568)
This commit is contained in:
parent
19c4b7bee6
commit
d70f899f71
29 changed files with 199 additions and 199 deletions
|
|
@ -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,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<String> {
|
||||
pub(crate) fn overloaded_name(model: &SemanticModel, definition: &Definition) -> Option<String> {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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<F>(
|
||||
checker: &Checker,
|
||||
model: &SemanticModel,
|
||||
annotation: &Expr,
|
||||
func: F,
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
|
|
@ -438,7 +439,7 @@ fn check_dynamically_typed<F>(
|
|||
) 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,
|
||||
|
|
|
|||
|
|
@ -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<Regex> = 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"]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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" {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<CallPath<'a>>,
|
||||
diagnostics: Vec<(DiagnosticKind, TextRange)>,
|
||||
}
|
||||
|
||||
impl<'a> ArgumentDefaultVisitor<'a> {
|
||||
fn new(model: &'a SemanticModel<'a>, extend_immutable_calls: Vec<CallPath<'a>>) -> 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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Diagnostic> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ContentType> {
|
||||
fn get_element_type(model: &SemanticModel, element: &Stmt) -> Option<ContentType> {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String> {
|
||||
fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option<String> {
|
||||
let all_literals = elts.iter().all(|e| {
|
||||
matches!(
|
||||
e,
|
||||
|
|
@ -77,7 +78,7 @@ fn elts_to_csv(elts: &[Expr], checker: &Checker) -> Option<String> {
|
|||
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<String> {
|
|||
/// ```
|
||||
///
|
||||
/// 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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<usize> {
|
||||
|
|
@ -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<String>,
|
||||
) -> 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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"] {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue