Make Arguments boxed

This commit is contained in:
Charlie Marsh 2024-02-09 21:54:57 -05:00
parent 7a349660e4
commit 4e23ee0e1d
48 changed files with 203 additions and 314 deletions

View File

@ -343,15 +343,16 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
Expr::Call( Expr::Call(
call @ ast::ExprCall { call @ ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range: _, range: _,
}, },
) => { ) => {
let Arguments {
args,
keywords,
range: _,
} = &**arguments;
if checker.any_enabled(&[ if checker.any_enabled(&[
// pylint // pylint
Rule::BadStringFormatCharacter, Rule::BadStringFormatCharacter,

View File

@ -57,7 +57,7 @@ fn assertion_error(msg: Option<&Expr>) -> Stmt {
ctx: ExprContext::Load, ctx: ExprContext::Load,
range: TextRange::default(), range: TextRange::default(),
})), })),
arguments: Arguments { arguments: Box::new(Arguments {
args: if let Some(msg) = msg { args: if let Some(msg) = msg {
Box::from([msg.clone()]) Box::from([msg.clone()])
} else { } else {
@ -65,7 +65,7 @@ fn assertion_error(msg: Option<&Expr>) -> Stmt {
}, },
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}))), }))),
cause: None, cause: None,

View File

@ -1,7 +1,7 @@
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Expr}; use ruff_python_ast::{self as ast, Expr};
use ruff_python_semantic::SemanticModel; use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
@ -91,9 +91,7 @@ pub(crate) fn zip_without_explicit_strict(checker: &mut Checker, call: &ast::Exp
/// `itertools.cycle` or similar). /// `itertools.cycle` or similar).
fn is_infinite_iterator(arg: &Expr, semantic: &SemanticModel) -> bool { fn is_infinite_iterator(arg: &Expr, semantic: &SemanticModel) -> bool {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, keywords, .. },
..
}) = &arg }) = &arg
else { else {
return false; return false;
@ -104,17 +102,17 @@ fn is_infinite_iterator(arg: &Expr, semantic: &SemanticModel) -> bool {
["itertools", "cycle" | "count"] => true, ["itertools", "cycle" | "count"] => true,
["itertools", "repeat"] => { ["itertools", "repeat"] => {
// Ex) `itertools.repeat(1)` // Ex) `itertools.repeat(1)`
if keywords.is_empty() && args.len() == 1 { if arguments.keywords.is_empty() && arguments.args.len() == 1 {
return true; return true;
} }
// Ex) `itertools.repeat(1, None)` // Ex) `itertools.repeat(1, None)`
if args.len() == 2 && args[1].is_none_literal_expr() { if arguments.args.len() == 2 && arguments.args[1].is_none_literal_expr() {
return true; return true;
} }
// Ex) `iterools.repeat(1, times=None)` // Ex) `iterools.repeat(1, times=None)`
for keyword in keywords.iter() { for keyword in arguments.keywords.iter() {
if keyword.arg.as_ref().is_some_and(|name| name == "times") { if keyword.arg.as_ref().is_some_and(|name| name == "times") {
if keyword.value.is_none_literal_expr() { if keyword.value.is_none_literal_expr() {
return true; return true;

View File

@ -1,7 +1,7 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::comparable::ComparableKeyword; use ruff_python_ast::comparable::ComparableKeyword;
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword}; use ruff_python_ast::{self as ast, Expr, Keyword};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -84,11 +84,7 @@ pub(crate) fn unnecessary_double_cast_or_process(
return; return;
}; };
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments {
keywords: inner_kw, ..
},
..
}) = arg }) = arg
else { else {
return; return;
@ -103,10 +99,10 @@ pub(crate) fn unnecessary_double_cast_or_process(
// Avoid collapsing nested `sorted` calls with non-identical keyword arguments // Avoid collapsing nested `sorted` calls with non-identical keyword arguments
// (i.e., `key`, `reverse`). // (i.e., `key`, `reverse`).
if &*inner.id == "sorted" && &*outer.id == "sorted" { if &*inner.id == "sorted" && &*outer.id == "sorted" {
if inner_kw.len() != outer_kw.len() { if arguments.keywords.len() != outer_kw.len() {
return; return;
} }
if !inner_kw.iter().all(|inner| { if !arguments.keywords.iter().all(|inner| {
outer_kw outer_kw
.iter() .iter()
.any(|outer| ComparableKeyword::from(inner) == ComparableKeyword::from(outer)) .any(|outer| ComparableKeyword::from(inner) == ComparableKeyword::from(outer))

View File

@ -5,7 +5,7 @@ use ruff_diagnostics::{FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::visitor; use ruff_python_ast::visitor;
use ruff_python_ast::visitor::Visitor; use ruff_python_ast::visitor::Visitor;
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Parameters, Stmt}; use ruff_python_ast::{self as ast, Expr, ExprContext, Parameters, Stmt};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -125,23 +125,22 @@ pub(crate) fn unnecessary_map(
ObjectType::List | ObjectType::Set => { ObjectType::List | ObjectType::Set => {
// Only flag, e.g., `list(map(lambda x: x + 1, iterable))`. // Only flag, e.g., `list(map(lambda x: x + 1, iterable))`.
let [Expr::Call(ast::ExprCall { let [Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, keywords, .. },
..
})] = args })] = args
else { else {
return; return;
}; };
if args.len() != 2 { if arguments.args.len() != 2 {
return; return;
} }
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
return; return;
} }
let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) let Some(argument) =
helpers::first_argument_with_matching_function("map", func, &arguments.args)
else { else {
return; return;
}; };
@ -170,23 +169,22 @@ pub(crate) fn unnecessary_map(
ObjectType::Dict => { ObjectType::Dict => {
// Only flag, e.g., `dict(map(lambda v: (v, v ** 2), values))`. // Only flag, e.g., `dict(map(lambda v: (v, v ** 2), values))`.
let [Expr::Call(ast::ExprCall { let [Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, keywords, .. },
..
})] = args })] = args
else { else {
return; return;
}; };
if args.len() != 2 { if arguments.args.len() != 2 {
return; return;
} }
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
return; return;
} }
let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) let Some(argument) =
helpers::first_argument_with_matching_function("map", func, &arguments.args)
else { else {
return; return;
}; };

View File

@ -1,4 +1,4 @@
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_source_file::Locator; use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
@ -175,12 +175,8 @@ impl Violation for DotFormatInException {
/// EM101, EM102, EM103 /// EM101, EM102, EM103
pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) { pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) {
if let Expr::Call(ast::ExprCall { if let Expr::Call(ast::ExprCall { arguments, .. }) = exc {
arguments: Arguments { args, .. }, if let Some(first) = arguments.args.first() {
..
}) = exc
{
if let Some(first) = args.first() {
match first { match first {
// Check for string literals. // Check for string literals.
Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) => { Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) => {

View File

@ -1,5 +1,5 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword, Operator}; use ruff_python_ast::{self as ast, Expr, Keyword, Operator};
use ruff_python_semantic::analyze::logging; use ruff_python_semantic::analyze::logging;
use ruff_python_stdlib::logging::LoggingLevel; use ruff_python_stdlib::logging::LoggingLevel;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
@ -104,16 +104,14 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
} }
} }
Expr::Call(ast::ExprCall { Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { keywords, .. },
..
}) => { }) => {
if checker if checker
.semantic() .semantic()
.resolve_call_path(func) .resolve_call_path(func)
.is_some_and(|call_path| matches!(call_path.as_slice(), ["", "dict"])) .is_some_and(|call_path| matches!(call_path.as_slice(), ["", "dict"]))
{ {
for keyword in keywords.iter() { for keyword in arguments.keywords.iter() {
if let Some(attr) = &keyword.arg { if let Some(attr) = &keyword.arg {
if is_reserved_attr(attr) { if is_reserved_attr(attr) {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(

View File

@ -81,23 +81,18 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
for (index, call) in values.iter().enumerate() { for (index, call) in values.iter().enumerate() {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range: _, range: _,
}) = &call }) = &call
else { else {
continue; continue;
}; };
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
continue; continue;
} }
let [arg] = &**args else { let [arg] = &*arguments.args else {
continue; continue;
}; };
@ -140,12 +135,7 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
.map(|expr| { .map(|expr| {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func: _, func: _,
arguments: arguments,
Arguments {
args,
keywords: _,
range: _,
},
range: _, range: _,
}) = expr }) = expr
else { else {
@ -154,7 +144,9 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
format!("Indices should only contain `{attr_name}` calls") format!("Indices should only contain `{attr_name}` calls")
) )
}; };
args.first() arguments
.args
.first()
.unwrap_or_else(|| panic!("`{attr_name}` should have one argument")) .unwrap_or_else(|| panic!("`{attr_name}` should have one argument"))
}) })
.collect(); .collect();
@ -187,11 +179,11 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
}); });
let node3 = Expr::Call(ast::ExprCall { let node3 = Expr::Call(ast::ExprCall {
func: Box::new(node2), func: Box::new(node2),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([node]), args: Box::from([node]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}); });
let call = node3; let call = node3;

View File

@ -1,4 +1,4 @@
use ruff_python_ast::{self as ast, Arguments, Decorator, Expr}; use ruff_python_ast::{self as ast, Decorator, Expr};
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -137,18 +137,10 @@ fn check_mark_parentheses(checker: &mut Checker, decorator: &Decorator, marker:
match &decorator.expression { match &decorator.expression {
Expr::Call(ast::ExprCall { Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range: _, range: _,
}) => { }) => {
if !checker.settings.flake8_pytest_style.mark_parentheses if !checker.settings.flake8_pytest_style.mark_parentheses && arguments.is_empty() {
&& args.is_empty()
&& keywords.is_empty()
{
let fix = Fix::safe_edit(Edit::deletion(func.end(), decorator.end())); let fix = Fix::safe_edit(Edit::deletion(func.end(), decorator.end()));
pytest_mark_parentheses(checker, decorator, marker, fix, "", "()"); pytest_mark_parentheses(checker, decorator, marker, fix, "", "()");
} }
@ -171,11 +163,8 @@ fn check_useless_usefixtures(checker: &mut Checker, decorator: &Decorator, marke
// @pytest.mark.usefixtures // @pytest.mark.usefixtures
Expr::Attribute(..) => {} Expr::Attribute(..) => {}
// @pytest.mark.usefixtures(...) // @pytest.mark.usefixtures(...)
Expr::Call(ast::ExprCall { Expr::Call(ast::ExprCall { arguments, .. }) => {
arguments: Arguments { args, keywords, .. }, if !arguments.is_empty() {
..
}) => {
if !args.is_empty() || !keywords.is_empty() {
return; return;
} }
} }

View File

@ -7,7 +7,7 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::comparable::ComparableExpr; use ruff_python_ast::comparable::ComparableExpr;
use ruff_python_ast::parenthesize::parenthesized_range; use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::AstNode; use ruff_python_ast::AstNode;
use ruff_python_ast::{self as ast, Arguments, Decorator, Expr, ExprContext}; use ruff_python_ast::{self as ast, Decorator, Expr, ExprContext};
use ruff_python_codegen::Generator; use ruff_python_codegen::Generator;
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer}; use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
@ -632,23 +632,19 @@ fn handle_value_rows(
pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Decorator]) { pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Decorator]) {
for decorator in decorators { for decorator in decorators {
if is_pytest_parametrize(decorator, checker.semantic()) { if is_pytest_parametrize(decorator, checker.semantic()) {
if let Expr::Call(ast::ExprCall { if let Expr::Call(ast::ExprCall { arguments, .. }) = &decorator.expression {
arguments: Arguments { args, .. },
..
}) = &decorator.expression
{
if checker.enabled(Rule::PytestParametrizeNamesWrongType) { if checker.enabled(Rule::PytestParametrizeNamesWrongType) {
if let [names, ..] = &**args { if let [names, ..] = &*arguments.args {
check_names(checker, decorator, names); check_names(checker, decorator, names);
} }
} }
if checker.enabled(Rule::PytestParametrizeValuesWrongType) { if checker.enabled(Rule::PytestParametrizeValuesWrongType) {
if let [names, values, ..] = &**args { if let [names, values, ..] = &*arguments.args {
check_values(checker, names, values); check_values(checker, names, values);
} }
} }
if checker.enabled(Rule::PytestDuplicateParametrizeTestCases) { if checker.enabled(Rule::PytestDuplicateParametrizeTestCases) {
if let [_, values, ..] = &**args { if let [_, values, ..] = &*arguments.args {
check_duplicates(checker, values); check_duplicates(checker, values);
} }
} }

View File

@ -389,11 +389,11 @@ impl UnittestAssert {
}; };
let node1 = ast::ExprCall { let node1 = ast::ExprCall {
func: Box::new(node.into()), func: Box::new(node.into()),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([(**obj).clone(), (**cls).clone()]), args: Box::from([(**obj).clone(), (**cls).clone()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
let isinstance = node1.into(); let isinstance = node1.into();
@ -433,11 +433,11 @@ impl UnittestAssert {
}; };
let node2 = ast::ExprCall { let node2 = ast::ExprCall {
func: Box::new(node1.into()), func: Box::new(node1.into()),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([(**regex).clone(), (**text).clone()]), args: Box::from([(**regex).clone(), (**text).clone()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
let re_search = node2.into(); let re_search = node2.into();

View File

@ -303,21 +303,16 @@ fn isinstance_target<'a>(call: &'a Expr, semantic: &'a SemanticModel) -> Option<
// Verify that this is an `isinstance` call. // Verify that this is an `isinstance` call.
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range: _, range: _,
}) = &call }) = &call
else { else {
return None; return None;
}; };
if args.len() != 2 { if !arguments.keywords.is_empty() {
return None; return None;
} }
if !keywords.is_empty() { if arguments.args.len() != 2 {
return None; return None;
} }
let Expr::Name(ast::ExprName { id: func_name, .. }) = func.as_ref() else { let Expr::Name(ast::ExprName { id: func_name, .. }) = func.as_ref() else {
@ -331,7 +326,7 @@ fn isinstance_target<'a>(call: &'a Expr, semantic: &'a SemanticModel) -> Option<
} }
// Collect the target (e.g., `obj` in `isinstance(obj, int)`). // Collect the target (e.g., `obj` in `isinstance(obj, int)`).
Some(&args[0]) Some(&arguments.args[0])
} }
/// SIM101 /// SIM101
@ -374,12 +369,10 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
if indices.len() > 1 { if indices.len() > 1 {
// Grab the target used in each duplicate `isinstance` call (e.g., `obj` in // Grab the target used in each duplicate `isinstance` call (e.g., `obj` in
// `isinstance(obj, int)`). // `isinstance(obj, int)`).
let target = if let Expr::Call(ast::ExprCall { let target = if let Expr::Call(ast::ExprCall { arguments, .. }) = &values[indices[0]] {
arguments: Arguments { args, .. }, arguments
.. .args
}) = &values[indices[0]] .first()
{
args.first()
.expect("`isinstance` should have two arguments") .expect("`isinstance` should have two arguments")
} else { } else {
unreachable!("Indices should only contain `isinstance` calls") unreachable!("Indices should only contain `isinstance` calls")
@ -401,14 +394,13 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
.iter() .iter()
.map(|index| &values[*index]) .map(|index| &values[*index])
.map(|expr| { .map(|expr| {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall { arguments, .. }) = expr else {
arguments: Arguments { args, .. },
..
}) = expr
else {
unreachable!("Indices should only contain `isinstance` calls") unreachable!("Indices should only contain `isinstance` calls")
}; };
args.get(1).expect("`isinstance` should have two arguments") arguments
.args
.get(1)
.expect("`isinstance` should have two arguments")
}) })
.collect(); .collect();
@ -436,11 +428,11 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
}; };
let node2 = ast::ExprCall { let node2 = ast::ExprCall {
func: Box::new(node1.into()), func: Box::new(node1.into()),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([target.clone(), node.into()]), args: Box::from([target.clone(), node.into()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
let call = node2.into(); let call = node2.into();

View File

@ -1,4 +1,4 @@
use ruff_python_ast::{self as ast, Arguments, Expr}; use ruff_python_ast::{self as ast, Expr};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::fix::snippet::SourceCodeSnippet; use crate::fix::snippet::SourceCodeSnippet;
@ -134,14 +134,12 @@ pub(crate) fn use_capital_environment_variables(checker: &mut Checker, expr: &Ex
// Ex) `os.environ.get('foo')`, `os.getenv('foo')` // Ex) `os.environ.get('foo')`, `os.getenv('foo')`
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, .. },
..
}) = expr }) = expr
else { else {
return; return;
}; };
let Some(arg) = args.first() else { let Some(arg) = arguments.args.first() else {
return; return;
}; };
let Expr::StringLiteral(ast::ExprStringLiteral { value: env_var, .. }) = arg else { let Expr::StringLiteral(ast::ExprStringLiteral { value: env_var, .. }) = arg else {
@ -233,13 +231,13 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) { pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
arguments: Arguments { args, keywords, .. }, arguments,
range: _, range: _,
}) = expr }) = expr
else { else {
return; return;
}; };
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
return; return;
} }
let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() else { let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() else {
@ -248,13 +246,13 @@ pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
if attr != "get" { if attr != "get" {
return; return;
} }
let Some(key) = args.first() else { let Some(key) = arguments.args.first() else {
return; return;
}; };
if !(key.is_literal_expr() || key.is_name_expr()) { if !(key.is_literal_expr() || key.is_name_expr()) {
return; return;
} }
let Some(default) = args.get(1) else { let Some(default) = arguments.args.get(1) else {
return; return;
}; };
if !default.is_none_literal_expr() { if !default.is_none_literal_expr() {

View File

@ -184,11 +184,11 @@ pub(crate) fn if_expr_with_true_false(
} }
.into(), .into(),
), ),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([test.clone()]), args: Box::from([test.clone()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
} }
.into(), .into(),

View File

@ -278,11 +278,11 @@ pub(crate) fn double_negation(checker: &mut Checker, expr: &Expr, op: UnaryOp, o
}; };
let node1 = ast::ExprCall { let node1 = ast::ExprCall {
func: Box::new(node.into()), func: Box::new(node.into()),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([*operand.clone()]), args: Box::from([*operand.clone()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(

View File

@ -175,11 +175,11 @@ pub(crate) fn if_else_block_instead_of_dict_get(checker: &mut Checker, stmt_if:
}; };
let node3 = ast::ExprCall { let node3 = ast::ExprCall {
func: Box::new(node2.into()), func: Box::new(node2.into()),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([node1, node]), args: Box::from([node1, node]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
let node4 = expected_var.clone(); let node4 = expected_var.clone();
@ -275,11 +275,11 @@ pub(crate) fn if_exp_instead_of_dict_get(
}; };
let fixed_node = ast::ExprCall { let fixed_node = ast::ExprCall {
func: Box::new(dict_get_node.into()), func: Box::new(dict_get_node.into()),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([dict_key_node, default_value_node]), args: Box::from([dict_key_node, default_value_node]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };

View File

@ -160,11 +160,11 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt_if: &ast::StmtIf) {
}; };
let value_node = ast::ExprCall { let value_node = ast::ExprCall {
func: Box::new(func_node.into()), func: Box::new(func_node.into()),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([if_test.clone()]), args: Box::from([if_test.clone()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
let return_node = ast::StmtReturn { let return_node = ast::StmtReturn {

View File

@ -390,11 +390,11 @@ fn return_stmt(id: &str, test: &Expr, target: &Expr, iter: &Expr, generator: Gen
}; };
let node2 = ast::ExprCall { let node2 = ast::ExprCall {
func: Box::new(node1.into()), func: Box::new(node1.into()),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([node.into()]), args: Box::from([node.into()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
let node3 = ast::StmtReturn { let node3 = ast::StmtReturn {

View File

@ -1,6 +1,6 @@
use ast::{ExprAttribute, ExprName, Identifier}; use ast::{ExprAttribute, ExprName, Identifier};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Expr, ExprCall}; use ruff_python_ast::{self as ast, Expr, ExprCall};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::{checkers::ast::Checker, fix::snippet::SourceCodeSnippet}; use crate::{checkers::ast::Checker, fix::snippet::SourceCodeSnippet};
@ -61,11 +61,9 @@ impl AlwaysFixableViolation for ZipDictKeysAndValues {
/// SIM911 /// SIM911
pub(crate) fn zip_dict_keys_and_values(checker: &mut Checker, expr: &ExprCall) { pub(crate) fn zip_dict_keys_and_values(checker: &mut Checker, expr: &ExprCall) {
let ExprCall { let ExprCall {
func, func, arguments, ..
arguments: Arguments { args, keywords, .. },
..
} = expr; } = expr;
match &keywords[..] { match &*arguments.keywords {
[] => {} [] => {}
[ast::Keyword { [ast::Keyword {
arg: Some(name), .. arg: Some(name), ..
@ -75,7 +73,7 @@ pub(crate) fn zip_dict_keys_and_values(checker: &mut Checker, expr: &ExprCall) {
if matches!(func.as_ref(), Expr::Name(ExprName { id, .. }) if &**id != "zip") { if matches!(func.as_ref(), Expr::Name(ExprName { id, .. }) if &**id != "zip") {
return; return;
} }
let [arg1, arg2] = &args[..] else { let [arg1, arg2] = &*arguments.args else {
return; return;
}; };
let Some((var1, attr1)) = get_var_attr(arg1) else { let Some((var1, attr1)) = get_var_attr(arg1) else {

View File

@ -1,4 +1,4 @@
use ruff_python_ast::{self as ast, Arguments, ConversionFlag, Expr}; use ruff_python_ast::{self as ast, ConversionFlag, Expr};
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
/// Wrap an expression in a [`ast::FStringElement::Expression`] with no special formatting. /// Wrap an expression in a [`ast::FStringElement::Expression`] with no special formatting.
@ -26,14 +26,9 @@ fn is_simple_call(expr: &Expr) -> bool {
match expr { match expr {
Expr::Call(ast::ExprCall { Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range: _, range: _,
}) => args.is_empty() && keywords.is_empty() && is_simple_callee(func), }) => arguments.is_empty() && is_simple_callee(func),
_ => false, _ => false,
} }
} }

View File

@ -3,7 +3,7 @@ use itertools::Itertools;
use crate::fix::edits::pad; use crate::fix::edits::pad;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Expr}; use ruff_python_ast::{self as ast, Expr};
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -103,20 +103,16 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
/// FLY002 /// FLY002
pub(crate) fn static_join_to_fstring(checker: &mut Checker, expr: &Expr, joiner: &str) { pub(crate) fn static_join_to_fstring(checker: &mut Checker, expr: &Expr, joiner: &str) {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall { arguments, .. }) = expr else {
arguments: Arguments { args, keywords, .. },
..
}) = expr
else {
return; return;
}; };
// If there are kwargs or more than one argument, this is some non-standard // If there are kwargs or more than one argument, this is some non-standard
// string join call. // string join call.
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
return; return;
} }
let [arg] = &**args else { let [arg] = &*arguments.args else {
return; return;
}; };

View File

@ -3,7 +3,7 @@ use std::fmt;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast as ast; use ruff_python_ast as ast;
use ruff_python_ast::{Arguments, Expr}; use ruff_python_ast::Expr;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -70,14 +70,12 @@ pub(crate) fn incorrect_dict_iterator(checker: &mut Checker, stmt_for: &ast::Stm
return; return;
}; };
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, .. },
..
}) = stmt_for.iter.as_ref() }) = stmt_for.iter.as_ref()
else { else {
return; return;
}; };
if !args.is_empty() { if !arguments.is_empty() {
return; return;
} }
let Expr::Attribute(ast::ExprAttribute { attr, .. }) = func.as_ref() else { let Expr::Attribute(ast::ExprAttribute { attr, .. }) = func.as_ref() else {

View File

@ -1,4 +1,4 @@
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -93,23 +93,18 @@ pub(crate) fn manual_list_comprehension(checker: &mut Checker, target: &Expr, bo
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range, range,
}) = value.as_ref() }) = value.as_ref()
else { else {
return; return;
}; };
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
return; return;
} }
let [arg] = &**args else { let [arg] = &*arguments.args else {
return; return;
}; };

View File

@ -1,7 +1,7 @@
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::any_over_expr; use ruff_python_ast::helpers::any_over_expr;
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_python_semantic::analyze::typing::is_list; use ruff_python_semantic::analyze::typing::is_list;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -60,23 +60,18 @@ pub(crate) fn manual_list_copy(checker: &mut Checker, target: &Expr, body: &[Stm
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range, range,
}) = value.as_ref() }) = value.as_ref()
else { else {
return; return;
}; };
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
return; return;
} }
let [arg] = &**args else { let [arg] = &*arguments.args else {
return; return;
}; };

View File

@ -1,6 +1,6 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_python_semantic::analyze::typing::find_assigned_value; use ruff_python_semantic::analyze::typing::find_assigned_value;
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
@ -52,19 +52,14 @@ impl AlwaysFixableViolation for UnnecessaryListCast {
pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr, body: &[Stmt]) { pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr, body: &[Stmt]) {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords: _,
range: _,
},
range: list_range, range: list_range,
}) = iter }) = iter
else { else {
return; return;
}; };
let [arg] = &**args else { let [arg] = &*arguments.args else {
return; return;
}; };

View File

@ -97,16 +97,11 @@ fn collect_nested_args(min_max: MinMax, args: &[Expr], semantic: &SemanticModel)
for arg in args { for arg in args {
if let Expr::Call(ast::ExprCall { if let Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range: _, range: _,
}) = arg }) = arg
{ {
if let [arg] = &**args { if let [arg] = &*arguments.args {
if arg.as_starred_expr().is_none() { if arg.as_starred_expr().is_none() {
let new_arg = Expr::Starred(ast::ExprStarred { let new_arg = Expr::Starred(ast::ExprStarred {
value: Box::new(arg.clone()), value: Box::new(arg.clone()),
@ -117,8 +112,8 @@ fn collect_nested_args(min_max: MinMax, args: &[Expr], semantic: &SemanticModel)
continue; continue;
} }
} }
if MinMax::try_from_call(func, keywords, semantic) == Some(min_max) { if MinMax::try_from_call(func, &arguments.keywords, semantic) == Some(min_max) {
inner(min_max, args, semantic, new_args); inner(min_max, &arguments.args, semantic, new_args);
continue; continue;
} }
} }
@ -143,31 +138,29 @@ pub(crate) fn nested_min_max(
return; return;
}; };
if matches!(&args, [Expr::Call(ast::ExprCall { arguments: Arguments {args, .. }, .. })] if args.len() == 1) if matches!(&args, [Expr::Call(ast::ExprCall { arguments, .. })] if arguments.args.len() == 1) {
{
return; return;
} }
if args.iter().any(|arg| { if args.iter().any(|arg| {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { keywords, .. },
..
}) = arg }) = arg
else { else {
return false; return false;
}; };
MinMax::try_from_call(func.as_ref(), keywords.as_ref(), checker.semantic()) == Some(min_max) let keywords = arguments.keywords.as_ref();
MinMax::try_from_call(func.as_ref(), keywords, checker.semantic()) == Some(min_max)
}) { }) {
let mut diagnostic = Diagnostic::new(NestedMinMax { func: min_max }, expr.range()); let mut diagnostic = Diagnostic::new(NestedMinMax { func: min_max }, expr.range());
if !checker.indexer().has_comments(expr, checker.locator()) { if !checker.indexer().has_comments(expr, checker.locator()) {
let flattened_expr = Expr::Call(ast::ExprCall { let flattened_expr = Expr::Call(ast::ExprCall {
func: Box::new(func.clone()), func: Box::new(func.clone()),
arguments: Arguments { arguments: Box::new(Arguments {
args: collect_nested_args(min_max, args, checker.semantic()).into_boxed_slice(), args: collect_nested_args(min_max, args, checker.semantic()).into_boxed_slice(),
keywords: Box::from(keywords), keywords: Box::from(keywords),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}); });
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(

View File

@ -1,7 +1,7 @@
use std::{fmt, iter}; use std::{fmt, iter};
use regex::Regex; use regex::Regex;
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Stmt, WithItem}; use ruff_python_ast::{self as ast, Expr, ExprContext, Stmt, WithItem};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
@ -238,9 +238,7 @@ fn assignment_is_cast_expr(value: &Expr, target: &Expr, semantic: &SemanticModel
} }
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, .. },
..
}) = value }) = value
else { else {
return false; return false;
@ -248,10 +246,10 @@ fn assignment_is_cast_expr(value: &Expr, target: &Expr, semantic: &SemanticModel
let Expr::Name(ast::ExprName { id: target_id, .. }) = target else { let Expr::Name(ast::ExprName { id: target_id, .. }) = target else {
return false; return false;
}; };
if args.len() != 2 { if arguments.args.len() != 2 {
return false; return false;
} }
let Expr::Name(ast::ExprName { id: arg_id, .. }) = &args[1] else { let Expr::Name(ast::ExprName { id: arg_id, .. }) = &arguments.args[1] else {
return false; return false;
}; };
if arg_id != target_id { if arg_id != target_id {

View File

@ -1,5 +1,5 @@
use itertools::Itertools; use itertools::Itertools;
use ruff_python_ast::{self as ast, Arguments, BoolOp, Expr}; use ruff_python_ast::{self as ast, BoolOp, Expr};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use crate::fix::edits::pad; use crate::fix::edits::pad;
@ -85,9 +85,7 @@ pub(crate) fn repeated_isinstance_calls(
FxHashMap::default(); FxHashMap::default();
for value in values { for value in values {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, .. },
..
}) = value }) = value
else { else {
continue; continue;
@ -95,7 +93,7 @@ pub(crate) fn repeated_isinstance_calls(
if !matches!(func.as_ref(), Expr::Name(ast::ExprName { id, .. }) if &**id =="isinstance") { if !matches!(func.as_ref(), Expr::Name(ast::ExprName { id, .. }) if &**id =="isinstance") {
continue; continue;
} }
let [obj, types] = &args[..] else { let [obj, types] = &*arguments.args else {
continue; continue;
}; };
if !checker.semantic().is_builtin("isinstance") { if !checker.semantic().is_builtin("isinstance") {

View File

@ -135,7 +135,7 @@ fn match_named_tuple_assign<'a>(
}; };
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
arguments: Arguments { args, keywords, .. }, arguments,
range: _, range: _,
}) = value }) = value
else { else {
@ -144,7 +144,7 @@ fn match_named_tuple_assign<'a>(
if !semantic.match_typing_expr(func, "NamedTuple") { if !semantic.match_typing_expr(func, "NamedTuple") {
return None; return None;
} }
Some((typename, args, keywords, func)) Some((typename, &arguments.args, &arguments.keywords, func))
} }
/// Generate a [`Stmt::AnnAssign`] representing the provided field definition. /// Generate a [`Stmt::AnnAssign`] representing the provided field definition.

View File

@ -238,9 +238,9 @@ fn match_fields_and_total(arguments: &Arguments) -> Option<(Vec<Stmt>, Option<&K
}) => Some((fields_from_dict_literal(keys, values)?, total)), }) => Some((fields_from_dict_literal(keys, values)?, total)),
Expr::Call(ast::ExprCall { Expr::Call(ast::ExprCall {
func, func,
arguments: Arguments { keywords, .. }, arguments,
range: _, range: _,
}) => Some((fields_from_dict_call(func, keywords)?, total)), }) => Some((fields_from_dict_call(func, &arguments.keywords)?, total)),
_ => None, _ => None,
} }
} }

View File

@ -1,4 +1,4 @@
use ruff_python_ast::{self as ast, Arguments, Decorator, Expr, Keyword}; use ruff_python_ast::{self as ast, Decorator, Expr, Keyword};
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
@ -59,12 +59,7 @@ pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list:
for decorator in decorator_list { for decorator in decorator_list {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
arguments: arguments,
Arguments {
args,
keywords,
range: _,
},
range: _, range: _,
}) = &decorator.expression }) = &decorator.expression
else { else {
@ -72,8 +67,8 @@ pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list:
}; };
// Look for, e.g., `import functools; @functools.lru_cache(maxsize=None)`. // Look for, e.g., `import functools; @functools.lru_cache(maxsize=None)`.
if args.is_empty() if arguments.args.is_empty()
&& keywords.len() == 1 && arguments.keywords.len() == 1
&& checker && checker
.semantic() .semantic()
.resolve_call_path(func) .resolve_call_path(func)
@ -83,7 +78,7 @@ pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list:
arg, arg,
value, value,
range: _, range: _,
} = &keywords[0]; } = &arguments.keywords[0];
if arg.as_ref().is_some_and(|arg| arg == "maxsize") && value.is_none_literal_expr() { if arg.as_ref().is_some_and(|arg| arg == "maxsize") && value.is_none_literal_expr() {
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
LRUCacheWithMaxsizeNone, LRUCacheWithMaxsizeNone,

View File

@ -141,12 +141,7 @@ pub(crate) fn native_literals(
) { ) {
let ast::ExprCall { let ast::ExprCall {
func, func,
arguments: arguments,
ast::Arguments {
args,
keywords,
range: _,
},
range: _, range: _,
} = call; } = call;
@ -154,7 +149,7 @@ pub(crate) fn native_literals(
return; return;
}; };
if !keywords.is_empty() || args.len() > 1 { if !arguments.keywords.is_empty() || arguments.args.len() > 1 {
return; return;
} }
@ -179,7 +174,7 @@ pub(crate) fn native_literals(
} }
} }
match args.first() { match arguments.args.first() {
None => { None => {
let mut diagnostic = Diagnostic::new(NativeLiterals { literal_type }, call.range()); let mut diagnostic = Diagnostic::new(NativeLiterals { literal_type }, call.range());

View File

@ -20,11 +20,11 @@ pub(super) fn generate_method_call(name: &str, method: &str, generator: Generato
// Make it into a call `name.method()` // Make it into a call `name.method()`
let call = ast::ExprCall { let call = ast::ExprCall {
func: Box::new(attr.into()), func: Box::new(attr.into()),
arguments: ast::Arguments { arguments: Box::new(ast::Arguments {
args: Box::from([]), args: Box::from([]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
// And finally, turn it into a statement. // And finally, turn it into a statement.

View File

@ -151,7 +151,7 @@ fn match_remove(if_stmt: &ast::StmtIf) -> Option<(&Expr, &ast::ExprName)> {
let ast::ExprCall { let ast::ExprCall {
func: attr, func: attr,
arguments: ast::Arguments { args, keywords, .. }, arguments,
.. ..
} = expr.as_call_expr()?; } = expr.as_call_expr()?;
@ -165,11 +165,11 @@ fn match_remove(if_stmt: &ast::StmtIf) -> Option<(&Expr, &ast::ExprName)> {
return None; return None;
}; };
let [arg] = &**args else { let [arg] = &*arguments.args else {
return None; return None;
}; };
if func_name != "remove" || !keywords.is_empty() { if func_name != "remove" || !arguments.keywords.is_empty() {
return None; return None;
} }
@ -190,11 +190,11 @@ fn make_suggestion(set: &ast::ExprName, element: &Expr, generator: Generator) ->
// Make the actual call `set.discard(element)` // Make the actual call `set.discard(element)`
let call = ast::ExprCall { let call = ast::ExprCall {
func: Box::new(attr.into()), func: Box::new(attr.into()),
arguments: ast::Arguments { arguments: Box::new(ast::Arguments {
args: Box::from([element.clone()]), args: Box::from([element.clone()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
// And finally, turn it into a statement. // And finally, turn it into a statement.

View File

@ -136,9 +136,7 @@ fn find_file_open<'a>(
) -> Option<FileOpen<'a>> { ) -> Option<FileOpen<'a>> {
// We want to match `open(...) as var`. // We want to match `open(...) as var`.
let ast::ExprCall { let ast::ExprCall {
func, func, arguments, ..
arguments: ast::Arguments { args, keywords, .. },
..
} = item.context_expr.as_call_expr()?; } = item.context_expr.as_call_expr()?;
let func = func.as_name_expr()?; let func = func.as_name_expr()?;
@ -151,17 +149,20 @@ fn find_file_open<'a>(
// Ignore calls with `*args` and `**kwargs`. In the exact case of `open(*filename, mode="r")`, // Ignore calls with `*args` and `**kwargs`. In the exact case of `open(*filename, mode="r")`,
// it could be a match; but in all other cases, the call _could_ contain unsupported keyword // it could be a match; but in all other cases, the call _could_ contain unsupported keyword
// arguments, like `buffering`. // arguments, like `buffering`.
if args.iter().any(Expr::is_starred_expr) if arguments.args.iter().any(Expr::is_starred_expr)
|| keywords.iter().any(|keyword| keyword.arg.is_none()) || arguments
.keywords
.iter()
.any(|keyword| keyword.arg.is_none())
{ {
return None; return None;
} }
// Match positional arguments, get filename and read mode. // Match positional arguments, get filename and read mode.
let (filename, pos_mode) = match_open_args(args)?; let (filename, pos_mode) = match_open_args(&arguments.args)?;
// Match keyword arguments, get keyword arguments to forward and possibly read mode. // Match keyword arguments, get keyword arguments to forward and possibly read mode.
let (keywords, kw_mode) = match_open_keywords(keywords)?; let (keywords, kw_mode) = match_open_keywords(&arguments.keywords)?;
// `pos_mode` could've been assigned default value corresponding to "r", while // `pos_mode` could've been assigned default value corresponding to "r", while
// keyword mode should override that. // keyword mode should override that.
@ -322,11 +323,11 @@ fn make_suggestion(open: &FileOpen<'_>, generator: Generator) -> SourceCodeSnipp
}; };
let call = ast::ExprCall { let call = ast::ExprCall {
func: Box::new(name.into()), func: Box::new(name.into()),
arguments: ast::Arguments { arguments: Box::new(ast::Arguments {
args: Box::from([]), args: Box::from([]),
keywords: open.keywords.iter().copied().cloned().collect(), keywords: open.keywords.iter().copied().cloned().collect(),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
SourceCodeSnippet::from_str(&generator.expr(&call.into())) SourceCodeSnippet::from_str(&generator.expr(&call.into()))

View File

@ -303,11 +303,11 @@ fn construct_starmap_call(starmap_binding: String, iter: &Expr, func: &Expr) ->
}; };
ast::ExprCall { ast::ExprCall {
func: Box::new(starmap.into()), func: Box::new(starmap.into()),
arguments: ast::Arguments { arguments: Box::new(ast::Arguments {
args: Box::from([func.clone(), iter.clone()]), args: Box::from([func.clone(), iter.clone()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
} }
} }
@ -321,11 +321,11 @@ fn wrap_with_call_to(call: ast::ExprCall, func_name: &str) -> ast::ExprCall {
}; };
ast::ExprCall { ast::ExprCall {
func: Box::new(name.into()), func: Box::new(name.into()),
arguments: ast::Arguments { arguments: Box::new(ast::Arguments {
args: Box::from([call.into()]), args: Box::from([call.into()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
} }
} }
@ -353,14 +353,12 @@ fn match_comprehension_target(comprehension: &ast::Comprehension) -> Option<Comp
/// Match that the given expression is `func(x, y, z, ...)`. /// Match that the given expression is `func(x, y, z, ...)`.
fn match_call(element: &Expr) -> Option<(&[Expr], &Expr)> { fn match_call(element: &Expr) -> Option<(&[Expr], &Expr)> {
let ast::ExprCall { let ast::ExprCall {
func, func, arguments, ..
arguments: ast::Arguments { args, keywords, .. },
..
} = element.as_call_expr()?; } = element.as_call_expr()?;
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
return None; return None;
} }
Some((args, func)) Some((&arguments.args, func))
} }

View File

@ -359,11 +359,11 @@ fn make_suggestion(group: &AppendGroup, generator: Generator) -> String {
// Make the actual call `var.extend((elt1, elt2, ..., eltN))` // Make the actual call `var.extend((elt1, elt2, ..., eltN))`
let call = ast::ExprCall { let call = ast::ExprCall {
func: Box::new(attr.into()), func: Box::new(attr.into()),
arguments: ast::Arguments { arguments: Box::new(ast::Arguments {
args: Box::from([tuple.into()]), args: Box::from([tuple.into()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
// And finally, turn it into a statement. // And finally, turn it into a statement.

View File

@ -250,11 +250,11 @@ fn generate_range_len_call(name: &str, generator: Generator) -> String {
} }
.into(), .into(),
), ),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([var.into()]), args: Box::from([var.into()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
// Construct `range(len(name))`. // Construct `range(len(name))`.
@ -267,11 +267,11 @@ fn generate_range_len_call(name: &str, generator: Generator) -> String {
} }
.into(), .into(),
), ),
arguments: Arguments { arguments: Box::new(Arguments {
args: Box::from([len.into()]), args: Box::from([len.into()]),
keywords: Box::from([]), keywords: Box::from([]),
range: TextRange::default(), range: TextRange::default(),
}, }),
range: TextRange::default(), range: TextRange::default(),
}; };
// And finally, turn it into a statement. // And finally, turn it into a statement.

View File

@ -2,7 +2,7 @@ use anyhow::{bail, Result};
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Expr}; use ruff_python_ast::{self as ast, Expr};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_source_file::Locator; use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
@ -69,26 +69,19 @@ pub(crate) fn explicit_f_string_type_conversion(checker: &mut Checker, f_string:
} }
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments:
Arguments {
args,
keywords,
range: _,
},
..
}) = expression.as_ref() }) = expression.as_ref()
else { else {
continue; continue;
}; };
// Can't be a conversion otherwise. // Can't be a conversion otherwise.
if !keywords.is_empty() { if !arguments.keywords.is_empty() {
continue; continue;
} }
// Can't be a conversion otherwise. // Can't be a conversion otherwise.
let [arg] = &**args else { let [arg] = &*arguments.args else {
continue; continue;
}; };

View File

@ -99,9 +99,7 @@ fn should_be_fstring(
for expr in semantic.current_expressions() { for expr in semantic.current_expressions() {
match expr { match expr {
ast::Expr::Call(ast::ExprCall { ast::Expr::Call(ast::ExprCall {
arguments: ast::Arguments { keywords, args, .. }, arguments, func, ..
func,
..
}) => { }) => {
if let ast::Expr::Attribute(ast::ExprAttribute { value, .. }) = func.as_ref() { if let ast::Expr::Attribute(ast::ExprAttribute { value, .. }) = func.as_ref() {
match value.as_ref() { match value.as_ref() {
@ -123,12 +121,12 @@ fn should_be_fstring(
_ => {} _ => {}
} }
} }
for keyword in keywords.iter() { for keyword in arguments.keywords.iter() {
if let Some(ident) = keyword.arg.as_ref() { if let Some(ident) = keyword.arg.as_ref() {
arg_names.insert(ident.as_str()); arg_names.insert(ident.as_str());
} }
} }
for arg in args.iter() { for arg in arguments.args.iter() {
if let ast::Expr::Name(ast::ExprName { id, .. }) = arg { if let ast::Expr::Name(ast::ExprName { id, .. }) = arg {
arg_names.insert(&**id); arg_names.insert(&**id);
} }

View File

@ -102,12 +102,10 @@ pub(crate) fn sort_dunder_all_aug_assign(checker: &mut Checker, node: &ast::Stmt
pub(crate) fn sort_dunder_all_extend_call( pub(crate) fn sort_dunder_all_extend_call(
checker: &mut Checker, checker: &mut Checker,
ast::ExprCall { ast::ExprCall {
func, func, arguments, ..
arguments: ast::Arguments { args, keywords, .. },
..
}: &ast::ExprCall, }: &ast::ExprCall,
) { ) {
let ([value_passed], []) = (&**args, &**keywords) else { let ([value_passed], []) = (&*arguments.args, &*arguments.keywords) else {
return; return;
}; };
let ast::Expr::Attribute(ast::ExprAttribute { let ast::Expr::Attribute(ast::ExprAttribute {

View File

@ -158,7 +158,7 @@ fn is_constant_like(expr: &Expr) -> bool {
/// - Given `{n: 1 for n in [1,2,3]}`, generate `dict.fromkeys([1,2,3], 1)`. /// - Given `{n: 1 for n in [1,2,3]}`, generate `dict.fromkeys([1,2,3], 1)`.
fn fix_unnecessary_dict_comprehension(value: &Expr, generator: &Comprehension) -> Expr { fn fix_unnecessary_dict_comprehension(value: &Expr, generator: &Comprehension) -> Expr {
let iterable = generator.iter.clone(); let iterable = generator.iter.clone();
let args = Arguments { let arguments = Arguments {
args: if value.is_none_literal_expr() { args: if value.is_none_literal_expr() {
Box::from([iterable]) Box::from([iterable])
} else { } else {
@ -173,7 +173,7 @@ fn fix_unnecessary_dict_comprehension(value: &Expr, generator: &Comprehension) -
ctx: ExprContext::Load, ctx: ExprContext::Load,
range: TextRange::default(), range: TextRange::default(),
})), })),
arguments: args, arguments: Box::new(arguments),
range: TextRange::default(), range: TextRange::default(),
}) })
} }

View File

@ -2,7 +2,7 @@ use std::borrow::Cow;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Comprehension, Expr, Int}; use ruff_python_ast::{self as ast, Comprehension, Expr, Int};
use ruff_python_semantic::SemanticModel; use ruff_python_semantic::SemanticModel;
use ruff_python_stdlib::builtins::is_iterator; use ruff_python_stdlib::builtins::is_iterator;
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
@ -136,9 +136,7 @@ struct IterationTarget {
fn match_iteration_target(expr: &Expr, semantic: &SemanticModel) -> Option<IterationTarget> { fn match_iteration_target(expr: &Expr, semantic: &SemanticModel) -> Option<IterationTarget> {
let result = match expr { let result = match expr {
Expr::Call(ast::ExprCall { Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, .. },
..
}) => { }) => {
let ast::ExprName { id, .. } = func.as_name_expr()?; let ast::ExprName { id, .. } = func.as_name_expr()?;
@ -146,7 +144,7 @@ fn match_iteration_target(expr: &Expr, semantic: &SemanticModel) -> Option<Itera
return None; return None;
} }
let [arg] = &**args else { let [arg] = &*arguments.args else {
return None; return None;
}; };

View File

@ -1,6 +1,6 @@
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Expr}; use ruff_python_ast::{self as ast, Expr};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -56,15 +56,13 @@ impl Violation for RaiseVanillaArgs {
/// TRY003 /// TRY003
pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) { pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func, arguments, ..
arguments: Arguments { args, .. },
..
}) = expr }) = expr
else { else {
return; return;
}; };
let Some(arg) = args.first() else { let Some(arg) = arguments.args.first() else {
return; return;
}; };

View File

@ -909,7 +909,7 @@ impl From<ExprCompare> for Expr {
pub struct ExprCall { pub struct ExprCall {
pub range: TextRange, pub range: TextRange,
pub func: Box<Expr>, pub func: Box<Expr>,
pub arguments: Arguments, pub arguments: Box<Arguments>,
} }
impl From<ExprCall> for Expr { impl From<ExprCall> for Expr {
@ -3891,14 +3891,14 @@ mod tests {
// 88 for Rustc < 1.76 // 88 for Rustc < 1.76
assert!(matches!(std::mem::size_of::<Pattern>(), 80 | 88)); assert!(matches!(std::mem::size_of::<Pattern>(), 80 | 88));
assert_eq!(std::mem::size_of::<Expr>(), 64); assert_eq!(std::mem::size_of::<Expr>(), 56);
assert_eq!(std::mem::size_of::<ExprAttribute>(), 48); assert_eq!(std::mem::size_of::<ExprAttribute>(), 48);
assert_eq!(std::mem::size_of::<ExprAwait>(), 16); assert_eq!(std::mem::size_of::<ExprAwait>(), 16);
assert_eq!(std::mem::size_of::<ExprBinOp>(), 32); assert_eq!(std::mem::size_of::<ExprBinOp>(), 32);
assert_eq!(std::mem::size_of::<ExprBoolOp>(), 40); assert_eq!(std::mem::size_of::<ExprBoolOp>(), 40);
assert_eq!(std::mem::size_of::<ExprBooleanLiteral>(), 12); assert_eq!(std::mem::size_of::<ExprBooleanLiteral>(), 12);
assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 40); assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 40);
assert_eq!(std::mem::size_of::<ExprCall>(), 56); assert_eq!(std::mem::size_of::<ExprCall>(), 24);
assert_eq!(std::mem::size_of::<ExprCompare>(), 48); assert_eq!(std::mem::size_of::<ExprCompare>(), 48);
assert_eq!(std::mem::size_of::<ExprDict>(), 40); assert_eq!(std::mem::size_of::<ExprDict>(), 40);
assert_eq!(std::mem::size_of::<ExprDictComp>(), 48); assert_eq!(std::mem::size_of::<ExprDictComp>(), 48);

View File

@ -43,7 +43,7 @@ fn test_parenthesized_argument() {
let expr = parse_expression(source_code).unwrap(); let expr = parse_expression(source_code).unwrap();
let call = expr.as_call_expr().unwrap(); let call = expr.as_call_expr().unwrap();
let arguments = &call.arguments; let arguments = &*call.arguments;
let argument = arguments.args.first().unwrap(); let argument = arguments.args.first().unwrap();
let parenthesized = parenthesized_range( let parenthesized = parenthesized_range(
@ -61,7 +61,7 @@ fn test_non_parenthesized_argument() {
let expr = parse_expression(source_code).unwrap(); let expr = parse_expression(source_code).unwrap();
let call = expr.as_call_expr().unwrap(); let call = expr.as_call_expr().unwrap();
let arguments = &call.arguments; let arguments = &*call.arguments;
let argument = arguments.args.first().unwrap(); let argument = arguments.args.first().unwrap();
let parenthesized = parenthesized_range( let parenthesized = parenthesized_range(
@ -130,7 +130,7 @@ fn test_twice_parenthesized_argument() {
let expr = parse_expression(source_code).unwrap(); let expr = parse_expression(source_code).unwrap();
let call = expr.as_call_expr().unwrap(); let call = expr.as_call_expr().unwrap();
let arguments = &call.arguments; let arguments = &*call.arguments;
let argument = arguments.args.first().unwrap(); let argument = arguments.args.first().unwrap();
let parenthesized = parenthesized_range( let parenthesized = parenthesized_range(

View File

@ -1549,7 +1549,7 @@ AtomExpr2<Goal>: crate::parser::ParenthesizedExpr = {
Atom<Goal>, Atom<Goal>,
<location:@L> <func:AtomExpr2<"all">> <arguments:Arguments> <end_location:@R> => ast::ExprCall { <location:@L> <func:AtomExpr2<"all">> <arguments:Arguments> <end_location:@R> => ast::ExprCall {
func: Box::new(func.into()), func: Box::new(func.into()),
arguments, arguments: Box::new(arguments),
range: (location..end_location).into(), range: (location..end_location).into(),
}.into(), }.into(),
<location:@L> <value:AtomExpr2<"all">> "[" <slice:SubscriptList> "]" <end_location:@R> => ast::ExprSubscript { <location:@L> <value:AtomExpr2<"all">> "[" <slice:SubscriptList> "]" <end_location:@R> => ast::ExprSubscript {

View File

@ -1,5 +1,5 @@
// auto-generated: "lalrpop 0.20.0" // auto-generated: "lalrpop 0.20.0"
// sha3: 8f9c419cf07ccd6289047223fa22bb70c6afd0133b58ea606f601340160cab8b // sha3: 06d23132da088f5a6184a546b53be668a940ce6dfd046b5ac08b6e70b7c9eb99
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use ruff_python_ast::{self as ast, Int, IpyEscapeKind}; use ruff_python_ast::{self as ast, Int, IpyEscapeKind};
use crate::{ use crate::{
@ -41071,7 +41071,7 @@ fn __action541<
{ {
ast::ExprCall { ast::ExprCall {
func: Box::new(func.into()), func: Box::new(func.into()),
arguments, arguments: Box::new(arguments),
range: (location..end_location).into(), range: (location..end_location).into(),
}.into() }.into()
} }
@ -41868,7 +41868,7 @@ fn __action588<
{ {
ast::ExprCall { ast::ExprCall {
func: Box::new(func.into()), func: Box::new(func.into()),
arguments, arguments: Box::new(arguments),
range: (location..end_location).into(), range: (location..end_location).into(),
}.into() }.into()
} }