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

[ruff] Implemented used-dummy-variable (RUF052) #14611

Merged
merged 22 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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
Loading