Skip to content

Commit

Permalink
[ruff] Implemented used-dummy-variable (RUF052) (#14611)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Waygood <[email protected]>
  • Loading branch information
Lokejoke and AlexWaygood authored Dec 3, 2024
1 parent a69dfd4 commit bf0fd04
Show file tree
Hide file tree
Showing 12 changed files with 778 additions and 8 deletions.
106 changes: 106 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF052.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Correct

for _ in range(5):
pass

_valid_type = int

_valid_var_1: _valid_type

_valid_var_1 = 1

_valid_var_2 = 2

_valid_var_3 = _valid_var_1 + _valid_var_2

def _valid_fun():
pass

_valid_fun()

def fun(arg):
_valid_unused_var = arg
pass

_x = "global"

def fun():
global _x
return _x

def fun():
__dunder__ = "dunder variable"
return __dunder__

def fun():
global _x
_x = "reassigned global"
return _x

class _ValidClass:
pass

_ValidClass()

class ClassOk:
_valid_private_cls_attr = 1

print(_valid_private_cls_attr)

def __init__(self):
self._valid_private_ins_attr = 2
print(self._valid_private_ins_attr)

def _valid_method(self):
return self._valid_private_ins_attr

def method(arg):
_valid_unused_var = arg
return

def fun(x):
_ = 1
__ = 2
___ = 3
if x == 1:
return _
if x == 2:
return __
if x == 3:
return ___
return x

# Incorrect

class Class_:
def fun(self):
_var = "method variable" # [RUF052]
return _var

def fun(_var): # [RUF052]
return _var

def fun():
_list = "built-in" # [RUF052]
return _list

x = "global"

def fun():
global x
_x = "shadows global" # [RUF052]
return _x

def foo():
x = "outer"
def bar():
nonlocal x
_x = "shadows nonlocal" # [RUF052]
return _x
bar()
return x

def fun():
x = "local"
_x = "shadows local" # [RUF052]
return _x
8 changes: 7 additions & 1 deletion crates/ruff_linter/src/checkers/ast/analyze/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::rules::{
/// Run lint rules over the [`Binding`]s.
pub(crate) fn bindings(checker: &mut Checker) {
if !checker.any_enabled(&[
Rule::AssignmentInAssert,
Rule::InvalidAllFormat,
Rule::InvalidAllObject,
Rule::NonAsciiName,
Expand All @@ -18,7 +19,7 @@ pub(crate) fn bindings(checker: &mut Checker) {
Rule::UnsortedDunderSlots,
Rule::UnusedVariable,
Rule::UnquotedTypeAlias,
Rule::AssignmentInAssert,
Rule::UsedDummyVariable,
]) {
return;
}
Expand Down Expand Up @@ -88,6 +89,11 @@ pub(crate) fn bindings(checker: &mut Checker) {
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::UsedDummyVariable) {
if let Some(diagnostic) = ruff::rules::used_dummy_variable(checker, binding) {
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::AssignmentInAssert) {
if let Some(diagnostic) = ruff::rules::assignment_in_assert(checker, binding) {
checker.diagnostics.push(diagnostic);
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_linter/src/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "040") => (RuleGroup::Preview, rules::ruff::rules::InvalidAssertMessageLiteralArgument),
(Ruff, "041") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryNestedLiteral),
(Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
(Ruff, "052") => (RuleGroup::Preview, rules::ruff::rules::UsedDummyVariable),
(Ruff, "055") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRegularExpression),
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
Expand Down
30 changes: 30 additions & 0 deletions crates/ruff_linter/src/rules/ruff/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod tests {
use std::path::Path;

use anyhow::Result;
use regex::Regex;
use rustc_hash::FxHashSet;
use test_case::test_case;

Expand Down Expand Up @@ -70,6 +71,7 @@ mod tests {
#[test_case(Rule::InvalidAssertMessageLiteralArgument, Path::new("RUF040.py"))]
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.py"))]
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.pyi"))]
#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Expand Down Expand Up @@ -449,4 +451,32 @@ mod tests {
assert_messages!(snapshot, diagnostics);
Ok(())
}

#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"), r"^_+", 1)]
#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"), r"", 2)]
fn custom_regexp_preset(
rule_code: Rule,
path: &Path,
regex_pattern: &str,
id: u8,
) -> Result<()> {
// Compile the regex from the pattern string
let regex = Regex::new(regex_pattern).unwrap();

let snapshot = format!(
"custom_dummy_var_regexp_preset__{}_{}_{}",
rule_code.noqa_code(),
path.to_string_lossy(),
id,
);
let diagnostics = test_path(
Path::new("ruff").join(path).as_path(),
&settings::LinterSettings {
dummy_variable_rgx: regex,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}
2 changes: 2 additions & 0 deletions crates/ruff_linter/src/rules/ruff/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub(crate) use unraw_re_pattern::*;
pub(crate) use unsafe_markup_use::*;
pub(crate) use unused_async::*;
pub(crate) use unused_noqa::*;
pub(crate) use used_dummy_variable::*;
pub(crate) use useless_if_else::*;
pub(crate) use zip_instead_of_pairwise::*;

Expand Down Expand Up @@ -85,6 +86,7 @@ mod unraw_re_pattern;
mod unsafe_markup_use;
mod unused_async;
mod unused_noqa;
mod used_dummy_variable;
mod useless_if_else;
mod zip_instead_of_pairwise;

Expand Down
Loading

0 comments on commit bf0fd04

Please sign in to comment.