Skip to content

Commit

Permalink
Treat unary operations on constants as constant-like (#3348)
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh authored Mar 4, 2023
1 parent d7767b2 commit 51fe9f7
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 41 deletions.
2 changes: 2 additions & 0 deletions crates/ruff/resources/test/fixtures/flake8_simplify/SIM300.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"yoda" <= compare # SIM300
"yoda" < compare # SIM300
42 > age # SIM300
-42 > age # SIM300
+42 > age # SIM300
YODA == age # SIM300
YODA > age # SIM300
YODA >= age # SIM300
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
if 1 == 3: # [comparison-of-constants] R0133
pass

if 1 == -3: # [comparison-of-constants] R0133
pass

x = 0
if 4 == 3 == x: # [comparison-of-constants] R0133
pass
Expand All @@ -35,6 +38,12 @@
if argc != 2: # [magic-value-comparison]
pass

if argc != -2: # [magic-value-comparison]
pass

if argc != +2: # [magic-value-comparison]
pass

if __name__ == "__main__": # correct
pass

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::Result;
use libcst_native::{Codegen, CodegenState, CompOp};
use ruff_macros::{define_violation, derive_message_formats};
use ruff_python::str::{self};
use rustpython_parser::ast::{Cmpop, Expr, ExprKind};
use rustpython_parser::ast::{Cmpop, Expr, ExprKind, Unaryop};

use crate::ast::types::Range;
use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -50,6 +50,10 @@ fn is_constant_like(expr: &Expr) -> bool {
ExprKind::Constant { .. } => true,
ExprKind::Tuple { elts, .. } => elts.iter().all(is_constant_like),
ExprKind::Name { id, .. } => str::is_upper(id),
ExprKind::UnaryOp {
op: Unaryop::UAdd | Unaryop::USub | Unaryop::Invert,
operand,
} => matches!(operand.node, ExprKind::Constant { .. }),
_ => false,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,51 +130,51 @@ expression: diagnostics
parent: ~
- kind:
YodaConditions:
suggestion: age == YODA
suggestion: age < -42
location:
row: 9
column: 0
end_location:
row: 9
column: 11
column: 9
fix:
content: age == YODA
content: age < -42
location:
row: 9
column: 0
end_location:
row: 9
column: 11
column: 9
parent: ~
- kind:
YodaConditions:
suggestion: age < YODA
suggestion: age < +42
location:
row: 10
column: 0
end_location:
row: 10
column: 10
column: 9
fix:
content: age < YODA
content: age < +42
location:
row: 10
column: 0
end_location:
row: 10
column: 10
column: 9
parent: ~
- kind:
YodaConditions:
suggestion: age <= YODA
suggestion: age == YODA
location:
row: 11
column: 0
end_location:
row: 11
column: 11
fix:
content: age <= YODA
content: age == YODA
location:
row: 11
column: 0
Expand All @@ -184,56 +184,92 @@ expression: diagnostics
parent: ~
- kind:
YodaConditions:
suggestion: age == JediOrder.YODA
suggestion: age < YODA
location:
row: 12
column: 0
end_location:
row: 12
column: 21
column: 10
fix:
content: age == JediOrder.YODA
content: age < YODA
location:
row: 12
column: 0
end_location:
row: 12
column: 21
column: 10
parent: ~
- kind:
YodaConditions:
suggestion: (number - 100) > 0
suggestion: age <= YODA
location:
row: 13
column: 0
end_location:
row: 13
column: 18
column: 11
fix:
content: (number - 100) > 0
content: age <= YODA
location:
row: 13
column: 0
end_location:
row: 13
column: 18
column: 11
parent: ~
- kind:
YodaConditions:
suggestion: (60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE
suggestion: age == JediOrder.YODA
location:
row: 14
column: 0
end_location:
row: 14
column: 52
column: 21
fix:
content: (60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE
content: age == JediOrder.YODA
location:
row: 14
column: 0
end_location:
row: 14
column: 21
parent: ~
- kind:
YodaConditions:
suggestion: (number - 100) > 0
location:
row: 15
column: 0
end_location:
row: 15
column: 18
fix:
content: (number - 100) > 0
location:
row: 15
column: 0
end_location:
row: 15
column: 18
parent: ~
- kind:
YodaConditions:
suggestion: (60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE
location:
row: 16
column: 0
end_location:
row: 16
column: 52
fix:
content: (60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE
location:
row: 16
column: 0
end_location:
row: 16
column: 52
parent: ~

31 changes: 23 additions & 8 deletions crates/ruff/src/rules/pylint/rules/magic_value_comparison.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use itertools::Itertools;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Unaryop};

use ruff_macros::{define_violation, derive_message_formats};
use rustpython_parser::ast::{Constant, Expr, ExprKind};

use crate::ast::helpers::unparse_constant;
use crate::ast::helpers::unparse_expr;
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::Diagnostic;
Expand All @@ -24,6 +25,22 @@ impl Violation for MagicValueComparison {
}
}

/// If an [`Expr`] is a constant (or unary operation on a constant), return the [`Constant`].
fn as_constant(expr: &Expr) -> Option<&Constant> {
match &expr.node {
ExprKind::Constant { value, .. } => Some(value),
ExprKind::UnaryOp {
op: Unaryop::UAdd | Unaryop::USub | Unaryop::Invert,
operand,
} => match &operand.node {
ExprKind::Constant { value, .. } => Some(value),
_ => None,
},
_ => None,
}
}

/// Return `true` if a [`Constant`] is a magic value.
fn is_magic_value(constant: &Constant, allowed_types: &[ConstantType]) -> bool {
if let Ok(constant_type) = ConstantType::try_from(constant) {
if allowed_types.contains(&constant_type) {
Expand All @@ -37,7 +54,7 @@ fn is_magic_value(constant: &Constant, allowed_types: &[ConstantType]) -> bool {
Constant::Ellipsis => false,
// Otherwise, special-case some common string and integer types.
Constant::Str(value) => !matches!(value.as_str(), "" | "__main__"),
Constant::Int(value) => !matches!(value.try_into(), Ok(-1 | 0 | 1)),
Constant::Int(value) => !matches!(value.try_into(), Ok(0 | 1)),
Constant::Bytes(_) => true,
Constant::Tuple(_) => true,
Constant::Float(_) => true,
Expand All @@ -53,19 +70,17 @@ pub fn magic_value_comparison(checker: &mut Checker, left: &Expr, comparators: &
{
// If both of the comparators are constant, skip rule for the whole expression.
// R0133: comparison-of-constants
if matches!(left.node, ExprKind::Constant { .. })
&& matches!(right.node, ExprKind::Constant { .. })
{
if as_constant(left).is_some() && as_constant(right).is_some() {
return;
}
}

for comparison_expr in std::iter::once(left).chain(comparators.iter()) {
if let ExprKind::Constant { value, .. } = &comparison_expr.node {
if let Some(value) = as_constant(comparison_expr) {
if is_magic_value(value, &checker.settings.pylint.allow_magic_value_types) {
checker.diagnostics.push(Diagnostic::new(
MagicValueComparison {
value: unparse_constant(value, checker.stylist),
value: unparse_expr(comparison_expr, checker.stylist),
},
Range::from_located(comparison_expr),
));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: src/rules/pylint/mod.rs
source: crates/ruff/src/rules/pylint/mod.rs
expression: diagnostics
---
- kind:
Expand All @@ -17,21 +17,43 @@ expression: diagnostics
MagicValueComparison:
value: "2"
location:
row: 35
row: 38
column: 11
end_location:
row: 35
row: 38
column: 12
fix: ~
parent: ~
- kind:
MagicValueComparison:
value: "-2"
location:
row: 41
column: 11
end_location:
row: 41
column: 13
fix: ~
parent: ~
- kind:
MagicValueComparison:
value: "+2"
location:
row: 44
column: 11
end_location:
row: 44
column: 13
fix: ~
parent: ~
- kind:
MagicValueComparison:
value: "3.141592653589793"
location:
row: 56
row: 65
column: 20
end_location:
row: 56
row: 65
column: 40
fix: ~
parent: ~
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,32 @@ expression: diagnostics
MagicValueComparison:
value: "\"Hunter2\""
location:
row: 50
row: 59
column: 21
end_location:
row: 50
row: 59
column: 30
fix: ~
parent: ~
- kind:
MagicValueComparison:
value: "3.141592653589793"
location:
row: 56
row: 65
column: 20
end_location:
row: 56
row: 65
column: 40
fix: ~
parent: ~
- kind:
MagicValueComparison:
value: "b\"something\""
location:
row: 65
row: 74
column: 17
end_location:
row: 65
row: 74
column: 29
fix: ~
parent: ~
Expand Down

0 comments on commit 51fe9f7

Please sign in to comment.