diff --git a/README.md b/README.md index 97075e6874..4987f7d3f2 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis F | E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | | E741 | AmbiguousVariableName | ambiguous variable name '...' | | E742 | AmbiguousClassName | ambiguous class name '...' | +| E743 | AmbiguousFunctionName | ambiguous function name '...' | | E902 | IOError | No such file or directory: `...` | | F401 | UnusedImport | `...` imported but unused | | F403 | ImportStarUsage | Unable to detect undefined names | diff --git a/examples/generate_rules_table.rs b/examples/generate_rules_table.rs index 21491c6c4c..410b2ab027 100644 --- a/examples/generate_rules_table.rs +++ b/examples/generate_rules_table.rs @@ -5,6 +5,7 @@ fn main() { let mut check_kinds: Vec = vec![ CheckKind::AmbiguousVariableName("...".to_string()), CheckKind::AmbiguousClassName("...".to_string()), + CheckKind::AmbiguousFunctionName("...".to_string()), CheckKind::AssertTuple, CheckKind::DefaultExceptNotLast, CheckKind::DoNotAssignLambda, diff --git a/resources/test/fixtures/E743.py b/resources/test/fixtures/E743.py new file mode 100644 index 0000000000..0339d4a010 --- /dev/null +++ b/resources/test/fixtures/E743.py @@ -0,0 +1,15 @@ +def l(): + pass + + +def I(): + pass + + +class X: + def O(self): + pass + + +def x(): + pass diff --git a/resources/test/fixtures/pyproject.toml b/resources/test/fixtures/pyproject.toml index f5f1af9de5..a1e0a23c76 100644 --- a/resources/test/fixtures/pyproject.toml +++ b/resources/test/fixtures/pyproject.toml @@ -11,6 +11,7 @@ select = [ "E731", "E741", "E742", + "E743", "E902", "F401", "F403", diff --git a/src/ast/checks.rs b/src/ast/checks.rs index 04918898ed..0f2122b741 100644 --- a/src/ast/checks.rs +++ b/src/ast/checks.rs @@ -121,6 +121,18 @@ pub fn check_ambiguous_class_name(name: &str, location: Location) -> Option Option { + if is_ambiguous_name(name) { + Some(Check::new( + CheckKind::AmbiguousFunctionName(name.to_string()), + location, + )) + } else { + None + } +} + /// Check UselessObjectInheritance compliance. pub fn check_useless_object_inheritance( stmt: &Stmt, diff --git a/src/check_ast.rs b/src/check_ast.rs index c929b5c9ff..fb1763df81 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -208,6 +208,12 @@ where args, .. } => { + if self.settings.select.contains(&CheckCode::E743) { + if let Some(check) = checks::check_ambiguous_function_name(name, stmt.location) + { + self.checks.push(check); + } + } for expr in decorator_list { self.visit_expr(expr); } diff --git a/src/checks.rs b/src/checks.rs index eeb19ed027..c3973fd460 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -17,6 +17,7 @@ pub enum CheckCode { E731, E741, E742, + E743, E902, F401, F403, @@ -56,6 +57,7 @@ impl FromStr for CheckCode { "E731" => Ok(CheckCode::E731), "E741" => Ok(CheckCode::E741), "E742" => Ok(CheckCode::E742), + "E743" => Ok(CheckCode::E743), "E902" => Ok(CheckCode::E902), "F401" => Ok(CheckCode::F401), "F403" => Ok(CheckCode::F403), @@ -96,6 +98,7 @@ impl CheckCode { CheckCode::E731 => "E731", CheckCode::E741 => "E741", CheckCode::E742 => "E742", + CheckCode::E743 => "E743", CheckCode::E902 => "E902", CheckCode::F401 => "F401", CheckCode::F403 => "F403", @@ -134,6 +137,7 @@ impl CheckCode { CheckCode::E731 => &LintSource::AST, CheckCode::E741 => &LintSource::AST, CheckCode::E742 => &LintSource::AST, + CheckCode::E743 => &LintSource::AST, CheckCode::E902 => &LintSource::FileSystem, CheckCode::F401 => &LintSource::AST, CheckCode::F403 => &LintSource::AST, @@ -179,6 +183,7 @@ pub enum CheckKind { AssertTuple, AmbiguousVariableName(String), AmbiguousClassName(String), + AmbiguousFunctionName(String), DefaultExceptNotLast, DoNotAssignLambda, DuplicateArgumentName, @@ -217,6 +222,7 @@ impl CheckKind { CheckKind::AssertTuple => "AssertTuple", CheckKind::AmbiguousVariableName(_) => "AmbiguousVariableName", CheckKind::AmbiguousClassName(_) => "AmbiguousClassName", + CheckKind::AmbiguousFunctionName(_) => "AmbiguousFunctionName", CheckKind::DefaultExceptNotLast => "DefaultExceptNotLast", CheckKind::DuplicateArgumentName => "DuplicateArgumentName", CheckKind::FStringMissingPlaceholders => "FStringMissingPlaceholders", @@ -267,6 +273,7 @@ impl CheckKind { CheckKind::DoNotAssignLambda => &CheckCode::E731, CheckKind::AmbiguousVariableName(_) => &CheckCode::E741, CheckKind::AmbiguousClassName(_) => &CheckCode::E742, + CheckKind::AmbiguousFunctionName(_) => &CheckCode::E743, CheckKind::ModuleImportNotAtTopOfFile => &CheckCode::E402, CheckKind::MultiValueRepeatedKeyLiteral => &CheckCode::F601, CheckKind::MultiValueRepeatedKeyVariable(_) => &CheckCode::F602, @@ -322,6 +329,9 @@ impl CheckKind { CheckKind::AmbiguousClassName(name) => { format!("ambiguous class name '{}'", name) } + CheckKind::AmbiguousFunctionName(name) => { + format!("ambiguous function name '{}'", name) + } CheckKind::AmbiguousVariableName(name) => { format!("ambiguous variable name '{}'", name) } @@ -399,6 +409,7 @@ impl CheckKind { pub fn fixable(&self) -> bool { match self { CheckKind::AmbiguousClassName(_) => true, + CheckKind::AmbiguousFunctionName(_) => true, CheckKind::AmbiguousVariableName(_) => false, CheckKind::AssertTuple => false, CheckKind::DefaultExceptNotLast => false, diff --git a/src/linter.rs b/src/linter.rs index 91dd4d559e..91a6865b31 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -479,6 +479,44 @@ mod tests { Ok(()) } + #[test] + fn e743() -> Result<()> { + let mut actual = check_path( + Path::new("./resources/test/fixtures/E743.py"), + &settings::Settings { + line_length: 88, + exclude: vec![], + select: BTreeSet::from([CheckCode::E743]), + }, + &fixer::Mode::Generate, + )?; + actual.sort_by_key(|check| check.location); + let expected = vec![ + Check { + kind: CheckKind::AmbiguousFunctionName("l".to_string()), + location: Location::new(1, 1), + fix: None, + }, + Check { + kind: CheckKind::AmbiguousFunctionName("I".to_string()), + location: Location::new(5, 1), + fix: None, + }, + Check { + kind: CheckKind::AmbiguousFunctionName("O".to_string()), + location: Location::new(10, 5), + fix: None, + }, + ]; + + assert_eq!(actual.len(), expected.len()); + for i in 0..actual.len() { + assert_eq!(actual[i], expected[i]); + } + + Ok(()) + } + #[test] fn f401() -> Result<()> { let mut actual = check_path( diff --git a/src/pyproject.rs b/src/pyproject.rs index ddb63f8820..57bed20e0f 100644 --- a/src/pyproject.rs +++ b/src/pyproject.rs @@ -268,6 +268,7 @@ other-attribute = 1 CheckCode::E731, CheckCode::E741, CheckCode::E742, + CheckCode::E743, CheckCode::E902, CheckCode::F401, CheckCode::F403, diff --git a/src/settings.rs b/src/settings.rs index 691d27ff4b..d779618572 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -53,6 +53,7 @@ impl Settings { CheckCode::E731, CheckCode::E741, CheckCode::E742, + CheckCode::E743, CheckCode::E902, CheckCode::F401, CheckCode::F403,