mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +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.
|
||||
/// 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(
|
||||
locator: &Locator,
|
||||
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_diagnostics::Diagnostic;
|
||||
|
@ -211,11 +211,14 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
}
|
||||
}
|
||||
if checker.enabled(Rule::MixedCaseVariableInClassScope) {
|
||||
if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) =
|
||||
if let ScopeKind::Class(ast::StmtClassDef { arguments, .. }) =
|
||||
&checker.semantic.scope().kind
|
||||
{
|
||||
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(
|
||||
call @ ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
},
|
||||
) => {
|
||||
|
|
|
@ -363,8 +363,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
Stmt::ClassDef(
|
||||
class_def @ ast::StmtClassDef {
|
||||
name,
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
type_params: _,
|
||||
decorator_list,
|
||||
body,
|
||||
|
@ -376,20 +375,24 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
}
|
||||
if checker.enabled(Rule::DjangoExcludeWithModelForm) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::DjangoAllWithModelForm) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
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.enabled(Rule::DjangoModelWithoutDunderStr) {
|
||||
|
@ -425,7 +428,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
if checker.enabled(Rule::ErrorSuffixOnExceptionName) {
|
||||
if let Some(diagnostic) = pep8_naming::rules::error_suffix_on_exception_name(
|
||||
stmt,
|
||||
bases,
|
||||
arguments.as_ref(),
|
||||
name,
|
||||
&checker.settings.pep8_naming.ignore_names,
|
||||
) {
|
||||
|
@ -438,7 +441,11 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
Rule::EmptyMethodWithoutAbstractDecorator,
|
||||
]) {
|
||||
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());
|
||||
}
|
||||
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) {
|
||||
flake8_slots::rules::no_slots_in_str_subclass(checker, stmt, class_def);
|
||||
|
|
|
@ -31,8 +31,9 @@ use std::path::Path;
|
|||
use itertools::Itertools;
|
||||
use log::error;
|
||||
use ruff_python_ast::{
|
||||
self as ast, Comprehension, Constant, ElifElseClause, ExceptHandler, Expr, ExprContext,
|
||||
Keyword, Parameter, ParameterWithDefault, Parameters, Pattern, Ranged, Stmt, Suite, UnaryOp,
|
||||
self as ast, Arguments, Comprehension, Constant, ElifElseClause, ExceptHandler, Expr,
|
||||
ExprContext, Keyword, Parameter, ParameterWithDefault, Parameters, Pattern, Ranged, Stmt,
|
||||
Suite, UnaryOp,
|
||||
};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
|
||||
|
@ -552,8 +553,7 @@ where
|
|||
Stmt::ClassDef(
|
||||
class_def @ ast::StmtClassDef {
|
||||
body,
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
decorator_list,
|
||||
type_params,
|
||||
..
|
||||
|
@ -568,11 +568,9 @@ where
|
|||
for type_param in type_params {
|
||||
self.visit_type_param(type_param);
|
||||
}
|
||||
for expr in bases {
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
for keyword in keywords {
|
||||
self.visit_keyword(keyword);
|
||||
|
||||
if let Some(arguments) = arguments {
|
||||
self.visit_arguments(arguments);
|
||||
}
|
||||
|
||||
let definition = docstrings::extraction::extract_definition(
|
||||
|
@ -837,8 +835,7 @@ where
|
|||
match expr {
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args: _,
|
||||
keywords: _,
|
||||
arguments: _,
|
||||
range: _,
|
||||
}) => {
|
||||
if let Expr::Name(ast::ExprName { id, ctx, range: _ }) = func.as_ref() {
|
||||
|
@ -924,8 +921,12 @@ where
|
|||
}
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) => {
|
||||
self.visit_expr(func);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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_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.
|
||||
let Expr::Call(ast::ExprCall { func, keywords, .. }) = value else {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
arguments: Arguments { keywords, .. },
|
||||
..
|
||||
}) = value
|
||||
else {
|
||||
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_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 body.iter().any(|stmt| {
|
||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
||||
if let Expr::Call(ast::ExprCall { func, keywords, .. }) = value.as_ref() {
|
||||
if let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
arguments: Arguments { keywords, .. },
|
||||
..
|
||||
}) = value.as_ref()
|
||||
{
|
||||
if logging::is_logger_candidate(
|
||||
func,
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -139,14 +139,17 @@ pub(crate) fn abstract_base_class(
|
|||
checker: &mut Checker,
|
||||
stmt: &Stmt,
|
||||
name: &str,
|
||||
bases: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
arguments: Option<&Arguments>,
|
||||
body: &[Stmt],
|
||||
) {
|
||||
if bases.len() + keywords.len() != 1 {
|
||||
let Some(Arguments { args, keywords, .. }) = arguments else {
|
||||
return;
|
||||
};
|
||||
|
||||
if args.len() + keywords.len() != 1 {
|
||||
return;
|
||||
}
|
||||
if !is_abc_class(bases, keywords, checker.semantic()) {
|
||||
if !is_abc_class(args, keywords, checker.semantic()) {
|
||||
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_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
|
@ -53,12 +53,15 @@ fn assertion_error(msg: Option<&Expr>) -> Stmt {
|
|||
ctx: ExprContext::Load,
|
||||
range: TextRange::default(),
|
||||
})),
|
||||
args: if let Some(msg) = msg {
|
||||
vec![msg.clone()]
|
||||
} else {
|
||||
vec![]
|
||||
arguments: Arguments {
|
||||
args: if let Some(msg) = msg {
|
||||
vec![msg.clone()]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
}))),
|
||||
cause: None,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -81,8 +81,12 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, items: &[WithItem])
|
|||
for item in items {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) = &item.context_expr
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -130,8 +130,12 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
|
|||
match expr {
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) => {
|
||||
match func.as_ref() {
|
||||
|
|
|
@ -68,7 +68,7 @@ pub(crate) fn re_sub_positional_args(checker: &mut Checker, call: &ast::ExprCall
|
|||
return;
|
||||
};
|
||||
|
||||
if call.args.len() > method.num_args() {
|
||||
if call.arguments.args.len() > method.num_args() {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
ReSubPositionalArgs { method },
|
||||
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_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 {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
..
|
||||
}) = &arg
|
||||
else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::Decorator;
|
||||
use ruff_python_ast::{Arguments, Decorator};
|
||||
use ruff_text_size::TextRange;
|
||||
|
||||
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
|
||||
// subscripting and not through attribute access.
|
||||
if class_def
|
||||
.bases
|
||||
.iter()
|
||||
.bases()
|
||||
.any(|base| checker.semantic().match_typing_expr(base, "TypedDict"))
|
||||
{
|
||||
return;
|
||||
|
@ -133,15 +132,18 @@ fn is_standard_library_override(
|
|||
class_def: &ast::StmtClassDef,
|
||||
model: &SemanticModel,
|
||||
) -> bool {
|
||||
let Some(Arguments { args: bases, .. }) = class_def.arguments.as_ref() else {
|
||||
return false;
|
||||
};
|
||||
match name {
|
||||
// Ex) `Event#set`
|
||||
"set" => class_def.bases.iter().any(|base| {
|
||||
"set" => bases.iter().any(|base| {
|
||||
model
|
||||
.resolve_call_path(base)
|
||||
.is_some_and(|call_path| matches!(call_path.as_slice(), ["threading", "Event"]))
|
||||
}),
|
||||
// Ex) `Filter#filter`
|
||||
"filter" => class_def.bases.iter().any(|base| {
|
||||
"filter" => bases.iter().any(|base| {
|
||||
model
|
||||
.resolve_call_path(base)
|
||||
.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_macros::{derive_message_formats, violation};
|
||||
|
@ -88,7 +88,9 @@ pub(crate) fn unnecessary_double_cast_or_process(
|
|||
};
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
keywords: inner_kw,
|
||||
arguments: Arguments {
|
||||
keywords: inner_kw, ..
|
||||
},
|
||||
..
|
||||
}) = arg
|
||||
else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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::{Diagnostic, Fix};
|
||||
|
@ -111,7 +111,12 @@ pub(crate) fn unnecessary_map(
|
|||
}
|
||||
ObjectType::List | ObjectType::Set => {
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
@ -137,7 +142,12 @@ pub(crate) fn unnecessary_map(
|
|||
}
|
||||
ObjectType::Dict => {
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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_diagnostics::{Diagnostic, Violation};
|
||||
|
@ -59,7 +59,11 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
|||
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 {
|
||||
let attr = attr.as_str();
|
||||
// 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_macros::{derive_message_formats, violation};
|
||||
|
@ -49,15 +49,18 @@ impl Violation for DjangoAllWithModelForm {
|
|||
/// DJ007
|
||||
pub(crate) fn all_with_model_form(
|
||||
checker: &Checker,
|
||||
bases: &[Expr],
|
||||
arguments: Option<&Arguments>,
|
||||
body: &[Stmt],
|
||||
) -> Option<Diagnostic> {
|
||||
if !bases
|
||||
.iter()
|
||||
.any(|base| is_model_form(base, checker.semantic()))
|
||||
{
|
||||
if !arguments.is_some_and(|arguments| {
|
||||
arguments
|
||||
.args
|
||||
.iter()
|
||||
.any(|base| is_model_form(base, checker.semantic()))
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
|
||||
for element in body {
|
||||
let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else {
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -47,15 +47,18 @@ impl Violation for DjangoExcludeWithModelForm {
|
|||
/// DJ006
|
||||
pub(crate) fn exclude_with_model_form(
|
||||
checker: &Checker,
|
||||
bases: &[Expr],
|
||||
arguments: Option<&Arguments>,
|
||||
body: &[Stmt],
|
||||
) -> Option<Diagnostic> {
|
||||
if !bases
|
||||
.iter()
|
||||
.any(|base| is_model_form(base, checker.semantic()))
|
||||
{
|
||||
if !arguments.is_some_and(|arguments| {
|
||||
arguments
|
||||
.args
|
||||
.iter()
|
||||
.any(|base| is_model_form(base, checker.semantic()))
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
|
||||
for element in body {
|
||||
let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else {
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -54,10 +54,13 @@ impl Violation for DjangoModelWithoutDunderStr {
|
|||
pub(crate) fn model_without_dunder_str(
|
||||
checker: &mut Checker,
|
||||
ast::StmtClassDef {
|
||||
name, bases, body, ..
|
||||
name,
|
||||
arguments,
|
||||
body,
|
||||
..
|
||||
}: &ast::StmtClassDef,
|
||||
) {
|
||||
if !is_non_abstract_model(bases, body, checker.semantic()) {
|
||||
if !is_non_abstract_model(arguments.as_ref(), body, checker.semantic()) {
|
||||
return;
|
||||
}
|
||||
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 {
|
||||
for base in bases {
|
||||
if is_model_abstract(body) {
|
||||
continue;
|
||||
}
|
||||
if helpers::is_model(base, semantic) {
|
||||
return true;
|
||||
}
|
||||
fn is_non_abstract_model(
|
||||
arguments: Option<&Arguments>,
|
||||
body: &[Stmt],
|
||||
semantic: &SemanticModel,
|
||||
) -> bool {
|
||||
let Some(Arguments { args: bases, .. }) = arguments else {
|
||||
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.
|
||||
|
|
|
@ -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_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> {
|
||||
let Expr::Call(ast::ExprCall { func, keywords, .. }) = value else {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
arguments: Arguments { keywords, .. },
|
||||
..
|
||||
}) = value
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -143,13 +143,15 @@ fn get_element_type(element: &Stmt, semantic: &SemanticModel) -> Option<ContentT
|
|||
/// DJ012
|
||||
pub(crate) fn unordered_body_content_in_model(
|
||||
checker: &mut Checker,
|
||||
bases: &[Expr],
|
||||
arguments: Option<&Arguments>,
|
||||
body: &[Stmt],
|
||||
) {
|
||||
if !bases
|
||||
.iter()
|
||||
.any(|base| helpers::is_model(base, checker.semantic()))
|
||||
{
|
||||
if !arguments.is_some_and(|arguments| {
|
||||
arguments
|
||||
.args
|
||||
.iter()
|
||||
.any(|base| helpers::is_model(base, checker.semantic()))
|
||||
}) {
|
||||
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_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
|
@ -174,7 +174,11 @@ impl Violation for DotFormatInException {
|
|||
|
||||
/// EM101, EM102, EM103
|
||||
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() {
|
||||
match first {
|
||||
// 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_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
|
||||
.semantic()
|
||||
.resolve_call_path(func)
|
||||
|
|
|
@ -5,7 +5,7 @@ use itertools::Either::{Left, Right};
|
|||
|
||||
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::{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() {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) = &call
|
||||
else {
|
||||
|
@ -118,8 +122,12 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
|
|||
.map(|expr| {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func: _,
|
||||
args,
|
||||
keywords: _,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords: _,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) = expr
|
||||
else {
|
||||
|
@ -161,8 +169,11 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
|
|||
});
|
||||
let node3 = Expr::Call(ast::ExprCall {
|
||||
func: Box::new(node2),
|
||||
args: vec![node],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![node],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
});
|
||||
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 ruff_diagnostics::Diagnostic;
|
||||
|
@ -54,7 +54,11 @@ impl Violation for NonUniqueEnums {
|
|||
|
||||
/// PIE796
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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_macros::{derive_message_formats, violation};
|
||||
|
@ -186,7 +186,7 @@ pub(crate) fn non_self_return_type(
|
|||
match name {
|
||||
"__iter__" => {
|
||||
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(
|
||||
NonSelfReturnType {
|
||||
|
@ -199,7 +199,7 @@ pub(crate) fn non_self_return_type(
|
|||
}
|
||||
"__aiter__" => {
|
||||
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(
|
||||
NonSelfReturnType {
|
||||
|
@ -248,7 +248,10 @@ fn is_self(expr: &Expr, semantic: &SemanticModel) -> bool {
|
|||
}
|
||||
|
||||
/// 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| {
|
||||
semantic
|
||||
.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`.
|
||||
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| {
|
||||
semantic
|
||||
.resolve_call_path(map_subscript(expr))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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};
|
||||
|
@ -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.
|
||||
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| {
|
||||
semantic.resolve_call_path(expr).is_some_and(|call_path| {
|
||||
matches!(
|
||||
|
@ -565,8 +569,8 @@ pub(crate) fn unannotated_assignment_in_stub(
|
|||
return;
|
||||
}
|
||||
|
||||
if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) = checker.semantic().scope().kind {
|
||||
if is_enum(bases, checker.semantic()) {
|
||||
if let ScopeKind::Class(ast::StmtClassDef { arguments, .. }) = checker.semantic().scope().kind {
|
||||
if is_enum(arguments.as_ref(), checker.semantic()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, 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 crate::checkers::ast::Checker;
|
||||
|
@ -216,8 +216,12 @@ pub(crate) fn unused_private_protocol(
|
|||
let Some(source) = binding.source else {
|
||||
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 {
|
||||
continue;
|
||||
};
|
||||
|
@ -304,8 +308,11 @@ pub(crate) fn unused_private_typed_dict(
|
|||
let Some(source) = binding.source else {
|
||||
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 {
|
||||
continue;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use ruff_python_ast::Decorator;
|
||||
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_diagnostics::{AlwaysAutofixableViolation, Violation};
|
||||
|
@ -476,8 +476,12 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &D
|
|||
match &decorator.expression {
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) => {
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -106,8 +106,12 @@ fn check_mark_parentheses(checker: &mut Checker, decorator: &Decorator, call_pat
|
|||
match &decorator.expression {
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) => {
|
||||
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;
|
||||
|
||||
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() {
|
||||
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_text_size::TextRange;
|
||||
|
||||
|
@ -414,7 +414,11 @@ fn handle_value_rows(
|
|||
pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Decorator]) {
|
||||
for decorator in decorators {
|
||||
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 let Some(names) = args.get(0) {
|
||||
check_names(checker, decorator, names);
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::hash::BuildHasherDefault;
|
|||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
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 rustc_hash::FxHashMap;
|
||||
|
@ -355,8 +355,11 @@ impl UnittestAssert {
|
|||
};
|
||||
let node1 = ast::ExprCall {
|
||||
func: Box::new(node.into()),
|
||||
args: vec![(**obj).clone(), (**cls).clone()],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![(**obj).clone(), (**cls).clone()],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
};
|
||||
let isinstance = node1.into();
|
||||
|
@ -396,8 +399,11 @@ impl UnittestAssert {
|
|||
};
|
||||
let node2 = ast::ExprCall {
|
||||
func: Box::new(node1.into()),
|
||||
args: vec![(**regex).clone(), (**text).clone()],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![(**regex).clone(), (**text).clone()],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
};
|
||||
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_text_size::{TextRange, TextSize};
|
||||
|
||||
|
@ -47,31 +47,37 @@ impl AlwaysAutofixableViolation for UnnecessaryParenOnRaiseException {
|
|||
|
||||
/// RSE102
|
||||
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,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) = expr
|
||||
{
|
||||
if args.is_empty() && keywords.is_empty() {
|
||||
// `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;
|
||||
}
|
||||
else {
|
||||
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);
|
||||
if args.is_empty() && keywords.is_empty() {
|
||||
// `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())
|
||||
.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::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 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.
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) = &call
|
||||
else {
|
||||
|
@ -351,7 +355,11 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
|
|||
if indices.len() > 1 {
|
||||
// Grab the target used in each duplicate `isinstance` call (e.g., `obj` in
|
||||
// `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")
|
||||
} else {
|
||||
unreachable!("Indices should only contain `isinstance` calls")
|
||||
|
@ -374,7 +382,11 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
|
|||
.iter()
|
||||
.map(|index| &values[*index])
|
||||
.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")
|
||||
};
|
||||
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 {
|
||||
func: Box::new(node1.into()),
|
||||
args: vec![target.clone(), node.into()],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![target.clone(), node.into()],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
};
|
||||
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_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')`
|
||||
let Expr::Call(ast::ExprCall { func, args, .. }) = expr else {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
arguments: Arguments { args, .. },
|
||||
..
|
||||
}) = expr
|
||||
else {
|
||||
return;
|
||||
};
|
||||
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) {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
range: _,
|
||||
}) = expr
|
||||
else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use log::error;
|
||||
use ruff_python_ast::{
|
||||
self as ast, CmpOp, Constant, ElifElseClause, Expr, ExprContext, Identifier, Ranged, Stmt,
|
||||
StmtIf,
|
||||
self as ast, Arguments, CmpOp, Constant, ElifElseClause, Expr, ExprContext, Identifier, Ranged,
|
||||
Stmt,
|
||||
};
|
||||
use ruff_text_size::TextRange;
|
||||
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`
|
||||
fn nested_if_body(stmt_if: &StmtIf) -> Option<(&[Stmt], TextRange, bool)> {
|
||||
let StmtIf {
|
||||
fn nested_if_body(stmt_if: &ast::StmtIf) -> Option<(&[Stmt], TextRange, bool)> {
|
||||
let ast::StmtIf {
|
||||
test,
|
||||
body,
|
||||
elif_else_clauses,
|
||||
|
@ -361,7 +361,11 @@ fn nested_if_body(stmt_if: &StmtIf) -> Option<(&[Stmt], TextRange, bool)> {
|
|||
}
|
||||
|
||||
/// 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 {
|
||||
return;
|
||||
};
|
||||
|
@ -538,8 +542,11 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt: &Stmt) {
|
|||
};
|
||||
let node1 = ast::ExprCall {
|
||||
func: Box::new(node.into()),
|
||||
args: vec![if_test.clone()],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![if_test.clone()],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
};
|
||||
let node2 = ast::StmtReturn {
|
||||
|
@ -692,7 +699,7 @@ fn body_range(branch: &IfElifBranch, locator: &Locator) -> TextRange {
|
|||
}
|
||||
|
||||
/// 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();
|
||||
while let Some(current_branch) = branches_iter.next() {
|
||||
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
|
||||
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:
|
||||
// * 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`.
|
||||
// * The else clause must be empty, or a single `return`.
|
||||
let StmtIf {
|
||||
let ast::StmtIf {
|
||||
body,
|
||||
test,
|
||||
elif_else_clauses,
|
||||
|
@ -842,8 +849,8 @@ pub(crate) fn manual_dict_lookup(checker: &mut Checker, stmt_if: &StmtIf) {
|
|||
}
|
||||
|
||||
/// SIM401
|
||||
pub(crate) fn use_dict_get_with_default(checker: &mut Checker, stmt_if: &StmtIf) {
|
||||
let StmtIf {
|
||||
pub(crate) fn use_dict_get_with_default(checker: &mut Checker, stmt_if: &ast::StmtIf) {
|
||||
let ast::StmtIf {
|
||||
test,
|
||||
body,
|
||||
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 {
|
||||
func: Box::new(node2.into()),
|
||||
args: vec![node1, node],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![node1, node],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
};
|
||||
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_diagnostics::{AlwaysAutofixableViolation, AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
|
@ -166,8 +166,11 @@ pub(crate) fn explicit_true_false_in_ifexpr(
|
|||
};
|
||||
let node1 = ast::ExprCall {
|
||||
func: Box::new(node.into()),
|
||||
args: vec![test.clone()],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![test.clone()],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
};
|
||||
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_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 {
|
||||
func: Box::new(node.into()),
|
||||
args: vec![*operand.clone()],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![*operand.clone()],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
};
|
||||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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_diagnostics::Edit;
|
||||
|
@ -71,8 +71,7 @@ fn key_in_dict(
|
|||
) {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
range: _,
|
||||
}) = &right
|
||||
else {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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;
|
||||
|
||||
|
@ -394,8 +395,11 @@ fn return_stmt(id: &str, test: &Expr, target: &Expr, iter: &Expr, generator: Gen
|
|||
};
|
||||
let node2 = ast::ExprCall {
|
||||
func: Box::new(node1.into()),
|
||||
args: vec![node.into()],
|
||||
keywords: vec![],
|
||||
arguments: Arguments {
|
||||
args: vec![node.into()],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
};
|
||||
let node3 = ast::StmtReturn {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -63,7 +63,11 @@ pub(crate) fn no_slots_in_namedtuple_subclass(
|
|||
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| {
|
||||
let Expr::Call(ast::ExprCall { func, .. }) = base else {
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -51,7 +51,11 @@ impl Violation for NoSlotsInStrSubclass {
|
|||
|
||||
/// SLOT000
|
||||
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) {
|
||||
checker
|
||||
.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_macros::{derive_message_formats, violation};
|
||||
|
@ -51,7 +51,11 @@ impl Violation for NoSlotsInTupleSubclass {
|
|||
|
||||
/// SLOT001
|
||||
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
|
||||
.semantic()
|
||||
.resolve_call_path(map_subscript(base))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::Arguments;
|
||||
|
||||
use ruff_python_ast::call_path::from_qualified_name;
|
||||
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 {
|
||||
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 {
|
||||
if let Some(call_path) = semantic.resolve_call_path(base) {
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -54,7 +54,11 @@ pub(crate) fn path_constructor_current_directory(checker: &mut Checker, expr: &E
|
|||
return;
|
||||
}
|
||||
|
||||
let Expr::Call(ExprCall { args, keywords, .. }) = expr else {
|
||||
let Expr::Call(ExprCall {
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
..
|
||||
}) = expr
|
||||
else {
|
||||
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;
|
||||
|
||||
/// Wrap an expression in a `FormattedValue` with no special formatting.
|
||||
|
@ -29,8 +29,12 @@ fn is_simple_call(expr: &Expr) -> bool {
|
|||
match expr {
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) => args.is_empty() && keywords.is_empty() && is_simple_callee(func),
|
||||
_ => false,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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_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) {
|
||||
let Expr::Call(ast::ExprCall { args, keywords, .. }) = expr else {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
..
|
||||
}) = expr
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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_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"]))
|
||||
}
|
||||
|
||||
pub(super) fn is_typed_dict_class(bases: &[Expr], semantic: &SemanticModel) -> bool {
|
||||
bases
|
||||
.iter()
|
||||
.any(|base| semantic.match_typing_expr(base, "TypedDict"))
|
||||
pub(super) fn is_typed_dict_class(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool {
|
||||
arguments.is_some_and(|arguments| {
|
||||
arguments
|
||||
.args
|
||||
.iter()
|
||||
.any(|base| semantic.match_typing_expr(base, "TypedDict"))
|
||||
})
|
||||
}
|
||||
|
||||
#[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_macros::{derive_message_formats, violation};
|
||||
|
@ -45,10 +45,26 @@ impl Violation for ErrorSuffixOnExceptionName {
|
|||
/// N818
|
||||
pub(crate) fn error_suffix_on_exception_name(
|
||||
class_def: &Stmt,
|
||||
bases: &[Expr],
|
||||
arguments: Option<&Arguments>,
|
||||
name: &str,
|
||||
ignore_names: &[IdentifierPattern],
|
||||
) -> 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
|
||||
.iter()
|
||||
.any(|ignore_name| ignore_name.matches(name))
|
||||
|
@ -56,19 +72,6 @@ pub(crate) fn error_suffix_on_exception_name(
|
|||
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(
|
||||
ErrorSuffixOnExceptionName {
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -54,7 +54,7 @@ pub(crate) fn mixed_case_variable_in_class_scope(
|
|||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
name: &str,
|
||||
bases: &[Expr],
|
||||
arguments: Option<&Arguments>,
|
||||
) {
|
||||
if checker
|
||||
.settings
|
||||
|
@ -72,7 +72,7 @@ pub(crate) fn mixed_case_variable_in_class_scope(
|
|||
let parent = checker.semantic().stmt();
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::fmt;
|
||||
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_python_ast::{Arguments, Expr};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
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 {
|
||||
return;
|
||||
};
|
||||
let Expr::Call(ast::ExprCall { func, args, .. }) = iter else {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
arguments: Arguments { args, .. },
|
||||
..
|
||||
}) = iter
|
||||
else {
|
||||
return;
|
||||
};
|
||||
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_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 {
|
||||
func,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range,
|
||||
args,
|
||||
keywords,
|
||||
}) = value.as_ref()
|
||||
else {
|
||||
return;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
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;
|
||||
|
||||
|
@ -59,9 +59,13 @@ pub(crate) fn manual_list_copy(checker: &mut Checker, target: &Expr, body: &[Stm
|
|||
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range,
|
||||
args,
|
||||
keywords,
|
||||
}) = value.as_ref()
|
||||
else {
|
||||
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_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
|
@ -54,17 +54,21 @@ impl AlwaysAutofixableViolation for UnnecessaryListCast {
|
|||
pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords: _,
|
||||
range: _,
|
||||
},
|
||||
range: list_range,
|
||||
..
|
||||
}) = iter
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if args.len() != 1 {
|
||||
let [arg] = args.as_slice() else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() else {
|
||||
return;
|
||||
|
@ -74,7 +78,7 @@ pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) {
|
|||
return;
|
||||
}
|
||||
|
||||
match &args[0] {
|
||||
match arg {
|
||||
Expr::Tuple(ast::ExprTuple {
|
||||
range: iterable_range,
|
||||
..
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -49,7 +49,11 @@ pub(crate) fn type_comparison(
|
|||
continue;
|
||||
}
|
||||
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() {
|
||||
// Ex) `type(False)`
|
||||
if id == "type" && checker.semantic().is_builtin("type") {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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 ruff_diagnostics::{Diagnostic, Violation};
|
||||
|
@ -51,7 +51,11 @@ impl Violation for DuplicateBases {
|
|||
}
|
||||
|
||||
/// 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> =
|
||||
FxHashSet::with_capacity_and_hasher(bases.len(), BuildHasherDefault::default());
|
||||
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_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 {
|
||||
if let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) = arg
|
||||
{
|
||||
|
@ -135,14 +139,18 @@ pub(crate) fn nested_min_max(
|
|||
return;
|
||||
};
|
||||
|
||||
if args.len() == 1
|
||||
&& matches!(&args[0], Expr::Call(ast::ExprCall { args, .. }) if args.len() == 1)
|
||||
if matches!(&args, [Expr::Call(ast::ExprCall { arguments: Arguments {args, .. }, .. })] if args.len() == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
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()) {
|
||||
let flattened_expr = Expr::Call(ast::ExprCall {
|
||||
func: Box::new(func.clone()),
|
||||
args: collect_nested_args(min_max, args, checker.semantic()),
|
||||
keywords: keywords.to_owned(),
|
||||
arguments: Arguments {
|
||||
args: collect_nested_args(min_max, args, checker.semantic()),
|
||||
keywords: keywords.to_owned(),
|
||||
range: TextRange::default(),
|
||||
},
|
||||
range: TextRange::default(),
|
||||
});
|
||||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{fmt, iter};
|
||||
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -237,7 +237,12 @@ impl<'a, 'b> StatementVisitor<'b> for InnerForWithAssignTargetsVisitor<'a, 'b> {
|
|||
/// x = cast(int, x)
|
||||
/// ```
|
||||
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;
|
||||
};
|
||||
let Expr::Name(ast::ExprName { id: target_id, .. }) = target else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 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>)> =
|
||||
FxHashMap::default();
|
||||
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;
|
||||
};
|
||||
if !matches!(func.as_ref(), Expr::Name(ast::ExprName { id, .. }) if id == "isinstance") {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -76,8 +76,7 @@ impl Violation for TypeBivariance {
|
|||
pub(crate) fn type_bivariance(checker: &mut Checker, value: &Expr) {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
..
|
||||
}) = value
|
||||
else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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_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) {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
..
|
||||
}) = value
|
||||
else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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_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 {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
..
|
||||
}) = value
|
||||
else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::{bail, Result};
|
||||
use log::debug;
|
||||
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;
|
||||
|
||||
|
@ -78,8 +78,7 @@ fn match_named_tuple_assign<'a>(
|
|||
};
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
range: _,
|
||||
}) = value
|
||||
else {
|
||||
|
@ -91,7 +90,7 @@ fn match_named_tuple_assign<'a>(
|
|||
Some((typename, args, keywords, func))
|
||||
}
|
||||
|
||||
/// Generate a `Stmt::AnnAssign` representing the provided property
|
||||
/// Generate a [`Stmt::AnnAssign`] representing the provided property
|
||||
/// definition.
|
||||
fn create_property_assignment_stmt(property: &str, annotation: &Expr) -> Stmt {
|
||||
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 {
|
||||
ast::StmtClassDef {
|
||||
name: Identifier::new(typename.to_string(), TextRange::default()),
|
||||
bases: vec![base_class.clone()],
|
||||
keywords: vec![],
|
||||
arguments: Some(Arguments {
|
||||
args: vec![base_class.clone()],
|
||||
keywords: vec![],
|
||||
range: TextRange::default(),
|
||||
}),
|
||||
body,
|
||||
type_params: vec![],
|
||||
decorator_list: vec![],
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::{bail, Result};
|
||||
use log::debug;
|
||||
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;
|
||||
|
||||
|
@ -77,8 +77,7 @@ fn match_typed_dict_assign<'a>(
|
|||
};
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
range: _,
|
||||
}) = value
|
||||
else {
|
||||
|
@ -90,7 +89,7 @@ fn match_typed_dict_assign<'a>(
|
|||
Some((class_name, args, keywords, func))
|
||||
}
|
||||
|
||||
/// Generate a `Stmt::AnnAssign` representing the provided property
|
||||
/// Generate a [`Stmt::AnnAssign`] representing the provided property
|
||||
/// definition.
|
||||
fn create_property_assignment_stmt(property: &str, annotation: &Expr) -> Stmt {
|
||||
ast::StmtAnnAssign {
|
||||
|
@ -118,14 +117,16 @@ fn create_class_def_stmt(
|
|||
total_keyword: Option<&Keyword>,
|
||||
base_class: &Expr,
|
||||
) -> Stmt {
|
||||
let keywords = match total_keyword {
|
||||
Some(keyword) => vec![keyword.clone()],
|
||||
None => vec![],
|
||||
};
|
||||
ast::StmtClassDef {
|
||||
name: Identifier::new(class_name.to_string(), TextRange::default()),
|
||||
bases: vec![base_class.clone()],
|
||||
keywords,
|
||||
arguments: Some(Arguments {
|
||||
args: vec![base_class.clone()],
|
||||
keywords: match total_keyword {
|
||||
Some(keyword) => vec![keyword.clone()],
|
||||
None => vec![],
|
||||
},
|
||||
range: TextRange::default(),
|
||||
}),
|
||||
body,
|
||||
type_params: vec![],
|
||||
decorator_list: vec![],
|
||||
|
@ -217,9 +218,11 @@ fn match_properties_and_total<'a>(
|
|||
values,
|
||||
range: _,
|
||||
}) => Ok((properties_from_dict_literal(keys, values)?, total)),
|
||||
Expr::Call(ast::ExprCall { func, keywords, .. }) => {
|
||||
Ok((properties_from_dict_call(func, keywords)?, total))
|
||||
}
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
arguments: Arguments { keywords, .. },
|
||||
..
|
||||
}) => Ok((properties_from_dict_call(func, keywords)?, total)),
|
||||
_ => bail!("Expected `arg` to be `Expr::Dict` or `Expr::Call`"),
|
||||
}
|
||||
} else if !keywords.is_empty() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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::{
|
||||
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> {
|
||||
let mut extracted_args: Vec<&Expr> = Vec::new();
|
||||
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 {
|
||||
if contains_invalids(locator.slice(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_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 {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
}) = &decorator.expression
|
||||
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_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::registry::AsRule;
|
||||
|
@ -59,8 +58,7 @@ pub(crate) fn lru_cache_without_parameters(checker: &mut Checker, decorator_list
|
|||
for decorator in decorator_list {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments,
|
||||
range: _,
|
||||
}) = &decorator.expression
|
||||
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()`.
|
||||
if args.is_empty()
|
||||
&& keywords.is_empty()
|
||||
if arguments.args.is_empty()
|
||||
&& arguments.keywords.is_empty()
|
||||
&& checker
|
||||
.semantic()
|
||||
.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()),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
||||
checker.generator().expr(func),
|
||||
decorator.expression.range(),
|
||||
diagnostic.set_fix(Fix::automatic(Edit::deletion(
|
||||
arguments.start(),
|
||||
arguments.end(),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
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_text_size::TextSize;
|
||||
|
||||
|
@ -119,8 +119,12 @@ fn match_open<'a>(
|
|||
) -> Option<(Option<&'a Expr>, &'a [Keyword])> {
|
||||
let ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
range: _,
|
||||
} = 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_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
@ -44,54 +40,20 @@ impl AlwaysAutofixableViolation for UnnecessaryClassParentheses {
|
|||
|
||||
/// UP039
|
||||
pub(crate) fn unnecessary_class_parentheses(checker: &mut Checker, class_def: &ast::StmtClassDef) {
|
||||
if !class_def.bases.is_empty() || !class_def.keywords.is_empty() {
|
||||
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 {
|
||||
let Some(arguments) = class_def.arguments.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Convert to `TextSize`.
|
||||
let start = TextSize::try_from(start).unwrap();
|
||||
let end = TextSize::try_from(end).unwrap();
|
||||
if !arguments.args.is_empty() || !arguments.keywords.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add initial offset.
|
||||
let start = offset.add(start);
|
||||
let end = offset.add(end);
|
||||
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryClassParentheses, TextRange::new(start, end));
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryClassParentheses, arguments.range());
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,11 @@ impl AlwaysAutofixableViolation for UselessObjectInheritance {
|
|||
|
||||
/// UP004
|
||||
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 {
|
||||
continue;
|
||||
};
|
||||
|
@ -70,8 +74,8 @@ pub(crate) fn useless_object_inheritance(checker: &mut Checker, class_def: &ast:
|
|||
checker.locator(),
|
||||
class_def.name.end(),
|
||||
expr.range(),
|
||||
&class_def.bases,
|
||||
&class_def.keywords,
|
||||
&arguments.args,
|
||||
&arguments.keywords,
|
||||
true,
|
||||
)?;
|
||||
Ok(Fix::automatic(edit))
|
||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{bail, Result};
|
|||
use libcst_native::{
|
||||
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_macros::{derive_message_formats, violation};
|
||||
|
@ -80,8 +80,12 @@ pub(crate) fn explicit_f_string_type_conversion(
|
|||
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
..
|
||||
}) = value.as_ref()
|
||||
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_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.
|
||||
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| {
|
||||
matches!(
|
||||
call_path.as_slice(),
|
||||
|
|
|
@ -5,7 +5,7 @@ use unicode_width::UnicodeWidthStr;
|
|||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
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_text_size::{TextRange, TextSize};
|
||||
|
||||
|
@ -151,7 +151,11 @@ struct IterationTarget {
|
|||
/// redundant comprehension).
|
||||
fn match_iteration_target(expr: &Expr, model: &SemanticModel) -> Option<IterationTarget> {
|
||||
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()?;
|
||||
|
||||
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 {
|
||||
if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = expr.func.as_ref() {
|
||||
if attr == "error" {
|
||||
if exc_info(&expr.keywords, checker.semantic()).is_none() {
|
||||
if exc_info(&expr.arguments.keywords, checker.semantic()).is_none() {
|
||||
checker
|
||||
.diagnostics
|
||||
.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_macros::{derive_message_formats, violation};
|
||||
|
@ -77,7 +77,11 @@ where
|
|||
|
||||
/// TRY003
|
||||
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 any_string(arg, |part| part.chars().any(char::is_whitespace)) {
|
||||
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.
|
||||
let names: Vec<&ast::ExprName> = {
|
||||
let mut names = Vec::new();
|
||||
for arg in &expr.args {
|
||||
for arg in &expr.arguments.args {
|
||||
let mut visitor = NameVisitor::default();
|
||||
visitor.visit_expr(arg);
|
||||
names.extend(visitor.names);
|
||||
|
|
|
@ -64,8 +64,7 @@ where
|
|||
}
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: ast::Arguments { args, keywords, .. },
|
||||
..
|
||||
}) => {
|
||||
// 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)]
|
||||
pub struct ComparableParameters<'a> {
|
||||
posonlyargs: Vec<ComparableParameterWithDefault<'a>>,
|
||||
|
@ -583,8 +604,7 @@ pub struct ExprCompare<'a> {
|
|||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ExprCall<'a> {
|
||||
func: Box<ComparableExpr<'a>>,
|
||||
args: Vec<ComparableExpr<'a>>,
|
||||
keywords: Vec<ComparableKeyword<'a>>,
|
||||
arguments: ComparableArguments<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -837,13 +857,11 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
|
|||
}),
|
||||
ast::Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments,
|
||||
range: _range,
|
||||
}) => Self::Call(ExprCall {
|
||||
func: func.into(),
|
||||
args: args.iter().map(Into::into).collect(),
|
||||
keywords: keywords.iter().map(Into::into).collect(),
|
||||
arguments: arguments.into(),
|
||||
}),
|
||||
ast::Expr::FormattedValue(ast::ExprFormattedValue {
|
||||
value,
|
||||
|
@ -968,8 +986,7 @@ pub struct StmtAsyncFunctionDef<'a> {
|
|||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct StmtClassDef<'a> {
|
||||
name: &'a str,
|
||||
bases: Vec<ComparableExpr<'a>>,
|
||||
keywords: Vec<ComparableKeyword<'a>>,
|
||||
arguments: Option<ComparableArguments<'a>>,
|
||||
body: Vec<ComparableStmt<'a>>,
|
||||
decorator_list: Vec<ComparableDecorator<'a>>,
|
||||
type_params: Vec<ComparableTypeParam<'a>>,
|
||||
|
@ -1240,16 +1257,14 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
|
|||
}),
|
||||
ast::Stmt::ClassDef(ast::StmtClassDef {
|
||||
name,
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
body,
|
||||
decorator_list,
|
||||
type_params,
|
||||
range: _range,
|
||||
}) => Self::ClassDef(StmtClassDef {
|
||||
name: name.as_str(),
|
||||
bases: bases.iter().map(Into::into).collect(),
|
||||
keywords: keywords.iter().map(Into::into).collect(),
|
||||
arguments: arguments.as_ref().map(Into::into),
|
||||
body: body.iter().map(Into::into).collect(),
|
||||
decorator_list: decorator_list.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 crate::{
|
||||
self as ast, Constant, ExceptHandler, Expr, Keyword, MatchCase, Parameters, Pattern, Ranged,
|
||||
Stmt, TypeParam,
|
||||
self as ast, Arguments, Constant, ExceptHandler, Expr, Keyword, MatchCase, Parameters, Pattern,
|
||||
Ranged, Stmt, TypeParam,
|
||||
};
|
||||
use num_traits::Zero;
|
||||
use ruff_text_size::TextRange;
|
||||
|
@ -50,8 +50,7 @@ where
|
|||
// Accept empty initializers.
|
||||
if let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
range: _range,
|
||||
}) = expr
|
||||
{
|
||||
|
@ -237,8 +236,7 @@ where
|
|||
}) => any_over_expr(left, func) || comparators.iter().any(|expr| any_over_expr(expr, func)),
|
||||
Expr::Call(ast::ExprCall {
|
||||
func: call_func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
range: _range,
|
||||
}) => {
|
||||
any_over_expr(call_func, func)
|
||||
|
@ -396,16 +394,19 @@ where
|
|||
.is_some_and(|value| any_over_expr(value, func))
|
||||
}
|
||||
Stmt::ClassDef(ast::StmtClassDef {
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
body,
|
||||
decorator_list,
|
||||
..
|
||||
}) => {
|
||||
bases.iter().any(|expr| any_over_expr(expr, func))
|
||||
|| keywords
|
||||
.iter()
|
||||
.any(|keyword| any_over_expr(&keyword.value, func))
|
||||
arguments
|
||||
.as_ref()
|
||||
.is_some_and(|Arguments { args, keywords, .. }| {
|
||||
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))
|
||||
|| decorator_list
|
||||
.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
|
||||
/// [`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> {
|
||||
keywords.iter().find(|keyword| {
|
||||
let Keyword { arg, .. } = keyword;
|
||||
|
@ -1229,30 +1232,14 @@ impl Truthiness {
|
|||
None
|
||||
}
|
||||
}
|
||||
Expr::List(ast::ExprList {
|
||||
elts,
|
||||
range: _range,
|
||||
..
|
||||
})
|
||||
| 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::List(ast::ExprList { elts, .. })
|
||||
| Expr::Set(ast::ExprSet { elts, .. })
|
||||
| Expr::Tuple(ast::ExprTuple { elts, .. }) => Some(!elts.is_empty()),
|
||||
Expr::Dict(ast::ExprDict { keys, .. }) => Some(!keys.is_empty()),
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
range: _range,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
..
|
||||
}) => {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
|
||||
if is_iterable_initializer(id.as_str(), |id| is_builtin(id)) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
self as ast, Alias, Comprehension, Decorator, ExceptHandler, Expr, Keyword, MatchCase, Mod,
|
||||
Parameter, ParameterWithDefault, Parameters, Pattern, Ranged, Stmt, TypeParam,
|
||||
self as ast, Alias, Arguments, Comprehension, Decorator, ExceptHandler, Expr, Keyword,
|
||||
MatchCase, Mod, Parameter, ParameterWithDefault, Parameters, Pattern, Ranged, Stmt, TypeParam,
|
||||
TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple, WithItem,
|
||||
};
|
||||
use ruff_text_size::TextRange;
|
||||
|
@ -90,6 +90,7 @@ pub enum AnyNode {
|
|||
PatternMatchAs(ast::PatternMatchAs),
|
||||
PatternMatchOr(ast::PatternMatchOr),
|
||||
Comprehension(Comprehension),
|
||||
Arguments(Arguments),
|
||||
Parameters(Parameters),
|
||||
Parameter(Parameter),
|
||||
ParameterWithDefault(ParameterWithDefault),
|
||||
|
@ -177,6 +178,7 @@ impl AnyNode {
|
|||
| AnyNode::PatternMatchAs(_)
|
||||
| AnyNode::PatternMatchOr(_)
|
||||
| AnyNode::Comprehension(_)
|
||||
| AnyNode::Arguments(_)
|
||||
| AnyNode::Parameters(_)
|
||||
| AnyNode::Parameter(_)
|
||||
| AnyNode::ParameterWithDefault(_)
|
||||
|
@ -264,6 +266,7 @@ impl AnyNode {
|
|||
| AnyNode::PatternMatchAs(_)
|
||||
| AnyNode::PatternMatchOr(_)
|
||||
| AnyNode::Comprehension(_)
|
||||
| AnyNode::Arguments(_)
|
||||
| AnyNode::Parameters(_)
|
||||
| AnyNode::Parameter(_)
|
||||
| AnyNode::ParameterWithDefault(_)
|
||||
|
@ -351,6 +354,7 @@ impl AnyNode {
|
|||
| AnyNode::PatternMatchAs(_)
|
||||
| AnyNode::PatternMatchOr(_)
|
||||
| AnyNode::Comprehension(_)
|
||||
| AnyNode::Arguments(_)
|
||||
| AnyNode::Parameters(_)
|
||||
| AnyNode::Parameter(_)
|
||||
| AnyNode::ParameterWithDefault(_)
|
||||
|
@ -438,6 +442,7 @@ impl AnyNode {
|
|||
| AnyNode::ExprLineMagic(_)
|
||||
| AnyNode::ExceptHandlerExceptHandler(_)
|
||||
| AnyNode::Comprehension(_)
|
||||
| AnyNode::Arguments(_)
|
||||
| AnyNode::Parameters(_)
|
||||
| AnyNode::Parameter(_)
|
||||
| AnyNode::ParameterWithDefault(_)
|
||||
|
@ -525,6 +530,7 @@ impl AnyNode {
|
|||
| AnyNode::PatternMatchAs(_)
|
||||
| AnyNode::PatternMatchOr(_)
|
||||
| AnyNode::Comprehension(_)
|
||||
| AnyNode::Arguments(_)
|
||||
| AnyNode::Parameters(_)
|
||||
| AnyNode::Parameter(_)
|
||||
| AnyNode::ParameterWithDefault(_)
|
||||
|
@ -631,6 +637,7 @@ impl AnyNode {
|
|||
Self::PatternMatchAs(node) => AnyNodeRef::PatternMatchAs(node),
|
||||
Self::PatternMatchOr(node) => AnyNodeRef::PatternMatchOr(node),
|
||||
Self::Comprehension(node) => AnyNodeRef::Comprehension(node),
|
||||
Self::Arguments(node) => AnyNodeRef::Arguments(node),
|
||||
Self::Parameters(node) => AnyNodeRef::Parameters(node),
|
||||
Self::Parameter(node) => AnyNodeRef::Parameter(node),
|
||||
Self::ParameterWithDefault(node) => AnyNodeRef::ParameterWithDefault(node),
|
||||
|
@ -3574,6 +3581,7 @@ impl Ranged for AnyNode {
|
|||
AnyNode::PatternMatchAs(node) => node.range(),
|
||||
AnyNode::PatternMatchOr(node) => node.range(),
|
||||
AnyNode::Comprehension(node) => node.range(),
|
||||
AnyNode::Arguments(node) => node.range(),
|
||||
AnyNode::Parameters(node) => node.range(),
|
||||
AnyNode::Parameter(node) => node.range(),
|
||||
AnyNode::ParameterWithDefault(node) => node.range(),
|
||||
|
@ -3661,6 +3669,7 @@ pub enum AnyNodeRef<'a> {
|
|||
PatternMatchAs(&'a ast::PatternMatchAs),
|
||||
PatternMatchOr(&'a ast::PatternMatchOr),
|
||||
Comprehension(&'a Comprehension),
|
||||
Arguments(&'a Arguments),
|
||||
Parameters(&'a Parameters),
|
||||
Parameter(&'a Parameter),
|
||||
ParameterWithDefault(&'a ParameterWithDefault),
|
||||
|
@ -3747,6 +3756,7 @@ impl AnyNodeRef<'_> {
|
|||
AnyNodeRef::PatternMatchAs(node) => NonNull::from(*node).cast(),
|
||||
AnyNodeRef::PatternMatchOr(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::Parameter(node) => NonNull::from(*node).cast(),
|
||||
AnyNodeRef::ParameterWithDefault(node) => NonNull::from(*node).cast(),
|
||||
|
@ -3839,6 +3849,7 @@ impl AnyNodeRef<'_> {
|
|||
AnyNodeRef::PatternMatchAs(_) => NodeKind::PatternMatchAs,
|
||||
AnyNodeRef::PatternMatchOr(_) => NodeKind::PatternMatchOr,
|
||||
AnyNodeRef::Comprehension(_) => NodeKind::Comprehension,
|
||||
AnyNodeRef::Arguments(_) => NodeKind::Arguments,
|
||||
AnyNodeRef::Parameters(_) => NodeKind::Parameters,
|
||||
AnyNodeRef::Parameter(_) => NodeKind::Parameter,
|
||||
AnyNodeRef::ParameterWithDefault(_) => NodeKind::ParameterWithDefault,
|
||||
|
@ -3926,6 +3937,7 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::PatternMatchAs(_)
|
||||
| AnyNodeRef::PatternMatchOr(_)
|
||||
| AnyNodeRef::Comprehension(_)
|
||||
| AnyNodeRef::Arguments(_)
|
||||
| AnyNodeRef::Parameters(_)
|
||||
| AnyNodeRef::Parameter(_)
|
||||
| AnyNodeRef::ParameterWithDefault(_)
|
||||
|
@ -4013,6 +4025,7 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::PatternMatchAs(_)
|
||||
| AnyNodeRef::PatternMatchOr(_)
|
||||
| AnyNodeRef::Comprehension(_)
|
||||
| AnyNodeRef::Arguments(_)
|
||||
| AnyNodeRef::Parameters(_)
|
||||
| AnyNodeRef::Parameter(_)
|
||||
| AnyNodeRef::ParameterWithDefault(_)
|
||||
|
@ -4099,6 +4112,7 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::PatternMatchAs(_)
|
||||
| AnyNodeRef::PatternMatchOr(_)
|
||||
| AnyNodeRef::Comprehension(_)
|
||||
| AnyNodeRef::Arguments(_)
|
||||
| AnyNodeRef::Parameters(_)
|
||||
| AnyNodeRef::Parameter(_)
|
||||
| AnyNodeRef::ParameterWithDefault(_)
|
||||
|
@ -4186,6 +4200,7 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::ExprLineMagic(_)
|
||||
| AnyNodeRef::ExceptHandlerExceptHandler(_)
|
||||
| AnyNodeRef::Comprehension(_)
|
||||
| AnyNodeRef::Arguments(_)
|
||||
| AnyNodeRef::Parameters(_)
|
||||
| AnyNodeRef::Parameter(_)
|
||||
| AnyNodeRef::ParameterWithDefault(_)
|
||||
|
@ -4273,6 +4288,7 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::PatternMatchAs(_)
|
||||
| AnyNodeRef::PatternMatchOr(_)
|
||||
| AnyNodeRef::Comprehension(_)
|
||||
| AnyNodeRef::Arguments(_)
|
||||
| AnyNodeRef::Parameters(_)
|
||||
| AnyNodeRef::Parameter(_)
|
||||
| AnyNodeRef::ParameterWithDefault(_)
|
||||
|
@ -4985,6 +5001,7 @@ impl Ranged for AnyNodeRef<'_> {
|
|||
AnyNodeRef::PatternMatchAs(node) => node.range(),
|
||||
AnyNodeRef::PatternMatchOr(node) => node.range(),
|
||||
AnyNodeRef::Comprehension(node) => node.range(),
|
||||
AnyNodeRef::Arguments(node) => node.range(),
|
||||
AnyNodeRef::Parameters(node) => node.range(),
|
||||
AnyNodeRef::Parameter(node) => node.range(),
|
||||
AnyNodeRef::ParameterWithDefault(node) => node.range(),
|
||||
|
@ -5075,6 +5092,7 @@ pub enum NodeKind {
|
|||
PatternMatchOr,
|
||||
TypeIgnoreTypeIgnore,
|
||||
Comprehension,
|
||||
Arguments,
|
||||
Parameters,
|
||||
Parameter,
|
||||
ParameterWithDefault,
|
||||
|
|
|
@ -158,13 +158,32 @@ impl From<StmtAsyncFunctionDef> for Stmt {
|
|||
pub struct StmtClassDef {
|
||||
pub range: TextRange,
|
||||
pub name: Identifier,
|
||||
pub bases: Vec<Expr>,
|
||||
pub keywords: Vec<Keyword>,
|
||||
pub arguments: Option<Arguments>,
|
||||
pub body: Vec<Stmt>,
|
||||
pub type_params: Vec<TypeParam>,
|
||||
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 {
|
||||
fn from(payload: StmtClassDef) -> Self {
|
||||
Stmt::ClassDef(payload)
|
||||
|
@ -836,8 +855,7 @@ impl From<ExprCompare> for Expr {
|
|||
pub struct ExprCall {
|
||||
pub range: TextRange,
|
||||
pub func: Box<Expr>,
|
||||
pub args: Vec<Expr>,
|
||||
pub keywords: Vec<Keyword>,
|
||||
pub arguments: Arguments,
|
||||
}
|
||||
|
||||
impl From<ExprCall> for Expr {
|
||||
|
@ -2073,6 +2091,35 @@ pub struct ParameterWithDefault {
|
|||
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>;
|
||||
|
||||
impl CmpOp {
|
||||
|
@ -2934,6 +2981,11 @@ impl Ranged for crate::nodes::Decorator {
|
|||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::nodes::Arguments {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
impl Ranged for crate::nodes::Parameters {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
|
@ -2951,9 +3003,9 @@ mod size_assertions {
|
|||
use super::*;
|
||||
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!(StmtClassDef, [u8; 160]);
|
||||
assert_eq_size!(StmtClassDef, [u8; 168]);
|
||||
assert_eq_size!(StmtTry, [u8; 104]);
|
||||
assert_eq_size!(Expr, [u8; 80]);
|
||||
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;
|
||||
|
||||
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 {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments: Arguments { args, keywords, .. },
|
||||
range,
|
||||
}) => {
|
||||
*range = location;
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
pub mod preorder;
|
||||
|
||||
use crate::{
|
||||
self as ast, Alias, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause, ExceptHandler,
|
||||
Expr, ExprContext, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, Stmt,
|
||||
TypeParam, TypeParamTypeVar, UnaryOp, WithItem,
|
||||
self as ast, Alias, Arguments, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause,
|
||||
ExceptHandler, Expr, ExprContext, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern,
|
||||
Stmt, TypeParam, TypeParamTypeVar, UnaryOp, WithItem,
|
||||
};
|
||||
|
||||
/// 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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
Stmt::ClassDef(ast::StmtClassDef {
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
body,
|
||||
decorator_list,
|
||||
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 {
|
||||
visitor.visit_type_param(type_param);
|
||||
}
|
||||
for expr in bases {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
for keyword in keywords {
|
||||
visitor.visit_keyword(keyword);
|
||||
if let Some(arguments) = arguments {
|
||||
visitor.visit_arguments(arguments);
|
||||
}
|
||||
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 {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments,
|
||||
range: _range,
|
||||
}) => {
|
||||
visitor.visit_expr(func);
|
||||
for expr in args {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
for keyword in keywords {
|
||||
visitor.visit_keyword(keyword);
|
||||
}
|
||||
visitor.visit_arguments(arguments);
|
||||
}
|
||||
Expr::FormattedValue(ast::ExprFormattedValue {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
// Defaults are evaluated before annotations.
|
||||
for arg in ¶meters.posonlyargs {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{
|
||||
self as ast, Alias, BoolOp, CmpOp, Comprehension, Constant, Decorator, ElifElseClause,
|
||||
ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, Parameter, ParameterWithDefault,
|
||||
Parameters, Pattern, Stmt, TypeParam, TypeParamTypeVar, UnaryOp, WithItem,
|
||||
self as ast, Alias, Arguments, BoolOp, CmpOp, Comprehension, Constant, Decorator,
|
||||
ElifElseClause, ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, Parameter,
|
||||
ParameterWithDefault, Parameters, Pattern, Stmt, TypeParam, TypeParamTypeVar, UnaryOp,
|
||||
WithItem,
|
||||
};
|
||||
|
||||
/// Visitor that traverses all nodes recursively in pre-order.
|
||||
|
@ -56,6 +57,10 @@ pub trait PreorderVisitor<'a> {
|
|||
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) {
|
||||
walk_parameters(self, parameters);
|
||||
}
|
||||
|
@ -166,8 +171,7 @@ where
|
|||
}
|
||||
|
||||
Stmt::ClassDef(ast::StmtClassDef {
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
body,
|
||||
decorator_list,
|
||||
type_params,
|
||||
|
@ -181,12 +185,8 @@ where
|
|||
visitor.visit_type_param(type_param);
|
||||
}
|
||||
|
||||
for expr in bases {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
|
||||
for keyword in keywords {
|
||||
visitor.visit_keyword(keyword);
|
||||
if let Some(arguments) = arguments {
|
||||
visitor.visit_arguments(arguments);
|
||||
}
|
||||
|
||||
visitor.visit_body(body);
|
||||
|
@ -592,17 +592,11 @@ where
|
|||
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments,
|
||||
range: _range,
|
||||
}) => {
|
||||
visitor.visit_expr(func);
|
||||
for expr in args {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
for keyword in keywords {
|
||||
visitor.visit_keyword(keyword);
|
||||
}
|
||||
visitor.visit_arguments(arguments);
|
||||
}
|
||||
|
||||
Expr::FormattedValue(ast::ExprFormattedValue {
|
||||
|
@ -749,6 +743,19 @@ pub fn walk_format_spec<'a, V: PreorderVisitor<'a> + ?Sized>(
|
|||
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)
|
||||
where
|
||||
V: PreorderVisitor<'a> + ?Sized,
|
||||
|
|
|
@ -273,8 +273,7 @@ impl<'a> Generator<'a> {
|
|||
}
|
||||
Stmt::ClassDef(ast::StmtClassDef {
|
||||
name,
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
body,
|
||||
decorator_list,
|
||||
type_params,
|
||||
|
@ -291,24 +290,25 @@ impl<'a> Generator<'a> {
|
|||
self.p("class ");
|
||||
self.p_id(name);
|
||||
self.unparse_type_params(type_params);
|
||||
let mut first = true;
|
||||
for base in bases {
|
||||
self.p_if(first, "(");
|
||||
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("**");
|
||||
if let Some(arguments) = arguments {
|
||||
self.p("(");
|
||||
let mut first = true;
|
||||
for base in &arguments.args {
|
||||
self.p_delim(&mut first, ", ");
|
||||
self.unparse_expr(base, precedence::MAX);
|
||||
}
|
||||
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.body(body);
|
||||
|
@ -1149,8 +1149,7 @@ impl<'a> Generator<'a> {
|
|||
}
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments,
|
||||
range: _range,
|
||||
}) => {
|
||||
self.unparse_expr(func, precedence::MAX);
|
||||
|
@ -1162,18 +1161,18 @@ impl<'a> Generator<'a> {
|
|||
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.
|
||||
self.unparse_expr(elt, precedence::COMMA);
|
||||
self.unparse_comp(generators);
|
||||
} else {
|
||||
let mut first = true;
|
||||
for arg in args {
|
||||
for arg in &arguments.args {
|
||||
self.p_delim(&mut first, ", ");
|
||||
self.unparse_expr(arg, precedence::COMMA);
|
||||
}
|
||||
for kw in keywords {
|
||||
for kw in &arguments.keywords {
|
||||
self.p_delim(&mut first, ", ");
|
||||
if let Some(arg) = &kw.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 crate::builders::empty_parenthesized_with_dangling_comments;
|
||||
|
@ -21,8 +21,12 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
|
|||
let ExprCall {
|
||||
range: _,
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
arguments:
|
||||
Arguments {
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
},
|
||||
} = item;
|
||||
|
||||
// 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 {
|
||||
range: _,
|
||||
func,
|
||||
args: _,
|
||||
keywords: _,
|
||||
arguments: _,
|
||||
}) => {
|
||||
self.any_parenthesized_expressions = true;
|
||||
// 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_formatter::write;
|
||||
|
@ -17,8 +17,7 @@ impl FormatNodeRule<StmtClassDef> for FormatStmtClassDef {
|
|||
let StmtClassDef {
|
||||
range: _,
|
||||
name,
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
body,
|
||||
type_params: _,
|
||||
decorator_list,
|
||||
|
@ -34,7 +33,12 @@ impl FormatNodeRule<StmtClassDef> for FormatStmtClassDef {
|
|||
|
||||
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(
|
||||
"(",
|
||||
&FormatInheritanceClause {
|
||||
|
@ -75,12 +79,19 @@ struct FormatInheritanceClause<'a> {
|
|||
impl Format<PyFormatContext<'_>> for FormatInheritanceClause<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
||||
let StmtClassDef {
|
||||
bases,
|
||||
keywords,
|
||||
arguments:
|
||||
Some(Arguments {
|
||||
args: bases,
|
||||
keywords,
|
||||
..
|
||||
}),
|
||||
name,
|
||||
body,
|
||||
..
|
||||
} = self.class_definition;
|
||||
} = self.class_definition
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let source = f.context().source();
|
||||
|
||||
|
|
|
@ -78,14 +78,18 @@ type FunctionArgument = (
|
|||
);
|
||||
|
||||
// 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 keywords = vec![];
|
||||
|
||||
let mut keyword_names =
|
||||
FxHashSet::with_capacity_and_hasher(func_args.len(), BuildHasherDefault::default());
|
||||
let mut keyword_names = FxHashSet::with_capacity_and_hasher(
|
||||
function_arguments.len(),
|
||||
BuildHasherDefault::default(),
|
||||
);
|
||||
let mut double_starred = false;
|
||||
for (name, value) in func_args {
|
||||
for (name, value) in function_arguments {
|
||||
if let Some((start, end, name)) = name {
|
||||
// Check for duplicate keyword arguments in the call.
|
||||
if let Some(keyword_name) = &name {
|
||||
|
|
|
@ -9,7 +9,7 @@ use ruff_python_ast::{self as ast, Ranged, MagicKind};
|
|||
use crate::{
|
||||
Mode,
|
||||
lexer::{LexicalError, LexicalErrorType},
|
||||
function::{ArgumentList, parse_args, validate_pos_params, validate_arguments},
|
||||
function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments},
|
||||
context::set_context,
|
||||
string::parse_strings,
|
||||
token::{self, StringKind},
|
||||
|
@ -1194,17 +1194,12 @@ KwargParameter<ParameterType>: Option<Box<ast::Parameter>> = {
|
|||
};
|
||||
|
||||
ClassDef: ast::Stmt = {
|
||||
<location:@L> <decorator_list:Decorator*> "class" <name:Identifier> <type_params:TypeParamList?> <a:("(" ArgumentList ")")?> ":" <body:Suite> => {
|
||||
let (bases, keywords) = match a {
|
||||
Some((_, arg, _)) => (arg.args, arg.keywords),
|
||||
None => (vec![], vec![]),
|
||||
};
|
||||
<location:@L> <decorator_list:Decorator*> "class" <name:Identifier> <type_params:TypeParamList?> <arguments:Arguments?> ":" <body:Suite> => {
|
||||
let end_location = body.last().unwrap().end();
|
||||
ast::Stmt::ClassDef(
|
||||
ast::StmtClassDef {
|
||||
name,
|
||||
bases,
|
||||
keywords,
|
||||
arguments,
|
||||
body,
|
||||
decorator_list,
|
||||
type_params: type_params.unwrap_or_default(),
|
||||
|
@ -1444,9 +1439,9 @@ AtomExpr<Goal>: ast::Expr = {
|
|||
|
||||
AtomExpr2<Goal>: ast::Expr = {
|
||||
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::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(
|
||||
|
@ -1663,10 +1658,14 @@ SingleForComprehension: ast::Comprehension = {
|
|||
ExpressionNoCond: ast::Expr = OrTest<"all">;
|
||||
ComprehensionIf: ast::Expr = "if" <c:ExpressionNoCond> => c;
|
||||
|
||||
ArgumentList: ArgumentList = {
|
||||
<e: Comma<FunctionArgument>> =>? {
|
||||
let arg_list = parse_args(e)?;
|
||||
Ok(arg_list)
|
||||
Arguments: ast::Arguments = {
|
||||
<location:@L> "(" <e: Comma<FunctionArgument>> ")" <end_location:@R> =>? {
|
||||
let ArgumentList { args, keywords } = parse_arguments(e)?;
|
||||
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",
|
||||
range: 59..63,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: None,
|
||||
body: [
|
||||
Pass(
|
||||
StmtPass {
|
||||
|
|
|
@ -24,124 +24,127 @@ Call(
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
GeneratorExp(
|
||||
ExprGeneratorExp {
|
||||
range: 14..139,
|
||||
elt: Name(
|
||||
ExprName {
|
||||
range: 14..17,
|
||||
id: "sql",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
generators: [
|
||||
Comprehension {
|
||||
range: 22..139,
|
||||
target: Name(
|
||||
ExprName {
|
||||
range: 26..29,
|
||||
id: "sql",
|
||||
ctx: Store,
|
||||
},
|
||||
),
|
||||
iter: Tuple(
|
||||
ExprTuple {
|
||||
range: 33..139,
|
||||
elts: [
|
||||
IfExp(
|
||||
ExprIfExp {
|
||||
range: 43..80,
|
||||
test: Name(
|
||||
ExprName {
|
||||
range: 65..70,
|
||||
id: "limit",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
body: BinOp(
|
||||
ExprBinOp {
|
||||
range: 43..61,
|
||||
left: Constant(
|
||||
ExprConstant {
|
||||
range: 43..53,
|
||||
value: Str(
|
||||
"LIMIT %d",
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
op: Mod,
|
||||
right: Name(
|
||||
ExprName {
|
||||
range: 56..61,
|
||||
id: "limit",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
orelse: Constant(
|
||||
ExprConstant {
|
||||
range: 76..80,
|
||||
value: None,
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
IfExp(
|
||||
ExprIfExp {
|
||||
range: 90..132,
|
||||
test: Name(
|
||||
ExprName {
|
||||
range: 116..122,
|
||||
id: "offset",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
body: BinOp(
|
||||
ExprBinOp {
|
||||
range: 91..111,
|
||||
left: Constant(
|
||||
ExprConstant {
|
||||
range: 91..102,
|
||||
value: Str(
|
||||
"OFFSET %d",
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
op: Mod,
|
||||
right: Name(
|
||||
ExprName {
|
||||
range: 105..111,
|
||||
id: "offset",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
orelse: Constant(
|
||||
ExprConstant {
|
||||
range: 128..132,
|
||||
value: None,
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
ifs: [],
|
||||
is_async: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 8..141,
|
||||
args: [
|
||||
GeneratorExp(
|
||||
ExprGeneratorExp {
|
||||
range: 14..139,
|
||||
elt: Name(
|
||||
ExprName {
|
||||
range: 14..17,
|
||||
id: "sql",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
generators: [
|
||||
Comprehension {
|
||||
range: 22..139,
|
||||
target: Name(
|
||||
ExprName {
|
||||
range: 26..29,
|
||||
id: "sql",
|
||||
ctx: Store,
|
||||
},
|
||||
),
|
||||
iter: Tuple(
|
||||
ExprTuple {
|
||||
range: 33..139,
|
||||
elts: [
|
||||
IfExp(
|
||||
ExprIfExp {
|
||||
range: 43..80,
|
||||
test: Name(
|
||||
ExprName {
|
||||
range: 65..70,
|
||||
id: "limit",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
body: BinOp(
|
||||
ExprBinOp {
|
||||
range: 43..61,
|
||||
left: Constant(
|
||||
ExprConstant {
|
||||
range: 43..53,
|
||||
value: Str(
|
||||
"LIMIT %d",
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
op: Mod,
|
||||
right: Name(
|
||||
ExprName {
|
||||
range: 56..61,
|
||||
id: "limit",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
orelse: Constant(
|
||||
ExprConstant {
|
||||
range: 76..80,
|
||||
value: None,
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
IfExp(
|
||||
ExprIfExp {
|
||||
range: 90..132,
|
||||
test: Name(
|
||||
ExprName {
|
||||
range: 116..122,
|
||||
id: "offset",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
body: BinOp(
|
||||
ExprBinOp {
|
||||
range: 91..111,
|
||||
left: Constant(
|
||||
ExprConstant {
|
||||
range: 91..102,
|
||||
value: Str(
|
||||
"OFFSET %d",
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
op: Mod,
|
||||
right: Name(
|
||||
ExprName {
|
||||
range: 105..111,
|
||||
id: "offset",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
orelse: Constant(
|
||||
ExprConstant {
|
||||
range: 128..132,
|
||||
value: None,
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
ifs: [],
|
||||
is_async: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
@ -216,18 +216,21 @@ Module(
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Constant(
|
||||
ExprConstant {
|
||||
range: 716..717,
|
||||
value: Int(
|
||||
5,
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 715..718,
|
||||
args: [
|
||||
Constant(
|
||||
ExprConstant {
|
||||
range: 716..717,
|
||||
value: Int(
|
||||
5,
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
body: [
|
||||
|
|
|
@ -66,16 +66,19 @@ expression: parse_ast
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Name(
|
||||
ExprName {
|
||||
range: 68..72,
|
||||
id: "rest",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 67..73,
|
||||
args: [
|
||||
Name(
|
||||
ExprName {
|
||||
range: 68..72,
|
||||
id: "rest",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -195,16 +198,19 @@ expression: parse_ast
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Name(
|
||||
ExprName {
|
||||
range: 171..176,
|
||||
id: "label",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 170..177,
|
||||
args: [
|
||||
Name(
|
||||
ExprName {
|
||||
range: 171..176,
|
||||
id: "label",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
|
|
@ -122,42 +122,45 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Starred(
|
||||
ExprStarred {
|
||||
range: 93..99,
|
||||
value: BinOp(
|
||||
ExprBinOp {
|
||||
range: 94..99,
|
||||
left: Name(
|
||||
ExprName {
|
||||
range: 94..95,
|
||||
id: "a",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
op: Add,
|
||||
right: Name(
|
||||
ExprName {
|
||||
range: 98..99,
|
||||
id: "b",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
Name(
|
||||
ExprName {
|
||||
range: 101..102,
|
||||
id: "c",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 92..103,
|
||||
args: [
|
||||
Starred(
|
||||
ExprStarred {
|
||||
range: 93..99,
|
||||
value: BinOp(
|
||||
ExprBinOp {
|
||||
range: 94..99,
|
||||
left: Name(
|
||||
ExprName {
|
||||
range: 94..95,
|
||||
id: "a",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
op: Add,
|
||||
right: Name(
|
||||
ExprName {
|
||||
range: 98..99,
|
||||
id: "b",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
Name(
|
||||
ExprName {
|
||||
range: 101..102,
|
||||
id: "c",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -283,22 +286,25 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
UnaryOp(
|
||||
ExprUnaryOp {
|
||||
range: 225..227,
|
||||
op: USub,
|
||||
operand: Name(
|
||||
ExprName {
|
||||
range: 226..227,
|
||||
id: "a",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 224..228,
|
||||
args: [
|
||||
UnaryOp(
|
||||
ExprUnaryOp {
|
||||
range: 225..227,
|
||||
op: USub,
|
||||
operand: Name(
|
||||
ExprName {
|
||||
range: 226..227,
|
||||
id: "a",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
op: Mult,
|
||||
|
@ -339,8 +345,11 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 270..272,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
attr: Identifier {
|
||||
|
@ -368,16 +377,19 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Tuple(
|
||||
ExprTuple {
|
||||
range: 298..300,
|
||||
elts: [],
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 297..301,
|
||||
args: [
|
||||
Tuple(
|
||||
ExprTuple {
|
||||
range: 298..300,
|
||||
elts: [],
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
attr: Identifier {
|
||||
|
@ -405,16 +417,19 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Tuple(
|
||||
ExprTuple {
|
||||
range: 329..331,
|
||||
elts: [],
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 328..333,
|
||||
args: [
|
||||
Tuple(
|
||||
ExprTuple {
|
||||
range: 329..331,
|
||||
elts: [],
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
attr: Identifier {
|
||||
|
@ -563,8 +578,11 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 476..478,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
slice: Slice(
|
||||
|
@ -771,33 +789,39 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Call(
|
||||
ExprCall {
|
||||
range: 626..635,
|
||||
func: Name(
|
||||
ExprName {
|
||||
range: 626..631,
|
||||
id: "match",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Constant(
|
||||
ExprConstant {
|
||||
range: 632..634,
|
||||
value: Int(
|
||||
12,
|
||||
),
|
||||
kind: None,
|
||||
arguments: Arguments {
|
||||
range: 625..636,
|
||||
args: [
|
||||
Call(
|
||||
ExprCall {
|
||||
range: 626..635,
|
||||
func: Name(
|
||||
ExprName {
|
||||
range: 626..631,
|
||||
id: "match",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 631..635,
|
||||
args: [
|
||||
Constant(
|
||||
ExprConstant {
|
||||
range: 632..634,
|
||||
value: Int(
|
||||
12,
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: crates/ruff_python_parser/src/parser.rs
|
||||
expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||
expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||
---
|
||||
[
|
||||
Assign(
|
||||
|
@ -37,8 +37,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 17..19,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -176,8 +179,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 88..90,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -249,8 +255,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 165..167,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -324,35 +333,41 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Call(
|
||||
ExprCall {
|
||||
range: 221..240,
|
||||
func: Attribute(
|
||||
ExprAttribute {
|
||||
range: 221..238,
|
||||
value: Constant(
|
||||
ExprConstant {
|
||||
range: 221..227,
|
||||
value: Int(
|
||||
11,
|
||||
),
|
||||
kind: None,
|
||||
arguments: Arguments {
|
||||
range: 220..241,
|
||||
args: [
|
||||
Call(
|
||||
ExprCall {
|
||||
range: 221..240,
|
||||
func: Attribute(
|
||||
ExprAttribute {
|
||||
range: 221..238,
|
||||
value: Constant(
|
||||
ExprConstant {
|
||||
range: 221..227,
|
||||
value: Int(
|
||||
11,
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
attr: Identifier {
|
||||
id: "bit_length",
|
||||
range: 228..238,
|
||||
},
|
||||
),
|
||||
attr: Identifier {
|
||||
id: "bit_length",
|
||||
range: 228..238,
|
||||
ctx: Load,
|
||||
},
|
||||
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,
|
||||
},
|
||||
),
|
||||
args: [],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 263..265,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -431,8 +449,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 287..289,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -504,8 +525,11 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 327..329,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -639,16 +663,19 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
kind: None,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Name(
|
||||
ExprName {
|
||||
range: 388..390,
|
||||
id: "no",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Arguments {
|
||||
range: 387..391,
|
||||
args: [
|
||||
Name(
|
||||
ExprName {
|
||||
range: 388..390,
|
||||
id: "no",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
|
|
|
@ -10,23 +10,28 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 6..9,
|
||||
},
|
||||
bases: [
|
||||
Name(
|
||||
ExprName {
|
||||
range: 10..11,
|
||||
id: "A",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
Name(
|
||||
ExprName {
|
||||
range: 13..14,
|
||||
id: "B",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 9..15,
|
||||
args: [
|
||||
Name(
|
||||
ExprName {
|
||||
range: 10..11,
|
||||
id: "A",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
Name(
|
||||
ExprName {
|
||||
range: 13..14,
|
||||
id: "B",
|
||||
ctx: Load,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
FunctionDef(
|
||||
StmtFunctionDef {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: crates/ruff_python_parser/src/parser.rs
|
||||
expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
||||
expression: "parse_suite(source, \"<test>\").unwrap()"
|
||||
---
|
||||
[
|
||||
ClassDef(
|
||||
|
@ -10,8 +10,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 16..19,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 22..24,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
Expr(
|
||||
StmtExpr {
|
||||
|
@ -48,8 +53,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 58..61,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 69..71,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
Expr(
|
||||
StmtExpr {
|
||||
|
@ -94,8 +104,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 111..114,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 131..133,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
Expr(
|
||||
StmtExpr {
|
||||
|
@ -155,8 +170,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 165..168,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 174..176,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
Expr(
|
||||
StmtExpr {
|
||||
|
@ -203,8 +223,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 206..209,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 216..218,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
Expr(
|
||||
StmtExpr {
|
||||
|
@ -251,8 +276,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 246..249,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 254..256,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
Expr(
|
||||
StmtExpr {
|
||||
|
@ -288,8 +318,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 281..284,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 289..291,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
Expr(
|
||||
StmtExpr {
|
||||
|
@ -325,8 +360,13 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
|
|||
id: "Foo",
|
||||
range: 318..321,
|
||||
},
|
||||
bases: [],
|
||||
keywords: [],
|
||||
arguments: Some(
|
||||
Arguments {
|
||||
range: 341..343,
|
||||
args: [],
|
||||
keywords: [],
|
||||
},
|
||||
),
|
||||
body: [
|
||||
Pass(
|
||||
StmtPass {
|
||||
|
|
|
@ -16,37 +16,40 @@ expression: parse_ast
|
|||
ctx: Load,
|
||||
},
|
||||
),
|
||||
args: [
|
||||
Constant(
|
||||
ExprConstant {
|
||||
range: 8..20,
|
||||
value: Str(
|
||||
"positional",
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
),
|
||||
],
|
||||
keywords: [
|
||||
Keyword {
|
||||
range: 22..31,
|
||||
arg: Some(
|
||||
Identifier {
|
||||
id: "keyword",
|
||||
range: 22..29,
|
||||
},
|
||||
),
|
||||
value: Constant(
|
||||
arguments: Arguments {
|
||||
range: 7..32,
|
||||
args: [
|
||||
Constant(
|
||||
ExprConstant {
|
||||
range: 30..31,
|
||||
value: Int(
|
||||
2,
|
||||
range: 8..20,
|
||||
value: Str(
|
||||
"positional",
|
||||
),
|
||||
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