Skip to content

Commit aa0db33

Browse files
authored
Implement iter(), len() and is_empty() for all display-literal AST nodes (#12807)
1 parent a99a458 commit aa0db33

File tree

56 files changed

+304
-240
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+304
-240
lines changed

crates/ruff_linter/src/checkers/ast/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,8 +1290,8 @@ impl<'a> Visitor<'a> for Checker<'a> {
12901290
let Keyword { arg, value, .. } = keyword;
12911291
match (arg.as_ref(), value) {
12921292
// Ex) NamedTuple("a", **{"a": int})
1293-
(None, Expr::Dict(ast::ExprDict { items, .. })) => {
1294-
for ast::DictItem { key, value } in items {
1293+
(None, Expr::Dict(dict)) => {
1294+
for ast::DictItem { key, value } in dict {
12951295
if let Some(key) = key.as_ref() {
12961296
self.visit_non_type_definition(key);
12971297
self.visit_type_definition(value);

crates/ruff_linter/src/fix/edits.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,24 +151,23 @@ pub(crate) fn add_to_dunder_all<'a>(
151151
stylist: &Stylist,
152152
) -> Vec<Edit> {
153153
let (insertion_point, export_prefix_length) = match expr {
154-
Expr::List(ExprList { elts, range, .. }) => (
155-
elts.last()
156-
.map_or(range.end() - "]".text_len(), Ranged::end),
154+
Expr::List(ExprList { elts, .. }) => (
155+
elts.last().map_or(expr.end() - "]".text_len(), Ranged::end),
157156
elts.len(),
158157
),
159158
Expr::Tuple(tup) if tup.parenthesized => (
160159
tup.elts
161160
.last()
162161
.map_or(tup.end() - ")".text_len(), Ranged::end),
163-
tup.elts.len(),
162+
tup.len(),
164163
),
165164
Expr::Tuple(tup) if !tup.parenthesized => (
166165
tup.elts
167166
.last()
168167
.expect("unparenthesized empty tuple is not possible")
169168
.range()
170169
.end(),
171-
tup.elts.len(),
170+
tup.len(),
172171
),
173172
_ => {
174173
// we don't know how to insert into this expression

crates/ruff_linter/src/rules/fastapi/rules/fastapi_redundant_response_model.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,15 @@ fn is_identical_types(
122122
return_value: &Expr,
123123
semantic: &SemanticModel,
124124
) -> bool {
125-
if let (Some(response_mode_name_expr), Some(return_value_name_expr)) = (
126-
response_model_arg.as_name_expr(),
127-
return_value.as_name_expr(),
128-
) {
125+
if let (Expr::Name(response_mode_name_expr), Expr::Name(return_value_name_expr)) =
126+
(response_model_arg, return_value)
127+
{
129128
return semantic.resolve_name(response_mode_name_expr)
130129
== semantic.resolve_name(return_value_name_expr);
131130
}
132-
if let (Some(response_mode_subscript), Some(return_value_subscript)) = (
133-
response_model_arg.as_subscript_expr(),
134-
return_value.as_subscript_expr(),
135-
) {
131+
if let (Expr::Subscript(response_mode_subscript), Expr::Subscript(return_value_subscript)) =
132+
(response_model_arg, return_value)
133+
{
136134
return is_identical_types(
137135
&response_mode_subscript.value,
138136
&return_value_subscript.value,
@@ -143,15 +141,13 @@ fn is_identical_types(
143141
semantic,
144142
);
145143
}
146-
if let (Some(response_mode_tuple), Some(return_value_tuple)) = (
147-
response_model_arg.as_tuple_expr(),
148-
return_value.as_tuple_expr(),
149-
) {
150-
return response_mode_tuple.elts.len() == return_value_tuple.elts.len()
144+
if let (Expr::Tuple(response_mode_tuple), Expr::Tuple(return_value_tuple)) =
145+
(response_model_arg, return_value)
146+
{
147+
return response_mode_tuple.len() == return_value_tuple.len()
151148
&& response_mode_tuple
152-
.elts
153149
.iter()
154-
.zip(return_value_tuple.elts.iter())
150+
.zip(return_value_tuple)
155151
.all(|(x, y)| is_identical_types(x, y, semantic));
156152
}
157153
false

crates/ruff_linter/src/rules/flake8_bandit/rules/django_extra.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use ruff_diagnostics::{Diagnostic, Violation};
22
use ruff_macros::{derive_message_formats, violation};
3-
use ruff_python_ast::{self as ast, Expr, ExprAttribute, ExprDict, ExprList};
3+
use ruff_python_ast::{self as ast, Expr, ExprAttribute};
44
use ruff_text_size::Ranged;
55

66
use crate::checkers::ast::Checker;
@@ -65,8 +65,8 @@ fn is_call_insecure(call: &ast::ExprCall) -> bool {
6565
if let Some(argument) = call.arguments.find_argument(argument_name, position) {
6666
match argument_name {
6767
"select" => match argument {
68-
Expr::Dict(ExprDict { items, .. }) => {
69-
if items.iter().any(|ast::DictItem { key, value }| {
68+
Expr::Dict(dict) => {
69+
if dict.iter().any(|ast::DictItem { key, value }| {
7070
key.as_ref()
7171
.is_some_and(|key| !key.is_string_literal_expr())
7272
|| !value.is_string_literal_expr()
@@ -77,8 +77,8 @@ fn is_call_insecure(call: &ast::ExprCall) -> bool {
7777
_ => return true,
7878
},
7979
"where" | "tables" => match argument {
80-
Expr::List(ExprList { elts, .. }) => {
81-
if !elts.iter().all(Expr::is_string_literal_expr) {
80+
Expr::List(list) => {
81+
if !list.iter().all(Expr::is_string_literal_expr) {
8282
return true;
8383
}
8484
}

crates/ruff_linter/src/rules/flake8_bandit/rules/shell_injection.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -530,11 +530,11 @@ fn is_partial_path(expr: &Expr) -> bool {
530530
/// subprocess.Popen(["/usr/local/bin/rsync", "*", "some_where:"], shell=True)
531531
/// ```
532532
fn is_wildcard_command(expr: &Expr) -> bool {
533-
if let Expr::List(ast::ExprList { elts, .. }) = expr {
533+
if let Expr::List(list) = expr {
534534
let mut has_star = false;
535535
let mut has_command = false;
536-
for elt in elts {
537-
if let Some(text) = string_literal(elt) {
536+
for item in list {
537+
if let Some(text) = string_literal(item) {
538538
has_star |= text.contains('*');
539539
has_command |= text.contains("chown")
540540
|| text.contains("chmod")

crates/ruff_linter/src/rules/flake8_bugbear/rules/duplicate_value.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,16 @@ impl Violation for DuplicateValue {
4949
/// B033
5050
pub(crate) fn duplicate_value(checker: &mut Checker, set: &ast::ExprSet) {
5151
let mut seen_values: FxHashSet<ComparableExpr> = FxHashSet::default();
52-
for (index, elt) in set.elts.iter().enumerate() {
53-
if elt.is_literal_expr() {
54-
let comparable_value: ComparableExpr = elt.into();
52+
for (index, value) in set.iter().enumerate() {
53+
if value.is_literal_expr() {
54+
let comparable_value = ComparableExpr::from(value);
5555

5656
if !seen_values.insert(comparable_value) {
5757
let mut diagnostic = Diagnostic::new(
5858
DuplicateValue {
59-
value: checker.generator().expr(elt),
59+
value: checker.generator().expr(value),
6060
},
61-
elt.range(),
61+
value.range(),
6262
);
6363

6464
diagnostic.try_set_fix(|| {
@@ -73,7 +73,7 @@ pub(crate) fn duplicate_value(checker: &mut Checker, set: &ast::ExprSet) {
7373

7474
/// Remove the member at the given index from the [`ast::ExprSet`].
7575
fn remove_member(set: &ast::ExprSet, index: usize, source: &str) -> Result<Edit> {
76-
if index < set.elts.len() - 1 {
76+
if index < set.len() - 1 {
7777
// Case 1: the expression is _not_ the last node, so delete from the start of the
7878
// expression to the end of the subsequent comma.
7979
// Ex) Delete `"a"` in `{"a", "b", "c"}`.

crates/ruff_linter/src/rules/flake8_bugbear/rules/reuse_of_groupby_generator.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,15 +315,15 @@ pub(crate) fn reuse_of_groupby_generator(
315315
let Expr::Call(ast::ExprCall { func, .. }) = &iter else {
316316
return;
317317
};
318-
let Expr::Tuple(ast::ExprTuple { elts, .. }) = target else {
318+
let Expr::Tuple(tuple) = target else {
319319
// Ignore any `groupby()` invocation that isn't unpacked
320320
return;
321321
};
322-
if elts.len() != 2 {
322+
if tuple.len() != 2 {
323323
return;
324324
}
325325
// We have an invocation of groupby which is a simple unpacking
326-
let Expr::Name(ast::ExprName { id: group_name, .. }) = &elts[1] else {
326+
let Expr::Name(ast::ExprName { id: group_name, .. }) = &tuple.elts[1] else {
327327
return;
328328
};
329329
// Check if the function call is `itertools.groupby`

crates/ruff_linter/src/rules/flake8_bugbear/rules/static_key_dict_comprehension.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub(crate) fn static_key_dict_comprehension(checker: &mut Checker, dict_comp: &a
7272
/// comprehension.
7373
fn is_constant(key: &Expr, names: &FxHashMap<&str, &ast::ExprName>) -> bool {
7474
match key {
75-
Expr::Tuple(ast::ExprTuple { elts, .. }) => elts.iter().all(|elt| is_constant(elt, names)),
75+
Expr::Tuple(tuple) => tuple.iter().all(|elem| is_constant(elem, names)),
7676
Expr::Name(ast::ExprName { id, .. }) => !names.contains_key(id.as_str()),
7777
Expr::Attribute(ast::ExprAttribute { value, .. }) => is_constant(value, names),
7878
Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => {

crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ pub(crate) fn unnecessary_generator_dict(
6161
let Expr::Generator(ast::ExprGenerator { elt, .. }) = argument else {
6262
return;
6363
};
64-
let Expr::Tuple(ast::ExprTuple { elts, .. }) = elt.as_ref() else {
64+
let Expr::Tuple(tuple) = &**elt else {
6565
return;
6666
};
67-
if elts.len() != 2 {
67+
if tuple.len() != 2 {
6868
return;
6969
}
70-
if elts.iter().any(Expr::is_starred_expr) {
70+
if tuple.iter().any(Expr::is_starred_expr) {
7171
return;
7272
}
7373
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorDict, expr.range());

crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ pub(crate) fn unnecessary_list_comprehension_dict(
6262
let Expr::ListComp(ast::ExprListComp { elt, .. }) = argument else {
6363
return;
6464
};
65-
let Expr::Tuple(ast::ExprTuple { elts, .. }) = elt.as_ref() else {
65+
let Expr::Tuple(tuple) = &**elt else {
6666
return;
6767
};
68-
if elts.len() != 2 {
68+
if tuple.len() != 2 {
6969
return;
7070
}
7171
let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionDict, expr.range());

crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub(crate) fn unnecessary_literal_dict(
7474
// Accept `dict((1, 2), ...))` `dict([(1, 2), ...])`.
7575
if !elts
7676
.iter()
77-
.all(|elt| matches!(&elt, Expr::Tuple(ast::ExprTuple { elts, .. }) if elts.len() == 2))
77+
.all(|elt| matches!(&elt, Expr::Tuple(tuple) if tuple.len() == 2))
7878
{
7979
return;
8080
}

crates/ruff_linter/src/rules/flake8_pie/rules/multiple_starts_ends_with.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
163163
elts: words
164164
.iter()
165165
.flat_map(|value| {
166-
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = value {
167-
Left(elts.iter())
166+
if let Expr::Tuple(tuple) = value {
167+
Left(tuple.iter())
168168
} else {
169169
Right(iter::once(*value))
170170
}

crates/ruff_linter/src/rules/flake8_pie/rules/reimplemented_container_builtin.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ruff_python_ast::{self as ast, Expr, ExprLambda};
1+
use ruff_python_ast::{Expr, ExprLambda};
22

33
use ruff_diagnostics::{Diagnostic, Edit, Fix};
44
use ruff_diagnostics::{FixAvailability, Violation};
@@ -70,8 +70,8 @@ pub(crate) fn reimplemented_container_builtin(checker: &mut Checker, expr: &Expr
7070
}
7171

7272
let container = match &**body {
73-
Expr::List(ast::ExprList { elts, .. }) if elts.is_empty() => Container::List,
74-
Expr::Dict(ast::ExprDict { items, .. }) if items.is_empty() => Container::Dict,
73+
Expr::List(list) if list.is_empty() => Container::List,
74+
Expr::Dict(dict) if dict.is_empty() => Container::Dict,
7575
_ => return,
7676
};
7777
let mut diagnostic = Diagnostic::new(ReimplementedContainerBuiltin { container }, expr.range());

crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, call: &ast::ExprCal
8787
.iter_keys()
8888
.filter_map(|key| key.and_then(as_kwarg))
8989
.collect();
90-
if kwargs.len() != dict.items.len() {
90+
if kwargs.len() != dict.len() {
9191
continue;
9292
}
9393

9494
let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, keyword.range());
9595

96-
if dict.items.is_empty() {
96+
if dict.is_empty() {
9797
diagnostic.try_set_fix(|| {
9898
remove_argument(
9999
keyword,

crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_spread.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl Violation for UnnecessarySpread {
4949
pub(crate) fn unnecessary_spread(checker: &mut Checker, dict: &ast::ExprDict) {
5050
// The first "end" is the start of the dictionary, immediately following the open bracket.
5151
let mut prev_end = dict.start() + TextSize::from(1);
52-
for ast::DictItem { key, value } in &dict.items {
52+
for ast::DictItem { key, value } in dict {
5353
if key.is_none() {
5454
// We only care about when the key is None which indicates a spread `**`
5555
// inside a dict.

crates/ruff_linter/src/rules/flake8_pyi/rules/bad_generator_return_type.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,11 @@ pub(crate) fn bad_generator_return_type(
162162
// - if not, don't emit the diagnostic
163163
let yield_type_info = match returns {
164164
ast::Expr::Subscript(ast::ExprSubscript { slice, .. }) => match slice.as_ref() {
165-
ast::Expr::Tuple(slice_tuple @ ast::ExprTuple { .. }) => {
165+
ast::Expr::Tuple(slice_tuple) => {
166166
if !slice_tuple
167-
.elts
168167
.iter()
169168
.skip(1)
170-
.all(|elt| is_any_or_none(elt, semantic))
169+
.all(|element| is_any_or_none(element, semantic))
171170
{
172171
return;
173172
}

crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_literal_union.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ pub(crate) fn redundant_literal_union<'a>(checker: &mut Checker, union: &'a Expr
6767
let mut func = |expr: &'a Expr, _parent: &'a Expr| {
6868
if let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr {
6969
if checker.semantic().match_typing_expr(value, "Literal") {
70-
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice.as_ref() {
71-
typing_literal_exprs.extend(elts.iter());
70+
if let Expr::Tuple(tuple) = &**slice {
71+
typing_literal_exprs.extend(tuple);
7272
} else {
7373
typing_literal_exprs.push(slice);
7474
}

crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,10 +298,10 @@ fn is_valid_default_value_with_annotation(
298298
.iter()
299299
.all(|e| is_valid_default_value_with_annotation(e, false, locator, semantic));
300300
}
301-
Expr::Dict(ast::ExprDict { items, range: _ }) => {
301+
Expr::Dict(dict) => {
302302
return allow_container
303-
&& items.len() <= 10
304-
&& items.iter().all(|ast::DictItem { key, value }| {
303+
&& dict.len() <= 10
304+
&& dict.iter().all(|ast::DictItem { key, value }| {
305305
key.as_ref().is_some_and(|key| {
306306
is_valid_default_value_with_annotation(key, false, locator, semantic)
307307
}) && is_valid_default_value_with_annotation(value, false, locator, semantic)

crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,15 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &mut Checker, expr: &'a Exp
7070
literal_subscript = Some(value.as_ref());
7171
}
7272

73+
let slice = &**slice;
74+
7375
// flatten already-unioned literals to later union again
74-
if let Expr::Tuple(ast::ExprTuple {
75-
elts,
76-
range: _,
77-
ctx: _,
78-
parenthesized: _,
79-
}) = slice.as_ref()
80-
{
81-
for expr in elts {
82-
literal_exprs.push(expr);
76+
if let Expr::Tuple(tuple) = slice {
77+
for item in tuple {
78+
literal_exprs.push(item);
8379
}
8480
} else {
85-
literal_exprs.push(slice.as_ref());
81+
literal_exprs.push(slice);
8682
}
8783
}
8884
} else {

crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_version_info.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ fn version_check(
181181
}
182182

183183
// Tuple comparison, e.g., `sys.version_info == (3, 4)`.
184-
let Expr::Tuple(ast::ExprTuple { elts, .. }) = comparator else {
184+
let Expr::Tuple(tuple) = comparator else {
185185
if checker.enabled(Rule::UnrecognizedVersionInfoCheck) {
186186
checker
187187
.diagnostics
@@ -190,15 +190,15 @@ fn version_check(
190190
return;
191191
};
192192

193-
if !elts.iter().all(is_int_constant) {
193+
if !tuple.iter().all(is_int_constant) {
194194
// All tuple elements must be integers, e.g., `sys.version_info == (3, 4)` instead of
195195
// `sys.version_info == (3.0, 4)`.
196196
if checker.enabled(Rule::UnrecognizedVersionInfoCheck) {
197197
checker
198198
.diagnostics
199199
.push(Diagnostic::new(UnrecognizedVersionInfoCheck, test.range()));
200200
}
201-
} else if elts.len() > 2 {
201+
} else if tuple.len() > 2 {
202202
// Must compare against major and minor version only, e.g., `sys.version_info == (3, 4)`
203203
// instead of `sys.version_info == (3, 4, 0)`.
204204
if checker.enabled(Rule::PatchVersionComparison) {
@@ -216,7 +216,7 @@ fn version_check(
216216
_ => return,
217217
};
218218

219-
if elts.len() != expected_length {
219+
if tuple.len() != expected_length {
220220
checker.diagnostics.push(Diagnostic::new(
221221
WrongTupleLengthVersionComparison { expected_length },
222222
test.range(),

0 commit comments

Comments
 (0)