Skip to content
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
15 changes: 15 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/flake8_builtins/A003.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,18 @@ def method_usage(self) -> str:

def attribute_usage(self) -> id:
pass


class C:
@staticmethod
def property(f):
return f

id = 1

@[property][0]
def f(self, x=[id]):
return x

bin = 2
foo = [bin]
7 changes: 7 additions & 0 deletions crates/ruff_linter/src/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,10 @@ pub(crate) const fn is_maxsplit_without_separator_fix_enabled(settings: &LinterS
pub(crate) const fn is_bidi_forbid_arabic_letter_mark_enabled(settings: &LinterSettings) -> bool {
settings.preview.is_enabled()
}

// https://github.com/astral-sh/ruff/pull/20178
pub(crate) const fn is_a003_class_scope_shadowing_expansion_enabled(
settings: &LinterSettings,
) -> bool {
settings.preview.is_enabled()
}
23 changes: 23 additions & 0 deletions crates/ruff_linter/src/rules/flake8_builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod tests {
use crate::registry::Rule;
use crate::rules::flake8_builtins;
use crate::settings::LinterSettings;
use crate::settings::types::PreviewMode;
use crate::test::{test_path, test_resource_path};
use ruff_python_ast::PythonVersion;

Expand Down Expand Up @@ -63,6 +64,28 @@ mod tests {
Ok(())
}

#[test_case(Rule::BuiltinAttributeShadowing, Path::new("A003.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("flake8_builtins").join(path).as_path(),
&LinterSettings {
preview: PreviewMode::Enabled,
flake8_builtins: flake8_builtins::settings::Settings {
strict_checking: true,
..Default::default()
},
..LinterSettings::for_rule(rule_code)
},
)?;
assert_diagnostics!(snapshot, diagnostics);
Ok(())
}

#[test_case(
Rule::StdlibModuleShadowing,
Path::new("A005/modules/utils/logging.py"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ruff_text_size::Ranged;

use crate::Violation;
use crate::checkers::ast::Checker;
use crate::preview::is_a003_class_scope_shadowing_expansion_enabled;
use crate::rules::flake8_builtins::helpers::shadows_builtin;

/// ## What it does
Expand Down Expand Up @@ -123,16 +124,26 @@ pub(crate) fn builtin_attribute_shadowing(
// def repeat(value: int, times: int) -> list[int]:
// return [value] * times
// ```
// In stable, only consider references whose first non-type parent scope is the class
// scope (e.g., decorators, default args, and attribute initializers).
// In preview, also consider references from within the class scope.
let consider_reference = |reference_scope_id: ScopeId| {
if is_a003_class_scope_shadowing_expansion_enabled(checker.settings()) {
if reference_scope_id == scope_id {
return true;
}
}
checker
.semantic()
.first_non_type_parent_scope_id(reference_scope_id)
== Some(scope_id)
};

for reference in binding
.references
.iter()
.map(|reference_id| checker.semantic().reference(*reference_id))
.filter(|reference| {
checker
.semantic()
.first_non_type_parent_scope_id(reference.scope_id())
== Some(scope_id)
})
.filter(|reference| consider_reference(reference.scope_id()))
{
checker.report_diagnostic(
BuiltinAttributeShadowing {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
source: crates/ruff_linter/src/rules/flake8_builtins/mod.rs
---
A003 Python builtin is shadowed by method `str` from line 14
--> A003.py:17:31
|
15 | pass
16 |
17 | def method_usage(self) -> str:
| ^^^
18 | pass
|

A003 Python builtin is shadowed by class attribute `id` from line 3
--> A003.py:20:34
|
18 | pass
19 |
20 | def attribute_usage(self) -> id:
| ^^
21 | pass
|

A003 Python builtin is shadowed by method `property` from line 26
--> A003.py:31:7
|
29 | id = 1
30 |
31 | @[property][0]
| ^^^^^^^^
32 | def f(self, x=[id]):
33 | return x
|

A003 Python builtin is shadowed by class attribute `id` from line 29
--> A003.py:32:20
|
31 | @[property][0]
32 | def f(self, x=[id]):
| ^^
33 | return x
|

A003 Python builtin is shadowed by class attribute `bin` from line 35
--> A003.py:36:12
|
35 | bin = 2
36 | foo = [bin]
| ^^^
|