diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/N802.py b/crates/ruff/resources/test/fixtures/pep8_naming/N802.py index 73fee4e20707f..ea7f97948854d 100644 --- a/crates/ruff/resources/test/fixtures/pep8_naming/N802.py +++ b/crates/ruff/resources/test/fixtures/pep8_naming/N802.py @@ -39,3 +39,11 @@ def tearDown(self): def testTest(self): assert True + + +from typing import override + + +@override +def BAD_FUNC(): + pass diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index ff33cbbbb434e..e6815c8974e4f 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -344,6 +344,7 @@ where |expr| self.ctx.resolve_call_path(expr), )); } + if self.settings.rules.enabled(Rule::AmbiguousFunctionName) { if let Some(diagnostic) = pycodestyle::rules::ambiguous_function_name(name, || { @@ -358,7 +359,9 @@ where if let Some(diagnostic) = pep8_naming::rules::invalid_function_name( stmt, name, + decorator_list, &self.settings.pep8_naming.ignore_names, + &self.ctx, self.locator, ) { self.diagnostics.push(diagnostic); diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs index 92921f3f96700..f6bb4e48fc046 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs @@ -1,9 +1,11 @@ -use rustpython_parser::ast::Stmt; +use rustpython_parser::ast::{Expr, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::identifier_range; use ruff_python_ast::source_code::Locator; +use ruff_python_semantic::analyze::visibility; +use ruff_python_semantic::context::Context; /// ## What it does /// Checks for functions names that do not follow the `snake_case` naming @@ -47,21 +49,33 @@ impl Violation for InvalidFunctionName { /// N802 pub fn invalid_function_name( - func_def: &Stmt, + stmt: &Stmt, name: &str, + decorator_list: &[Expr], ignore_names: &[String], + ctx: &Context, locator: &Locator, ) -> Option { + // Ignore any explicitly-ignored function names. if ignore_names.iter().any(|ignore_name| ignore_name == name) { return None; } - if name.to_lowercase() != name { - return Some(Diagnostic::new( - InvalidFunctionName { - name: name.to_string(), - }, - identifier_range(func_def, locator), - )); + + // Ignore any function names that are already lowercase. + if name.to_lowercase() == name { + return None; + } + + // Ignore any functions that are explicitly `@override`. These are defined elsewhere, + // so if they're first-party, we'll flag them at the definition site. + if visibility::is_override(ctx, decorator_list) { + return None; } - None + + Some(Diagnostic::new( + InvalidFunctionName { + name: name.to_string(), + }, + identifier_range(stmt, locator), + )) }