diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF042.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF042.py new file mode 100644 index 00000000000000..56ef4dbb814103 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF042.py @@ -0,0 +1,204 @@ +from typing import Any + + +##### Errors + + +### Lists + +def f(l: list[Any]): l.extend(("append",)) # `l.append("append")` (safe) +def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) +def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + +def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) +def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) +def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) +def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) + +def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) +def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) +def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) +def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) + +def f(l: list[Any]): l += (*extend,) # `l.extend(extend)` (safe) +def f(l: list[Any]): l += [*extend] # `l.extend(extend)` (safe) + + +### Sets +def f(s: set[Any]): s.update(("add",)) # `s.add("add")` (safe) +def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) +def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) +def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) + +def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) +def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) +def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) +def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) + +def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) +def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) + +def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) +def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) + +def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) +def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) +def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) + +def f(s: set[Any]): s |= {*update} # `s.update(update)` (safe) +def f(s: set[Any]): s -= {*update} # `s.difference_update(update)` (safe) + + +### Dictionaries + +def f(d: dict[Any, Any]): d.update(**update) # `d.update(update)` (safe) +def f(d: dict[Any, Any]): d.update({**update}) # `d.update(update)` (safe) + +def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) +def f(d: dict[Any, Any]): d.update(s="et") # `d["s"] = "et"` (safe) + +def f(d: dict[Any, Any]): d |= {"s": "et"} # `d["s"] = "et"` (safe) + +def f(d: dict[Any, Any]): d |= {**update} # `d.update(update)` (safe) + + +##### No errors + + +### Lists + +# Empty +def f(l: list[Any]): l += () +def f(l: list[Any]): l += [] +def f(l: list[Any]): l += {} + +# Non-literals +def f(l: list[Any]): l += set() +def f(l: list[Any]): l += frozenset() + +# Unpacks +def f(l: list[Any]): l += {*unpack} +def f(l: list[Any]): l += {**unpack} +def f(l: list[Any]): l += ("unp", *ack) +def f(l: list[Any]): l += ["unp", *ack] +def f(l: list[Any]): l += {"unp", *ack} +def f(l: list[Any]): l += {"u": "np", **ack} + +# .append(iterable) +def f(l: list[Any]): l.append(("iterable",)) +def f(l: list[Any]): l.append(["iterable"]) +def f(l: list[Any]): l.append({"iterable"}) +def f(l: list[Any]): l.append({"iter": "able"}) + +# .extend(name) +def f(l: list[Any]): l.extend(l) +def f(l: list[Any]): l.extend(s) +def f(l: list[Any]): l.extend(d) + +# Comprehensions +def f(l: list[Any]): l += ("append" for _ in range(0)) +def f(l: list[Any]): l += ["append" for _ in range(0)] +def f(l: list[Any]): l += {"append" for _ in range(0)} +def f(l: list[Any]): l += {"app": "end" for _ in range(0)} + + +### Sets + +# Unpacks +def f(s: set[Any]): s |= {"unp", *ack} + +# Non-literals +def f(s: set[Any]): s |= set() +def f(s: set[Any]): s |= frozenset() + +# [&^]= single +def f(s: set[Any]): s &= {"update"} +def f(s: set[Any]): s ^= {"update"} + +# [|&^-]= name +def f(s: set[Any]): s |= l +def f(s: set[Any]): s |= s +def f(s: set[Any]): s |= d +def f(s: set[Any]): s &= l +def f(s: set[Any]): s &= s +def f(s: set[Any]): s &= d +def f(s: set[Any]): s -= l +def f(s: set[Any]): s -= s +def f(s: set[Any]): s -= d +def f(s: set[Any]): s ^= l +def f(s: set[Any]): s ^= s +def f(s: set[Any]): s ^= d + +# .*update(name) +def f(s: set[Any]): s.update(l) +def f(s: set[Any]): s.update(s) +def f(s: set[Any]): s.update(d) +def f(s: set[Any]): s.intersection_update(l) +def f(s: set[Any]): s.intersection_update(s) +def f(s: set[Any]): s.intersection_update(d) +def f(s: set[Any]): s.difference_update(l) +def f(s: set[Any]): s.difference_update(s) +def f(s: set[Any]): s.difference_update(d) +def f(s: set[Any]): s.symmetric_difference_update(l) +def f(s: set[Any]): s.symmetric_difference_update(s) +def f(s: set[Any]): s.symmetric_difference_update(d) + +# Unsupported operations +def f(s: set[Any]): s |= ("upd", "ate") +def f(s: set[Any]): s |= ["upd", "ate"] +def f(s: set[Any]): s |= {"upd": 1, "ate": 2} +def f(s: set[Any]): s &= ("upd", "ate") +def f(s: set[Any]): s &= ["upd", "ate"] +def f(s: set[Any]): s &= {"upd": 1, "ate": 2} +def f(s: set[Any]): s -= ("upd", "ate") +def f(s: set[Any]): s -= ["upd", "ate"] +def f(s: set[Any]): s -= {"upd": 1, "ate": 2} +def f(s: set[Any]): s ^= ("upd", "ate") +def f(s: set[Any]): s ^= ["upd", "ate"] +def f(s: set[Any]): s ^= {"upd": 1, "ate": 2} + +# Comprehensions +def f(s: set[Any]): s |= ("append" for _ in range(0)) +def f(s: set[Any]): s |= ["append" for _ in range(0)] +def f(s: set[Any]): s |= {"append" for _ in range(0)} +def f(s: set[Any]): s |= {"app": "end" for _ in range(0)} +def f(s: set[Any]): s &= ("append" for _ in range(0)) +def f(s: set[Any]): s &= ["append" for _ in range(0)] +def f(s: set[Any]): s &= {"append" for _ in range(0)} +def f(s: set[Any]): s &= {"app": "end" for _ in range(0)} +def f(s: set[Any]): s -= ("append" for _ in range(0)) +def f(s: set[Any]): s -= ["append" for _ in range(0)] +def f(s: set[Any]): s -= {"append" for _ in range(0)} +def f(s: set[Any]): s -= {"app": "end" for _ in range(0)} +def f(s: set[Any]): s ^= ("append" for _ in range(0)) +def f(s: set[Any]): s ^= ["append" for _ in range(0)] +def f(s: set[Any]): s ^= {"append" for _ in range(0)} +def f(s: set[Any]): s ^= {"app": "end" for _ in range(0)} + + +### Dictionaries + +# Empty +def f(d: dict[Any, Any]): d |= {} + +# Unpacks +def f(d: dict[Any, Any]): d |= {"unp": "ack", **unpack} + +# Non-literals +def f(d: dict[Any, Any]): d |= dict() + +# .update(name) +def f(d: dict[Any, Any]): d.update(l) +def f(d: dict[Any, Any]): d.update(s) +def f(d: dict[Any, Any]): d.update(d) + +# Multiple items +def f(d: dict[Any, Any]): d |= {"mult": "iple", "it": "ems"} +def f(d: dict[Any, Any]): d.update({"mult": "iple", "it": "ems"}) +def f(d: dict[Any, Any]): d.update(mult="iple", it="ems") + +# Comprehensions +def f(d: dict[Any, Any]): d |= {"app": "end" for _ in range(0)} +def f(d: dict[Any, Any]): d.update({"app": "end" for _ in range(0)}) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 87d104f2521846..2287556bc47e9a 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -1129,6 +1129,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::StarmapZip) { ruff::rules::starmap_zip(checker, call); } + if checker.enabled(Rule::UnnecessaryIntermediateRepresentation) { + ruff::rules::unnecessary_intermediate_representation_call(checker, call); + } } Expr::Dict(dict) => { if checker.any_enabled(&[ diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 5611a307f44df6..1c258ef6ee4ada 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1104,6 +1104,11 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::UnsortedDunderAll) { ruff::rules::sort_dunder_all_aug_assign(checker, aug_assign); } + if checker.enabled(Rule::UnnecessaryIntermediateRepresentation) { + ruff::rules::unnecessary_intermediate_representation_aug_assign( + checker, aug_assign, + ); + } } Stmt::If( if_ @ ast::StmtIf { diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 91123b2724a213..fa26bf1c4767a3 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -995,6 +995,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Ruff, "039") => (RuleGroup::Preview, rules::ruff::rules::UnrawRePattern), (Ruff, "040") => (RuleGroup::Preview, rules::ruff::rules::InvalidAssertMessageLiteralArgument), (Ruff, "041") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryNestedLiteral), + (Ruff, "042") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryIntermediateRepresentation), (Ruff, "043") => (RuleGroup::Preview, rules::ruff::rules::PytestRaisesAmbiguousPattern), (Ruff, "046") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryCastToInt), (Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing), diff --git a/crates/ruff_linter/src/rules/ruff/mod.rs b/crates/ruff_linter/src/rules/ruff/mod.rs index 4e117304b28c9f..1cc5d5f49c86ff 100644 --- a/crates/ruff_linter/src/rules/ruff/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/mod.rs @@ -419,6 +419,7 @@ mod tests { #[test_case(Rule::UnnecessaryRegularExpression, Path::new("RUF055_0.py"))] #[test_case(Rule::UnnecessaryRegularExpression, Path::new("RUF055_1.py"))] #[test_case(Rule::UnnecessaryCastToInt, Path::new("RUF046.py"))] + #[test_case(Rule::UnnecessaryIntermediateRepresentation, Path::new("RUF042.py"))] #[test_case(Rule::PytestRaisesAmbiguousPattern, Path::new("RUF043.py"))] #[test_case(Rule::UnnecessaryRound, Path::new("RUF057.py"))] #[test_case(Rule::DataclassEnum, Path::new("RUF049.py"))] diff --git a/crates/ruff_linter/src/rules/ruff/rules/mod.rs b/crates/ruff_linter/src/rules/ruff/rules/mod.rs index 15ea76f49f828c..98406e79681fc2 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/mod.rs @@ -36,6 +36,7 @@ pub(crate) use static_key_dict_comprehension::*; #[cfg(any(feature = "test-rules", test))] pub(crate) use test_rules::*; pub(crate) use unnecessary_cast_to_int::*; +pub(crate) use unnecessary_intermediate_representation::*; pub(crate) use unnecessary_iterable_allocation_for_first_element::*; pub(crate) use unnecessary_key_check::*; pub(crate) use unnecessary_literal_within_deque_call::*; @@ -92,6 +93,7 @@ mod suppression_comment_visitor; #[cfg(any(feature = "test-rules", test))] pub(crate) mod test_rules; mod unnecessary_cast_to_int; +mod unnecessary_intermediate_representation; mod unnecessary_iterable_allocation_for_first_element; mod unnecessary_key_check; mod unnecessary_literal_within_deque_call; diff --git a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_intermediate_representation.rs b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_intermediate_representation.rs new file mode 100644 index 00000000000000..e6a222fdcd143d --- /dev/null +++ b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_intermediate_representation.rs @@ -0,0 +1,670 @@ +use crate::checkers::ast::Checker; +use crate::Locator; +use itertools::Itertools; +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; +use ruff_macros::{derive_message_formats, ViolationMetadata}; +use ruff_python_ast::{ + Arguments, DictItem, Expr, ExprAttribute, ExprCall, ExprName, ExprStarred, ExprStringLiteral, + Operator, StmtAugAssign, StringLiteral, StringLiteralFlags, StringLiteralValue, +}; +use ruff_python_semantic::analyze::typing::{is_dict, is_list, is_set}; +use ruff_python_semantic::SemanticModel; +use ruff_text_size::{Ranged, TextRange, TextSize}; + +/// ## What it does +/// Checks for situations where collections are unnecessarily created +/// and then immediately discarded. +/// +/// ## Why is this bad? +/// Such collections may cause the code to be less performant. +/// Use tuples instead, as they can be evaluated at compile time. +/// +/// ## Known problems +/// This rule is prone to false negatives due to type inference limitations. +/// Only variables instantiated as literals or have type annotations are detected correctly. +/// +/// ## Example +/// +/// ```python +/// lst = [] +/// lst += ["value"] +/// lst += ["value 1", "value 2"] +/// +/// s = set() +/// s |= {"value"} +/// s |= {"value 1", "value 2"} +/// +/// d = {} +/// d |= {"key": "value"} +/// ``` +/// +/// Use instead: +/// +/// ```python +/// lst = [] +/// lst.append("value") +/// lst.extend(("value 1", "value 2")) +/// +/// s = set() +/// s.add("value") +/// s.update(("value 1", "value 2")) +/// +/// d = {} +/// d["key"] = "value" +/// ``` +#[derive(ViolationMetadata)] +pub(crate) struct UnnecessaryIntermediateRepresentation { + fix_title: String, +} + +impl AlwaysFixableViolation for UnnecessaryIntermediateRepresentation { + #[derive_message_formats] + fn message(&self) -> String { + "Unnecessary intermediate representation".to_string() + } + + fn fix_title(&self) -> String { + self.fix_title.to_string() + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, is_macro::Is)] +enum IterableKind { + Tuple, + List, + Set, + Dict, +} + +impl IterableKind { + fn from_target(semantic: &SemanticModel, name: &ExprName) -> Option { + let binding_id = semantic.only_binding(name)?; + let binding = semantic.binding(binding_id); + + match () { + () if is_list(binding, semantic) => Some(IterableKind::List), + () if is_set(binding, semantic) => Some(IterableKind::Set), + () if is_dict(binding, semantic) => Some(IterableKind::Dict), + () => None, + } + } +} + +struct Iterable { + kind: IterableKind, + elements: Vec, +} + +impl Iterable { + fn len(&self) -> usize { + self.elements.len() + } + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn has_unpack(&self) -> bool { + self.elements.iter().any(Element::is_unpack) + } + + fn element_exprs(&self, locator: &Locator) -> String { + let elements = &self.elements; + + if self.kind.is_dict() { + return elements.iter().map(|it| it.expr(locator)).join(", "); + } + + let start = elements.first().unwrap().start(); + let end = elements.last().unwrap().end(); + + locator.slice(TextRange::new(start, end)).to_string() + } +} + +impl Iterable { + fn from(expr: &Expr) -> Option { + let (kind, elements) = match expr { + Expr::Tuple(tuple) => ( + IterableKind::Tuple, + tuple.iter().map(Element::from).collect_vec(), + ), + Expr::List(list) => ( + IterableKind::List, + list.iter().map(Element::from).collect_vec(), + ), + Expr::Set(set) => ( + IterableKind::Set, + set.iter().map(Element::from).collect_vec(), + ), + Expr::Dict(dict) => ( + IterableKind::Dict, + dict.iter().map(Element::from).collect_vec(), + ), + _ => return None, + }; + + Some(Self { kind, elements }) + } + + fn from_single(arguments: &[Expr]) -> Option { + let [single] = arguments else { + return None; + }; + + Self::from(single) + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum Element { + /// `"foo"`, `bar`, `42`, etc. + Single(TextRange), + /// `*baz` + StarUnpack(TextRange), + /// `**qux` + DictUnpack(TextRange), + /// `lorem: ipsum` + DictItem { key: TextRange, value: TextRange }, +} + +impl Element { + fn is_unpack(&self) -> bool { + matches!(self, Self::StarUnpack(..) | Self::DictUnpack(..)) + } + + /// This element as it is expressed in the source code. + /// + /// For a [`Self::DictItem`], only the key is returned. + fn expr(&self, locator: &Locator) -> String { + let in_source = locator.slice(self); + + match self { + Self::Single(..) => in_source.to_string(), + Self::DictItem { key, .. } => locator.slice(key).to_string(), + Self::StarUnpack(..) => format!("*({in_source})"), + Self::DictUnpack(..) => format!("**({in_source})"), + } + } +} + +impl From<&Expr> for Element { + fn from(expr: &Expr) -> Self { + match expr { + Expr::Starred(ExprStarred { value, .. }) => Self::StarUnpack(value.range()), + _ => Self::Single(expr.range()), + } + } +} + +impl From<&DictItem> for Element { + fn from(item: &DictItem) -> Self { + let key = item.key.as_ref().map(Ranged::range); + let value = item.value.range(); + + match key { + None => Element::DictUnpack(value), + Some(key) => Element::DictItem { key, value }, + } + } +} + +impl Ranged for Element { + fn range(&self) -> TextRange { + match self { + Element::Single(range) => *range, + Element::StarUnpack(range) => *range, + Element::DictUnpack(range) => *range, + Element::DictItem { key, value } => TextRange::new(key.start(), value.end()), + } + } + + fn start(&self) -> TextSize { + self.range().start() + } + + fn end(&self) -> TextSize { + self.range().end() + } +} + +fn create_string_expr(content: String) -> Expr { + let range = TextRange::default(); + + let literal = StringLiteral { + range, + value: Box::from(content), + flags: StringLiteralFlags::default(), + }; + + let value = StringLiteralValue::single(literal); + + Expr::StringLiteral(ExprStringLiteral { range, value }) +} + +/// Returns a [`Diagnostic`] whose fix suggests replacing `range` +/// with `{target}.{method}({element})` (one pair of parentheses). +fn use_single_arg_method_call( + range: TextRange, + target: &str, + method: &str, + element: &str, +) -> Diagnostic { + let new_content = format!("{target}.{method}({element})"); + let edit = Edit::range_replacement(new_content, range); + let fix = Fix::safe_edit(edit); + + let fix_title = format!("Replace with `.{method}()`"); + let kind = UnnecessaryIntermediateRepresentation { fix_title }; + let diagnostic = Diagnostic::new(kind, range); + + diagnostic.with_fix(fix) +} + +/// Returns a [`Diagnostic`] whose fix suggests replacing `range` +/// with `{target}.{method}(({element}))` (two pairs of parentheses). +fn use_tuple_arg_method_call( + range: TextRange, + target: &str, + method: &str, + element: &str, +) -> Diagnostic { + let new_content = format!("{target}.{method}(({element}))"); + let edit = Edit::range_replacement(new_content, range); + let fix = Fix::safe_edit(edit); + + let fix_title = format!("Replace with `.{method}()`"); + let kind = UnnecessaryIntermediateRepresentation { fix_title }; + let diagnostic = Diagnostic::new(kind, range); + + diagnostic.with_fix(fix) +} + +/// Returns a [`Diagnostic`] whose fix suggests replacing `range` +/// with `{target}[{key}] = {value}`. +fn use_item_assignment(range: TextRange, target: &str, value: &str, key: &str) -> Diagnostic { + let new_content = format!("{target}[{key}] = {value}"); + let edit = Edit::range_replacement(new_content, range); + let fix = Fix::safe_edit(edit); + + let fix_title = "Replace with item assignment".to_string(); + let kind = UnnecessaryIntermediateRepresentation { fix_title }; + let diagnostic = Diagnostic::new(kind, range); + + diagnostic.with_fix(fix) +} + +/// RUF042: Method calls +pub(crate) fn unnecessary_intermediate_representation_call(checker: &mut Checker, call: &ExprCall) { + let (func, arguments) = (&call.func, &call.arguments); + let range = call.range; + + let Expr::Attribute(ExprAttribute { value, attr, .. }) = func.as_ref() else { + return; + }; + let Expr::Name(target) = value.as_ref() else { + return; + }; + let Some(target_kind) = IterableKind::from_target(checker.semantic(), target) else { + return; + }; + + let (positionals, keywords) = (&arguments.args, &arguments.keywords); + let in_stmt_context = checker.semantic().current_expression_parent().is_none(); + + match (target_kind, attr.as_str()) { + (IterableKind::List, "extend") if keywords.is_empty() => { + let Some(iterable) = Iterable::from_single(positionals) else { + return; + }; + + list_extend_single(checker, range, target, &iterable); + } + + (IterableKind::Set, method @ ("update" | "difference_update")) => { + let Some(iterable) = Iterable::from_single(positionals) else { + return; + }; + + set_update_single(checker, range, target, method, &iterable); + } + + (IterableKind::Dict, "update") if !keywords.is_empty() && in_stmt_context => { + if !positionals.is_empty() { + return; + } + + let [argument] = &keywords[..] else { + return; + }; + + if argument.arg.is_none() { + let element = Element::DictUnpack(argument.value.range()); + dict_update_unpack(checker, range, target, &element); + } else { + dict_update_single_keyword(checker, range, target, arguments); + } + } + + (IterableKind::Dict, "update") if in_stmt_context => { + let Some(iterable) = Iterable::from_single(positionals) else { + return; + }; + let [element] = &iterable.elements[..] else { + return; + }; + + if element.is_unpack() { + dict_update_single_unpack(checker, range, target, element); + } else { + dict_update_single(checker, range, target, element); + } + } + + _ => {} + }; +} + +/// * `l.extend(["foo"])` -> `l.append("foo")` +/// * `l.extend([*foo])` -> `l.extend(foo)` +fn list_extend_single( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + iterable: &Iterable, +) { + list_iadd_single(checker, range, target, iterable); +} + +/// * `s.update({"foo"})` -> `s.add("foo")` +/// * `s.difference_update({"foo"})` -> `s.discard("foo")` +fn set_update_single( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + method: &str, + iterable: &Iterable, +) { + let op = match method { + "update" => Operator::BitOr, + "difference_update" => Operator::Sub, + _ => return, + }; + + set_iop_single(checker, range, target, op, iterable); +} + +/// `d.update({"foo": "bar"})` -> `d["foo"] = "bar"` +fn dict_update_single( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + element: &Element, +) { + dict_ior_single(checker, range, target, element); +} + +/// `d.update({**foo})` -> `d.update(foo)` +fn dict_update_single_unpack( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + element: &Element, +) { + let locator = checker.locator(); + let target_expr = locator.slice(target); + let element_expr = locator.slice(element); + + let method = "update"; + let diagnostic = use_single_arg_method_call(range, target_expr, method, element_expr); + + checker.diagnostics.push(diagnostic); +} + +/// `d.update(**foo)` -> `d.update(foo)` +fn dict_update_unpack( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + element: &Element, +) { + let locator = checker.locator(); + let target_expr = locator.slice(target); + let element_expr = locator.slice(element); + + let method = "update"; + let diagnostic = use_single_arg_method_call(range, target_expr, method, element_expr); + + checker.diagnostics.push(diagnostic); +} + +/// `d.update(foo="bar")` -> `d["foo"] = "bar"` +fn dict_update_single_keyword( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + arguments: &Arguments, +) { + if !arguments.args.is_empty() { + return; + } + + let [argument] = &arguments.keywords[..] else { + return; + }; + let (Some(name), value) = (&argument.arg, &argument.value) else { + return; + }; + + let locator = checker.locator(); + let generator = checker.generator(); + + let target_expr = locator.slice(target); + let value_expr = locator.slice(value); + let key_expr = generator.expr(&create_string_expr(name.to_string())); + + let diagnostic = use_item_assignment(range, target_expr, value_expr, &key_expr); + + checker.diagnostics.push(diagnostic); +} + +/// RUF042: Augmented assignments +pub(crate) fn unnecessary_intermediate_representation_aug_assign( + checker: &mut Checker, + aug_assign: &StmtAugAssign, +) { + let (target, op, value) = (&aug_assign.target, aug_assign.op, &aug_assign.value); + let range = aug_assign.range; + + let Expr::Name(target) = target.as_ref() else { + return; + }; + + let Some(target_kind) = IterableKind::from_target(checker.semantic(), target) else { + return; + }; + let Some(iterable) = Iterable::from(value) else { + return; + }; + + match (target_kind, op, iterable.kind) { + (IterableKind::List, Operator::Add, _) => { + if iterable.len() == 1 { + list_iadd_single(checker, range, target, &iterable); + } else { + list_iadd_multiple(checker, range, target, &iterable); + } + } + + (IterableKind::Set, _, IterableKind::Set) => { + if iterable.len() == 1 { + set_iop_single(checker, range, target, op, &iterable); + } else { + set_iop_multiple(checker, range, op, target, &iterable); + } + } + + (IterableKind::Dict, Operator::BitOr, IterableKind::Dict) => { + let [element] = &iterable.elements[..] else { + return; + }; + + if element.is_unpack() { + dict_ior_single_unpack(checker, range, target, element); + } else { + dict_ior_single(checker, range, target, element); + }; + } + + _ => {} + }; +} + +/// * `l += [foo]` -> `l.append(foo)` +/// * `l += [*foo]` -> `l.extend(foo)` +fn list_iadd_single( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + iterable: &Iterable, +) { + let [element] = &iterable.elements[..] else { + return; + }; + + if element.is_unpack() && !(iterable.kind.is_list() || iterable.kind.is_tuple()) { + return; + } + + let locator = checker.locator(); + let target_expr = locator.slice(target); + + let (method, element_expr) = if element.is_unpack() { + ("extend", locator.slice(element)) + } else { + ("append", &*element.expr(locator)) + }; + + let diagnostic = use_single_arg_method_call(range, target_expr, method, element_expr); + + checker.diagnostics.push(diagnostic); +} + +/// * `l += ["foo", "bar"]` -> `l.extend(("foo", "bar"))` +fn list_iadd_multiple( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + iterable: &Iterable, +) { + if iterable.is_empty() || iterable.has_unpack() { + return; + } + + let locator = checker.locator(); + let target_expr = locator.slice(target); + let element_exprs = iterable.element_exprs(locator); + + let method = "extend"; + let diagnostic = use_tuple_arg_method_call(range, target_expr, method, &element_exprs); + + checker.diagnostics.push(diagnostic); +} + +/// * `s |= {"foo"}` -> `s.add("foo")` +/// * `s -= {"foo"}` -> `s.discard("foo")` +/// * `s |= {*foo}` -> `s.update(foo)` +/// * `s -= {*foo}` -> `s.difference_update(foo)` +fn set_iop_single( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + op: Operator, + iterable: &Iterable, +) { + let [element] = &iterable.elements[..] else { + return; + }; + + let locator = checker.locator(); + let target_expr = locator.slice(target); + + let (method, element_expr) = match (op, element.is_unpack()) { + (Operator::BitOr, true) => ("update", locator.slice(element)), + (Operator::Sub, true) => ("difference_update", locator.slice(element)), + + (Operator::BitOr, false) => ("add", &*element.expr(locator)), + (Operator::Sub, false) => ("discard", &*element.expr(locator)), + + _ => return, + }; + + let diagnostic = use_single_arg_method_call(range, target_expr, method, element_expr); + + checker.diagnostics.push(diagnostic); +} + +/// * `s |= {"foo", "bar"}` -> `s.update(("foo", "bar"))` +/// * `s &= {"foo", "bar"}` -> `s.intersection_update(("foo", "bar"))` +/// * `s -= {"foo", "bar"}` -> `s.difference_update(("foo", "bar"))` +/// * `s ^= {"foo", "bar"}` -> `s.symmetric_difference_update(("foo", "bar"))` +fn set_iop_multiple( + checker: &mut Checker, + range: TextRange, + op: Operator, + target: &ExprName, + iterable: &Iterable, +) { + if iterable.is_empty() || iterable.has_unpack() { + return; + } + + let method = match op { + Operator::Sub => "difference_update", + Operator::BitOr => "update", + Operator::BitXor => "symmetric_difference_update", + Operator::BitAnd => "intersection_update", + _ => return, + }; + + let locator = checker.locator(); + let target_expr = locator.slice(target); + let element_exprs = iterable.element_exprs(locator); + + let diagnostic = use_tuple_arg_method_call(range, target_expr, method, &element_exprs); + + checker.diagnostics.push(diagnostic); +} + +/// * `d |= {"foo": "bar"}` -> `d["foo"] = "bar"` +fn dict_ior_single(checker: &mut Checker, range: TextRange, target: &ExprName, element: &Element) { + let Element::DictItem { key, value } = element else { + return; + }; + + let locator = checker.locator(); + let target_expr = locator.slice(target); + let key_expr = locator.slice(key); + let value_expr = locator.slice(value); + + let diagnostic = use_item_assignment(range, target_expr, key_expr, value_expr); + + checker.diagnostics.push(diagnostic); +} + +/// * `d |= {**unpack}` -> `d.update(unpack)` +fn dict_ior_single_unpack( + checker: &mut Checker, + range: TextRange, + target: &ExprName, + element: &Element, +) { + let locator = checker.locator(); + let target_expr = locator.slice(target); + let element_expr = locator.slice(element); + + let method = "update"; + let diagnostic = use_single_arg_method_call(range, target_expr, method, element_expr); + + checker.diagnostics.push(diagnostic); +} diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__preview__RUF042_RUF042.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__preview__RUF042_RUF042.py.snap new file mode 100644 index 00000000000000..547a059e81785d --- /dev/null +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__preview__RUF042_RUF042.py.snap @@ -0,0 +1,770 @@ +--- +source: crates/ruff_linter/src/rules/ruff/mod.rs +--- +RUF042.py:9:22: RUF042 [*] Unnecessary intermediate representation + | + 7 | ### Lists + 8 | + 9 | def f(l: list[Any]): l.extend(("append",)) # `l.append("append")` (safe) + | ^^^^^^^^^^^^^^^^^^^^^ RUF042 +10 | def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) +11 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + | + = help: Replace with `.append()` + +ℹ Safe fix +6 6 | +7 7 | ### Lists +8 8 | +9 |-def f(l: list[Any]): l.extend(("append",)) # `l.append("append")` (safe) + 9 |+def f(l: list[Any]): l.append("append") # `l.append("append")` (safe) +10 10 | def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) +11 11 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +12 12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + +RUF042.py:10:22: RUF042 [*] Unnecessary intermediate representation + | + 9 | def f(l: list[Any]): l.extend(("append",)) # `l.append("append")` (safe) +10 | def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) + | ^^^^^^^^^^^^^^^^^^^^ RUF042 +11 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + | + = help: Replace with `.append()` + +ℹ Safe fix +7 7 | ### Lists +8 8 | +9 9 | def f(l: list[Any]): l.extend(("append",)) # `l.append("append")` (safe) +10 |-def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) + 10 |+def f(l: list[Any]): l.append("append") # `l.append("append")` (safe) +11 11 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +12 12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +13 13 | + +RUF042.py:11:22: RUF042 [*] Unnecessary intermediate representation + | + 9 | def f(l: list[Any]): l.extend(("append",)) # `l.append("append")` (safe) +10 | def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) +11 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + | ^^^^^^^^^^^^^^^^^^^^ RUF042 +12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + | + = help: Replace with `.append()` + +ℹ Safe fix +8 8 | +9 9 | def f(l: list[Any]): l.extend(("append",)) # `l.append("append")` (safe) +10 10 | def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) +11 |-def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + 11 |+def f(l: list[Any]): l.append("append") # `l.append("append")` (safe) +12 12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +13 13 | +14 14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) + +RUF042.py:12:22: RUF042 [*] Unnecessary intermediate representation + | +10 | def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) +11 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + | ^^^^^^^^^^^^^^^^^^^^ RUF042 +13 | +14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) + | + = help: Replace with `.append()` + +ℹ Safe fix +9 9 | def f(l: list[Any]): l.extend(("append",)) # `l.append("append")` (safe) +10 10 | def f(l: list[Any]): l.extend(["append"]) # `l.append("append")` (safe) +11 11 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +12 |-def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) + 12 |+def f(l: list[Any]): l.append("append") # `l.append("append")` (safe) +13 13 | +14 14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) +15 15 | def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) + +RUF042.py:14:22: RUF042 [*] Unnecessary intermediate representation + | +12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +13 | +14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) + | ^^^^^^^^^^^^^^^^ RUF042 +15 | def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) +16 | def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) + | + = help: Replace with `.append()` + +ℹ Safe fix +11 11 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +12 12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +13 13 | +14 |-def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) + 14 |+def f(l: list[Any]): l.append("append") # `l.append("append")` (safe) +15 15 | def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) +16 16 | def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) +17 17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) + +RUF042.py:15:22: RUF042 [*] Unnecessary intermediate representation + | +14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) +15 | def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) + | ^^^^^^^^^^^^^^^ RUF042 +16 | def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) +17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) + | + = help: Replace with `.append()` + +ℹ Safe fix +12 12 | def f(l: list[Any]): l.extend({"append"}) # `l.append("append")` (safe) +13 13 | +14 14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) +15 |-def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) + 15 |+def f(l: list[Any]): l.append("append") # `l.append("append")` (safe) +16 16 | def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) +17 17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) +18 18 | + +RUF042.py:16:22: RUF042 [*] Unnecessary intermediate representation + | +14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) +15 | def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) +16 | def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) + | ^^^^^^^^^^^^^^^ RUF042 +17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) + | + = help: Replace with `.append()` + +ℹ Safe fix +13 13 | +14 14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) +15 15 | def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) +16 |-def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) + 16 |+def f(l: list[Any]): l.append("append") # `l.append("append")` (safe) +17 17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) +18 18 | +19 19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) + +RUF042.py:17:22: RUF042 [*] Unnecessary intermediate representation + | +15 | def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) +16 | def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) +17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) + | ^^^^^^^^^^^^^^^^^^ RUF042 +18 | +19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) + | + = help: Replace with `.append()` + +ℹ Safe fix +14 14 | def f(l: list[Any]): l += ("append",) # `l.append("append")` (safe) +15 15 | def f(l: list[Any]): l += ["append"] # `l.append("append")` (safe) +16 16 | def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) +17 |-def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) + 17 |+def f(l: list[Any]): l.append("append") # `l.append("append")` (safe) +18 18 | +19 19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) +20 20 | def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) + +RUF042.py:19:22: RUF042 [*] Unnecessary intermediate representation + | +17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) +18 | +19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +20 | def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) +21 | def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) + | + = help: Replace with `.extend()` + +ℹ Safe fix +16 16 | def f(l: list[Any]): l += {"append"} # `l.append("append")` (safe) +17 17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) +18 18 | +19 |-def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) + 19 |+def f(l: list[Any]): l.extend(("ext", "end")) # `l.extend(("ext", "end"))` (safe) +20 20 | def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) +21 21 | def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) +22 22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) + +RUF042.py:20:22: RUF042 [*] Unnecessary intermediate representation + | +19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) +20 | def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +21 | def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) +22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) + | + = help: Replace with `.extend()` + +ℹ Safe fix +17 17 | def f(l: list[Any]): l += {"append": 0} # `l.append("append")` (safe) +18 18 | +19 19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) +20 |-def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) + 20 |+def f(l: list[Any]): l.extend(("ext", "end")) # `l.extend(("ext", "end"))` (safe) +21 21 | def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) +22 22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) +23 23 | + +RUF042.py:21:22: RUF042 [*] Unnecessary intermediate representation + | +19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) +20 | def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) +21 | def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) + | + = help: Replace with `.extend()` + +ℹ Safe fix +18 18 | +19 19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) +20 20 | def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) +21 |-def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) + 21 |+def f(l: list[Any]): l.extend(("ext", "end")) # `l.extend(("ext", "end"))` (safe) +22 22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) +23 23 | +24 24 | def f(l: list[Any]): l += (*extend,) # `l.extend(extend)` (safe) + +RUF042.py:22:22: RUF042 [*] Unnecessary intermediate representation + | +20 | def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) +21 | def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) +22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF042 +23 | +24 | def f(l: list[Any]): l += (*extend,) # `l.extend(extend)` (safe) + | + = help: Replace with `.extend()` + +ℹ Safe fix +19 19 | def f(l: list[Any]): l += ("ext", "end") # `l.extend(("ext", "end"))` (safe) +20 20 | def f(l: list[Any]): l += ["ext", "end"] # `l.extend(("ext", "end"))` (safe) +21 21 | def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) +22 |-def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) + 22 |+def f(l: list[Any]): l.extend(("ext", "end")) # `l.extend(("ext", "end"))` (safe) +23 23 | +24 24 | def f(l: list[Any]): l += (*extend,) # `l.extend(extend)` (safe) +25 25 | def f(l: list[Any]): l += [*extend] # `l.extend(extend)` (safe) + +RUF042.py:24:22: RUF042 [*] Unnecessary intermediate representation + | +22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) +23 | +24 | def f(l: list[Any]): l += (*extend,) # `l.extend(extend)` (safe) + | ^^^^^^^^^^^^^^^ RUF042 +25 | def f(l: list[Any]): l += [*extend] # `l.extend(extend)` (safe) + | + = help: Replace with `.extend()` + +ℹ Safe fix +21 21 | def f(l: list[Any]): l += {"ext", "end"} # `l.extend(("ext", "end"))` (safe) +22 22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) +23 23 | +24 |-def f(l: list[Any]): l += (*extend,) # `l.extend(extend)` (safe) + 24 |+def f(l: list[Any]): l.extend(extend) # `l.extend(extend)` (safe) +25 25 | def f(l: list[Any]): l += [*extend] # `l.extend(extend)` (safe) +26 26 | +27 27 | + +RUF042.py:25:22: RUF042 [*] Unnecessary intermediate representation + | +24 | def f(l: list[Any]): l += (*extend,) # `l.extend(extend)` (safe) +25 | def f(l: list[Any]): l += [*extend] # `l.extend(extend)` (safe) + | ^^^^^^^^^^^^^^ RUF042 + | + = help: Replace with `.extend()` + +ℹ Safe fix +22 22 | def f(l: list[Any]): l += {"ext": 0, "end": 1} # `l.extend(("ext", "end"))` (safe) +23 23 | +24 24 | def f(l: list[Any]): l += (*extend,) # `l.extend(extend)` (safe) +25 |-def f(l: list[Any]): l += [*extend] # `l.extend(extend)` (safe) + 25 |+def f(l: list[Any]): l.extend(extend) # `l.extend(extend)` (safe) +26 26 | +27 27 | +28 28 | ### Sets + +RUF042.py:29:21: RUF042 [*] Unnecessary intermediate representation + | +28 | ### Sets +29 | def f(s: set[Any]): s.update(("add",)) # `s.add("add")` (safe) + | ^^^^^^^^^^^^^^^^^^ RUF042 +30 | def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) +31 | def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) + | + = help: Replace with `.add()` + +ℹ Safe fix +26 26 | +27 27 | +28 28 | ### Sets +29 |-def f(s: set[Any]): s.update(("add",)) # `s.add("add")` (safe) + 29 |+def f(s: set[Any]): s.add("add") # `s.add("add")` (safe) +30 30 | def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) +31 31 | def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) +32 32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) + +RUF042.py:30:21: RUF042 [*] Unnecessary intermediate representation + | +28 | ### Sets +29 | def f(s: set[Any]): s.update(("add",)) # `s.add("add")` (safe) +30 | def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) + | ^^^^^^^^^^^^^^^^^ RUF042 +31 | def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) +32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) + | + = help: Replace with `.add()` + +ℹ Safe fix +27 27 | +28 28 | ### Sets +29 29 | def f(s: set[Any]): s.update(("add",)) # `s.add("add")` (safe) +30 |-def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) + 30 |+def f(s: set[Any]): s.add("add") # `s.add("add")` (safe) +31 31 | def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) +32 32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) +33 33 | + +RUF042.py:31:21: RUF042 [*] Unnecessary intermediate representation + | +29 | def f(s: set[Any]): s.update(("add",)) # `s.add("add")` (safe) +30 | def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) +31 | def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) + | ^^^^^^^^^^^^^^^^^ RUF042 +32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) + | + = help: Replace with `.add()` + +ℹ Safe fix +28 28 | ### Sets +29 29 | def f(s: set[Any]): s.update(("add",)) # `s.add("add")` (safe) +30 30 | def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) +31 |-def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) + 31 |+def f(s: set[Any]): s.add("add") # `s.add("add")` (safe) +32 32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) +33 33 | +34 34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) + +RUF042.py:32:21: RUF042 [*] Unnecessary intermediate representation + | +30 | def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) +31 | def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) +32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) + | ^^^^^^^^^^^^^^^^^^^^ RUF042 +33 | +34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) + | + = help: Replace with `.add()` + +ℹ Safe fix +29 29 | def f(s: set[Any]): s.update(("add",)) # `s.add("add")` (safe) +30 30 | def f(s: set[Any]): s.update(["add"]) # `s.add("add")` (safe) +31 31 | def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) +32 |-def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) + 32 |+def f(s: set[Any]): s.add("add") # `s.add("add")` (safe) +33 33 | +34 34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) +35 35 | def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) + +RUF042.py:34:21: RUF042 [*] Unnecessary intermediate representation + | +32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) +33 | +34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF042 +35 | def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) +36 | def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) + | + = help: Replace with `.discard()` + +ℹ Safe fix +31 31 | def f(s: set[Any]): s.update({"add"}) # `s.add("add")` (safe) +32 32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) +33 33 | +34 |-def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) + 34 |+def f(s: set[Any]): s.discard("discard") # `s.discard("discard")` (safe) +35 35 | def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) +36 36 | def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) +37 37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) + +RUF042.py:35:21: RUF042 [*] Unnecessary intermediate representation + | +34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) +35 | def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF042 +36 | def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) +37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) + | + = help: Replace with `.discard()` + +ℹ Safe fix +32 32 | def f(s: set[Any]): s.update({"add": 0}) # `s.add("add")` (safe) +33 33 | +34 34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) +35 |-def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) + 35 |+def f(s: set[Any]): s.discard("discard") # `s.discard("discard")` (safe) +36 36 | def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) +37 37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) +38 38 | + +RUF042.py:36:21: RUF042 [*] Unnecessary intermediate representation + | +34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) +35 | def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) +36 | def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF042 +37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) + | + = help: Replace with `.discard()` + +ℹ Safe fix +33 33 | +34 34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) +35 35 | def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) +36 |-def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) + 36 |+def f(s: set[Any]): s.discard("discard") # `s.discard("discard")` (safe) +37 37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) +38 38 | +39 39 | def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) + +RUF042.py:37:21: RUF042 [*] Unnecessary intermediate representation + | +35 | def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) +36 | def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) +37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF042 +38 | +39 | def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) + | + = help: Replace with `.discard()` + +ℹ Safe fix +34 34 | def f(s: set[Any]): s.difference_update(("discard",)) # `s.discard("discard")` (safe) +35 35 | def f(s: set[Any]): s.difference_update(["discard"]) # `s.discard("discard")` (safe) +36 36 | def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) +37 |-def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) + 37 |+def f(s: set[Any]): s.discard("discard") # `s.discard("discard")` (safe) +38 38 | +39 39 | def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) +40 40 | def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) + +RUF042.py:39:21: RUF042 [*] Unnecessary intermediate representation + | +37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) +38 | +39 | def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) + | ^^^^^^^^^^^^ RUF042 +40 | def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) + | + = help: Replace with `.add()` + +ℹ Safe fix +36 36 | def f(s: set[Any]): s.difference_update({"discard"}) # `s.discard("discard")` (safe) +37 37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) +38 38 | +39 |-def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) + 39 |+def f(s: set[Any]): s.add("add") # `s.add("add")` (safe) +40 40 | def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) +41 41 | +42 42 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) + +RUF042.py:40:21: RUF042 [*] Unnecessary intermediate representation + | +39 | def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) +40 | def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) + | ^^^^^^^^^^^^^^^^ RUF042 +41 | +42 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) + | + = help: Replace with `.discard()` + +ℹ Safe fix +37 37 | def f(s: set[Any]): s.difference_update({"discard": 0}) # `s.discard("discard")` (safe) +38 38 | +39 39 | def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) +40 |-def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) + 40 |+def f(s: set[Any]): s.discard("discard") # `s.discard("discard"))` (safe) +41 41 | +42 42 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) +43 43 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) + +RUF042.py:42:21: RUF042 [*] Unnecessary intermediate representation + | +40 | def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) +41 | +42 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +43 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) + | + = help: Replace with `.update()` + +ℹ Safe fix +39 39 | def f(s: set[Any]): s |= {"add"} # `s.add("add")` (safe) +40 40 | def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) +41 41 | +42 |-def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) + 42 |+def f(s: set[Any]): s.update(("upd", "ate")) # `s.update(("upd", "ate"))` (safe) +43 43 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +44 44 | +45 45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) + +RUF042.py:43:21: RUF042 [*] Unnecessary intermediate representation + | +42 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) +43 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +44 | +45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) + | + = help: Replace with `.difference_update()` + +ℹ Safe fix +40 40 | def f(s: set[Any]): s -= {"discard"} # `s.discard("discard"))` (safe) +41 41 | +42 42 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) +43 |-def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) + 43 |+def f(s: set[Any]): s.difference_update(("upd", "ate")) # `s.difference_update(("upd", "ate"))` (safe) +44 44 | +45 45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) +46 46 | def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) + +RUF042.py:45:21: RUF042 [*] Unnecessary intermediate representation + | +43 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +44 | +45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +46 | def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) +47 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) + | + = help: Replace with `.update()` + +ℹ Safe fix +42 42 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate"))` (safe) +43 43 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +44 44 | +45 |-def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) + 45 |+def f(s: set[Any]): s.update(("upd", "ate")) # `s.update(("upd", "ate")` (safe) +46 46 | def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) +47 47 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +48 48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) + +RUF042.py:46:21: RUF042 [*] Unnecessary intermediate representation + | +45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) +46 | def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +47 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) + | + = help: Replace with `.intersection_update()` + +ℹ Safe fix +43 43 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +44 44 | +45 45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) +46 |-def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) + 46 |+def f(s: set[Any]): s.intersection_update(("upd", "ate")) # `s.intersection_update(("upd", "ate"))` (safe) +47 47 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +48 48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) +49 49 | + +RUF042.py:47:21: RUF042 [*] Unnecessary intermediate representation + | +45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) +46 | def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) +47 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) + | + = help: Replace with `.difference_update()` + +ℹ Safe fix +44 44 | +45 45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) +46 46 | def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) +47 |-def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) + 47 |+def f(s: set[Any]): s.difference_update(("upd", "ate")) # `s.difference_update(("upd", "ate"))` (safe) +48 48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) +49 49 | +50 50 | def f(s: set[Any]): s |= {*update} # `s.update(update)` (safe) + +RUF042.py:48:21: RUF042 [*] Unnecessary intermediate representation + | +46 | def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) +47 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) + | ^^^^^^^^^^^^^^^^^^^ RUF042 +49 | +50 | def f(s: set[Any]): s |= {*update} # `s.update(update)` (safe) + | + = help: Replace with `.symmetric_difference_update()` + +ℹ Safe fix +45 45 | def f(s: set[Any]): s |= {"upd", "ate"} # `s.update(("upd", "ate")` (safe) +46 46 | def f(s: set[Any]): s &= {"upd", "ate"} # `s.intersection_update(("upd", "ate"))` (safe) +47 47 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +48 |-def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) + 48 |+def f(s: set[Any]): s.symmetric_difference_update(("upd", "ate")) # `s.symmetric_difference_update(("upd", "ate"))` (safe) +49 49 | +50 50 | def f(s: set[Any]): s |= {*update} # `s.update(update)` (safe) +51 51 | def f(s: set[Any]): s -= {*update} # `s.difference_update(update)` (safe) + +RUF042.py:50:21: RUF042 [*] Unnecessary intermediate representation + | +48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) +49 | +50 | def f(s: set[Any]): s |= {*update} # `s.update(update)` (safe) + | ^^^^^^^^^^^^^^ RUF042 +51 | def f(s: set[Any]): s -= {*update} # `s.difference_update(update)` (safe) + | + = help: Replace with `.update()` + +ℹ Safe fix +47 47 | def f(s: set[Any]): s -= {"upd", "ate"} # `s.difference_update(("upd", "ate"))` (safe) +48 48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) +49 49 | +50 |-def f(s: set[Any]): s |= {*update} # `s.update(update)` (safe) + 50 |+def f(s: set[Any]): s.update(update) # `s.update(update)` (safe) +51 51 | def f(s: set[Any]): s -= {*update} # `s.difference_update(update)` (safe) +52 52 | +53 53 | + +RUF042.py:51:21: RUF042 [*] Unnecessary intermediate representation + | +50 | def f(s: set[Any]): s |= {*update} # `s.update(update)` (safe) +51 | def f(s: set[Any]): s -= {*update} # `s.difference_update(update)` (safe) + | ^^^^^^^^^^^^^^ RUF042 + | + = help: Replace with `.difference_update()` + +ℹ Safe fix +48 48 | def f(s: set[Any]): s ^= {"upd", "ate"} # `s.symmetric_difference_update(("upd", "ate"))` (safe) +49 49 | +50 50 | def f(s: set[Any]): s |= {*update} # `s.update(update)` (safe) +51 |-def f(s: set[Any]): s -= {*update} # `s.difference_update(update)` (safe) + 51 |+def f(s: set[Any]): s.difference_update(update) # `s.difference_update(update)` (safe) +52 52 | +53 53 | +54 54 | ### Dictionaries + +RUF042.py:56:27: RUF042 [*] Unnecessary intermediate representation + | +54 | ### Dictionaries +55 | +56 | def f(d: dict[Any, Any]): d.update(**update) # `d.update(update)` (safe) + | ^^^^^^^^^^^^^^^^^^ RUF042 +57 | def f(d: dict[Any, Any]): d.update({**update}) # `d.update(update)` (safe) + | + = help: Replace with `.update()` + +ℹ Safe fix +53 53 | +54 54 | ### Dictionaries +55 55 | +56 |-def f(d: dict[Any, Any]): d.update(**update) # `d.update(update)` (safe) + 56 |+def f(d: dict[Any, Any]): d.update(update) # `d.update(update)` (safe) +57 57 | def f(d: dict[Any, Any]): d.update({**update}) # `d.update(update)` (safe) +58 58 | +59 59 | def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) + +RUF042.py:57:27: RUF042 [*] Unnecessary intermediate representation + | +56 | def f(d: dict[Any, Any]): d.update(**update) # `d.update(update)` (safe) +57 | def f(d: dict[Any, Any]): d.update({**update}) # `d.update(update)` (safe) + | ^^^^^^^^^^^^^^^^^^^^ RUF042 +58 | +59 | def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) + | + = help: Replace with `.update()` + +ℹ Safe fix +54 54 | ### Dictionaries +55 55 | +56 56 | def f(d: dict[Any, Any]): d.update(**update) # `d.update(update)` (safe) +57 |-def f(d: dict[Any, Any]): d.update({**update}) # `d.update(update)` (safe) + 57 |+def f(d: dict[Any, Any]): d.update(update) # `d.update(update)` (safe) +58 58 | +59 59 | def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) +60 60 | def f(d: dict[Any, Any]): d.update(s="et") # `d["s"] = "et"` (safe) + +RUF042.py:59:27: RUF042 [*] Unnecessary intermediate representation + | +57 | def f(d: dict[Any, Any]): d.update({**update}) # `d.update(update)` (safe) +58 | +59 | def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) + | ^^^^^^^^^^^^^^^^^^^^^ RUF042 +60 | def f(d: dict[Any, Any]): d.update(s="et") # `d["s"] = "et"` (safe) + | + = help: Replace with item assignment + +ℹ Safe fix +56 56 | def f(d: dict[Any, Any]): d.update(**update) # `d.update(update)` (safe) +57 57 | def f(d: dict[Any, Any]): d.update({**update}) # `d.update(update)` (safe) +58 58 | +59 |-def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) + 59 |+def f(d: dict[Any, Any]): d["et"] = "s" # `d["s"] = "et"` (safe) +60 60 | def f(d: dict[Any, Any]): d.update(s="et") # `d["s"] = "et"` (safe) +61 61 | +62 62 | def f(d: dict[Any, Any]): d |= {"s": "et"} # `d["s"] = "et"` (safe) + +RUF042.py:60:27: RUF042 [*] Unnecessary intermediate representation + | +59 | def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) +60 | def f(d: dict[Any, Any]): d.update(s="et") # `d["s"] = "et"` (safe) + | ^^^^^^^^^^^^^^^^ RUF042 +61 | +62 | def f(d: dict[Any, Any]): d |= {"s": "et"} # `d["s"] = "et"` (safe) + | + = help: Replace with item assignment + +ℹ Safe fix +57 57 | def f(d: dict[Any, Any]): d.update({**update}) # `d.update(update)` (safe) +58 58 | +59 59 | def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) +60 |-def f(d: dict[Any, Any]): d.update(s="et") # `d["s"] = "et"` (safe) + 60 |+def f(d: dict[Any, Any]): d["s"] = "et" # `d["s"] = "et"` (safe) +61 61 | +62 62 | def f(d: dict[Any, Any]): d |= {"s": "et"} # `d["s"] = "et"` (safe) +63 63 | + +RUF042.py:62:27: RUF042 [*] Unnecessary intermediate representation + | +60 | def f(d: dict[Any, Any]): d.update(s="et") # `d["s"] = "et"` (safe) +61 | +62 | def f(d: dict[Any, Any]): d |= {"s": "et"} # `d["s"] = "et"` (safe) + | ^^^^^^^^^^^^^^^^ RUF042 +63 | +64 | def f(d: dict[Any, Any]): d |= {**update} # `d.update(update)` (safe) + | + = help: Replace with item assignment + +ℹ Safe fix +59 59 | def f(d: dict[Any, Any]): d.update({"s": "et"}) # `d["s"] = "et"` (safe) +60 60 | def f(d: dict[Any, Any]): d.update(s="et") # `d["s"] = "et"` (safe) +61 61 | +62 |-def f(d: dict[Any, Any]): d |= {"s": "et"} # `d["s"] = "et"` (safe) + 62 |+def f(d: dict[Any, Any]): d["et"] = "s" # `d["s"] = "et"` (safe) +63 63 | +64 64 | def f(d: dict[Any, Any]): d |= {**update} # `d.update(update)` (safe) +65 65 | + +RUF042.py:64:27: RUF042 [*] Unnecessary intermediate representation + | +62 | def f(d: dict[Any, Any]): d |= {"s": "et"} # `d["s"] = "et"` (safe) +63 | +64 | def f(d: dict[Any, Any]): d |= {**update} # `d.update(update)` (safe) + | ^^^^^^^^^^^^^^^ RUF042 + | + = help: Replace with `.update()` + +ℹ Safe fix +61 61 | +62 62 | def f(d: dict[Any, Any]): d |= {"s": "et"} # `d["s"] = "et"` (safe) +63 63 | +64 |-def f(d: dict[Any, Any]): d |= {**update} # `d.update(update)` (safe) + 64 |+def f(d: dict[Any, Any]): d.update(update) # `d.update(update)` (safe) +65 65 | +66 66 | +67 67 | ##### No errors diff --git a/ruff.schema.json b/ruff.schema.json index 7469867d0197c7..d8c9918d551ea4 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3919,6 +3919,7 @@ "RUF04", "RUF040", "RUF041", + "RUF042", "RUF043", "RUF046", "RUF048",