From 760ff26c0608ba4a025f5f55e1a48d596ccaae85 Mon Sep 17 00:00:00 2001 From: asafamr-mm Date: Sat, 16 Dec 2023 21:01:22 +0200 Subject: [PATCH] sim300 constant likelihood levels --- .../test/fixtures/flake8_simplify/SIM300.py | 8 +- .../flake8_simplify/rules/yoda_conditions.rs | 51 +++++-- ...ke8_simplify__tests__SIM300_SIM300.py.snap | 125 ++++++++++-------- 3 files changed, 123 insertions(+), 61 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM300.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM300.py index a9cd7df872..d97692d793 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM300.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM300.py @@ -13,9 +13,10 @@ YODA > age # SIM300 YODA >= age # SIM300 JediOrder.YODA == age # SIM300 0 < (number - 100) # SIM300 -SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 B 0 +UPPER_LIST == ['upper'] +DummyHandler.CONFIG == {} +{"thats": "acceptable"} == DummyHandler.CONFIG +SECONDS_IN_DAY == 60 * 60 * 24 +SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) \ No newline at end of file diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/yoda_conditions.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/yoda_conditions.rs index c196823de7..68f38713bc 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/yoda_conditions.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/yoda_conditions.rs @@ -1,3 +1,5 @@ +use std::cmp; + use anyhow::Result; use libcst_native::CompOp; @@ -78,18 +80,51 @@ impl Violation for YodaConditions { } } -/// Return `true` if an [`Expr`] is a constant or a constant-like name. -fn is_constant_like(expr: &Expr) -> bool { +/// Comparisons left hand side must not be more [`ConstantLikelihood`] than their right hand side +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] +enum ConstantLikelihood { + Unlikely = 0, + Probably = 1, // CAMEL_CASED vars + Definitely = 2, // literals, empty dicts and tuples... +} + +fn how_likely_constant_str(s: &str) -> ConstantLikelihood { + if str::is_cased_uppercase(s) { + ConstantLikelihood::Probably + } else { + ConstantLikelihood::Unlikely + } +} + +/// Return [`Expr`] [`ConstantLikelihood`] level depending on simple heuristics. +fn how_likely_constant(expr: &Expr) -> ConstantLikelihood { + if expr.is_literal_expr() { + return ConstantLikelihood::Definitely; + } match expr { - Expr::Attribute(ast::ExprAttribute { attr, .. }) => str::is_cased_uppercase(attr), - Expr::Tuple(ast::ExprTuple { elts, .. }) => elts.iter().all(is_constant_like), - Expr::Name(ast::ExprName { id, .. }) => str::is_cased_uppercase(id), + Expr::Attribute(ast::ExprAttribute { attr, .. }) => how_likely_constant_str(attr), + Expr::Name(ast::ExprName { id, .. }) => how_likely_constant_str(id), + Expr::Tuple(ast::ExprTuple { elts, .. }) | Expr::List(ast::ExprList { elts, .. }) => elts + .iter() + .map(how_likely_constant) + .min() + .unwrap_or(ConstantLikelihood::Definitely), + Expr::Dict(ast::ExprDict { values: vs, .. }) => { + if vs.is_empty() { + ConstantLikelihood::Definitely + } else { + ConstantLikelihood::Probably + } + } + Expr::BinOp(ast::ExprBinOp { left, right, .. }) => { + cmp::min(how_likely_constant(left), how_likely_constant(right)) + } Expr::UnaryOp(ast::ExprUnaryOp { op: UnaryOp::UAdd | UnaryOp::USub | UnaryOp::Invert, operand, range: _, - }) => operand.is_literal_expr(), - _ => expr.is_literal_expr(), + }) => how_likely_constant(operand), + _ => ConstantLikelihood::Unlikely, } } @@ -180,7 +215,7 @@ pub(crate) fn yoda_conditions( return; } - if !is_constant_like(left) || is_constant_like(right) { + if how_likely_constant(left) <= how_likely_constant(right) { return; } diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM300_SIM300.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM300_SIM300.py.snap index 036cabca9d..0cf1810323 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM300_SIM300.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM300_SIM300.py.snap @@ -247,7 +247,7 @@ SIM300.py:13:1: SIM300 [*] Yoda conditions are discouraged, use `age <= YODA` in 13 |+age <= YODA # SIM300 14 14 | JediOrder.YODA == age # SIM300 15 15 | 0 < (number - 100) # SIM300 -16 16 | SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 +16 16 | B (60 * 60) # SIM300 +16 | B (60 * 60) # SIM300 -17 17 | B 0` instead | @@ -276,8 +276,8 @@ SIM300.py:15:1: SIM300 [*] Yoda conditions are discouraged, use `(number - 100) 14 | JediOrder.YODA == age # SIM300 15 | 0 < (number - 100) # SIM300 | ^^^^^^^^^^^^^^^^^^ SIM300 -16 | SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 -17 | B 0` @@ -287,70 +287,91 @@ SIM300.py:15:1: SIM300 [*] Yoda conditions are discouraged, use `(number - 100) 14 14 | JediOrder.YODA == age # SIM300 15 |-0 < (number - 100) # SIM300 15 |+(number - 100) > 0 # SIM300 -16 16 | SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 -17 17 | B B` instead | 14 | JediOrder.YODA == age # SIM300 15 | 0 < (number - 100) # SIM300 -16 | SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM300 -17 | B B` ℹ Safe fix 13 13 | YODA >= age # SIM300 14 14 | JediOrder.YODA == age # SIM300 15 15 | 0 < (number - 100) # SIM300 -16 |-SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 - 16 |+(60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE # SIM300 -17 17 | B B or B +17 17 | B or(B) B` instead +SIM300.py:17:5: SIM300 [*] Yoda conditions are discouraged, use `A[0][0] > (B)` instead | 15 | 0 < (number - 100) # SIM300 -16 | SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 -17 | B B` - -ℹ Safe fix -14 14 | JediOrder.YODA == age # SIM300 -15 15 | 0 < (number - 100) # SIM300 -16 16 | SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 -17 |-B B or B -18 18 | B or(B) (B)` instead - | -16 | SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 -17 | B (B)` ℹ Safe fix +14 14 | JediOrder.YODA == age # SIM300 15 15 | 0 < (number - 100) # SIM300 -16 16 | SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300 -17 17 | B (B) -19 19 | -20 20 | # OK -21 21 | compare == "yoda" +16 16 | B (B) +18 18 | ['upper'] == UPPER_LIST +19 19 | {} == DummyHandler.CONFIG +20 20 | + +SIM300.py:18:1: SIM300 [*] Yoda conditions are discouraged, use `UPPER_LIST == ['upper']` instead + | +16 | B