mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-25 13:36:47 +00:00
Introduce an Arguments AST node for function calls and class definitions (#6259)
## Summary This PR adds a new `Arguments` AST node, which we can use for function calls and class definitions. The `Arguments` node spans from the left (open) to right (close) parentheses inclusive. In the case of classes, the `Arguments` is an option, to differentiate between: ```python # None class C: ... # Some, with empty vectors class C(): ... ``` In this PR, we don't really leverage this change (except that a few rules get much simpler, since we don't need to lex to find the start and end ranges of the parentheses, e.g., `crates/ruff/src/rules/pyupgrade/rules/lru_cache_without_parameters.rs`, `crates/ruff/src/rules/pyupgrade/rules/unnecessary_class_parentheses.rs`). In future PRs, this will be especially helpful for the formatter, since we can track comments enclosed on the node itself. ## Test Plan `cargo test`
This commit is contained in:
parent
0d62ad2480
commit
981e64f82b
107 changed files with 24258 additions and 23835 deletions
|
|
@ -74,6 +74,9 @@ pub(crate) fn remove_unused_imports<'a>(
|
||||||
///
|
///
|
||||||
/// Supports the removal of parentheses when this is the only (kw)arg left.
|
/// Supports the removal of parentheses when this is the only (kw)arg left.
|
||||||
/// For this behavior, set `remove_parentheses` to `true`.
|
/// For this behavior, set `remove_parentheses` to `true`.
|
||||||
|
///
|
||||||
|
/// TODO(charlie): Migrate this signature to take [`Arguments`] rather than
|
||||||
|
/// separate args and keywords.
|
||||||
pub(crate) fn remove_argument(
|
pub(crate) fn remove_argument(
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
call_at: TextSize,
|
call_at: TextSize,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, ExprContext, Operator, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, ExprContext, Operator, Ranged};
|
||||||
use ruff_python_literal::cformat::{CFormatError, CFormatErrorType};
|
use ruff_python_literal::cformat::{CFormatError, CFormatErrorType};
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_diagnostics::Diagnostic;
|
||||||
|
|
@ -211,11 +211,14 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::MixedCaseVariableInClassScope) {
|
if checker.enabled(Rule::MixedCaseVariableInClassScope) {
|
||||||
if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) =
|
if let ScopeKind::Class(ast::StmtClassDef { arguments, .. }) =
|
||||||
&checker.semantic.scope().kind
|
&checker.semantic.scope().kind
|
||||||
{
|
{
|
||||||
pep8_naming::rules::mixed_case_variable_in_class_scope(
|
pep8_naming::rules::mixed_case_variable_in_class_scope(
|
||||||
checker, expr, id, bases,
|
checker,
|
||||||
|
expr,
|
||||||
|
id,
|
||||||
|
arguments.as_ref(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -323,8 +326,12 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||||
Expr::Call(
|
Expr::Call(
|
||||||
call @ ast::ExprCall {
|
call @ ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
|
|
|
||||||
|
|
@ -363,8 +363,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||||
Stmt::ClassDef(
|
Stmt::ClassDef(
|
||||||
class_def @ ast::StmtClassDef {
|
class_def @ ast::StmtClassDef {
|
||||||
name,
|
name,
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
type_params: _,
|
type_params: _,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
body,
|
body,
|
||||||
|
|
@ -376,20 +375,24 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::DjangoExcludeWithModelForm) {
|
if checker.enabled(Rule::DjangoExcludeWithModelForm) {
|
||||||
if let Some(diagnostic) =
|
if let Some(diagnostic) =
|
||||||
flake8_django::rules::exclude_with_model_form(checker, bases, body)
|
flake8_django::rules::exclude_with_model_form(checker, arguments.as_ref(), body)
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::DjangoAllWithModelForm) {
|
if checker.enabled(Rule::DjangoAllWithModelForm) {
|
||||||
if let Some(diagnostic) =
|
if let Some(diagnostic) =
|
||||||
flake8_django::rules::all_with_model_form(checker, bases, body)
|
flake8_django::rules::all_with_model_form(checker, arguments.as_ref(), body)
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::DjangoUnorderedBodyContentInModel) {
|
if checker.enabled(Rule::DjangoUnorderedBodyContentInModel) {
|
||||||
flake8_django::rules::unordered_body_content_in_model(checker, bases, body);
|
flake8_django::rules::unordered_body_content_in_model(
|
||||||
|
checker,
|
||||||
|
arguments.as_ref(),
|
||||||
|
body,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if !checker.is_stub {
|
if !checker.is_stub {
|
||||||
if checker.enabled(Rule::DjangoModelWithoutDunderStr) {
|
if checker.enabled(Rule::DjangoModelWithoutDunderStr) {
|
||||||
|
|
@ -425,7 +428,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||||
if checker.enabled(Rule::ErrorSuffixOnExceptionName) {
|
if checker.enabled(Rule::ErrorSuffixOnExceptionName) {
|
||||||
if let Some(diagnostic) = pep8_naming::rules::error_suffix_on_exception_name(
|
if let Some(diagnostic) = pep8_naming::rules::error_suffix_on_exception_name(
|
||||||
stmt,
|
stmt,
|
||||||
bases,
|
arguments.as_ref(),
|
||||||
name,
|
name,
|
||||||
&checker.settings.pep8_naming.ignore_names,
|
&checker.settings.pep8_naming.ignore_names,
|
||||||
) {
|
) {
|
||||||
|
|
@ -438,7 +441,11 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||||
Rule::EmptyMethodWithoutAbstractDecorator,
|
Rule::EmptyMethodWithoutAbstractDecorator,
|
||||||
]) {
|
]) {
|
||||||
flake8_bugbear::rules::abstract_base_class(
|
flake8_bugbear::rules::abstract_base_class(
|
||||||
checker, stmt, name, bases, keywords, body,
|
checker,
|
||||||
|
stmt,
|
||||||
|
name,
|
||||||
|
arguments.as_ref(),
|
||||||
|
body,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -478,7 +485,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||||
flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range());
|
flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range());
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::DuplicateBases) {
|
if checker.enabled(Rule::DuplicateBases) {
|
||||||
pylint::rules::duplicate_bases(checker, name, bases);
|
pylint::rules::duplicate_bases(checker, name, arguments.as_ref());
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::NoSlotsInStrSubclass) {
|
if checker.enabled(Rule::NoSlotsInStrSubclass) {
|
||||||
flake8_slots::rules::no_slots_in_str_subclass(checker, stmt, class_def);
|
flake8_slots::rules::no_slots_in_str_subclass(checker, stmt, class_def);
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ use std::path::Path;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::error;
|
use log::error;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, Comprehension, Constant, ElifElseClause, ExceptHandler, Expr, ExprContext,
|
self as ast, Arguments, Comprehension, Constant, ElifElseClause, ExceptHandler, Expr,
|
||||||
Keyword, Parameter, ParameterWithDefault, Parameters, Pattern, Ranged, Stmt, Suite, UnaryOp,
|
ExprContext, Keyword, Parameter, ParameterWithDefault, Parameters, Pattern, Ranged, Stmt,
|
||||||
|
Suite, UnaryOp,
|
||||||
};
|
};
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
|
|
@ -552,8 +553,7 @@ where
|
||||||
Stmt::ClassDef(
|
Stmt::ClassDef(
|
||||||
class_def @ ast::StmtClassDef {
|
class_def @ ast::StmtClassDef {
|
||||||
body,
|
body,
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
decorator_list,
|
decorator_list,
|
||||||
type_params,
|
type_params,
|
||||||
..
|
..
|
||||||
|
|
@ -568,11 +568,9 @@ where
|
||||||
for type_param in type_params {
|
for type_param in type_params {
|
||||||
self.visit_type_param(type_param);
|
self.visit_type_param(type_param);
|
||||||
}
|
}
|
||||||
for expr in bases {
|
|
||||||
self.visit_expr(expr);
|
if let Some(arguments) = arguments {
|
||||||
}
|
self.visit_arguments(arguments);
|
||||||
for keyword in keywords {
|
|
||||||
self.visit_keyword(keyword);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let definition = docstrings::extraction::extract_definition(
|
let definition = docstrings::extraction::extract_definition(
|
||||||
|
|
@ -837,8 +835,7 @@ where
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args: _,
|
arguments: _,
|
||||||
keywords: _,
|
|
||||||
range: _,
|
range: _,
|
||||||
}) => {
|
}) => {
|
||||||
if let Expr::Name(ast::ExprName { id, ctx, range: _ }) = func.as_ref() {
|
if let Expr::Name(ast::ExprName { id, ctx, range: _ }) = func.as_ref() {
|
||||||
|
|
@ -924,8 +921,12 @@ where
|
||||||
}
|
}
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) => {
|
}) => {
|
||||||
self.visit_expr(func);
|
self.visit_expr(func);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_ast::{Expr, Ranged};
|
use ruff_python_ast::{Arguments, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -60,7 +60,12 @@ pub(crate) fn variable_name_task_id(
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the value is not a call, we can't do anything.
|
// If the value is not a call, we can't do anything.
|
||||||
let Expr::Call(ast::ExprCall { func, keywords, .. }) = value else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { keywords, .. },
|
||||||
|
..
|
||||||
|
}) = value
|
||||||
|
else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -94,7 +94,12 @@ pub(crate) fn blind_except(
|
||||||
// If the exception is logged, don't flag an error.
|
// If the exception is logged, don't flag an error.
|
||||||
if body.iter().any(|stmt| {
|
if body.iter().any(|stmt| {
|
||||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
||||||
if let Expr::Call(ast::ExprCall { func, keywords, .. }) = value.as_ref() {
|
if let Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { keywords, .. },
|
||||||
|
..
|
||||||
|
}) = value.as_ref()
|
||||||
|
{
|
||||||
if logging::is_logger_candidate(
|
if logging::is_logger_candidate(
|
||||||
func,
|
func,
|
||||||
checker.semantic(),
|
checker.semantic(),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Keyword, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -139,14 +139,17 @@ pub(crate) fn abstract_base_class(
|
||||||
checker: &mut Checker,
|
checker: &mut Checker,
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
name: &str,
|
name: &str,
|
||||||
bases: &[Expr],
|
arguments: Option<&Arguments>,
|
||||||
keywords: &[Keyword],
|
|
||||||
body: &[Stmt],
|
body: &[Stmt],
|
||||||
) {
|
) {
|
||||||
if bases.len() + keywords.len() != 1 {
|
let Some(Arguments { args, keywords, .. }) = arguments else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if args.len() + keywords.len() != 1 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !is_abc_class(bases, keywords, checker.semantic()) {
|
if !is_abc_class(args, keywords, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, ExprContext, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Ranged, Stmt};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
|
|
@ -53,12 +53,15 @@ fn assertion_error(msg: Option<&Expr>) -> Stmt {
|
||||||
ctx: ExprContext::Load,
|
ctx: ExprContext::Load,
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
})),
|
})),
|
||||||
args: if let Some(msg) = msg {
|
arguments: Arguments {
|
||||||
vec![msg.clone()]
|
args: if let Some(msg) = msg {
|
||||||
} else {
|
vec![msg.clone()]
|
||||||
vec![]
|
} else {
|
||||||
|
vec![]
|
||||||
|
},
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
},
|
},
|
||||||
keywords: vec![],
|
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
}))),
|
}))),
|
||||||
cause: None,
|
cause: None,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged, WithItem};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged, WithItem};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -81,8 +81,12 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, items: &[WithItem])
|
||||||
for item in items {
|
for item in items {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) = &item.context_expr
|
}) = &item.context_expr
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Comprehension, Expr, ExprContext, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Comprehension, Expr, ExprContext, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -130,8 +130,12 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) => {
|
}) => {
|
||||||
match func.as_ref() {
|
match func.as_ref() {
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ pub(crate) fn re_sub_positional_args(checker: &mut Checker, call: &ast::ExprCall
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if call.args.len() > method.num_args() {
|
if call.arguments.args.len() > method.num_args() {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
ReSubPositionalArgs { method },
|
ReSubPositionalArgs { method },
|
||||||
call.range(),
|
call.range(),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Keyword, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -68,8 +68,7 @@ pub(crate) fn zip_without_explicit_strict(
|
||||||
fn is_infinite_iterator(arg: &Expr, semantic: &SemanticModel) -> bool {
|
fn is_infinite_iterator(arg: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
..
|
..
|
||||||
}) = &arg
|
}) = &arg
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_ast::Decorator;
|
use ruff_python_ast::{Arguments, Decorator};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_diagnostics::Diagnostic;
|
||||||
|
|
@ -78,8 +78,7 @@ pub(crate) fn builtin_attribute_shadowing(
|
||||||
// Ignore shadowing within `TypedDict` definitions, since these are only accessible through
|
// Ignore shadowing within `TypedDict` definitions, since these are only accessible through
|
||||||
// subscripting and not through attribute access.
|
// subscripting and not through attribute access.
|
||||||
if class_def
|
if class_def
|
||||||
.bases
|
.bases()
|
||||||
.iter()
|
|
||||||
.any(|base| checker.semantic().match_typing_expr(base, "TypedDict"))
|
.any(|base| checker.semantic().match_typing_expr(base, "TypedDict"))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -133,15 +132,18 @@ fn is_standard_library_override(
|
||||||
class_def: &ast::StmtClassDef,
|
class_def: &ast::StmtClassDef,
|
||||||
model: &SemanticModel,
|
model: &SemanticModel,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
let Some(Arguments { args: bases, .. }) = class_def.arguments.as_ref() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
match name {
|
match name {
|
||||||
// Ex) `Event#set`
|
// Ex) `Event#set`
|
||||||
"set" => class_def.bases.iter().any(|base| {
|
"set" => bases.iter().any(|base| {
|
||||||
model
|
model
|
||||||
.resolve_call_path(base)
|
.resolve_call_path(base)
|
||||||
.is_some_and(|call_path| matches!(call_path.as_slice(), ["threading", "Event"]))
|
.is_some_and(|call_path| matches!(call_path.as_slice(), ["threading", "Event"]))
|
||||||
}),
|
}),
|
||||||
// Ex) `Filter#filter`
|
// Ex) `Filter#filter`
|
||||||
"filter" => class_def.bases.iter().any(|base| {
|
"filter" => bases.iter().any(|base| {
|
||||||
model
|
model
|
||||||
.resolve_call_path(base)
|
.resolve_call_path(base)
|
||||||
.is_some_and(|call_path| matches!(call_path.as_slice(), ["logging", "Filter"]))
|
.is_some_and(|call_path| matches!(call_path.as_slice(), ["logging", "Filter"]))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Keyword, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -88,7 +88,9 @@ pub(crate) fn unnecessary_double_cast_or_process(
|
||||||
};
|
};
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
keywords: inner_kw,
|
arguments: Arguments {
|
||||||
|
keywords: inner_kw, ..
|
||||||
|
},
|
||||||
..
|
..
|
||||||
}) = arg
|
}) = arg
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Expr, ExprContext, Parameters, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Parameters, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{AutofixKind, Violation};
|
use ruff_diagnostics::{AutofixKind, Violation};
|
||||||
use ruff_diagnostics::{Diagnostic, Fix};
|
use ruff_diagnostics::{Diagnostic, Fix};
|
||||||
|
|
@ -111,7 +111,12 @@ pub(crate) fn unnecessary_map(
|
||||||
}
|
}
|
||||||
ObjectType::List | ObjectType::Set => {
|
ObjectType::List | ObjectType::Set => {
|
||||||
// Only flag, e.g., `list(map(lambda x: x + 1, iterable))`.
|
// Only flag, e.g., `list(map(lambda x: x + 1, iterable))`.
|
||||||
let [Expr::Call(ast::ExprCall { func, args, .. })] = args else {
|
let [Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
})] = args
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -137,7 +142,12 @@ pub(crate) fn unnecessary_map(
|
||||||
}
|
}
|
||||||
ObjectType::Dict => {
|
ObjectType::Dict => {
|
||||||
// Only flag, e.g., `dict(map(lambda v: (v, v ** 2), values))`.
|
// Only flag, e.g., `dict(map(lambda v: (v, v ** 2), values))`.
|
||||||
let [Expr::Call(ast::ExprCall { func, args, .. })] = args else {
|
let [Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
})] = args
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
|
|
@ -59,7 +59,11 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Expr::Call(ast::ExprCall { keywords, .. }) = grandparent {
|
if let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { keywords, .. },
|
||||||
|
..
|
||||||
|
}) = grandparent
|
||||||
|
{
|
||||||
if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = parent {
|
if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = parent {
|
||||||
let attr = attr.as_str();
|
let attr = attr.as_str();
|
||||||
// Ex) `datetime.strptime(...).astimezone()`
|
// Ex) `datetime.strptime(...).astimezone()`
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -49,15 +49,18 @@ impl Violation for DjangoAllWithModelForm {
|
||||||
/// DJ007
|
/// DJ007
|
||||||
pub(crate) fn all_with_model_form(
|
pub(crate) fn all_with_model_form(
|
||||||
checker: &Checker,
|
checker: &Checker,
|
||||||
bases: &[Expr],
|
arguments: Option<&Arguments>,
|
||||||
body: &[Stmt],
|
body: &[Stmt],
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
if !bases
|
if !arguments.is_some_and(|arguments| {
|
||||||
.iter()
|
arguments
|
||||||
.any(|base| is_model_form(base, checker.semantic()))
|
.args
|
||||||
{
|
.iter()
|
||||||
|
.any(|base| is_model_form(base, checker.semantic()))
|
||||||
|
}) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
for element in body {
|
for element in body {
|
||||||
let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else {
|
let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -47,15 +47,18 @@ impl Violation for DjangoExcludeWithModelForm {
|
||||||
/// DJ006
|
/// DJ006
|
||||||
pub(crate) fn exclude_with_model_form(
|
pub(crate) fn exclude_with_model_form(
|
||||||
checker: &Checker,
|
checker: &Checker,
|
||||||
bases: &[Expr],
|
arguments: Option<&Arguments>,
|
||||||
body: &[Stmt],
|
body: &[Stmt],
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
if !bases
|
if !arguments.is_some_and(|arguments| {
|
||||||
.iter()
|
arguments
|
||||||
.any(|base| is_model_form(base, checker.semantic()))
|
.args
|
||||||
{
|
.iter()
|
||||||
|
.any(|base| is_model_form(base, checker.semantic()))
|
||||||
|
}) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
for element in body {
|
for element in body {
|
||||||
let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else {
|
let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -54,10 +54,13 @@ impl Violation for DjangoModelWithoutDunderStr {
|
||||||
pub(crate) fn model_without_dunder_str(
|
pub(crate) fn model_without_dunder_str(
|
||||||
checker: &mut Checker,
|
checker: &mut Checker,
|
||||||
ast::StmtClassDef {
|
ast::StmtClassDef {
|
||||||
name, bases, body, ..
|
name,
|
||||||
|
arguments,
|
||||||
|
body,
|
||||||
|
..
|
||||||
}: &ast::StmtClassDef,
|
}: &ast::StmtClassDef,
|
||||||
) {
|
) {
|
||||||
if !is_non_abstract_model(bases, body, checker.semantic()) {
|
if !is_non_abstract_model(arguments.as_ref(), body, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if has_dunder_method(body) {
|
if has_dunder_method(body) {
|
||||||
|
|
@ -80,16 +83,20 @@ fn has_dunder_method(body: &[Stmt]) -> bool {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_non_abstract_model(bases: &[Expr], body: &[Stmt], semantic: &SemanticModel) -> bool {
|
fn is_non_abstract_model(
|
||||||
for base in bases {
|
arguments: Option<&Arguments>,
|
||||||
if is_model_abstract(body) {
|
body: &[Stmt],
|
||||||
continue;
|
semantic: &SemanticModel,
|
||||||
}
|
) -> bool {
|
||||||
if helpers::is_model(base, semantic) {
|
let Some(Arguments { args: bases, .. }) = arguments else {
|
||||||
return true;
|
return false;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
if is_model_abstract(body) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
false
|
|
||||||
|
bases.iter().any(|base| helpers::is_model(base, semantic))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if class is abstract, in terms of Django model inheritance.
|
/// Check if class is abstract, in terms of Django model inheritance.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -69,7 +69,12 @@ pub(crate) fn nullable_model_string_field(checker: &mut Checker, body: &[Stmt])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a str> {
|
fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a str> {
|
||||||
let Expr::Call(ast::ExprCall { func, keywords, .. }) = value else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { keywords, .. },
|
||||||
|
..
|
||||||
|
}) = value
|
||||||
|
else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -143,13 +143,15 @@ fn get_element_type(element: &Stmt, semantic: &SemanticModel) -> Option<ContentT
|
||||||
/// DJ012
|
/// DJ012
|
||||||
pub(crate) fn unordered_body_content_in_model(
|
pub(crate) fn unordered_body_content_in_model(
|
||||||
checker: &mut Checker,
|
checker: &mut Checker,
|
||||||
bases: &[Expr],
|
arguments: Option<&Arguments>,
|
||||||
body: &[Stmt],
|
body: &[Stmt],
|
||||||
) {
|
) {
|
||||||
if !bases
|
if !arguments.is_some_and(|arguments| {
|
||||||
.iter()
|
arguments
|
||||||
.any(|base| helpers::is_model(base, checker.semantic()))
|
.args
|
||||||
{
|
.iter()
|
||||||
|
.any(|base| helpers::is_model(base, checker.semantic()))
|
||||||
|
}) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, ExprContext, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, ExprContext, Ranged, Stmt};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||||
|
|
@ -174,7 +174,11 @@ impl Violation for DotFormatInException {
|
||||||
|
|
||||||
/// EM101, EM102, EM103
|
/// EM101, EM102, EM103
|
||||||
pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) {
|
pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) {
|
||||||
if let Expr::Call(ast::ExprCall { args, .. }) = exc {
|
if let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = exc
|
||||||
|
{
|
||||||
if let Some(first) = args.first() {
|
if let Some(first) = args.first() {
|
||||||
match first {
|
match first {
|
||||||
// Check for string literals.
|
// Check for string literals.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Keyword, Operator, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Operator, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||||
use ruff_python_ast::helpers::{find_keyword, CallArguments};
|
use ruff_python_ast::helpers::{find_keyword, CallArguments};
|
||||||
|
|
@ -108,7 +108,11 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Call(ast::ExprCall { func, keywords, .. }) => {
|
Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { keywords, .. },
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
if checker
|
if checker
|
||||||
.semantic()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use itertools::Either::{Left, Right};
|
||||||
|
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, BoolOp, Expr, ExprContext, Identifier, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, BoolOp, Expr, ExprContext, Identifier, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::AlwaysAutofixableViolation;
|
use ruff_diagnostics::AlwaysAutofixableViolation;
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||||
|
|
@ -73,8 +73,12 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
|
||||||
for (index, call) in values.iter().enumerate() {
|
for (index, call) in values.iter().enumerate() {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) = &call
|
}) = &call
|
||||||
else {
|
else {
|
||||||
|
|
@ -118,8 +122,12 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
|
||||||
.map(|expr| {
|
.map(|expr| {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func: _,
|
func: _,
|
||||||
args,
|
arguments:
|
||||||
keywords: _,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords: _,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) = expr
|
}) = expr
|
||||||
else {
|
else {
|
||||||
|
|
@ -161,8 +169,11 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
|
||||||
});
|
});
|
||||||
let node3 = Expr::Call(ast::ExprCall {
|
let node3 = Expr::Call(ast::ExprCall {
|
||||||
func: Box::new(node2),
|
func: Box::new(node2),
|
||||||
args: vec![node],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![node],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
});
|
});
|
||||||
let call = node3;
|
let call = node3;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged, Stmt};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_diagnostics::Diagnostic;
|
||||||
|
|
@ -54,7 +54,11 @@ impl Violation for NonUniqueEnums {
|
||||||
|
|
||||||
/// PIE796
|
/// PIE796
|
||||||
pub(crate) fn non_unique_enums(checker: &mut Checker, parent: &Stmt, body: &[Stmt]) {
|
pub(crate) fn non_unique_enums(checker: &mut Checker, parent: &Stmt, body: &[Stmt]) {
|
||||||
let Stmt::ClassDef(ast::StmtClassDef { bases, .. }) = parent else {
|
let Stmt::ClassDef(ast::StmtClassDef {
|
||||||
|
arguments: Some(Arguments { args: bases, .. }),
|
||||||
|
..
|
||||||
|
}) = parent
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Decorator, Expr, Parameters, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Decorator, Expr, Parameters, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -186,7 +186,7 @@ pub(crate) fn non_self_return_type(
|
||||||
match name {
|
match name {
|
||||||
"__iter__" => {
|
"__iter__" => {
|
||||||
if is_iterable(returns, checker.semantic())
|
if is_iterable(returns, checker.semantic())
|
||||||
&& is_iterator(&class_def.bases, checker.semantic())
|
&& is_iterator(class_def.arguments.as_ref(), checker.semantic())
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NonSelfReturnType {
|
NonSelfReturnType {
|
||||||
|
|
@ -199,7 +199,7 @@ pub(crate) fn non_self_return_type(
|
||||||
}
|
}
|
||||||
"__aiter__" => {
|
"__aiter__" => {
|
||||||
if is_async_iterable(returns, checker.semantic())
|
if is_async_iterable(returns, checker.semantic())
|
||||||
&& is_async_iterator(&class_def.bases, checker.semantic())
|
&& is_async_iterator(class_def.arguments.as_ref(), checker.semantic())
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NonSelfReturnType {
|
NonSelfReturnType {
|
||||||
|
|
@ -248,7 +248,10 @@ fn is_self(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the given class extends `collections.abc.Iterator`.
|
/// Return `true` if the given class extends `collections.abc.Iterator`.
|
||||||
fn is_iterator(bases: &[Expr], semantic: &SemanticModel) -> bool {
|
fn is_iterator(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool {
|
||||||
|
let Some(Arguments { args: bases, .. }) = arguments else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
bases.iter().any(|expr| {
|
bases.iter().any(|expr| {
|
||||||
semantic
|
semantic
|
||||||
.resolve_call_path(map_subscript(expr))
|
.resolve_call_path(map_subscript(expr))
|
||||||
|
|
@ -275,7 +278,10 @@ fn is_iterable(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the given class extends `collections.abc.AsyncIterator`.
|
/// Return `true` if the given class extends `collections.abc.AsyncIterator`.
|
||||||
fn is_async_iterator(bases: &[Expr], semantic: &SemanticModel) -> bool {
|
fn is_async_iterator(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool {
|
||||||
|
let Some(Arguments { args: bases, .. }) = arguments else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
bases.iter().any(|expr| {
|
bases.iter().any(|expr| {
|
||||||
semantic
|
semantic
|
||||||
.resolve_call_path(map_subscript(expr))
|
.resolve_call_path(map_subscript(expr))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, Constant, Expr, Operator, ParameterWithDefault, Parameters, Ranged, Stmt, UnaryOp,
|
self as ast, Arguments, Constant, Expr, Operator, ParameterWithDefault, Parameters, Ranged,
|
||||||
|
Stmt, UnaryOp,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix, Violation};
|
||||||
|
|
@ -368,7 +369,10 @@ fn is_final_assignment(annotation: &Expr, value: &Expr, semantic: &SemanticModel
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the a class is an enum, based on its base classes.
|
/// Returns `true` if the a class is an enum, based on its base classes.
|
||||||
fn is_enum(bases: &[Expr], semantic: &SemanticModel) -> bool {
|
fn is_enum(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool {
|
||||||
|
let Some(Arguments { args: bases, .. }) = arguments else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
return bases.iter().any(|expr| {
|
return bases.iter().any(|expr| {
|
||||||
semantic.resolve_call_path(expr).is_some_and(|call_path| {
|
semantic.resolve_call_path(expr).is_some_and(|call_path| {
|
||||||
matches!(
|
matches!(
|
||||||
|
|
@ -565,8 +569,8 @@ pub(crate) fn unannotated_assignment_in_stub(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) = checker.semantic().scope().kind {
|
if let ScopeKind::Class(ast::StmtClassDef { arguments, .. }) = checker.semantic().scope().kind {
|
||||||
if is_enum(bases, checker.semantic()) {
|
if is_enum(arguments.as_ref(), checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
|
||||||
use ruff_python_semantic::Scope;
|
use ruff_python_semantic::Scope;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
@ -216,8 +216,12 @@ pub(crate) fn unused_private_protocol(
|
||||||
let Some(source) = binding.source else {
|
let Some(source) = binding.source else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Stmt::ClassDef(ast::StmtClassDef { name, bases, .. }) =
|
|
||||||
checker.semantic().stmts[source]
|
let Stmt::ClassDef(ast::StmtClassDef {
|
||||||
|
name,
|
||||||
|
arguments: Some(Arguments { args: bases, .. }),
|
||||||
|
..
|
||||||
|
}) = checker.semantic().stmts[source]
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
@ -304,8 +308,11 @@ pub(crate) fn unused_private_typed_dict(
|
||||||
let Some(source) = binding.source else {
|
let Some(source) = binding.source else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Stmt::ClassDef(ast::StmtClassDef { name, bases, .. }) =
|
let Stmt::ClassDef(ast::StmtClassDef {
|
||||||
checker.semantic().stmts[source]
|
name,
|
||||||
|
arguments: Some(Arguments { args: bases, .. }),
|
||||||
|
..
|
||||||
|
}) = checker.semantic().stmts[source]
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ruff_python_ast::Decorator;
|
|
||||||
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault, Parameters, Ranged, Stmt};
|
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault, Parameters, Ranged, Stmt};
|
||||||
|
use ruff_python_ast::{Arguments, Decorator};
|
||||||
use ruff_text_size::{TextLen, TextRange};
|
use ruff_text_size::{TextLen, TextRange};
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
|
||||||
|
|
@ -476,8 +476,12 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &D
|
||||||
match &decorator.expression {
|
match &decorator.expression {
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) => {
|
}) => {
|
||||||
if checker.enabled(Rule::PytestFixtureIncorrectParenthesesStyle) {
|
if checker.enabled(Rule::PytestFixtureIncorrectParenthesesStyle) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Decorator, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Decorator, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -106,8 +106,12 @@ fn check_mark_parentheses(checker: &mut Checker, decorator: &Decorator, call_pat
|
||||||
match &decorator.expression {
|
match &decorator.expression {
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) => {
|
}) => {
|
||||||
if !checker.settings.flake8_pytest_style.mark_parentheses
|
if !checker.settings.flake8_pytest_style.mark_parentheses
|
||||||
|
|
@ -134,7 +138,11 @@ fn check_useless_usefixtures(checker: &mut Checker, decorator: &Decorator, call_
|
||||||
|
|
||||||
let mut has_parameters = false;
|
let mut has_parameters = false;
|
||||||
|
|
||||||
if let Expr::Call(ast::ExprCall { args, keywords, .. }) = &decorator.expression {
|
if let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, keywords, .. },
|
||||||
|
..
|
||||||
|
}) = &decorator.expression
|
||||||
|
{
|
||||||
if !args.is_empty() || !keywords.is_empty() {
|
if !args.is_empty() || !keywords.is_empty() {
|
||||||
has_parameters = true;
|
has_parameters = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Decorator, Expr, ExprContext, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Decorator, Expr, ExprContext, Ranged};
|
||||||
use ruff_python_parser::{lexer, Mode, Tok};
|
use ruff_python_parser::{lexer, Mode, Tok};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
|
|
@ -414,7 +414,11 @@ fn handle_value_rows(
|
||||||
pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Decorator]) {
|
pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Decorator]) {
|
||||||
for decorator in decorators {
|
for decorator in decorators {
|
||||||
if is_pytest_parametrize(decorator, checker.semantic()) {
|
if is_pytest_parametrize(decorator, checker.semantic()) {
|
||||||
if let Expr::Call(ast::ExprCall { args, .. }) = &decorator.expression {
|
if let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = &decorator.expression
|
||||||
|
{
|
||||||
if checker.enabled(Rule::PytestParametrizeNamesWrongType) {
|
if checker.enabled(Rule::PytestParametrizeNamesWrongType) {
|
||||||
if let Some(names) = args.get(0) {
|
if let Some(names) = args.get(0) {
|
||||||
check_names(checker, decorator, names);
|
check_names(checker, decorator, names);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, CmpOp, Constant, Expr, ExprContext, Identifier, Keyword, Stmt, UnaryOp,
|
self as ast, Arguments, CmpOp, Constant, Expr, ExprContext, Identifier, Keyword, Stmt, UnaryOp,
|
||||||
};
|
};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
@ -355,8 +355,11 @@ impl UnittestAssert {
|
||||||
};
|
};
|
||||||
let node1 = ast::ExprCall {
|
let node1 = ast::ExprCall {
|
||||||
func: Box::new(node.into()),
|
func: Box::new(node.into()),
|
||||||
args: vec![(**obj).clone(), (**cls).clone()],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![(**obj).clone(), (**cls).clone()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
let isinstance = node1.into();
|
let isinstance = node1.into();
|
||||||
|
|
@ -396,8 +399,11 @@ impl UnittestAssert {
|
||||||
};
|
};
|
||||||
let node2 = ast::ExprCall {
|
let node2 = ast::ExprCall {
|
||||||
func: Box::new(node1.into()),
|
func: Box::new(node1.into()),
|
||||||
args: vec![(**regex).clone(), (**text).clone()],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![(**regex).clone(), (**text).clone()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
let re_search = node2.into();
|
let re_search = node2.into();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged};
|
||||||
use ruff_python_parser::{lexer, Mode, Tok};
|
use ruff_python_parser::{lexer, Mode, Tok};
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
|
|
@ -47,31 +47,37 @@ impl AlwaysAutofixableViolation for UnnecessaryParenOnRaiseException {
|
||||||
|
|
||||||
/// RSE102
|
/// RSE102
|
||||||
pub(crate) fn unnecessary_paren_on_raise_exception(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn unnecessary_paren_on_raise_exception(checker: &mut Checker, expr: &Expr) {
|
||||||
if let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) = expr
|
}) = expr
|
||||||
{
|
else {
|
||||||
if args.is_empty() && keywords.is_empty() {
|
return;
|
||||||
// `raise func()` still requires parentheses; only `raise Class()` does not.
|
};
|
||||||
if checker
|
|
||||||
.semantic()
|
|
||||||
.lookup_attribute(func)
|
|
||||||
.is_some_and(|id| checker.semantic().binding(id).kind.is_function_definition())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let range = match_parens(func.end(), checker.locator())
|
if args.is_empty() && keywords.is_empty() {
|
||||||
.expect("Expected call to include parentheses");
|
// `raise func()` still requires parentheses; only `raise Class()` does not.
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryParenOnRaiseException, range);
|
if checker
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
.semantic()
|
||||||
diagnostic.set_fix(Fix::automatic(Edit::deletion(func.end(), range.end())));
|
.lookup_attribute(func)
|
||||||
}
|
.is_some_and(|id| checker.semantic().binding(id).kind.is_function_definition())
|
||||||
checker.diagnostics.push(diagnostic);
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let range = match_parens(func.end(), checker.locator())
|
||||||
|
.expect("Expected call to include parentheses");
|
||||||
|
let mut diagnostic = Diagnostic::new(UnnecessaryParenOnRaiseException, range);
|
||||||
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
|
diagnostic.set_fix(Fix::automatic(Edit::deletion(func.end(), range.end())));
|
||||||
|
}
|
||||||
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::iter;
|
||||||
|
|
||||||
use itertools::Either::{Left, Right};
|
use itertools::Either::{Left, Right};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_python_ast::{self as ast, BoolOp, CmpOp, Expr, ExprContext, Ranged, UnaryOp};
|
use ruff_python_ast::{self as ast, Arguments, BoolOp, CmpOp, Expr, ExprContext, Ranged, UnaryOp};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
|
|
@ -315,8 +315,12 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
|
||||||
// Verify that this is an `isinstance` call.
|
// Verify that this is an `isinstance` call.
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) = &call
|
}) = &call
|
||||||
else {
|
else {
|
||||||
|
|
@ -351,7 +355,11 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
|
||||||
if indices.len() > 1 {
|
if indices.len() > 1 {
|
||||||
// Grab the target used in each duplicate `isinstance` call (e.g., `obj` in
|
// Grab the target used in each duplicate `isinstance` call (e.g., `obj` in
|
||||||
// `isinstance(obj, int)`).
|
// `isinstance(obj, int)`).
|
||||||
let target = if let Expr::Call(ast::ExprCall { args, .. }) = &values[indices[0]] {
|
let target = if let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = &values[indices[0]]
|
||||||
|
{
|
||||||
args.get(0).expect("`isinstance` should have two arguments")
|
args.get(0).expect("`isinstance` should have two arguments")
|
||||||
} else {
|
} else {
|
||||||
unreachable!("Indices should only contain `isinstance` calls")
|
unreachable!("Indices should only contain `isinstance` calls")
|
||||||
|
|
@ -374,7 +382,11 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|index| &values[*index])
|
.map(|index| &values[*index])
|
||||||
.map(|expr| {
|
.map(|expr| {
|
||||||
let Expr::Call(ast::ExprCall { args, .. }) = expr else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = expr
|
||||||
|
else {
|
||||||
unreachable!("Indices should only contain `isinstance` calls")
|
unreachable!("Indices should only contain `isinstance` calls")
|
||||||
};
|
};
|
||||||
args.get(1).expect("`isinstance` should have two arguments")
|
args.get(1).expect("`isinstance` should have two arguments")
|
||||||
|
|
@ -405,8 +417,11 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
|
||||||
};
|
};
|
||||||
let node2 = ast::ExprCall {
|
let node2 = ast::ExprCall {
|
||||||
func: Box::new(node1.into()),
|
func: Box::new(node1.into()),
|
||||||
args: vec![target.clone(), node.into()],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![target.clone(), node.into()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
let call = node2.into();
|
let call = node2.into();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Ranged};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, AutofixKind, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||||
|
|
@ -103,7 +103,12 @@ pub(crate) fn use_capital_environment_variables(checker: &mut Checker, expr: &Ex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ex) `os.environ.get('foo')`, `os.getenv('foo')`
|
// Ex) `os.environ.get('foo')`, `os.getenv('foo')`
|
||||||
let Expr::Call(ast::ExprCall { func, args, .. }) = expr else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = expr
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(arg) = args.get(0) else {
|
let Some(arg) = args.get(0) else {
|
||||||
|
|
@ -200,8 +205,7 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
|
||||||
pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
range: _,
|
range: _,
|
||||||
}) = expr
|
}) = expr
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use log::error;
|
use log::error;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, CmpOp, Constant, ElifElseClause, Expr, ExprContext, Identifier, Ranged, Stmt,
|
self as ast, Arguments, CmpOp, Constant, ElifElseClause, Expr, ExprContext, Identifier, Ranged,
|
||||||
StmtIf,
|
Stmt,
|
||||||
};
|
};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
@ -314,8 +314,8 @@ fn find_last_nested_if(body: &[Stmt]) -> Option<(&Expr, &Stmt)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the body, the range of the `if` or `elif` and whether the range is for an `if` or `elif`
|
/// Returns the body, the range of the `if` or `elif` and whether the range is for an `if` or `elif`
|
||||||
fn nested_if_body(stmt_if: &StmtIf) -> Option<(&[Stmt], TextRange, bool)> {
|
fn nested_if_body(stmt_if: &ast::StmtIf) -> Option<(&[Stmt], TextRange, bool)> {
|
||||||
let StmtIf {
|
let ast::StmtIf {
|
||||||
test,
|
test,
|
||||||
body,
|
body,
|
||||||
elif_else_clauses,
|
elif_else_clauses,
|
||||||
|
|
@ -361,7 +361,11 @@ fn nested_if_body(stmt_if: &StmtIf) -> Option<(&[Stmt], TextRange, bool)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SIM102
|
/// SIM102
|
||||||
pub(crate) fn nested_if_statements(checker: &mut Checker, stmt_if: &StmtIf, parent: Option<&Stmt>) {
|
pub(crate) fn nested_if_statements(
|
||||||
|
checker: &mut Checker,
|
||||||
|
stmt_if: &ast::StmtIf,
|
||||||
|
parent: Option<&Stmt>,
|
||||||
|
) {
|
||||||
let Some((body, range, is_elif)) = nested_if_body(stmt_if) else {
|
let Some((body, range, is_elif)) = nested_if_body(stmt_if) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
@ -538,8 +542,11 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt: &Stmt) {
|
||||||
};
|
};
|
||||||
let node1 = ast::ExprCall {
|
let node1 = ast::ExprCall {
|
||||||
func: Box::new(node.into()),
|
func: Box::new(node.into()),
|
||||||
args: vec![if_test.clone()],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![if_test.clone()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
let node2 = ast::StmtReturn {
|
let node2 = ast::StmtReturn {
|
||||||
|
|
@ -692,7 +699,7 @@ fn body_range(branch: &IfElifBranch, locator: &Locator) -> TextRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SIM114
|
/// SIM114
|
||||||
pub(crate) fn if_with_same_arms(checker: &mut Checker, locator: &Locator, stmt_if: &StmtIf) {
|
pub(crate) fn if_with_same_arms(checker: &mut Checker, locator: &Locator, stmt_if: &ast::StmtIf) {
|
||||||
let mut branches_iter = if_elif_branches(stmt_if).peekable();
|
let mut branches_iter = if_elif_branches(stmt_if).peekable();
|
||||||
while let Some(current_branch) = branches_iter.next() {
|
while let Some(current_branch) = branches_iter.next() {
|
||||||
let Some(following_branch) = branches_iter.peek() else {
|
let Some(following_branch) = branches_iter.peek() else {
|
||||||
|
|
@ -731,12 +738,12 @@ pub(crate) fn if_with_same_arms(checker: &mut Checker, locator: &Locator, stmt_i
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SIM116
|
/// SIM116
|
||||||
pub(crate) fn manual_dict_lookup(checker: &mut Checker, stmt_if: &StmtIf) {
|
pub(crate) fn manual_dict_lookup(checker: &mut Checker, stmt_if: &ast::StmtIf) {
|
||||||
// Throughout this rule:
|
// Throughout this rule:
|
||||||
// * Each if or elif statement's test must consist of a constant equality check with the same variable.
|
// * Each if or elif statement's test must consist of a constant equality check with the same variable.
|
||||||
// * Each if or elif statement's body must consist of a single `return`.
|
// * Each if or elif statement's body must consist of a single `return`.
|
||||||
// * The else clause must be empty, or a single `return`.
|
// * The else clause must be empty, or a single `return`.
|
||||||
let StmtIf {
|
let ast::StmtIf {
|
||||||
body,
|
body,
|
||||||
test,
|
test,
|
||||||
elif_else_clauses,
|
elif_else_clauses,
|
||||||
|
|
@ -842,8 +849,8 @@ pub(crate) fn manual_dict_lookup(checker: &mut Checker, stmt_if: &StmtIf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SIM401
|
/// SIM401
|
||||||
pub(crate) fn use_dict_get_with_default(checker: &mut Checker, stmt_if: &StmtIf) {
|
pub(crate) fn use_dict_get_with_default(checker: &mut Checker, stmt_if: &ast::StmtIf) {
|
||||||
let StmtIf {
|
let ast::StmtIf {
|
||||||
test,
|
test,
|
||||||
body,
|
body,
|
||||||
elif_else_clauses,
|
elif_else_clauses,
|
||||||
|
|
@ -949,8 +956,11 @@ pub(crate) fn use_dict_get_with_default(checker: &mut Checker, stmt_if: &StmtIf)
|
||||||
};
|
};
|
||||||
let node3 = ast::ExprCall {
|
let node3 = ast::ExprCall {
|
||||||
func: Box::new(node2.into()),
|
func: Box::new(node2.into()),
|
||||||
args: vec![node1, node],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![node1, node],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
let node4 = expected_var.clone();
|
let node4 = expected_var.clone();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, ExprContext, Ranged, UnaryOp};
|
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Ranged, UnaryOp};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, AutofixKind, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||||
|
|
@ -166,8 +166,11 @@ pub(crate) fn explicit_true_false_in_ifexpr(
|
||||||
};
|
};
|
||||||
let node1 = ast::ExprCall {
|
let node1 = ast::ExprCall {
|
||||||
func: Box::new(node.into()),
|
func: Box::new(node.into()),
|
||||||
args: vec![test.clone()],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![test.clone()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, CmpOp, Expr, ExprContext, Ranged, Stmt, UnaryOp};
|
use ruff_python_ast::{self as ast, Arguments, CmpOp, Expr, ExprContext, Ranged, Stmt, UnaryOp};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
|
|
@ -286,8 +286,11 @@ pub(crate) fn double_negation(checker: &mut Checker, expr: &Expr, op: UnaryOp, o
|
||||||
};
|
};
|
||||||
let node1 = ast::ExprCall {
|
let node1 = ast::ExprCall {
|
||||||
func: Box::new(node.into()),
|
func: Box::new(node.into()),
|
||||||
args: vec![*operand.clone()],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![*operand.clone()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ruff_python_ast::{self as ast, CmpOp, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, CmpOp, Expr, Ranged};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
use ruff_diagnostics::Edit;
|
||||||
|
|
@ -71,8 +71,7 @@ fn key_in_dict(
|
||||||
) {
|
) {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
range: _,
|
range: _,
|
||||||
}) = &right
|
}) = &right
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, CmpOp, Comprehension, Constant, Expr, ExprContext, Ranged, Stmt, UnaryOp,
|
self as ast, Arguments, CmpOp, Comprehension, Constant, Expr, ExprContext, Ranged, Stmt,
|
||||||
|
UnaryOp,
|
||||||
};
|
};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
|
|
@ -394,8 +395,11 @@ fn return_stmt(id: &str, test: &Expr, target: &Expr, iter: &Expr, generator: Gen
|
||||||
};
|
};
|
||||||
let node2 = ast::ExprCall {
|
let node2 = ast::ExprCall {
|
||||||
func: Box::new(node1.into()),
|
func: Box::new(node1.into()),
|
||||||
args: vec![node.into()],
|
arguments: Arguments {
|
||||||
keywords: vec![],
|
args: vec![node.into()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
let node3 = ast::StmtReturn {
|
let node3 = ast::StmtReturn {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_ast::{Expr, StmtClassDef};
|
use ruff_python_ast::{Arguments, Expr, StmtClassDef};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -63,7 +63,11 @@ pub(crate) fn no_slots_in_namedtuple_subclass(
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
class: &StmtClassDef,
|
class: &StmtClassDef,
|
||||||
) {
|
) {
|
||||||
if class.bases.iter().any(|base| {
|
let Some(Arguments { args: bases, .. }) = class.arguments.as_ref() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if bases.iter().any(|base| {
|
||||||
let Expr::Call(ast::ExprCall { func, .. }) = base else {
|
let Expr::Call(ast::ExprCall { func, .. }) = base else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{Expr, Stmt, StmtClassDef};
|
use ruff_python_ast::{Arguments, Expr, Stmt, StmtClassDef};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -51,7 +51,11 @@ impl Violation for NoSlotsInStrSubclass {
|
||||||
|
|
||||||
/// SLOT000
|
/// SLOT000
|
||||||
pub(crate) fn no_slots_in_str_subclass(checker: &mut Checker, stmt: &Stmt, class: &StmtClassDef) {
|
pub(crate) fn no_slots_in_str_subclass(checker: &mut Checker, stmt: &Stmt, class: &StmtClassDef) {
|
||||||
if is_str_subclass(&class.bases, checker.semantic()) {
|
let Some(Arguments { args: bases, .. }) = class.arguments.as_ref() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_str_subclass(bases, checker.semantic()) {
|
||||||
if !has_slots(&class.body) {
|
if !has_slots(&class.body) {
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{Stmt, StmtClassDef};
|
use ruff_python_ast::{Arguments, Stmt, StmtClassDef};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -51,7 +51,11 @@ impl Violation for NoSlotsInTupleSubclass {
|
||||||
|
|
||||||
/// SLOT001
|
/// SLOT001
|
||||||
pub(crate) fn no_slots_in_tuple_subclass(checker: &mut Checker, stmt: &Stmt, class: &StmtClassDef) {
|
pub(crate) fn no_slots_in_tuple_subclass(checker: &mut Checker, stmt: &Stmt, class: &StmtClassDef) {
|
||||||
if class.bases.iter().any(|base| {
|
let Some(Arguments { args: bases, .. }) = class.arguments.as_ref() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if bases.iter().any(|base| {
|
||||||
checker
|
checker
|
||||||
.semantic()
|
.semantic()
|
||||||
.resolve_call_path(map_subscript(base))
|
.resolve_call_path(map_subscript(base))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
|
use ruff_python_ast::Arguments;
|
||||||
|
|
||||||
use ruff_python_ast::call_path::from_qualified_name;
|
use ruff_python_ast::call_path::from_qualified_name;
|
||||||
use ruff_python_ast::helpers::map_callable;
|
use ruff_python_ast::helpers::map_callable;
|
||||||
|
|
@ -37,7 +38,11 @@ pub(crate) fn runtime_evaluated(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runtime_evaluated_base_class(base_classes: &[String], semantic: &SemanticModel) -> bool {
|
fn runtime_evaluated_base_class(base_classes: &[String], semantic: &SemanticModel) -> bool {
|
||||||
if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) = &semantic.scope().kind {
|
if let ScopeKind::Class(ast::StmtClassDef {
|
||||||
|
arguments: Some(Arguments { args: bases, .. }),
|
||||||
|
..
|
||||||
|
}) = &semantic.scope().kind
|
||||||
|
{
|
||||||
for base in bases {
|
for base in bases {
|
||||||
if let Some(call_path) = semantic.resolve_call_path(base) {
|
if let Some(call_path) = semantic.resolve_call_path(base) {
|
||||||
if base_classes
|
if base_classes
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{Constant, Expr, ExprCall, ExprConstant};
|
use ruff_python_ast::{Arguments, Constant, Expr, ExprCall, ExprConstant};
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -54,7 +54,11 @@ pub(crate) fn path_constructor_current_directory(checker: &mut Checker, expr: &E
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Expr::Call(ExprCall { args, keywords, .. }) = expr else {
|
let Expr::Call(ExprCall {
|
||||||
|
arguments: Arguments { args, keywords, .. },
|
||||||
|
..
|
||||||
|
}) = expr
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, ConversionFlag, Expr};
|
use ruff_python_ast::{self as ast, Arguments, Constant, ConversionFlag, Expr};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
/// Wrap an expression in a `FormattedValue` with no special formatting.
|
/// Wrap an expression in a `FormattedValue` with no special formatting.
|
||||||
|
|
@ -29,8 +29,12 @@ fn is_simple_call(expr: &Expr) -> bool {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) => args.is_empty() && keywords.is_empty() && is_simple_callee(func),
|
}) => args.is_empty() && keywords.is_empty() && is_simple_callee(func),
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Ranged};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
|
|
@ -106,7 +106,11 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn static_join_to_fstring(checker: &mut Checker, expr: &Expr, joiner: &str) {
|
pub(crate) fn static_join_to_fstring(checker: &mut Checker, expr: &Expr, joiner: &str) {
|
||||||
let Expr::Call(ast::ExprCall { args, keywords, .. }) = expr else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, keywords, .. },
|
||||||
|
..
|
||||||
|
}) = expr
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
|
||||||
|
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_python_stdlib::str::{is_cased_lowercase, is_cased_uppercase};
|
use ruff_python_stdlib::str::{is_cased_lowercase, is_cased_uppercase};
|
||||||
|
|
@ -61,10 +61,13 @@ pub(super) fn is_type_var_assignment(stmt: &Stmt, semantic: &SemanticModel) -> b
|
||||||
.is_some_and(|call_path| matches!(call_path.as_slice(), ["typing", "TypeVar" | "NewType"]))
|
.is_some_and(|call_path| matches!(call_path.as_slice(), ["typing", "TypeVar" | "NewType"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_typed_dict_class(bases: &[Expr], semantic: &SemanticModel) -> bool {
|
pub(super) fn is_typed_dict_class(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool {
|
||||||
bases
|
arguments.is_some_and(|arguments| {
|
||||||
.iter()
|
arguments
|
||||||
.any(|base| semantic.match_typing_expr(base, "TypedDict"))
|
.args
|
||||||
|
.iter()
|
||||||
|
.any(|base| semantic.match_typing_expr(base, "TypedDict"))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -45,10 +45,26 @@ impl Violation for ErrorSuffixOnExceptionName {
|
||||||
/// N818
|
/// N818
|
||||||
pub(crate) fn error_suffix_on_exception_name(
|
pub(crate) fn error_suffix_on_exception_name(
|
||||||
class_def: &Stmt,
|
class_def: &Stmt,
|
||||||
bases: &[Expr],
|
arguments: Option<&Arguments>,
|
||||||
name: &str,
|
name: &str,
|
||||||
ignore_names: &[IdentifierPattern],
|
ignore_names: &[IdentifierPattern],
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
|
if name.ends_with("Error") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !arguments.is_some_and(|arguments| {
|
||||||
|
arguments.args.iter().any(|base| {
|
||||||
|
if let Expr::Name(ast::ExprName { id, .. }) = &base {
|
||||||
|
id == "Exception" || id.ends_with("Error")
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
if ignore_names
|
if ignore_names
|
||||||
.iter()
|
.iter()
|
||||||
.any(|ignore_name| ignore_name.matches(name))
|
.any(|ignore_name| ignore_name.matches(name))
|
||||||
|
|
@ -56,19 +72,6 @@ pub(crate) fn error_suffix_on_exception_name(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bases.iter().any(|base| {
|
|
||||||
if let Expr::Name(ast::ExprName { id, .. }) = &base {
|
|
||||||
id == "Exception" || id.ends_with("Error")
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if name.ends_with("Error") {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(Diagnostic::new(
|
Some(Diagnostic::new(
|
||||||
ErrorSuffixOnExceptionName {
|
ErrorSuffixOnExceptionName {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{Expr, Ranged};
|
use ruff_python_ast::{Arguments, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -54,7 +54,7 @@ pub(crate) fn mixed_case_variable_in_class_scope(
|
||||||
checker: &mut Checker,
|
checker: &mut Checker,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
name: &str,
|
name: &str,
|
||||||
bases: &[Expr],
|
arguments: Option<&Arguments>,
|
||||||
) {
|
) {
|
||||||
if checker
|
if checker
|
||||||
.settings
|
.settings
|
||||||
|
|
@ -72,7 +72,7 @@ pub(crate) fn mixed_case_variable_in_class_scope(
|
||||||
let parent = checker.semantic().stmt();
|
let parent = checker.semantic().stmt();
|
||||||
|
|
||||||
if helpers::is_named_tuple_assignment(parent, checker.semantic())
|
if helpers::is_named_tuple_assignment(parent, checker.semantic())
|
||||||
|| helpers::is_typed_dict_class(bases, checker.semantic())
|
|| helpers::is_typed_dict_class(arguments, checker.semantic())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_ast::Expr;
|
|
||||||
use ruff_python_ast::Ranged;
|
use ruff_python_ast::Ranged;
|
||||||
|
use ruff_python_ast::{Arguments, Expr};
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -65,7 +65,12 @@ pub(crate) fn incorrect_dict_iterator(checker: &mut Checker, target: &Expr, iter
|
||||||
let [key, value] = elts.as_slice() else {
|
let [key, value] = elts.as_slice() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Expr::Call(ast::ExprCall { func, args, .. }) = iter else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = iter
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -92,9 +92,13 @@ pub(crate) fn manual_list_comprehension(checker: &mut Checker, target: &Expr, bo
|
||||||
|
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
|
arguments:
|
||||||
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range,
|
range,
|
||||||
args,
|
|
||||||
keywords,
|
|
||||||
}) = value.as_ref()
|
}) = value.as_ref()
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::helpers::any_over_expr;
|
use ruff_python_ast::helpers::any_over_expr;
|
||||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
|
|
@ -59,9 +59,13 @@ pub(crate) fn manual_list_copy(checker: &mut Checker, target: &Expr, body: &[Stm
|
||||||
|
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
|
arguments:
|
||||||
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range,
|
range,
|
||||||
args,
|
|
||||||
keywords,
|
|
||||||
}) = value.as_ref()
|
}) = value.as_ref()
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr};
|
use ruff_python_ast::{self as ast, Arguments, Expr};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
|
|
@ -54,17 +54,21 @@ impl AlwaysAutofixableViolation for UnnecessaryListCast {
|
||||||
pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) {
|
pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords: _,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: list_range,
|
range: list_range,
|
||||||
..
|
|
||||||
}) = iter
|
}) = iter
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if args.len() != 1 {
|
let [arg] = args.as_slice() else {
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() else {
|
let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -74,7 +78,7 @@ pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match &args[0] {
|
match arg {
|
||||||
Expr::Tuple(ast::ExprTuple {
|
Expr::Tuple(ast::ExprTuple {
|
||||||
range: iterable_range,
|
range: iterable_range,
|
||||||
..
|
..
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use itertools::izip;
|
use itertools::izip;
|
||||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, CmpOp, Constant, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -49,7 +49,11 @@ pub(crate) fn type_comparison(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match right {
|
match right {
|
||||||
Expr::Call(ast::ExprCall { func, args, .. }) => {
|
Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
|
if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
|
||||||
// Ex) `type(False)`
|
// Ex) `type(False)`
|
||||||
if id == "type" && checker.semantic().is_builtin("type") {
|
if id == "type" && checker.semantic().is_builtin("type") {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
|
|
@ -51,7 +51,11 @@ impl Violation for DuplicateBases {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PLE0241
|
/// PLE0241
|
||||||
pub(crate) fn duplicate_bases(checker: &mut Checker, name: &str, bases: &[Expr]) {
|
pub(crate) fn duplicate_bases(checker: &mut Checker, name: &str, arguments: Option<&Arguments>) {
|
||||||
|
let Some(Arguments { args: bases, .. }) = arguments else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let mut seen: FxHashSet<&str> =
|
let mut seen: FxHashSet<&str> =
|
||||||
FxHashSet::with_capacity_and_hasher(bases.len(), BuildHasherDefault::default());
|
FxHashSet::with_capacity_and_hasher(bases.len(), BuildHasherDefault::default());
|
||||||
for base in bases {
|
for base in bases {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr, Keyword, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword, Ranged};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||||
|
|
@ -95,8 +95,12 @@ fn collect_nested_args(min_max: MinMax, args: &[Expr], semantic: &SemanticModel)
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if let Expr::Call(ast::ExprCall {
|
if let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) = arg
|
}) = arg
|
||||||
{
|
{
|
||||||
|
|
@ -135,14 +139,18 @@ pub(crate) fn nested_min_max(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if args.len() == 1
|
if matches!(&args, [Expr::Call(ast::ExprCall { arguments: Arguments {args, .. }, .. })] if args.len() == 1)
|
||||||
&& matches!(&args[0], Expr::Call(ast::ExprCall { args, .. }) if args.len() == 1)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.iter().any(|arg| {
|
if args.iter().any(|arg| {
|
||||||
let Expr::Call(ast::ExprCall { func, keywords, .. }) = arg else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { keywords, .. },
|
||||||
|
..
|
||||||
|
}) = arg
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
MinMax::try_from_call(func.as_ref(), keywords.as_ref(), checker.semantic()) == Some(min_max)
|
MinMax::try_from_call(func.as_ref(), keywords.as_ref(), checker.semantic()) == Some(min_max)
|
||||||
|
|
@ -152,8 +160,11 @@ pub(crate) fn nested_min_max(
|
||||||
if !checker.indexer().has_comments(expr, checker.locator()) {
|
if !checker.indexer().has_comments(expr, checker.locator()) {
|
||||||
let flattened_expr = Expr::Call(ast::ExprCall {
|
let flattened_expr = Expr::Call(ast::ExprCall {
|
||||||
func: Box::new(func.clone()),
|
func: Box::new(func.clone()),
|
||||||
args: collect_nested_args(min_max, args, checker.semantic()),
|
arguments: Arguments {
|
||||||
keywords: keywords.to_owned(),
|
args: collect_nested_args(min_max, args, checker.semantic()),
|
||||||
|
keywords: keywords.to_owned(),
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
});
|
});
|
||||||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{fmt, iter};
|
use std::{fmt, iter};
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ruff_python_ast::{self as ast, Expr, ExprContext, Ranged, Stmt, WithItem};
|
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Ranged, Stmt, WithItem};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -237,7 +237,12 @@ impl<'a, 'b> StatementVisitor<'b> for InnerForWithAssignTargetsVisitor<'a, 'b> {
|
||||||
/// x = cast(int, x)
|
/// x = cast(int, x)
|
||||||
/// ```
|
/// ```
|
||||||
fn assignment_is_cast_expr(value: &Expr, target: &Expr, semantic: &SemanticModel) -> bool {
|
fn assignment_is_cast_expr(value: &Expr, target: &Expr, semantic: &SemanticModel) -> bool {
|
||||||
let Expr::Call(ast::ExprCall { func, args, .. }) = value else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = value
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let Expr::Name(ast::ExprName { id: target_id, .. }) = target else {
|
let Expr::Name(ast::ExprName { id: target_id, .. }) = target else {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_python_ast::{self as ast, BoolOp, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, BoolOp, Expr, Ranged};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
|
|
@ -73,7 +73,12 @@ pub(crate) fn repeated_isinstance_calls(
|
||||||
let mut obj_to_types: FxHashMap<HashableExpr, (usize, FxHashSet<HashableExpr>)> =
|
let mut obj_to_types: FxHashMap<HashableExpr, (usize, FxHashSet<HashableExpr>)> =
|
||||||
FxHashMap::default();
|
FxHashMap::default();
|
||||||
for value in values {
|
for value in values {
|
||||||
let Expr::Call(ast::ExprCall { func, args, .. }) = value else {
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = value
|
||||||
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if !matches!(func.as_ref(), Expr::Name(ast::ExprName { id, .. }) if id == "isinstance") {
|
if !matches!(func.as_ref(), Expr::Name(ast::ExprName { id, .. }) if id == "isinstance") {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -76,8 +76,7 @@ impl Violation for TypeBivariance {
|
||||||
pub(crate) fn type_bivariance(checker: &mut Checker, value: &Expr) {
|
pub(crate) fn type_bivariance(checker: &mut Checker, value: &Expr) {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
..
|
..
|
||||||
}) = value
|
}) = value
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -67,8 +67,7 @@ impl Violation for TypeNameIncorrectVariance {
|
||||||
pub(crate) fn type_name_incorrect_variance(checker: &mut Checker, value: &Expr) {
|
pub(crate) fn type_name_incorrect_variance(checker: &mut Checker, value: &Expr) {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
..
|
..
|
||||||
}) = value
|
}) = value
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -69,8 +69,7 @@ pub(crate) fn type_param_name_mismatch(checker: &mut Checker, value: &Expr, targ
|
||||||
|
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
..
|
..
|
||||||
}) = value
|
}) = value
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, Constant, Expr, ExprContext, Identifier, Keyword, Ranged, Stmt,
|
self as ast, Arguments, Constant, Expr, ExprContext, Identifier, Keyword, Ranged, Stmt,
|
||||||
};
|
};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
|
|
@ -78,8 +78,7 @@ fn match_named_tuple_assign<'a>(
|
||||||
};
|
};
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
range: _,
|
range: _,
|
||||||
}) = value
|
}) = value
|
||||||
else {
|
else {
|
||||||
|
|
@ -91,7 +90,7 @@ fn match_named_tuple_assign<'a>(
|
||||||
Some((typename, args, keywords, func))
|
Some((typename, args, keywords, func))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a `Stmt::AnnAssign` representing the provided property
|
/// Generate a [`Stmt::AnnAssign`] representing the provided property
|
||||||
/// definition.
|
/// definition.
|
||||||
fn create_property_assignment_stmt(property: &str, annotation: &Expr) -> Stmt {
|
fn create_property_assignment_stmt(property: &str, annotation: &Expr) -> Stmt {
|
||||||
ast::StmtAnnAssign {
|
ast::StmtAnnAssign {
|
||||||
|
|
@ -167,8 +166,11 @@ fn create_properties_from_keywords(keywords: &[Keyword]) -> Result<Vec<Stmt>> {
|
||||||
fn create_class_def_stmt(typename: &str, body: Vec<Stmt>, base_class: &Expr) -> Stmt {
|
fn create_class_def_stmt(typename: &str, body: Vec<Stmt>, base_class: &Expr) -> Stmt {
|
||||||
ast::StmtClassDef {
|
ast::StmtClassDef {
|
||||||
name: Identifier::new(typename.to_string(), TextRange::default()),
|
name: Identifier::new(typename.to_string(), TextRange::default()),
|
||||||
bases: vec![base_class.clone()],
|
arguments: Some(Arguments {
|
||||||
keywords: vec![],
|
args: vec![base_class.clone()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
}),
|
||||||
body,
|
body,
|
||||||
type_params: vec![],
|
type_params: vec![],
|
||||||
decorator_list: vec![],
|
decorator_list: vec![],
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, Constant, Expr, ExprContext, Identifier, Keyword, Ranged, Stmt,
|
self as ast, Arguments, Constant, Expr, ExprContext, Identifier, Keyword, Ranged, Stmt,
|
||||||
};
|
};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
|
|
@ -77,8 +77,7 @@ fn match_typed_dict_assign<'a>(
|
||||||
};
|
};
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
range: _,
|
range: _,
|
||||||
}) = value
|
}) = value
|
||||||
else {
|
else {
|
||||||
|
|
@ -90,7 +89,7 @@ fn match_typed_dict_assign<'a>(
|
||||||
Some((class_name, args, keywords, func))
|
Some((class_name, args, keywords, func))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a `Stmt::AnnAssign` representing the provided property
|
/// Generate a [`Stmt::AnnAssign`] representing the provided property
|
||||||
/// definition.
|
/// definition.
|
||||||
fn create_property_assignment_stmt(property: &str, annotation: &Expr) -> Stmt {
|
fn create_property_assignment_stmt(property: &str, annotation: &Expr) -> Stmt {
|
||||||
ast::StmtAnnAssign {
|
ast::StmtAnnAssign {
|
||||||
|
|
@ -118,14 +117,16 @@ fn create_class_def_stmt(
|
||||||
total_keyword: Option<&Keyword>,
|
total_keyword: Option<&Keyword>,
|
||||||
base_class: &Expr,
|
base_class: &Expr,
|
||||||
) -> Stmt {
|
) -> Stmt {
|
||||||
let keywords = match total_keyword {
|
|
||||||
Some(keyword) => vec![keyword.clone()],
|
|
||||||
None => vec![],
|
|
||||||
};
|
|
||||||
ast::StmtClassDef {
|
ast::StmtClassDef {
|
||||||
name: Identifier::new(class_name.to_string(), TextRange::default()),
|
name: Identifier::new(class_name.to_string(), TextRange::default()),
|
||||||
bases: vec![base_class.clone()],
|
arguments: Some(Arguments {
|
||||||
keywords,
|
args: vec![base_class.clone()],
|
||||||
|
keywords: match total_keyword {
|
||||||
|
Some(keyword) => vec![keyword.clone()],
|
||||||
|
None => vec![],
|
||||||
|
},
|
||||||
|
range: TextRange::default(),
|
||||||
|
}),
|
||||||
body,
|
body,
|
||||||
type_params: vec![],
|
type_params: vec![],
|
||||||
decorator_list: vec![],
|
decorator_list: vec![],
|
||||||
|
|
@ -217,9 +218,11 @@ fn match_properties_and_total<'a>(
|
||||||
values,
|
values,
|
||||||
range: _,
|
range: _,
|
||||||
}) => Ok((properties_from_dict_literal(keys, values)?, total)),
|
}) => Ok((properties_from_dict_literal(keys, values)?, total)),
|
||||||
Expr::Call(ast::ExprCall { func, keywords, .. }) => {
|
Expr::Call(ast::ExprCall {
|
||||||
Ok((properties_from_dict_call(func, keywords)?, total))
|
func,
|
||||||
}
|
arguments: Arguments { keywords, .. },
|
||||||
|
..
|
||||||
|
}) => Ok((properties_from_dict_call(func, keywords)?, total)),
|
||||||
_ => bail!("Expected `arg` to be `Expr::Dict` or `Expr::Call`"),
|
_ => bail!("Expected `arg` to be `Expr::Dict` or `Expr::Call`"),
|
||||||
}
|
}
|
||||||
} else if !keywords.is_empty() {
|
} else if !keywords.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Keyword, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Ranged};
|
||||||
use ruff_python_literal::format::{
|
use ruff_python_literal::format::{
|
||||||
FieldName, FieldNamePart, FieldType, FormatPart, FormatString, FromTemplate,
|
FieldName, FieldNamePart, FieldType, FormatPart, FormatString, FromTemplate,
|
||||||
};
|
};
|
||||||
|
|
@ -65,7 +65,11 @@ impl<'a> FormatSummaryValues<'a> {
|
||||||
fn try_from_expr(expr: &'a Expr, locator: &'a Locator) -> Option<Self> {
|
fn try_from_expr(expr: &'a Expr, locator: &'a Locator) -> Option<Self> {
|
||||||
let mut extracted_args: Vec<&Expr> = Vec::new();
|
let mut extracted_args: Vec<&Expr> = Vec::new();
|
||||||
let mut extracted_kwargs: FxHashMap<&str, &Expr> = FxHashMap::default();
|
let mut extracted_kwargs: FxHashMap<&str, &Expr> = FxHashMap::default();
|
||||||
if let Expr::Call(ast::ExprCall { args, keywords, .. }) = expr {
|
if let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, keywords, .. },
|
||||||
|
..
|
||||||
|
}) = expr
|
||||||
|
{
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if contains_invalids(locator.slice(arg.range()))
|
if contains_invalids(locator.slice(arg.range()))
|
||||||
|| locator.contains_line_break(arg.range())
|
|| locator.contains_line_break(arg.range())
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Decorator, Expr, Keyword, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Decorator, Expr, Keyword, Ranged};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
|
|
@ -61,8 +61,12 @@ pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list:
|
||||||
for decorator in decorator_list {
|
for decorator in decorator_list {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
}) = &decorator.expression
|
}) = &decorator.expression
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
use ruff_python_ast::{self as ast, Decorator, Expr, Ranged};
|
|
||||||
use ruff_text_size::TextRange;
|
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::{self as ast, Decorator, Expr, Ranged};
|
||||||
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
|
|
@ -59,8 +58,7 @@ pub(crate) fn lru_cache_without_parameters(checker: &mut Checker, decorator_list
|
||||||
for decorator in decorator_list {
|
for decorator in decorator_list {
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments,
|
||||||
keywords,
|
|
||||||
range: _,
|
range: _,
|
||||||
}) = &decorator.expression
|
}) = &decorator.expression
|
||||||
else {
|
else {
|
||||||
|
|
@ -68,8 +66,8 @@ pub(crate) fn lru_cache_without_parameters(checker: &mut Checker, decorator_list
|
||||||
};
|
};
|
||||||
|
|
||||||
// Look for, e.g., `import functools; @functools.lru_cache()`.
|
// Look for, e.g., `import functools; @functools.lru_cache()`.
|
||||||
if args.is_empty()
|
if arguments.args.is_empty()
|
||||||
&& keywords.is_empty()
|
&& arguments.keywords.is_empty()
|
||||||
&& checker
|
&& checker
|
||||||
.semantic()
|
.semantic()
|
||||||
.resolve_call_path(func)
|
.resolve_call_path(func)
|
||||||
|
|
@ -80,9 +78,9 @@ pub(crate) fn lru_cache_without_parameters(checker: &mut Checker, decorator_list
|
||||||
TextRange::new(func.end(), decorator.end()),
|
TextRange::new(func.end(), decorator.end()),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
diagnostic.set_fix(Fix::automatic(Edit::deletion(
|
||||||
checker.generator().expr(func),
|
arguments.start(),
|
||||||
decorator.expression.range(),
|
arguments.end(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Keyword, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Ranged};
|
||||||
use ruff_python_parser::{lexer, Mode};
|
use ruff_python_parser::{lexer, Mode};
|
||||||
use ruff_text_size::TextSize;
|
use ruff_text_size::TextSize;
|
||||||
|
|
||||||
|
|
@ -119,8 +119,12 @@ fn match_open<'a>(
|
||||||
) -> Option<(Option<&'a Expr>, &'a [Keyword])> {
|
) -> Option<(Option<&'a Expr>, &'a [Keyword])> {
|
||||||
let ast::ExprCall {
|
let ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
range: _,
|
range: _,
|
||||||
} = expr.as_call_expr()?;
|
} = expr.as_call_expr()?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
use std::ops::Add;
|
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Ranged};
|
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::{self as ast, Ranged};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
|
|
@ -44,54 +40,20 @@ impl AlwaysAutofixableViolation for UnnecessaryClassParentheses {
|
||||||
|
|
||||||
/// UP039
|
/// UP039
|
||||||
pub(crate) fn unnecessary_class_parentheses(checker: &mut Checker, class_def: &ast::StmtClassDef) {
|
pub(crate) fn unnecessary_class_parentheses(checker: &mut Checker, class_def: &ast::StmtClassDef) {
|
||||||
if !class_def.bases.is_empty() || !class_def.keywords.is_empty() {
|
let Some(arguments) = class_def.arguments.as_ref() else {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let offset = class_def.name.end();
|
|
||||||
let contents = checker.locator().after(offset);
|
|
||||||
|
|
||||||
// Find the open and closing parentheses between the class name and the colon, if they exist.
|
|
||||||
let mut depth = 0u32;
|
|
||||||
let mut start = None;
|
|
||||||
let mut end = None;
|
|
||||||
for (i, c) in contents.char_indices() {
|
|
||||||
match c {
|
|
||||||
'(' => {
|
|
||||||
if depth == 0 {
|
|
||||||
start = Some(i);
|
|
||||||
}
|
|
||||||
depth = depth.saturating_add(1);
|
|
||||||
}
|
|
||||||
')' => {
|
|
||||||
depth = depth.saturating_sub(1);
|
|
||||||
if depth == 0 {
|
|
||||||
end = Some(i + c.len_utf8());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
':' => {
|
|
||||||
if depth == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let (Some(start), Some(end)) = (start, end) else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert to `TextSize`.
|
if !arguments.args.is_empty() || !arguments.keywords.is_empty() {
|
||||||
let start = TextSize::try_from(start).unwrap();
|
return;
|
||||||
let end = TextSize::try_from(end).unwrap();
|
}
|
||||||
|
|
||||||
// Add initial offset.
|
let mut diagnostic = Diagnostic::new(UnnecessaryClassParentheses, arguments.range());
|
||||||
let start = offset.add(start);
|
|
||||||
let end = offset.add(end);
|
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryClassParentheses, TextRange::new(start, end));
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
diagnostic.set_fix(Fix::automatic(Edit::deletion(start, end)));
|
diagnostic.set_fix(Fix::automatic(Edit::deletion(
|
||||||
|
arguments.start(),
|
||||||
|
arguments.end(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,11 @@ impl AlwaysAutofixableViolation for UselessObjectInheritance {
|
||||||
|
|
||||||
/// UP004
|
/// UP004
|
||||||
pub(crate) fn useless_object_inheritance(checker: &mut Checker, class_def: &ast::StmtClassDef) {
|
pub(crate) fn useless_object_inheritance(checker: &mut Checker, class_def: &ast::StmtClassDef) {
|
||||||
for expr in &class_def.bases {
|
let Some(arguments) = class_def.arguments.as_ref() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
for expr in &arguments.args {
|
||||||
let Expr::Name(ast::ExprName { id, .. }) = expr else {
|
let Expr::Name(ast::ExprName { id, .. }) = expr else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
@ -70,8 +74,8 @@ pub(crate) fn useless_object_inheritance(checker: &mut Checker, class_def: &ast:
|
||||||
checker.locator(),
|
checker.locator(),
|
||||||
class_def.name.end(),
|
class_def.name.end(),
|
||||||
expr.range(),
|
expr.range(),
|
||||||
&class_def.bases,
|
&arguments.args,
|
||||||
&class_def.keywords,
|
&arguments.keywords,
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
Ok(Fix::automatic(edit))
|
Ok(Fix::automatic(edit))
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use anyhow::{bail, Result};
|
||||||
use libcst_native::{
|
use libcst_native::{
|
||||||
ConcatenatedString, Expression, FormattedStringContent, FormattedStringExpression,
|
ConcatenatedString, Expression, FormattedStringContent, FormattedStringExpression,
|
||||||
};
|
};
|
||||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -80,8 +80,12 @@ pub(crate) fn explicit_f_string_type_conversion(
|
||||||
|
|
||||||
let Expr::Call(ast::ExprCall {
|
let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
..
|
..
|
||||||
}) = value.as_ref()
|
}) = value.as_ref()
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Expr};
|
use ruff_python_ast::{self as ast, Arguments, Expr};
|
||||||
|
|
||||||
use ruff_python_ast::helpers::{map_callable, map_subscript};
|
use ruff_python_ast::helpers::{map_callable, map_subscript};
|
||||||
use ruff_python_semantic::{BindingKind, SemanticModel};
|
use ruff_python_semantic::{BindingKind, SemanticModel};
|
||||||
|
|
@ -51,7 +51,11 @@ pub(super) fn is_dataclass(class_def: &ast::StmtClassDef, semantic: &SemanticMod
|
||||||
|
|
||||||
/// Returns `true` if the given class is a Pydantic `BaseModel` or `BaseSettings` subclass.
|
/// Returns `true` if the given class is a Pydantic `BaseModel` or `BaseSettings` subclass.
|
||||||
pub(super) fn is_pydantic_model(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool {
|
pub(super) fn is_pydantic_model(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool {
|
||||||
class_def.bases.iter().any(|expr| {
|
let Some(Arguments { args: bases, .. }) = class_def.arguments.as_ref() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bases.iter().any(|expr| {
|
||||||
semantic.resolve_call_path(expr).is_some_and(|call_path| {
|
semantic.resolve_call_path(expr).is_some_and(|call_path| {
|
||||||
matches!(
|
matches!(
|
||||||
call_path.as_slice(),
|
call_path.as_slice(),
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::{self as ast, Comprehension, Constant, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Comprehension, Constant, Expr, Ranged};
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
|
|
@ -151,7 +151,11 @@ struct IterationTarget {
|
||||||
/// redundant comprehension).
|
/// redundant comprehension).
|
||||||
fn match_iteration_target(expr: &Expr, model: &SemanticModel) -> Option<IterationTarget> {
|
fn match_iteration_target(expr: &Expr, model: &SemanticModel) -> Option<IterationTarget> {
|
||||||
let result = match expr {
|
let result = match expr {
|
||||||
Expr::Call(ast::ExprCall { func, args, .. }) => {
|
Expr::Call(ast::ExprCall {
|
||||||
|
func,
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
let ast::ExprName { id, .. } = func.as_name_expr()?;
|
let ast::ExprName { id, .. } = func.as_name_expr()?;
|
||||||
|
|
||||||
if !matches!(id.as_str(), "tuple" | "list") {
|
if !matches!(id.as_str(), "tuple" | "list") {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ pub(crate) fn error_instead_of_exception(checker: &mut Checker, handlers: &[Exce
|
||||||
for expr in calls {
|
for expr in calls {
|
||||||
if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = expr.func.as_ref() {
|
if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = expr.func.as_ref() {
|
||||||
if attr == "error" {
|
if attr == "error" {
|
||||||
if exc_info(&expr.keywords, checker.semantic()).is_none() {
|
if exc_info(&expr.arguments.keywords, checker.semantic()).is_none() {
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
.push(Diagnostic::new(ErrorInsteadOfException, expr.range()));
|
.push(Diagnostic::new(ErrorInsteadOfException, expr.range()));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged};
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Ranged};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -77,7 +77,11 @@ where
|
||||||
|
|
||||||
/// TRY003
|
/// TRY003
|
||||||
pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) {
|
||||||
if let Expr::Call(ast::ExprCall { args, .. }) = expr {
|
if let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = expr
|
||||||
|
{
|
||||||
if let Some(arg) = args.first() {
|
if let Some(arg) = args.first() {
|
||||||
if any_string(arg, |part| part.chars().any(char::is_whitespace)) {
|
if any_string(arg, |part| part.chars().any(char::is_whitespace)) {
|
||||||
checker
|
checker
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ pub(crate) fn verbose_log_message(checker: &mut Checker, handlers: &[ExceptHandl
|
||||||
// Collect all referenced names in the `logging.exception` call.
|
// Collect all referenced names in the `logging.exception` call.
|
||||||
let names: Vec<&ast::ExprName> = {
|
let names: Vec<&ast::ExprName> = {
|
||||||
let mut names = Vec::new();
|
let mut names = Vec::new();
|
||||||
for arg in &expr.args {
|
for arg in &expr.arguments.args {
|
||||||
let mut visitor = NameVisitor::default();
|
let mut visitor = NameVisitor::default();
|
||||||
visitor.visit_expr(arg);
|
visitor.visit_expr(arg);
|
||||||
names.extend(visitor.names);
|
names.extend(visitor.names);
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,7 @@ where
|
||||||
}
|
}
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: ast::Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
// Allow `tuple()`, `list()`, and their generic forms, like `list[int]()`.
|
// Allow `tuple()`, `list()`, and their generic forms, like `list[int]()`.
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,27 @@ impl<'a> From<&'a ast::Constant> for ComparableConstant<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ComparableArguments<'a> {
|
||||||
|
args: Vec<ComparableExpr<'a>>,
|
||||||
|
keywords: Vec<ComparableKeyword<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ast::Arguments> for ComparableArguments<'a> {
|
||||||
|
fn from(arguments: &'a ast::Arguments) -> Self {
|
||||||
|
Self {
|
||||||
|
args: arguments.args.iter().map(Into::into).collect(),
|
||||||
|
keywords: arguments.keywords.iter().map(Into::into).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a Box<ast::Arguments>> for ComparableArguments<'a> {
|
||||||
|
fn from(arguments: &'a Box<ast::Arguments>) -> Self {
|
||||||
|
(arguments.as_ref()).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ComparableParameters<'a> {
|
pub struct ComparableParameters<'a> {
|
||||||
posonlyargs: Vec<ComparableParameterWithDefault<'a>>,
|
posonlyargs: Vec<ComparableParameterWithDefault<'a>>,
|
||||||
|
|
@ -583,8 +604,7 @@ pub struct ExprCompare<'a> {
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ExprCall<'a> {
|
pub struct ExprCall<'a> {
|
||||||
func: Box<ComparableExpr<'a>>,
|
func: Box<ComparableExpr<'a>>,
|
||||||
args: Vec<ComparableExpr<'a>>,
|
arguments: ComparableArguments<'a>,
|
||||||
keywords: Vec<ComparableKeyword<'a>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -837,13 +857,11 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
|
||||||
}),
|
}),
|
||||||
ast::Expr::Call(ast::ExprCall {
|
ast::Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments,
|
||||||
keywords,
|
|
||||||
range: _range,
|
range: _range,
|
||||||
}) => Self::Call(ExprCall {
|
}) => Self::Call(ExprCall {
|
||||||
func: func.into(),
|
func: func.into(),
|
||||||
args: args.iter().map(Into::into).collect(),
|
arguments: arguments.into(),
|
||||||
keywords: keywords.iter().map(Into::into).collect(),
|
|
||||||
}),
|
}),
|
||||||
ast::Expr::FormattedValue(ast::ExprFormattedValue {
|
ast::Expr::FormattedValue(ast::ExprFormattedValue {
|
||||||
value,
|
value,
|
||||||
|
|
@ -968,8 +986,7 @@ pub struct StmtAsyncFunctionDef<'a> {
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct StmtClassDef<'a> {
|
pub struct StmtClassDef<'a> {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
bases: Vec<ComparableExpr<'a>>,
|
arguments: Option<ComparableArguments<'a>>,
|
||||||
keywords: Vec<ComparableKeyword<'a>>,
|
|
||||||
body: Vec<ComparableStmt<'a>>,
|
body: Vec<ComparableStmt<'a>>,
|
||||||
decorator_list: Vec<ComparableDecorator<'a>>,
|
decorator_list: Vec<ComparableDecorator<'a>>,
|
||||||
type_params: Vec<ComparableTypeParam<'a>>,
|
type_params: Vec<ComparableTypeParam<'a>>,
|
||||||
|
|
@ -1240,16 +1257,14 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
|
||||||
}),
|
}),
|
||||||
ast::Stmt::ClassDef(ast::StmtClassDef {
|
ast::Stmt::ClassDef(ast::StmtClassDef {
|
||||||
name,
|
name,
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
body,
|
body,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
type_params,
|
type_params,
|
||||||
range: _range,
|
range: _range,
|
||||||
}) => Self::ClassDef(StmtClassDef {
|
}) => Self::ClassDef(StmtClassDef {
|
||||||
name: name.as_str(),
|
name: name.as_str(),
|
||||||
bases: bases.iter().map(Into::into).collect(),
|
arguments: arguments.as_ref().map(Into::into),
|
||||||
keywords: keywords.iter().map(Into::into).collect(),
|
|
||||||
body: body.iter().map(Into::into).collect(),
|
body: body.iter().map(Into::into).collect(),
|
||||||
decorator_list: decorator_list.iter().map(Into::into).collect(),
|
decorator_list: decorator_list.iter().map(Into::into).collect(),
|
||||||
type_params: type_params.iter().map(Into::into).collect(),
|
type_params: type_params.iter().map(Into::into).collect(),
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use std::borrow::Cow;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
self as ast, Constant, ExceptHandler, Expr, Keyword, MatchCase, Parameters, Pattern, Ranged,
|
self as ast, Arguments, Constant, ExceptHandler, Expr, Keyword, MatchCase, Parameters, Pattern,
|
||||||
Stmt, TypeParam,
|
Ranged, Stmt, TypeParam,
|
||||||
};
|
};
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
@ -50,8 +50,7 @@ where
|
||||||
// Accept empty initializers.
|
// Accept empty initializers.
|
||||||
if let Expr::Call(ast::ExprCall {
|
if let Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
range: _range,
|
range: _range,
|
||||||
}) = expr
|
}) = expr
|
||||||
{
|
{
|
||||||
|
|
@ -237,8 +236,7 @@ where
|
||||||
}) => any_over_expr(left, func) || comparators.iter().any(|expr| any_over_expr(expr, func)),
|
}) => any_over_expr(left, func) || comparators.iter().any(|expr| any_over_expr(expr, func)),
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func: call_func,
|
func: call_func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
range: _range,
|
range: _range,
|
||||||
}) => {
|
}) => {
|
||||||
any_over_expr(call_func, func)
|
any_over_expr(call_func, func)
|
||||||
|
|
@ -396,16 +394,19 @@ where
|
||||||
.is_some_and(|value| any_over_expr(value, func))
|
.is_some_and(|value| any_over_expr(value, func))
|
||||||
}
|
}
|
||||||
Stmt::ClassDef(ast::StmtClassDef {
|
Stmt::ClassDef(ast::StmtClassDef {
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
body,
|
body,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
bases.iter().any(|expr| any_over_expr(expr, func))
|
arguments
|
||||||
|| keywords
|
.as_ref()
|
||||||
.iter()
|
.is_some_and(|Arguments { args, keywords, .. }| {
|
||||||
.any(|keyword| any_over_expr(&keyword.value, func))
|
args.iter().any(|expr| any_over_expr(expr, func))
|
||||||
|
|| keywords
|
||||||
|
.iter()
|
||||||
|
.any(|keyword| any_over_expr(&keyword.value, func))
|
||||||
|
})
|
||||||
|| body.iter().any(|stmt| any_over_stmt(stmt, func))
|
|| body.iter().any(|stmt| any_over_stmt(stmt, func))
|
||||||
|| decorator_list
|
|| decorator_list
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -640,6 +641,8 @@ pub fn is_constant_non_singleton(expr: &Expr) -> bool {
|
||||||
|
|
||||||
/// Return the [`Keyword`] with the given name, if it's present in the list of
|
/// Return the [`Keyword`] with the given name, if it's present in the list of
|
||||||
/// [`Keyword`] arguments.
|
/// [`Keyword`] arguments.
|
||||||
|
///
|
||||||
|
/// TODO(charlie): Make this an associated function on [`Arguments`].
|
||||||
pub fn find_keyword<'a>(keywords: &'a [Keyword], keyword_name: &str) -> Option<&'a Keyword> {
|
pub fn find_keyword<'a>(keywords: &'a [Keyword], keyword_name: &str) -> Option<&'a Keyword> {
|
||||||
keywords.iter().find(|keyword| {
|
keywords.iter().find(|keyword| {
|
||||||
let Keyword { arg, .. } = keyword;
|
let Keyword { arg, .. } = keyword;
|
||||||
|
|
@ -1229,30 +1232,14 @@ impl Truthiness {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::List(ast::ExprList {
|
Expr::List(ast::ExprList { elts, .. })
|
||||||
elts,
|
| Expr::Set(ast::ExprSet { elts, .. })
|
||||||
range: _range,
|
| Expr::Tuple(ast::ExprTuple { elts, .. }) => Some(!elts.is_empty()),
|
||||||
..
|
Expr::Dict(ast::ExprDict { keys, .. }) => Some(!keys.is_empty()),
|
||||||
})
|
|
||||||
| Expr::Set(ast::ExprSet {
|
|
||||||
elts,
|
|
||||||
range: _range,
|
|
||||||
})
|
|
||||||
| Expr::Tuple(ast::ExprTuple {
|
|
||||||
elts,
|
|
||||||
range: _range,
|
|
||||||
..
|
|
||||||
}) => Some(!elts.is_empty()),
|
|
||||||
Expr::Dict(ast::ExprDict {
|
|
||||||
keys,
|
|
||||||
range: _range,
|
|
||||||
..
|
|
||||||
}) => Some(!keys.is_empty()),
|
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
..
|
||||||
range: _range,
|
|
||||||
}) => {
|
}) => {
|
||||||
if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
|
if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
|
||||||
if is_iterable_initializer(id.as_str(), |id| is_builtin(id)) {
|
if is_iterable_initializer(id.as_str(), |id| is_builtin(id)) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
self as ast, Alias, Comprehension, Decorator, ExceptHandler, Expr, Keyword, MatchCase, Mod,
|
self as ast, Alias, Arguments, Comprehension, Decorator, ExceptHandler, Expr, Keyword,
|
||||||
Parameter, ParameterWithDefault, Parameters, Pattern, Ranged, Stmt, TypeParam,
|
MatchCase, Mod, Parameter, ParameterWithDefault, Parameters, Pattern, Ranged, Stmt, TypeParam,
|
||||||
TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple, WithItem,
|
TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple, WithItem,
|
||||||
};
|
};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
@ -90,6 +90,7 @@ pub enum AnyNode {
|
||||||
PatternMatchAs(ast::PatternMatchAs),
|
PatternMatchAs(ast::PatternMatchAs),
|
||||||
PatternMatchOr(ast::PatternMatchOr),
|
PatternMatchOr(ast::PatternMatchOr),
|
||||||
Comprehension(Comprehension),
|
Comprehension(Comprehension),
|
||||||
|
Arguments(Arguments),
|
||||||
Parameters(Parameters),
|
Parameters(Parameters),
|
||||||
Parameter(Parameter),
|
Parameter(Parameter),
|
||||||
ParameterWithDefault(ParameterWithDefault),
|
ParameterWithDefault(ParameterWithDefault),
|
||||||
|
|
@ -177,6 +178,7 @@ impl AnyNode {
|
||||||
| AnyNode::PatternMatchAs(_)
|
| AnyNode::PatternMatchAs(_)
|
||||||
| AnyNode::PatternMatchOr(_)
|
| AnyNode::PatternMatchOr(_)
|
||||||
| AnyNode::Comprehension(_)
|
| AnyNode::Comprehension(_)
|
||||||
|
| AnyNode::Arguments(_)
|
||||||
| AnyNode::Parameters(_)
|
| AnyNode::Parameters(_)
|
||||||
| AnyNode::Parameter(_)
|
| AnyNode::Parameter(_)
|
||||||
| AnyNode::ParameterWithDefault(_)
|
| AnyNode::ParameterWithDefault(_)
|
||||||
|
|
@ -264,6 +266,7 @@ impl AnyNode {
|
||||||
| AnyNode::PatternMatchAs(_)
|
| AnyNode::PatternMatchAs(_)
|
||||||
| AnyNode::PatternMatchOr(_)
|
| AnyNode::PatternMatchOr(_)
|
||||||
| AnyNode::Comprehension(_)
|
| AnyNode::Comprehension(_)
|
||||||
|
| AnyNode::Arguments(_)
|
||||||
| AnyNode::Parameters(_)
|
| AnyNode::Parameters(_)
|
||||||
| AnyNode::Parameter(_)
|
| AnyNode::Parameter(_)
|
||||||
| AnyNode::ParameterWithDefault(_)
|
| AnyNode::ParameterWithDefault(_)
|
||||||
|
|
@ -351,6 +354,7 @@ impl AnyNode {
|
||||||
| AnyNode::PatternMatchAs(_)
|
| AnyNode::PatternMatchAs(_)
|
||||||
| AnyNode::PatternMatchOr(_)
|
| AnyNode::PatternMatchOr(_)
|
||||||
| AnyNode::Comprehension(_)
|
| AnyNode::Comprehension(_)
|
||||||
|
| AnyNode::Arguments(_)
|
||||||
| AnyNode::Parameters(_)
|
| AnyNode::Parameters(_)
|
||||||
| AnyNode::Parameter(_)
|
| AnyNode::Parameter(_)
|
||||||
| AnyNode::ParameterWithDefault(_)
|
| AnyNode::ParameterWithDefault(_)
|
||||||
|
|
@ -438,6 +442,7 @@ impl AnyNode {
|
||||||
| AnyNode::ExprLineMagic(_)
|
| AnyNode::ExprLineMagic(_)
|
||||||
| AnyNode::ExceptHandlerExceptHandler(_)
|
| AnyNode::ExceptHandlerExceptHandler(_)
|
||||||
| AnyNode::Comprehension(_)
|
| AnyNode::Comprehension(_)
|
||||||
|
| AnyNode::Arguments(_)
|
||||||
| AnyNode::Parameters(_)
|
| AnyNode::Parameters(_)
|
||||||
| AnyNode::Parameter(_)
|
| AnyNode::Parameter(_)
|
||||||
| AnyNode::ParameterWithDefault(_)
|
| AnyNode::ParameterWithDefault(_)
|
||||||
|
|
@ -525,6 +530,7 @@ impl AnyNode {
|
||||||
| AnyNode::PatternMatchAs(_)
|
| AnyNode::PatternMatchAs(_)
|
||||||
| AnyNode::PatternMatchOr(_)
|
| AnyNode::PatternMatchOr(_)
|
||||||
| AnyNode::Comprehension(_)
|
| AnyNode::Comprehension(_)
|
||||||
|
| AnyNode::Arguments(_)
|
||||||
| AnyNode::Parameters(_)
|
| AnyNode::Parameters(_)
|
||||||
| AnyNode::Parameter(_)
|
| AnyNode::Parameter(_)
|
||||||
| AnyNode::ParameterWithDefault(_)
|
| AnyNode::ParameterWithDefault(_)
|
||||||
|
|
@ -631,6 +637,7 @@ impl AnyNode {
|
||||||
Self::PatternMatchAs(node) => AnyNodeRef::PatternMatchAs(node),
|
Self::PatternMatchAs(node) => AnyNodeRef::PatternMatchAs(node),
|
||||||
Self::PatternMatchOr(node) => AnyNodeRef::PatternMatchOr(node),
|
Self::PatternMatchOr(node) => AnyNodeRef::PatternMatchOr(node),
|
||||||
Self::Comprehension(node) => AnyNodeRef::Comprehension(node),
|
Self::Comprehension(node) => AnyNodeRef::Comprehension(node),
|
||||||
|
Self::Arguments(node) => AnyNodeRef::Arguments(node),
|
||||||
Self::Parameters(node) => AnyNodeRef::Parameters(node),
|
Self::Parameters(node) => AnyNodeRef::Parameters(node),
|
||||||
Self::Parameter(node) => AnyNodeRef::Parameter(node),
|
Self::Parameter(node) => AnyNodeRef::Parameter(node),
|
||||||
Self::ParameterWithDefault(node) => AnyNodeRef::ParameterWithDefault(node),
|
Self::ParameterWithDefault(node) => AnyNodeRef::ParameterWithDefault(node),
|
||||||
|
|
@ -3574,6 +3581,7 @@ impl Ranged for AnyNode {
|
||||||
AnyNode::PatternMatchAs(node) => node.range(),
|
AnyNode::PatternMatchAs(node) => node.range(),
|
||||||
AnyNode::PatternMatchOr(node) => node.range(),
|
AnyNode::PatternMatchOr(node) => node.range(),
|
||||||
AnyNode::Comprehension(node) => node.range(),
|
AnyNode::Comprehension(node) => node.range(),
|
||||||
|
AnyNode::Arguments(node) => node.range(),
|
||||||
AnyNode::Parameters(node) => node.range(),
|
AnyNode::Parameters(node) => node.range(),
|
||||||
AnyNode::Parameter(node) => node.range(),
|
AnyNode::Parameter(node) => node.range(),
|
||||||
AnyNode::ParameterWithDefault(node) => node.range(),
|
AnyNode::ParameterWithDefault(node) => node.range(),
|
||||||
|
|
@ -3661,6 +3669,7 @@ pub enum AnyNodeRef<'a> {
|
||||||
PatternMatchAs(&'a ast::PatternMatchAs),
|
PatternMatchAs(&'a ast::PatternMatchAs),
|
||||||
PatternMatchOr(&'a ast::PatternMatchOr),
|
PatternMatchOr(&'a ast::PatternMatchOr),
|
||||||
Comprehension(&'a Comprehension),
|
Comprehension(&'a Comprehension),
|
||||||
|
Arguments(&'a Arguments),
|
||||||
Parameters(&'a Parameters),
|
Parameters(&'a Parameters),
|
||||||
Parameter(&'a Parameter),
|
Parameter(&'a Parameter),
|
||||||
ParameterWithDefault(&'a ParameterWithDefault),
|
ParameterWithDefault(&'a ParameterWithDefault),
|
||||||
|
|
@ -3747,6 +3756,7 @@ impl AnyNodeRef<'_> {
|
||||||
AnyNodeRef::PatternMatchAs(node) => NonNull::from(*node).cast(),
|
AnyNodeRef::PatternMatchAs(node) => NonNull::from(*node).cast(),
|
||||||
AnyNodeRef::PatternMatchOr(node) => NonNull::from(*node).cast(),
|
AnyNodeRef::PatternMatchOr(node) => NonNull::from(*node).cast(),
|
||||||
AnyNodeRef::Comprehension(node) => NonNull::from(*node).cast(),
|
AnyNodeRef::Comprehension(node) => NonNull::from(*node).cast(),
|
||||||
|
AnyNodeRef::Arguments(node) => NonNull::from(*node).cast(),
|
||||||
AnyNodeRef::Parameters(node) => NonNull::from(*node).cast(),
|
AnyNodeRef::Parameters(node) => NonNull::from(*node).cast(),
|
||||||
AnyNodeRef::Parameter(node) => NonNull::from(*node).cast(),
|
AnyNodeRef::Parameter(node) => NonNull::from(*node).cast(),
|
||||||
AnyNodeRef::ParameterWithDefault(node) => NonNull::from(*node).cast(),
|
AnyNodeRef::ParameterWithDefault(node) => NonNull::from(*node).cast(),
|
||||||
|
|
@ -3839,6 +3849,7 @@ impl AnyNodeRef<'_> {
|
||||||
AnyNodeRef::PatternMatchAs(_) => NodeKind::PatternMatchAs,
|
AnyNodeRef::PatternMatchAs(_) => NodeKind::PatternMatchAs,
|
||||||
AnyNodeRef::PatternMatchOr(_) => NodeKind::PatternMatchOr,
|
AnyNodeRef::PatternMatchOr(_) => NodeKind::PatternMatchOr,
|
||||||
AnyNodeRef::Comprehension(_) => NodeKind::Comprehension,
|
AnyNodeRef::Comprehension(_) => NodeKind::Comprehension,
|
||||||
|
AnyNodeRef::Arguments(_) => NodeKind::Arguments,
|
||||||
AnyNodeRef::Parameters(_) => NodeKind::Parameters,
|
AnyNodeRef::Parameters(_) => NodeKind::Parameters,
|
||||||
AnyNodeRef::Parameter(_) => NodeKind::Parameter,
|
AnyNodeRef::Parameter(_) => NodeKind::Parameter,
|
||||||
AnyNodeRef::ParameterWithDefault(_) => NodeKind::ParameterWithDefault,
|
AnyNodeRef::ParameterWithDefault(_) => NodeKind::ParameterWithDefault,
|
||||||
|
|
@ -3926,6 +3937,7 @@ impl AnyNodeRef<'_> {
|
||||||
| AnyNodeRef::PatternMatchAs(_)
|
| AnyNodeRef::PatternMatchAs(_)
|
||||||
| AnyNodeRef::PatternMatchOr(_)
|
| AnyNodeRef::PatternMatchOr(_)
|
||||||
| AnyNodeRef::Comprehension(_)
|
| AnyNodeRef::Comprehension(_)
|
||||||
|
| AnyNodeRef::Arguments(_)
|
||||||
| AnyNodeRef::Parameters(_)
|
| AnyNodeRef::Parameters(_)
|
||||||
| AnyNodeRef::Parameter(_)
|
| AnyNodeRef::Parameter(_)
|
||||||
| AnyNodeRef::ParameterWithDefault(_)
|
| AnyNodeRef::ParameterWithDefault(_)
|
||||||
|
|
@ -4013,6 +4025,7 @@ impl AnyNodeRef<'_> {
|
||||||
| AnyNodeRef::PatternMatchAs(_)
|
| AnyNodeRef::PatternMatchAs(_)
|
||||||
| AnyNodeRef::PatternMatchOr(_)
|
| AnyNodeRef::PatternMatchOr(_)
|
||||||
| AnyNodeRef::Comprehension(_)
|
| AnyNodeRef::Comprehension(_)
|
||||||
|
| AnyNodeRef::Arguments(_)
|
||||||
| AnyNodeRef::Parameters(_)
|
| AnyNodeRef::Parameters(_)
|
||||||
| AnyNodeRef::Parameter(_)
|
| AnyNodeRef::Parameter(_)
|
||||||
| AnyNodeRef::ParameterWithDefault(_)
|
| AnyNodeRef::ParameterWithDefault(_)
|
||||||
|
|
@ -4099,6 +4112,7 @@ impl AnyNodeRef<'_> {
|
||||||
| AnyNodeRef::PatternMatchAs(_)
|
| AnyNodeRef::PatternMatchAs(_)
|
||||||
| AnyNodeRef::PatternMatchOr(_)
|
| AnyNodeRef::PatternMatchOr(_)
|
||||||
| AnyNodeRef::Comprehension(_)
|
| AnyNodeRef::Comprehension(_)
|
||||||
|
| AnyNodeRef::Arguments(_)
|
||||||
| AnyNodeRef::Parameters(_)
|
| AnyNodeRef::Parameters(_)
|
||||||
| AnyNodeRef::Parameter(_)
|
| AnyNodeRef::Parameter(_)
|
||||||
| AnyNodeRef::ParameterWithDefault(_)
|
| AnyNodeRef::ParameterWithDefault(_)
|
||||||
|
|
@ -4186,6 +4200,7 @@ impl AnyNodeRef<'_> {
|
||||||
| AnyNodeRef::ExprLineMagic(_)
|
| AnyNodeRef::ExprLineMagic(_)
|
||||||
| AnyNodeRef::ExceptHandlerExceptHandler(_)
|
| AnyNodeRef::ExceptHandlerExceptHandler(_)
|
||||||
| AnyNodeRef::Comprehension(_)
|
| AnyNodeRef::Comprehension(_)
|
||||||
|
| AnyNodeRef::Arguments(_)
|
||||||
| AnyNodeRef::Parameters(_)
|
| AnyNodeRef::Parameters(_)
|
||||||
| AnyNodeRef::Parameter(_)
|
| AnyNodeRef::Parameter(_)
|
||||||
| AnyNodeRef::ParameterWithDefault(_)
|
| AnyNodeRef::ParameterWithDefault(_)
|
||||||
|
|
@ -4273,6 +4288,7 @@ impl AnyNodeRef<'_> {
|
||||||
| AnyNodeRef::PatternMatchAs(_)
|
| AnyNodeRef::PatternMatchAs(_)
|
||||||
| AnyNodeRef::PatternMatchOr(_)
|
| AnyNodeRef::PatternMatchOr(_)
|
||||||
| AnyNodeRef::Comprehension(_)
|
| AnyNodeRef::Comprehension(_)
|
||||||
|
| AnyNodeRef::Arguments(_)
|
||||||
| AnyNodeRef::Parameters(_)
|
| AnyNodeRef::Parameters(_)
|
||||||
| AnyNodeRef::Parameter(_)
|
| AnyNodeRef::Parameter(_)
|
||||||
| AnyNodeRef::ParameterWithDefault(_)
|
| AnyNodeRef::ParameterWithDefault(_)
|
||||||
|
|
@ -4985,6 +5001,7 @@ impl Ranged for AnyNodeRef<'_> {
|
||||||
AnyNodeRef::PatternMatchAs(node) => node.range(),
|
AnyNodeRef::PatternMatchAs(node) => node.range(),
|
||||||
AnyNodeRef::PatternMatchOr(node) => node.range(),
|
AnyNodeRef::PatternMatchOr(node) => node.range(),
|
||||||
AnyNodeRef::Comprehension(node) => node.range(),
|
AnyNodeRef::Comprehension(node) => node.range(),
|
||||||
|
AnyNodeRef::Arguments(node) => node.range(),
|
||||||
AnyNodeRef::Parameters(node) => node.range(),
|
AnyNodeRef::Parameters(node) => node.range(),
|
||||||
AnyNodeRef::Parameter(node) => node.range(),
|
AnyNodeRef::Parameter(node) => node.range(),
|
||||||
AnyNodeRef::ParameterWithDefault(node) => node.range(),
|
AnyNodeRef::ParameterWithDefault(node) => node.range(),
|
||||||
|
|
@ -5075,6 +5092,7 @@ pub enum NodeKind {
|
||||||
PatternMatchOr,
|
PatternMatchOr,
|
||||||
TypeIgnoreTypeIgnore,
|
TypeIgnoreTypeIgnore,
|
||||||
Comprehension,
|
Comprehension,
|
||||||
|
Arguments,
|
||||||
Parameters,
|
Parameters,
|
||||||
Parameter,
|
Parameter,
|
||||||
ParameterWithDefault,
|
ParameterWithDefault,
|
||||||
|
|
|
||||||
|
|
@ -158,13 +158,32 @@ impl From<StmtAsyncFunctionDef> for Stmt {
|
||||||
pub struct StmtClassDef {
|
pub struct StmtClassDef {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
pub bases: Vec<Expr>,
|
pub arguments: Option<Arguments>,
|
||||||
pub keywords: Vec<Keyword>,
|
|
||||||
pub body: Vec<Stmt>,
|
pub body: Vec<Stmt>,
|
||||||
pub type_params: Vec<TypeParam>,
|
pub type_params: Vec<TypeParam>,
|
||||||
pub decorator_list: Vec<Decorator>,
|
pub decorator_list: Vec<Decorator>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StmtClassDef {
|
||||||
|
/// Return an iterator over the bases of the class.
|
||||||
|
pub fn bases(&self) -> impl Iterator<Item = &Expr> {
|
||||||
|
self.arguments
|
||||||
|
.as_ref()
|
||||||
|
.map(|arguments| &arguments.args)
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an iterator over the metaclass keywords of the class.
|
||||||
|
pub fn keywords(&self) -> impl Iterator<Item = &Keyword> {
|
||||||
|
self.arguments
|
||||||
|
.as_ref()
|
||||||
|
.map(|arguments| &arguments.keywords)
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<StmtClassDef> for Stmt {
|
impl From<StmtClassDef> for Stmt {
|
||||||
fn from(payload: StmtClassDef) -> Self {
|
fn from(payload: StmtClassDef) -> Self {
|
||||||
Stmt::ClassDef(payload)
|
Stmt::ClassDef(payload)
|
||||||
|
|
@ -836,8 +855,7 @@ impl From<ExprCompare> for Expr {
|
||||||
pub struct ExprCall {
|
pub struct ExprCall {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
pub func: Box<Expr>,
|
pub func: Box<Expr>,
|
||||||
pub args: Vec<Expr>,
|
pub arguments: Arguments,
|
||||||
pub keywords: Vec<Keyword>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ExprCall> for Expr {
|
impl From<ExprCall> for Expr {
|
||||||
|
|
@ -2073,6 +2091,35 @@ pub struct ParameterWithDefault {
|
||||||
pub default: Option<Box<Expr>>,
|
pub default: Option<Box<Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An AST node used to represent the arguments passed to a function call or class definition.
|
||||||
|
///
|
||||||
|
/// For example, given:
|
||||||
|
/// ```python
|
||||||
|
/// foo(1, 2, 3, bar=4, baz=5)
|
||||||
|
/// ```
|
||||||
|
/// The `Arguments` node would span from the left to right parentheses (inclusive), and contain
|
||||||
|
/// the arguments and keyword arguments in the order they appear in the source code.
|
||||||
|
///
|
||||||
|
/// Similarly, given:
|
||||||
|
/// ```python
|
||||||
|
/// class Foo(Bar, baz=1, qux=2):
|
||||||
|
/// pass
|
||||||
|
/// ```
|
||||||
|
/// The `Arguments` node would again span from the left to right parentheses (inclusive), and
|
||||||
|
/// contain the `Bar` argument and the `baz` and `qux` keyword arguments in the order they
|
||||||
|
/// appear in the source code.
|
||||||
|
///
|
||||||
|
/// In the context of a class definition, the Python-style AST refers to the arguments as `bases`,
|
||||||
|
/// as they represent the "explicitly specified base classes", while the keyword arguments are
|
||||||
|
/// typically used for `metaclass`, with any additional arguments being passed to the `metaclass`.
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Arguments {
|
||||||
|
pub range: TextRange,
|
||||||
|
pub args: Vec<Expr>,
|
||||||
|
pub keywords: Vec<Keyword>,
|
||||||
|
}
|
||||||
|
|
||||||
pub type Suite = Vec<Stmt>;
|
pub type Suite = Vec<Stmt>;
|
||||||
|
|
||||||
impl CmpOp {
|
impl CmpOp {
|
||||||
|
|
@ -2934,6 +2981,11 @@ impl Ranged for crate::nodes::Decorator {
|
||||||
self.range
|
self.range
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Ranged for crate::nodes::Arguments {
|
||||||
|
fn range(&self) -> TextRange {
|
||||||
|
self.range
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Ranged for crate::nodes::Parameters {
|
impl Ranged for crate::nodes::Parameters {
|
||||||
fn range(&self) -> TextRange {
|
fn range(&self) -> TextRange {
|
||||||
self.range
|
self.range
|
||||||
|
|
@ -2951,9 +3003,9 @@ mod size_assertions {
|
||||||
use super::*;
|
use super::*;
|
||||||
use static_assertions::assert_eq_size;
|
use static_assertions::assert_eq_size;
|
||||||
|
|
||||||
assert_eq_size!(Stmt, [u8; 168]);
|
assert_eq_size!(Stmt, [u8; 176]);
|
||||||
assert_eq_size!(StmtFunctionDef, [u8; 128]);
|
assert_eq_size!(StmtFunctionDef, [u8; 128]);
|
||||||
assert_eq_size!(StmtClassDef, [u8; 160]);
|
assert_eq_size!(StmtClassDef, [u8; 168]);
|
||||||
assert_eq_size!(StmtTry, [u8; 104]);
|
assert_eq_size!(StmtTry, [u8; 104]);
|
||||||
assert_eq_size!(Expr, [u8; 80]);
|
assert_eq_size!(Expr, [u8; 80]);
|
||||||
assert_eq_size!(Constant, [u8; 32]);
|
assert_eq_size!(Constant, [u8; 32]);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{nodes, Expr, Keyword};
|
use crate::{nodes, Arguments, Expr, Keyword};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
fn relocate_keyword(keyword: &mut Keyword, location: TextRange) {
|
fn relocate_keyword(keyword: &mut Keyword, location: TextRange) {
|
||||||
|
|
@ -116,8 +116,7 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) {
|
||||||
}
|
}
|
||||||
Expr::Call(nodes::ExprCall {
|
Expr::Call(nodes::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments: Arguments { args, keywords, .. },
|
||||||
keywords,
|
|
||||||
range,
|
range,
|
||||||
}) => {
|
}) => {
|
||||||
*range = location;
|
*range = location;
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
pub mod preorder;
|
pub mod preorder;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
self as ast, Alias, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause, ExceptHandler,
|
self as ast, Alias, Arguments, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause,
|
||||||
Expr, ExprContext, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, Stmt,
|
ExceptHandler, Expr, ExprContext, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern,
|
||||||
TypeParam, TypeParamTypeVar, UnaryOp, WithItem,
|
Stmt, TypeParam, TypeParamTypeVar, UnaryOp, WithItem,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A trait for AST visitors. Visits all nodes in the AST recursively in evaluation-order.
|
/// A trait for AST visitors. Visits all nodes in the AST recursively in evaluation-order.
|
||||||
|
|
@ -52,6 +52,9 @@ pub trait Visitor<'a> {
|
||||||
fn visit_format_spec(&mut self, format_spec: &'a Expr) {
|
fn visit_format_spec(&mut self, format_spec: &'a Expr) {
|
||||||
walk_format_spec(self, format_spec);
|
walk_format_spec(self, format_spec);
|
||||||
}
|
}
|
||||||
|
fn visit_arguments(&mut self, arguments: &'a Arguments) {
|
||||||
|
walk_arguments(self, arguments);
|
||||||
|
}
|
||||||
fn visit_parameters(&mut self, parameters: &'a Parameters) {
|
fn visit_parameters(&mut self, parameters: &'a Parameters) {
|
||||||
walk_parameters(self, parameters);
|
walk_parameters(self, parameters);
|
||||||
}
|
}
|
||||||
|
|
@ -143,8 +146,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
}
|
}
|
||||||
Stmt::ClassDef(ast::StmtClassDef {
|
Stmt::ClassDef(ast::StmtClassDef {
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
body,
|
body,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
type_params,
|
type_params,
|
||||||
|
|
@ -156,11 +158,8 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||||
for type_param in type_params {
|
for type_param in type_params {
|
||||||
visitor.visit_type_param(type_param);
|
visitor.visit_type_param(type_param);
|
||||||
}
|
}
|
||||||
for expr in bases {
|
if let Some(arguments) = arguments {
|
||||||
visitor.visit_expr(expr);
|
visitor.visit_arguments(arguments);
|
||||||
}
|
|
||||||
for keyword in keywords {
|
|
||||||
visitor.visit_keyword(keyword);
|
|
||||||
}
|
}
|
||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
}
|
}
|
||||||
|
|
@ -522,17 +521,11 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
|
||||||
}
|
}
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments,
|
||||||
keywords,
|
|
||||||
range: _range,
|
range: _range,
|
||||||
}) => {
|
}) => {
|
||||||
visitor.visit_expr(func);
|
visitor.visit_expr(func);
|
||||||
for expr in args {
|
visitor.visit_arguments(arguments);
|
||||||
visitor.visit_expr(expr);
|
|
||||||
}
|
|
||||||
for keyword in keywords {
|
|
||||||
visitor.visit_keyword(keyword);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Expr::FormattedValue(ast::ExprFormattedValue {
|
Expr::FormattedValue(ast::ExprFormattedValue {
|
||||||
value, format_spec, ..
|
value, format_spec, ..
|
||||||
|
|
@ -645,6 +638,15 @@ pub fn walk_format_spec<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, format_spe
|
||||||
visitor.visit_expr(format_spec);
|
visitor.visit_expr(format_spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_arguments<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, arguments: &'a Arguments) {
|
||||||
|
for arg in &arguments.args {
|
||||||
|
visitor.visit_expr(arg);
|
||||||
|
}
|
||||||
|
for keyword in &arguments.keywords {
|
||||||
|
visitor.visit_keyword(keyword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_parameters<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, parameters: &'a Parameters) {
|
pub fn walk_parameters<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, parameters: &'a Parameters) {
|
||||||
// Defaults are evaluated before annotations.
|
// Defaults are evaluated before annotations.
|
||||||
for arg in ¶meters.posonlyargs {
|
for arg in ¶meters.posonlyargs {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
self as ast, Alias, BoolOp, CmpOp, Comprehension, Constant, Decorator, ElifElseClause,
|
self as ast, Alias, Arguments, BoolOp, CmpOp, Comprehension, Constant, Decorator,
|
||||||
ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, Parameter, ParameterWithDefault,
|
ElifElseClause, ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, Parameter,
|
||||||
Parameters, Pattern, Stmt, TypeParam, TypeParamTypeVar, UnaryOp, WithItem,
|
ParameterWithDefault, Parameters, Pattern, Stmt, TypeParam, TypeParamTypeVar, UnaryOp,
|
||||||
|
WithItem,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Visitor that traverses all nodes recursively in pre-order.
|
/// Visitor that traverses all nodes recursively in pre-order.
|
||||||
|
|
@ -56,6 +57,10 @@ pub trait PreorderVisitor<'a> {
|
||||||
walk_format_spec(self, format_spec);
|
walk_format_spec(self, format_spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_arguments(&mut self, arguments: &'a Arguments) {
|
||||||
|
walk_arguments(self, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_parameters(&mut self, parameters: &'a Parameters) {
|
fn visit_parameters(&mut self, parameters: &'a Parameters) {
|
||||||
walk_parameters(self, parameters);
|
walk_parameters(self, parameters);
|
||||||
}
|
}
|
||||||
|
|
@ -166,8 +171,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::ClassDef(ast::StmtClassDef {
|
Stmt::ClassDef(ast::StmtClassDef {
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
body,
|
body,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
type_params,
|
type_params,
|
||||||
|
|
@ -181,12 +185,8 @@ where
|
||||||
visitor.visit_type_param(type_param);
|
visitor.visit_type_param(type_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
for expr in bases {
|
if let Some(arguments) = arguments {
|
||||||
visitor.visit_expr(expr);
|
visitor.visit_arguments(arguments);
|
||||||
}
|
|
||||||
|
|
||||||
for keyword in keywords {
|
|
||||||
visitor.visit_keyword(keyword);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
|
|
@ -592,17 +592,11 @@ where
|
||||||
|
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments,
|
||||||
keywords,
|
|
||||||
range: _range,
|
range: _range,
|
||||||
}) => {
|
}) => {
|
||||||
visitor.visit_expr(func);
|
visitor.visit_expr(func);
|
||||||
for expr in args {
|
visitor.visit_arguments(arguments);
|
||||||
visitor.visit_expr(expr);
|
|
||||||
}
|
|
||||||
for keyword in keywords {
|
|
||||||
visitor.visit_keyword(keyword);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::FormattedValue(ast::ExprFormattedValue {
|
Expr::FormattedValue(ast::ExprFormattedValue {
|
||||||
|
|
@ -749,6 +743,19 @@ pub fn walk_format_spec<'a, V: PreorderVisitor<'a> + ?Sized>(
|
||||||
visitor.visit_expr(format_spec);
|
visitor.visit_expr(format_spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_arguments<'a, V>(visitor: &mut V, arguments: &'a Arguments)
|
||||||
|
where
|
||||||
|
V: PreorderVisitor<'a> + ?Sized,
|
||||||
|
{
|
||||||
|
for arg in &arguments.args {
|
||||||
|
visitor.visit_expr(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
for keyword in &arguments.keywords {
|
||||||
|
visitor.visit_keyword(keyword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_parameters<'a, V>(visitor: &mut V, parameters: &'a Parameters)
|
pub fn walk_parameters<'a, V>(visitor: &mut V, parameters: &'a Parameters)
|
||||||
where
|
where
|
||||||
V: PreorderVisitor<'a> + ?Sized,
|
V: PreorderVisitor<'a> + ?Sized,
|
||||||
|
|
|
||||||
|
|
@ -273,8 +273,7 @@ impl<'a> Generator<'a> {
|
||||||
}
|
}
|
||||||
Stmt::ClassDef(ast::StmtClassDef {
|
Stmt::ClassDef(ast::StmtClassDef {
|
||||||
name,
|
name,
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
body,
|
body,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
type_params,
|
type_params,
|
||||||
|
|
@ -291,24 +290,25 @@ impl<'a> Generator<'a> {
|
||||||
self.p("class ");
|
self.p("class ");
|
||||||
self.p_id(name);
|
self.p_id(name);
|
||||||
self.unparse_type_params(type_params);
|
self.unparse_type_params(type_params);
|
||||||
let mut first = true;
|
if let Some(arguments) = arguments {
|
||||||
for base in bases {
|
self.p("(");
|
||||||
self.p_if(first, "(");
|
let mut first = true;
|
||||||
self.p_delim(&mut first, ", ");
|
for base in &arguments.args {
|
||||||
self.unparse_expr(base, precedence::MAX);
|
self.p_delim(&mut first, ", ");
|
||||||
}
|
self.unparse_expr(base, precedence::MAX);
|
||||||
for keyword in keywords {
|
|
||||||
self.p_if(first, "(");
|
|
||||||
self.p_delim(&mut first, ", ");
|
|
||||||
if let Some(arg) = &keyword.arg {
|
|
||||||
self.p_id(arg);
|
|
||||||
self.p("=");
|
|
||||||
} else {
|
|
||||||
self.p("**");
|
|
||||||
}
|
}
|
||||||
self.unparse_expr(&keyword.value, precedence::MAX);
|
for keyword in &arguments.keywords {
|
||||||
|
self.p_delim(&mut first, ", ");
|
||||||
|
if let Some(arg) = &keyword.arg {
|
||||||
|
self.p_id(arg);
|
||||||
|
self.p("=");
|
||||||
|
} else {
|
||||||
|
self.p("**");
|
||||||
|
}
|
||||||
|
self.unparse_expr(&keyword.value, precedence::MAX);
|
||||||
|
}
|
||||||
|
self.p(")");
|
||||||
}
|
}
|
||||||
self.p_if(!first, ")");
|
|
||||||
self.p(":");
|
self.p(":");
|
||||||
});
|
});
|
||||||
self.body(body);
|
self.body(body);
|
||||||
|
|
@ -1149,8 +1149,7 @@ impl<'a> Generator<'a> {
|
||||||
}
|
}
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func,
|
func,
|
||||||
args,
|
arguments,
|
||||||
keywords,
|
|
||||||
range: _range,
|
range: _range,
|
||||||
}) => {
|
}) => {
|
||||||
self.unparse_expr(func, precedence::MAX);
|
self.unparse_expr(func, precedence::MAX);
|
||||||
|
|
@ -1162,18 +1161,18 @@ impl<'a> Generator<'a> {
|
||||||
range: _range,
|
range: _range,
|
||||||
})],
|
})],
|
||||||
[],
|
[],
|
||||||
) = (args.as_slice(), keywords.as_slice())
|
) = (arguments.args.as_slice(), arguments.keywords.as_slice())
|
||||||
{
|
{
|
||||||
// Ensure that a single generator doesn't get double-parenthesized.
|
// Ensure that a single generator doesn't get double-parenthesized.
|
||||||
self.unparse_expr(elt, precedence::COMMA);
|
self.unparse_expr(elt, precedence::COMMA);
|
||||||
self.unparse_comp(generators);
|
self.unparse_comp(generators);
|
||||||
} else {
|
} else {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for arg in args {
|
for arg in &arguments.args {
|
||||||
self.p_delim(&mut first, ", ");
|
self.p_delim(&mut first, ", ");
|
||||||
self.unparse_expr(arg, precedence::COMMA);
|
self.unparse_expr(arg, precedence::COMMA);
|
||||||
}
|
}
|
||||||
for kw in keywords {
|
for kw in &arguments.keywords {
|
||||||
self.p_delim(&mut first, ", ");
|
self.p_delim(&mut first, ", ");
|
||||||
if let Some(arg) = &kw.arg {
|
if let Some(arg) = &kw.arg {
|
||||||
self.p_id(arg);
|
self.p_id(arg);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{Expr, ExprCall, Ranged};
|
use ruff_python_ast::{Arguments, Expr, ExprCall, Ranged};
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
use crate::builders::empty_parenthesized_with_dangling_comments;
|
use crate::builders::empty_parenthesized_with_dangling_comments;
|
||||||
|
|
@ -21,8 +21,12 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
|
||||||
let ExprCall {
|
let ExprCall {
|
||||||
range: _,
|
range: _,
|
||||||
func,
|
func,
|
||||||
args,
|
arguments:
|
||||||
keywords,
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
} = item;
|
} = item;
|
||||||
|
|
||||||
// We have a case with `f()` without any argument, which is a special case because we can
|
// We have a case with `f()` without any argument, which is a special case because we can
|
||||||
|
|
|
||||||
|
|
@ -356,8 +356,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
range: _,
|
range: _,
|
||||||
func,
|
func,
|
||||||
args: _,
|
arguments: _,
|
||||||
keywords: _,
|
|
||||||
}) => {
|
}) => {
|
||||||
self.any_parenthesized_expressions = true;
|
self.any_parenthesized_expressions = true;
|
||||||
// Only walk the function, the arguments are always parenthesized
|
// Only walk the function, the arguments are always parenthesized
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::{Ranged, StmtClassDef};
|
use ruff_python_ast::{Arguments, Ranged, StmtClassDef};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_formatter::write;
|
use ruff_formatter::write;
|
||||||
|
|
@ -17,8 +17,7 @@ impl FormatNodeRule<StmtClassDef> for FormatStmtClassDef {
|
||||||
let StmtClassDef {
|
let StmtClassDef {
|
||||||
range: _,
|
range: _,
|
||||||
name,
|
name,
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
body,
|
body,
|
||||||
type_params: _,
|
type_params: _,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
|
|
@ -34,7 +33,12 @@ impl FormatNodeRule<StmtClassDef> for FormatStmtClassDef {
|
||||||
|
|
||||||
write!(f, [text("class"), space(), name.format()])?;
|
write!(f, [text("class"), space(), name.format()])?;
|
||||||
|
|
||||||
if !(bases.is_empty() && keywords.is_empty()) {
|
if arguments
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|Arguments { args, keywords, .. }| {
|
||||||
|
!(args.is_empty() && keywords.is_empty())
|
||||||
|
})
|
||||||
|
{
|
||||||
parenthesized(
|
parenthesized(
|
||||||
"(",
|
"(",
|
||||||
&FormatInheritanceClause {
|
&FormatInheritanceClause {
|
||||||
|
|
@ -75,12 +79,19 @@ struct FormatInheritanceClause<'a> {
|
||||||
impl Format<PyFormatContext<'_>> for FormatInheritanceClause<'_> {
|
impl Format<PyFormatContext<'_>> for FormatInheritanceClause<'_> {
|
||||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
||||||
let StmtClassDef {
|
let StmtClassDef {
|
||||||
bases,
|
arguments:
|
||||||
keywords,
|
Some(Arguments {
|
||||||
|
args: bases,
|
||||||
|
keywords,
|
||||||
|
..
|
||||||
|
}),
|
||||||
name,
|
name,
|
||||||
body,
|
body,
|
||||||
..
|
..
|
||||||
} = self.class_definition;
|
} = self.class_definition
|
||||||
|
else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
let source = f.context().source();
|
let source = f.context().source();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,14 +78,18 @@ type FunctionArgument = (
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse arguments as supplied during a function/lambda *call*.
|
// Parse arguments as supplied during a function/lambda *call*.
|
||||||
pub(crate) fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ArgumentList, LexicalError> {
|
pub(crate) fn parse_arguments(
|
||||||
|
function_arguments: Vec<FunctionArgument>,
|
||||||
|
) -> Result<ArgumentList, LexicalError> {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
let mut keywords = vec![];
|
let mut keywords = vec![];
|
||||||
|
|
||||||
let mut keyword_names =
|
let mut keyword_names = FxHashSet::with_capacity_and_hasher(
|
||||||
FxHashSet::with_capacity_and_hasher(func_args.len(), BuildHasherDefault::default());
|
function_arguments.len(),
|
||||||
|
BuildHasherDefault::default(),
|
||||||
|
);
|
||||||
let mut double_starred = false;
|
let mut double_starred = false;
|
||||||
for (name, value) in func_args {
|
for (name, value) in function_arguments {
|
||||||
if let Some((start, end, name)) = name {
|
if let Some((start, end, name)) = name {
|
||||||
// Check for duplicate keyword arguments in the call.
|
// Check for duplicate keyword arguments in the call.
|
||||||
if let Some(keyword_name) = &name {
|
if let Some(keyword_name) = &name {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use ruff_python_ast::{self as ast, Ranged, MagicKind};
|
||||||
use crate::{
|
use crate::{
|
||||||
Mode,
|
Mode,
|
||||||
lexer::{LexicalError, LexicalErrorType},
|
lexer::{LexicalError, LexicalErrorType},
|
||||||
function::{ArgumentList, parse_args, validate_pos_params, validate_arguments},
|
function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments},
|
||||||
context::set_context,
|
context::set_context,
|
||||||
string::parse_strings,
|
string::parse_strings,
|
||||||
token::{self, StringKind},
|
token::{self, StringKind},
|
||||||
|
|
@ -1194,17 +1194,12 @@ KwargParameter<ParameterType>: Option<Box<ast::Parameter>> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
ClassDef: ast::Stmt = {
|
ClassDef: ast::Stmt = {
|
||||||
<location:@L> <decorator_list:Decorator*> "class" <name:Identifier> <type_params:TypeParamList?> <a:("(" ArgumentList ")")?> ":" <body:Suite> => {
|
<location:@L> <decorator_list:Decorator*> "class" <name:Identifier> <type_params:TypeParamList?> <arguments:Arguments?> ":" <body:Suite> => {
|
||||||
let (bases, keywords) = match a {
|
|
||||||
Some((_, arg, _)) => (arg.args, arg.keywords),
|
|
||||||
None => (vec![], vec![]),
|
|
||||||
};
|
|
||||||
let end_location = body.last().unwrap().end();
|
let end_location = body.last().unwrap().end();
|
||||||
ast::Stmt::ClassDef(
|
ast::Stmt::ClassDef(
|
||||||
ast::StmtClassDef {
|
ast::StmtClassDef {
|
||||||
name,
|
name,
|
||||||
bases,
|
arguments,
|
||||||
keywords,
|
|
||||||
body,
|
body,
|
||||||
decorator_list,
|
decorator_list,
|
||||||
type_params: type_params.unwrap_or_default(),
|
type_params: type_params.unwrap_or_default(),
|
||||||
|
|
@ -1444,9 +1439,9 @@ AtomExpr<Goal>: ast::Expr = {
|
||||||
|
|
||||||
AtomExpr2<Goal>: ast::Expr = {
|
AtomExpr2<Goal>: ast::Expr = {
|
||||||
Atom<Goal>,
|
Atom<Goal>,
|
||||||
<location:@L> <f:AtomExpr2<"all">> "(" <a:ArgumentList> ")" <end_location:@R> => {
|
<location:@L> <f:AtomExpr2<"all">> <arguments:Arguments> <end_location:@R> => {
|
||||||
ast::Expr::Call(
|
ast::Expr::Call(
|
||||||
ast::ExprCall { func: Box::new(f), args: a.args, keywords: a.keywords, range: (location..end_location).into() }
|
ast::ExprCall { func: Box::new(f), arguments, range: (location..end_location).into() }
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
<location:@L> <e:AtomExpr2<"all">> "[" <s:SubscriptList> "]" <end_location:@R> => ast::Expr::Subscript(
|
<location:@L> <e:AtomExpr2<"all">> "[" <s:SubscriptList> "]" <end_location:@R> => ast::Expr::Subscript(
|
||||||
|
|
@ -1663,10 +1658,14 @@ SingleForComprehension: ast::Comprehension = {
|
||||||
ExpressionNoCond: ast::Expr = OrTest<"all">;
|
ExpressionNoCond: ast::Expr = OrTest<"all">;
|
||||||
ComprehensionIf: ast::Expr = "if" <c:ExpressionNoCond> => c;
|
ComprehensionIf: ast::Expr = "if" <c:ExpressionNoCond> => c;
|
||||||
|
|
||||||
ArgumentList: ArgumentList = {
|
Arguments: ast::Arguments = {
|
||||||
<e: Comma<FunctionArgument>> =>? {
|
<location:@L> "(" <e: Comma<FunctionArgument>> ")" <end_location:@R> =>? {
|
||||||
let arg_list = parse_args(e)?;
|
let ArgumentList { args, keywords } = parse_arguments(e)?;
|
||||||
Ok(arg_list)
|
Ok(ast::Arguments {
|
||||||
|
args,
|
||||||
|
keywords,
|
||||||
|
range: (location..end_location).into()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -48,8 +48,7 @@ expression: parse_ast
|
||||||
id: "Abcd",
|
id: "Abcd",
|
||||||
range: 59..63,
|
range: 59..63,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: None,
|
||||||
keywords: [],
|
|
||||||
body: [
|
body: [
|
||||||
Pass(
|
Pass(
|
||||||
StmtPass {
|
StmtPass {
|
||||||
|
|
|
||||||
|
|
@ -24,124 +24,127 @@ Call(
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
GeneratorExp(
|
range: 8..141,
|
||||||
ExprGeneratorExp {
|
args: [
|
||||||
range: 14..139,
|
GeneratorExp(
|
||||||
elt: Name(
|
ExprGeneratorExp {
|
||||||
ExprName {
|
range: 14..139,
|
||||||
range: 14..17,
|
elt: Name(
|
||||||
id: "sql",
|
ExprName {
|
||||||
ctx: Load,
|
range: 14..17,
|
||||||
},
|
id: "sql",
|
||||||
),
|
ctx: Load,
|
||||||
generators: [
|
},
|
||||||
Comprehension {
|
),
|
||||||
range: 22..139,
|
generators: [
|
||||||
target: Name(
|
Comprehension {
|
||||||
ExprName {
|
range: 22..139,
|
||||||
range: 26..29,
|
target: Name(
|
||||||
id: "sql",
|
ExprName {
|
||||||
ctx: Store,
|
range: 26..29,
|
||||||
},
|
id: "sql",
|
||||||
),
|
ctx: Store,
|
||||||
iter: Tuple(
|
},
|
||||||
ExprTuple {
|
),
|
||||||
range: 33..139,
|
iter: Tuple(
|
||||||
elts: [
|
ExprTuple {
|
||||||
IfExp(
|
range: 33..139,
|
||||||
ExprIfExp {
|
elts: [
|
||||||
range: 43..80,
|
IfExp(
|
||||||
test: Name(
|
ExprIfExp {
|
||||||
ExprName {
|
range: 43..80,
|
||||||
range: 65..70,
|
test: Name(
|
||||||
id: "limit",
|
ExprName {
|
||||||
ctx: Load,
|
range: 65..70,
|
||||||
},
|
id: "limit",
|
||||||
),
|
ctx: Load,
|
||||||
body: BinOp(
|
},
|
||||||
ExprBinOp {
|
),
|
||||||
range: 43..61,
|
body: BinOp(
|
||||||
left: Constant(
|
ExprBinOp {
|
||||||
ExprConstant {
|
range: 43..61,
|
||||||
range: 43..53,
|
left: Constant(
|
||||||
value: Str(
|
ExprConstant {
|
||||||
"LIMIT %d",
|
range: 43..53,
|
||||||
),
|
value: Str(
|
||||||
kind: None,
|
"LIMIT %d",
|
||||||
},
|
),
|
||||||
),
|
kind: None,
|
||||||
op: Mod,
|
},
|
||||||
right: Name(
|
),
|
||||||
ExprName {
|
op: Mod,
|
||||||
range: 56..61,
|
right: Name(
|
||||||
id: "limit",
|
ExprName {
|
||||||
ctx: Load,
|
range: 56..61,
|
||||||
},
|
id: "limit",
|
||||||
),
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
orelse: Constant(
|
},
|
||||||
ExprConstant {
|
),
|
||||||
range: 76..80,
|
orelse: Constant(
|
||||||
value: None,
|
ExprConstant {
|
||||||
kind: None,
|
range: 76..80,
|
||||||
},
|
value: None,
|
||||||
),
|
kind: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IfExp(
|
},
|
||||||
ExprIfExp {
|
),
|
||||||
range: 90..132,
|
IfExp(
|
||||||
test: Name(
|
ExprIfExp {
|
||||||
ExprName {
|
range: 90..132,
|
||||||
range: 116..122,
|
test: Name(
|
||||||
id: "offset",
|
ExprName {
|
||||||
ctx: Load,
|
range: 116..122,
|
||||||
},
|
id: "offset",
|
||||||
),
|
ctx: Load,
|
||||||
body: BinOp(
|
},
|
||||||
ExprBinOp {
|
),
|
||||||
range: 91..111,
|
body: BinOp(
|
||||||
left: Constant(
|
ExprBinOp {
|
||||||
ExprConstant {
|
range: 91..111,
|
||||||
range: 91..102,
|
left: Constant(
|
||||||
value: Str(
|
ExprConstant {
|
||||||
"OFFSET %d",
|
range: 91..102,
|
||||||
),
|
value: Str(
|
||||||
kind: None,
|
"OFFSET %d",
|
||||||
},
|
),
|
||||||
),
|
kind: None,
|
||||||
op: Mod,
|
},
|
||||||
right: Name(
|
),
|
||||||
ExprName {
|
op: Mod,
|
||||||
range: 105..111,
|
right: Name(
|
||||||
id: "offset",
|
ExprName {
|
||||||
ctx: Load,
|
range: 105..111,
|
||||||
},
|
id: "offset",
|
||||||
),
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
orelse: Constant(
|
},
|
||||||
ExprConstant {
|
),
|
||||||
range: 128..132,
|
orelse: Constant(
|
||||||
value: None,
|
ExprConstant {
|
||||||
kind: None,
|
range: 128..132,
|
||||||
},
|
value: None,
|
||||||
),
|
kind: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
},
|
||||||
ctx: Load,
|
),
|
||||||
},
|
],
|
||||||
),
|
ctx: Load,
|
||||||
ifs: [],
|
},
|
||||||
is_async: false,
|
),
|
||||||
},
|
ifs: [],
|
||||||
],
|
is_async: false,
|
||||||
},
|
},
|
||||||
),
|
],
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -216,18 +216,21 @@ Module(
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Constant(
|
range: 715..718,
|
||||||
ExprConstant {
|
args: [
|
||||||
range: 716..717,
|
Constant(
|
||||||
value: Int(
|
ExprConstant {
|
||||||
5,
|
range: 716..717,
|
||||||
),
|
value: Int(
|
||||||
kind: None,
|
5,
|
||||||
},
|
),
|
||||||
),
|
kind: None,
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
body: [
|
body: [
|
||||||
|
|
|
||||||
|
|
@ -66,16 +66,19 @@ expression: parse_ast
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Name(
|
range: 67..73,
|
||||||
ExprName {
|
args: [
|
||||||
range: 68..72,
|
Name(
|
||||||
id: "rest",
|
ExprName {
|
||||||
ctx: Load,
|
range: 68..72,
|
||||||
},
|
id: "rest",
|
||||||
),
|
ctx: Load,
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -195,16 +198,19 @@ expression: parse_ast
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Name(
|
range: 170..177,
|
||||||
ExprName {
|
args: [
|
||||||
range: 171..176,
|
Name(
|
||||||
id: "label",
|
ExprName {
|
||||||
ctx: Load,
|
range: 171..176,
|
||||||
},
|
id: "label",
|
||||||
),
|
ctx: Load,
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -122,42 +122,45 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Starred(
|
range: 92..103,
|
||||||
ExprStarred {
|
args: [
|
||||||
range: 93..99,
|
Starred(
|
||||||
value: BinOp(
|
ExprStarred {
|
||||||
ExprBinOp {
|
range: 93..99,
|
||||||
range: 94..99,
|
value: BinOp(
|
||||||
left: Name(
|
ExprBinOp {
|
||||||
ExprName {
|
range: 94..99,
|
||||||
range: 94..95,
|
left: Name(
|
||||||
id: "a",
|
ExprName {
|
||||||
ctx: Load,
|
range: 94..95,
|
||||||
},
|
id: "a",
|
||||||
),
|
ctx: Load,
|
||||||
op: Add,
|
},
|
||||||
right: Name(
|
),
|
||||||
ExprName {
|
op: Add,
|
||||||
range: 98..99,
|
right: Name(
|
||||||
id: "b",
|
ExprName {
|
||||||
ctx: Load,
|
range: 98..99,
|
||||||
},
|
id: "b",
|
||||||
),
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ctx: Load,
|
},
|
||||||
},
|
),
|
||||||
),
|
ctx: Load,
|
||||||
Name(
|
},
|
||||||
ExprName {
|
),
|
||||||
range: 101..102,
|
Name(
|
||||||
id: "c",
|
ExprName {
|
||||||
ctx: Load,
|
range: 101..102,
|
||||||
},
|
id: "c",
|
||||||
),
|
ctx: Load,
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -283,22 +286,25 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
UnaryOp(
|
range: 224..228,
|
||||||
ExprUnaryOp {
|
args: [
|
||||||
range: 225..227,
|
UnaryOp(
|
||||||
op: USub,
|
ExprUnaryOp {
|
||||||
operand: Name(
|
range: 225..227,
|
||||||
ExprName {
|
op: USub,
|
||||||
range: 226..227,
|
operand: Name(
|
||||||
id: "a",
|
ExprName {
|
||||||
ctx: Load,
|
range: 226..227,
|
||||||
},
|
id: "a",
|
||||||
),
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
op: Mult,
|
op: Mult,
|
||||||
|
|
@ -339,8 +345,11 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 270..272,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
attr: Identifier {
|
attr: Identifier {
|
||||||
|
|
@ -368,16 +377,19 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Tuple(
|
range: 297..301,
|
||||||
ExprTuple {
|
args: [
|
||||||
range: 298..300,
|
Tuple(
|
||||||
elts: [],
|
ExprTuple {
|
||||||
ctx: Load,
|
range: 298..300,
|
||||||
},
|
elts: [],
|
||||||
),
|
ctx: Load,
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
attr: Identifier {
|
attr: Identifier {
|
||||||
|
|
@ -405,16 +417,19 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Tuple(
|
range: 328..333,
|
||||||
ExprTuple {
|
args: [
|
||||||
range: 329..331,
|
Tuple(
|
||||||
elts: [],
|
ExprTuple {
|
||||||
ctx: Load,
|
range: 329..331,
|
||||||
},
|
elts: [],
|
||||||
),
|
ctx: Load,
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
attr: Identifier {
|
attr: Identifier {
|
||||||
|
|
@ -563,8 +578,11 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 476..478,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
slice: Slice(
|
slice: Slice(
|
||||||
|
|
@ -771,33 +789,39 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Call(
|
range: 625..636,
|
||||||
ExprCall {
|
args: [
|
||||||
range: 626..635,
|
Call(
|
||||||
func: Name(
|
ExprCall {
|
||||||
ExprName {
|
range: 626..635,
|
||||||
range: 626..631,
|
func: Name(
|
||||||
id: "match",
|
ExprName {
|
||||||
ctx: Load,
|
range: 626..631,
|
||||||
},
|
id: "match",
|
||||||
),
|
ctx: Load,
|
||||||
args: [
|
|
||||||
Constant(
|
|
||||||
ExprConstant {
|
|
||||||
range: 632..634,
|
|
||||||
value: Int(
|
|
||||||
12,
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 631..635,
|
||||||
},
|
args: [
|
||||||
),
|
Constant(
|
||||||
],
|
ExprConstant {
|
||||||
keywords: [],
|
range: 632..634,
|
||||||
|
value: Int(
|
||||||
|
12,
|
||||||
|
),
|
||||||
|
kind: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_parser/src/parser.rs
|
source: crates/ruff_python_parser/src/parser.rs
|
||||||
expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
Assign(
|
Assign(
|
||||||
|
|
@ -37,8 +37,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 17..19,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -176,8 +179,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 88..90,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -249,8 +255,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 165..167,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -324,35 +333,41 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Call(
|
range: 220..241,
|
||||||
ExprCall {
|
args: [
|
||||||
range: 221..240,
|
Call(
|
||||||
func: Attribute(
|
ExprCall {
|
||||||
ExprAttribute {
|
range: 221..240,
|
||||||
range: 221..238,
|
func: Attribute(
|
||||||
value: Constant(
|
ExprAttribute {
|
||||||
ExprConstant {
|
range: 221..238,
|
||||||
range: 221..227,
|
value: Constant(
|
||||||
value: Int(
|
ExprConstant {
|
||||||
11,
|
range: 221..227,
|
||||||
),
|
value: Int(
|
||||||
kind: None,
|
11,
|
||||||
|
),
|
||||||
|
kind: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
attr: Identifier {
|
||||||
|
id: "bit_length",
|
||||||
|
range: 228..238,
|
||||||
},
|
},
|
||||||
),
|
ctx: Load,
|
||||||
attr: Identifier {
|
|
||||||
id: "bit_length",
|
|
||||||
range: 228..238,
|
|
||||||
},
|
},
|
||||||
ctx: Load,
|
),
|
||||||
|
arguments: Arguments {
|
||||||
|
range: 238..240,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
},
|
},
|
||||||
),
|
},
|
||||||
args: [],
|
),
|
||||||
keywords: [],
|
],
|
||||||
},
|
keywords: [],
|
||||||
),
|
},
|
||||||
],
|
|
||||||
keywords: [],
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -391,8 +406,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 263..265,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -431,8 +449,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 287..289,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -504,8 +525,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [],
|
arguments: Arguments {
|
||||||
keywords: [],
|
range: 327..329,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -639,16 +663,19 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
kind: None,
|
kind: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Name(
|
range: 387..391,
|
||||||
ExprName {
|
args: [
|
||||||
range: 388..390,
|
Name(
|
||||||
id: "no",
|
ExprName {
|
||||||
ctx: Load,
|
range: 388..390,
|
||||||
},
|
id: "no",
|
||||||
),
|
ctx: Load,
|
||||||
],
|
},
|
||||||
keywords: [],
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -10,23 +10,28 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 6..9,
|
range: 6..9,
|
||||||
},
|
},
|
||||||
bases: [
|
arguments: Some(
|
||||||
Name(
|
Arguments {
|
||||||
ExprName {
|
range: 9..15,
|
||||||
range: 10..11,
|
args: [
|
||||||
id: "A",
|
Name(
|
||||||
ctx: Load,
|
ExprName {
|
||||||
},
|
range: 10..11,
|
||||||
),
|
id: "A",
|
||||||
Name(
|
ctx: Load,
|
||||||
ExprName {
|
},
|
||||||
range: 13..14,
|
),
|
||||||
id: "B",
|
Name(
|
||||||
ctx: Load,
|
ExprName {
|
||||||
},
|
range: 13..14,
|
||||||
),
|
id: "B",
|
||||||
],
|
ctx: Load,
|
||||||
keywords: [],
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
FunctionDef(
|
FunctionDef(
|
||||||
StmtFunctionDef {
|
StmtFunctionDef {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_parser/src/parser.rs
|
source: crates/ruff_python_parser/src/parser.rs
|
||||||
expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
ClassDef(
|
ClassDef(
|
||||||
|
|
@ -10,8 +10,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 16..19,
|
range: 16..19,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: Some(
|
||||||
keywords: [],
|
Arguments {
|
||||||
|
range: 22..24,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
Expr(
|
Expr(
|
||||||
StmtExpr {
|
StmtExpr {
|
||||||
|
|
@ -48,8 +53,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 58..61,
|
range: 58..61,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: Some(
|
||||||
keywords: [],
|
Arguments {
|
||||||
|
range: 69..71,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
Expr(
|
Expr(
|
||||||
StmtExpr {
|
StmtExpr {
|
||||||
|
|
@ -94,8 +104,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 111..114,
|
range: 111..114,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: Some(
|
||||||
keywords: [],
|
Arguments {
|
||||||
|
range: 131..133,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
Expr(
|
Expr(
|
||||||
StmtExpr {
|
StmtExpr {
|
||||||
|
|
@ -155,8 +170,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 165..168,
|
range: 165..168,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: Some(
|
||||||
keywords: [],
|
Arguments {
|
||||||
|
range: 174..176,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
Expr(
|
Expr(
|
||||||
StmtExpr {
|
StmtExpr {
|
||||||
|
|
@ -203,8 +223,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 206..209,
|
range: 206..209,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: Some(
|
||||||
keywords: [],
|
Arguments {
|
||||||
|
range: 216..218,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
Expr(
|
Expr(
|
||||||
StmtExpr {
|
StmtExpr {
|
||||||
|
|
@ -251,8 +276,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 246..249,
|
range: 246..249,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: Some(
|
||||||
keywords: [],
|
Arguments {
|
||||||
|
range: 254..256,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
Expr(
|
Expr(
|
||||||
StmtExpr {
|
StmtExpr {
|
||||||
|
|
@ -288,8 +318,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 281..284,
|
range: 281..284,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: Some(
|
||||||
keywords: [],
|
Arguments {
|
||||||
|
range: 289..291,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
Expr(
|
Expr(
|
||||||
StmtExpr {
|
StmtExpr {
|
||||||
|
|
@ -325,8 +360,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
range: 318..321,
|
range: 318..321,
|
||||||
},
|
},
|
||||||
bases: [],
|
arguments: Some(
|
||||||
keywords: [],
|
Arguments {
|
||||||
|
range: 341..343,
|
||||||
|
args: [],
|
||||||
|
keywords: [],
|
||||||
|
},
|
||||||
|
),
|
||||||
body: [
|
body: [
|
||||||
Pass(
|
Pass(
|
||||||
StmtPass {
|
StmtPass {
|
||||||
|
|
|
||||||
|
|
@ -16,37 +16,40 @@ expression: parse_ast
|
||||||
ctx: Load,
|
ctx: Load,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
args: [
|
arguments: Arguments {
|
||||||
Constant(
|
range: 7..32,
|
||||||
ExprConstant {
|
args: [
|
||||||
range: 8..20,
|
Constant(
|
||||||
value: Str(
|
|
||||||
"positional",
|
|
||||||
),
|
|
||||||
kind: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
keywords: [
|
|
||||||
Keyword {
|
|
||||||
range: 22..31,
|
|
||||||
arg: Some(
|
|
||||||
Identifier {
|
|
||||||
id: "keyword",
|
|
||||||
range: 22..29,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
value: Constant(
|
|
||||||
ExprConstant {
|
ExprConstant {
|
||||||
range: 30..31,
|
range: 8..20,
|
||||||
value: Int(
|
value: Str(
|
||||||
2,
|
"positional",
|
||||||
),
|
),
|
||||||
kind: None,
|
kind: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
],
|
||||||
],
|
keywords: [
|
||||||
|
Keyword {
|
||||||
|
range: 22..31,
|
||||||
|
arg: Some(
|
||||||
|
Identifier {
|
||||||
|
id: "keyword",
|
||||||
|
range: 22..29,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
value: Constant(
|
||||||
|
ExprConstant {
|
||||||
|
range: 30..31,
|
||||||
|
value: Int(
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
kind: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue