Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement PLR2004 (MagicValueComparison) #1828

Merged
merged 4 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,7 @@ For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
| PLR0402 | ConsiderUsingFromImport | Use `from ... import ...` in lieu of alias | |
| PLR1701 | ConsiderMergingIsinstance | Merge these isinstance calls: `isinstance(..., (...))` | |
| PLR1722 | UseSysExit | Use `sys.exit()` instead of `exit` | 🛠 |
| PLR2004 | MagicValueComparison | Magic number used in comparison, consider replacing magic with a constant variable | |
| PLW0120 | UselessElseOnLoop | Else clause on loop without a break statement, remove the else and de-indent all the code inside it | |
| PLW0602 | GlobalVariableNotAssigned | Using global for `...` but no assignment is done | |

Expand Down
21 changes: 21 additions & 0 deletions resources/test/fixtures/pylint/magic_value_comparison.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Check that magic values are not used in comparisons"""

user_input = 10

if 10 > user_input: # [magic-value-comparison]
pass

if 10 == 100: # [magic-value-comparison]
pass

time_delta = 7224
one_hour = 3600

if time_delta > one_hour: # correct
pass

argc = 1

if argc != 1: # correct
pass

4 changes: 4 additions & 0 deletions ruff.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,10 @@
"PLR1701",
"PLR172",
"PLR1722",
"PLR2",
"PLR20",
"PLR200",
"PLR2004",
"PLW",
"PLW0",
"PLW01",
Expand Down
4 changes: 4 additions & 0 deletions src/checkers/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2583,6 +2583,10 @@ where
);
}

if self.settings.enabled.contains(&RuleCode::PLR2004) {
pylint::rules::magic_value_comparison(self, expr, left, comparators);
}

if self.settings.enabled.contains(&RuleCode::SIM118) {
flake8_simplify::rules::key_in_dict_compare(self, expr, left, ops, comparators);
}
Expand Down
1 change: 1 addition & 0 deletions src/pylint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod tests {
#[test_case(RuleCode::PLR1722, Path::new("consider_using_sys_exit_4.py"); "PLR1722_4")]
#[test_case(RuleCode::PLR1722, Path::new("consider_using_sys_exit_5.py"); "PLR1722_5")]
#[test_case(RuleCode::PLR1722, Path::new("consider_using_sys_exit_6.py"); "PLR1722_6")]
#[test_case(RuleCode::PLR2004, Path::new("magic_value_comparison.py"); "PLR2004")]
#[test_case(RuleCode::PLW0120, Path::new("useless_else_on_loop.py"); "PLW0120")]
#[test_case(RuleCode::PLW0602, Path::new("global_variable_not_assigned.py"); "PLW0602")]
fn rules(rule_code: RuleCode, path: &Path) -> Result<()> {
Expand Down
41 changes: 41 additions & 0 deletions src/pylint/rules/magic_value_comparison.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use rustpython_ast::{Constant, Expr, ExprKind};

use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::Diagnostic;
use crate::violations;

fn is_magic_value(constant: &Constant) -> Option<String> {
match constant {
Constant::Int(value) => {
if matches!(value.try_into(), Ok(-1 | 0 | 1)) {
None
} else {
Some(value.to_string())
}
}
Constant::Float(value) => Some(value.to_string()),
max0x53 marked this conversation as resolved.
Show resolved Hide resolved
_ => None,
}
}

/// PLR2004
pub fn magic_value_comparison(
checker: &mut Checker,
expr: &Expr,
left: &Expr,
comparators: &[Expr],
) {
for comparison_expr in comparators.iter().chain([left]) {
if let ExprKind::Constant { value, .. } = &comparison_expr.node {
max0x53 marked this conversation as resolved.
Show resolved Hide resolved
if let Some(value) = is_magic_value(value) {
let diagnostic = Diagnostic::new(
violations::MagicValueComparison(value),
Range::from_located(expr),
);

checker.diagnostics.push(diagnostic);
}
}
}
}
2 changes: 2 additions & 0 deletions src/pylint/rules/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub use await_outside_async::await_outside_async;
pub use magic_value_comparison::magic_value_comparison;
pub use merge_isinstance::merge_isinstance;
pub use misplaced_comparison_constant::misplaced_comparison_constant;
pub use property_with_parameters::property_with_parameters;
Expand All @@ -10,6 +11,7 @@ pub use useless_else_on_loop::useless_else_on_loop;
pub use useless_import_alias::useless_import_alias;

mod await_outside_async;
mod magic_value_comparison;
mod merge_isinstance;
mod misplaced_comparison_constant;
mod property_with_parameters;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
source: src/pylint/mod.rs
expression: diagnostics
---
- kind:
MagicValueComparison: "10"
location:
row: 5
column: 3
end_location:
row: 5
column: 18
fix: ~
parent: ~
- kind:
MagicValueComparison: "100"
location:
row: 8
column: 3
end_location:
row: 8
column: 12
fix: ~
parent: ~
- kind:
MagicValueComparison: "10"
location:
row: 8
column: 3
end_location:
row: 8
column: 12
fix: ~
parent: ~

1 change: 1 addition & 0 deletions src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ define_rule_mapping!(
PLR0402 => violations::ConsiderUsingFromImport,
PLR1701 => violations::ConsiderMergingIsinstance,
PLR1722 => violations::UseSysExit,
PLR2004 => violations::MagicValueComparison,
PLW0120 => violations::UselessElseOnLoop,
PLW0602 => violations::GlobalVariableNotAssigned,
// flake8-builtins
Expand Down
16 changes: 16 additions & 0 deletions src/violations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,22 @@ impl AlwaysAutofixableViolation for UseSysExit {
}
}

define_violation!(
pub struct MagicValueComparison(pub String);
);
impl Violation for MagicValueComparison {
fn message(&self) -> String {
let MagicValueComparison(value) = self;
format!(
"Magic number used in comparison, consider replacing {value} with a constant variable"
)
}

fn placeholder() -> Self {
MagicValueComparison("magic".to_string())
}
}

define_violation!(
pub struct UselessElseOnLoop;
);
Expand Down