diff --git a/README.md b/README.md index 4e3ed9dfc7..5eaed1c320 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com | C402 | UnnecessaryGeneratorDict | Unnecessary generator - rewrite as a dict comprehension | | | | C403 | UnnecessaryListComprehensionSet | Unnecessary list comprehension - rewrite as a set comprehension | | | | C404 | UnnecessaryListComprehensionDict | Unnecessary list comprehension - rewrite as a dict comprehension | | | +| C405 | UnnecessaryLiteralSet | Unnecessary literal - rewrite as a set literal | | | | SPR001 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | | 🛠 | | T201 | PrintFound | `print` found | | 🛠 | | T203 | PPrintFound | `pprint` found | | 🛠 | diff --git a/resources/test/fixtures/C405.py b/resources/test/fixtures/C405.py new file mode 100644 index 0000000000..8456d427de --- /dev/null +++ b/resources/test/fixtures/C405.py @@ -0,0 +1,5 @@ +s1 = set([1, 2]) +s2 = set((1, 2)) +s3 = set([]) +s4 = set(()) +s5 = set() diff --git a/src/ast/checks.rs b/src/ast/checks.rs index 6d643e1bb1..25c1ccfbb1 100644 --- a/src/ast/checks.rs +++ b/src/ast/checks.rs @@ -877,6 +877,32 @@ pub fn unnecessary_list_comprehension_dict( None } +/// Check `set([1, 2])` compliance. +pub fn unnecessary_literal_set(expr: &Expr, func: &Expr, args: &Vec) -> Option { + if args.len() == 1 { + if let ExprKind::Name { id, .. } = &func.node { + if id == "set" { + match &args[0].node { + ExprKind::List { .. } => { + return Some(Check::new( + CheckKind::UnnecessaryLiteralSet("list".to_string()), + Range::from_located(expr), + )); + } + ExprKind::Tuple { .. } => { + return Some(Check::new( + CheckKind::UnnecessaryLiteralSet("tuple".to_string()), + Range::from_located(expr), + )); + } + _ => {} + } + } + } + } + None +} + // flake8-super /// Check that `super()` has no args pub fn check_super_args( diff --git a/src/check_ast.rs b/src/check_ast.rs index 9f65ab8599..1a4b45beb4 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -800,6 +800,12 @@ where }; } + if self.settings.enabled.contains(&CheckCode::C405) { + if let Some(check) = checks::unnecessary_literal_set(expr, func, args) { + self.checks.push(check); + }; + } + // pyupgrade if self.settings.enabled.contains(&CheckCode::U002) && self.settings.target_version >= PythonVersion::Py310 diff --git a/src/checks.rs b/src/checks.rs index 1aa4a6cace..cb48ea8d50 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -57,7 +57,7 @@ pub const DEFAULT_CHECK_CODES: [CheckCode; 43] = [ CheckCode::F901, ]; -pub const ALL_CHECK_CODES: [CheckCode; 60] = [ +pub const ALL_CHECK_CODES: [CheckCode; 61] = [ // pycodestyle errors CheckCode::E402, CheckCode::E501, @@ -114,6 +114,7 @@ pub const ALL_CHECK_CODES: [CheckCode; 60] = [ CheckCode::C402, CheckCode::C403, CheckCode::C404, + CheckCode::C405, // flake8-super CheckCode::SPR001, // flake8-print @@ -187,6 +188,7 @@ pub enum CheckCode { C402, C403, C404, + C405, // flake8-super SPR001, // flake8-print @@ -340,6 +342,7 @@ impl CheckCode { CheckCode::C402 => "C402", CheckCode::C403 => "C403", CheckCode::C404 => "C404", + CheckCode::C405 => "C405", // flake8-super CheckCode::SPR001 => "SPR001", // flake8-print @@ -426,6 +429,7 @@ impl CheckCode { CheckCode::C402 => CheckKind::UnnecessaryGeneratorDict, CheckCode::C403 => CheckKind::UnnecessaryListComprehensionSet, CheckCode::C404 => CheckKind::UnnecessaryListComprehensionDict, + CheckCode::C405 => CheckKind::UnnecessaryLiteralSet("".to_string()), // flake8-super CheckCode::SPR001 => CheckKind::SuperCallWithParameters, // flake8-print @@ -512,6 +516,7 @@ pub enum CheckKind { UnnecessaryGeneratorDict, UnnecessaryListComprehensionSet, UnnecessaryListComprehensionDict, + UnnecessaryLiteralSet(String), // flake8-super SuperCallWithParameters, // flake8-print @@ -585,6 +590,7 @@ impl CheckKind { CheckKind::UnnecessaryGeneratorDict => "UnnecessaryGeneratorDict", CheckKind::UnnecessaryListComprehensionSet => "UnnecessaryListComprehensionSet", CheckKind::UnnecessaryListComprehensionDict => "UnnecessaryListComprehensionDict", + CheckKind::UnnecessaryLiteralSet(_) => "UnnecessaryLiteralSet", // flake8-super CheckKind::SuperCallWithParameters => "SuperCallWithParameters", // flake8-print @@ -658,6 +664,7 @@ impl CheckKind { CheckKind::UnnecessaryGeneratorDict => &CheckCode::C402, CheckKind::UnnecessaryListComprehensionSet => &CheckCode::C403, CheckKind::UnnecessaryListComprehensionDict => &CheckCode::C404, + CheckKind::UnnecessaryLiteralSet(_) => &CheckCode::C405, // flake8-super CheckKind::SuperCallWithParameters => &CheckCode::SPR001, // flake8-print @@ -832,6 +839,9 @@ impl CheckKind { CheckKind::UnnecessaryListComprehensionDict => { "Unnecessary list comprehension - rewrite as a dict comprehension".to_string() } + CheckKind::UnnecessaryLiteralSet(obj_type) => { + format!("Unnecessary {obj_type} literal - rewrite as a set literal") + } // flake8-super CheckKind::SuperCallWithParameters => { "Use `super()` instead of `super(__class__, self)`".to_string() diff --git a/src/linter.rs b/src/linter.rs index de7850a4ca..d0549e48af 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -846,6 +846,18 @@ mod tests { Ok(()) } + #[test] + fn c405() -> Result<()> { + let mut checks = check_path( + Path::new("./resources/test/fixtures/C405.py"), + &settings::Settings::for_rule(CheckCode::C405), + &fixer::Mode::Generate, + )?; + checks.sort_by_key(|check| check.location); + insta::assert_yaml_snapshot!(checks); + Ok(()) + } + #[test] fn spr001() -> Result<()> { let mut checks = check_path( diff --git a/src/snapshots/ruff__linter__tests__c405.snap b/src/snapshots/ruff__linter__tests__c405.snap new file mode 100644 index 0000000000..e7488c4fd7 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__c405.snap @@ -0,0 +1,41 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: + UnnecessaryLiteralSet: list + location: + row: 1 + column: 6 + end_location: + row: 1 + column: 17 + fix: ~ +- kind: + UnnecessaryLiteralSet: tuple + location: + row: 2 + column: 6 + end_location: + row: 2 + column: 17 + fix: ~ +- kind: + UnnecessaryLiteralSet: list + location: + row: 3 + column: 6 + end_location: + row: 3 + column: 13 + fix: ~ +- kind: + UnnecessaryLiteralSet: tuple + location: + row: 4 + column: 6 + end_location: + row: 4 + column: 13 + fix: ~ +