From 515d0554477fd332fc8ee38c478add4c43b34df1 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 2 Jan 2024 14:44:47 -0500 Subject: [PATCH] Tweak example --- .../fixtures/pylint/super_without_brackets.py | 34 +++---- .../pylint/rules/super_without_brackets.rs | 91 +++++++++---------- ...ts__PLW0245_super_without_brackets.py.snap | 22 ++--- 3 files changed, 74 insertions(+), 73 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/super_without_brackets.py b/crates/ruff_linter/resources/test/fixtures/pylint/super_without_brackets.py index eb3bbe8922c906..7f190e1dbe436a 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/super_without_brackets.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/super_without_brackets.py @@ -1,31 +1,33 @@ -class Soup: +class Animal: @staticmethod - def temp() -> None: - print("Soup is hot!") + def speak(): + return f"This animal says something." -class TomatoSoup(Soup): +class BadDog(Animal): @staticmethod - def temp() -> None: - super.temp() # PLW0245 - print("But tomato soup is even hotter!") + def speak(): + original_speak = super.speak() # PLW0245 + return f"{original_speak} But as a dog, it barks!" -class ProperTomatoSoup(Soup): + +class GoodDog(Animal): @staticmethod - def temp() -> None: - super().temp() # OK - print("But tomato soup is even hotter!") + def speak(): + original_speak = super().speak() # OK + return f"{original_speak} But as a dog, it barks!" -class SuperSoup(Soup): +class FineDog(Animal): @staticmethod - def temp() -> None: - # override the super builtin + def speak(): super = "super" - super.temp() # OK (according to this rule, at least) - print(f"But super soup is {super}!") + original_speak = super.speak() # OK + return f"{original_speak} But as a dog, it barks!" + def super_without_class() -> None: super.blah() # OK + super.blah() # OK diff --git a/crates/ruff_linter/src/rules/pylint/rules/super_without_brackets.rs b/crates/ruff_linter/src/rules/pylint/rules/super_without_brackets.rs index 3270cb0b75eddb..34f12f294503a4 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/super_without_brackets.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/super_without_brackets.rs @@ -11,36 +11,35 @@ use crate::checkers::ast::Checker; /// Checks for `super` calls without parentheses. /// /// ## Why is this bad? -/// When `super` is used without parentheses, it is not an actual call. +/// When `super` is used without parentheses, it is not an actual call, and +/// thus has no effect. /// /// ## Example /// ```python -/// class Soup: +/// class Animal: /// @staticmethod -/// def temp(): -/// print("Soup is hot!") +/// def speak(): +/// return "This animal says something." /// -/// -/// class TomatoSoup(Soup): +/// class Dog(Animal): /// @staticmethod -/// def temp(): -/// super.temp() # [super-without-brackets] -/// print("But tomato soup is even hotter!") +/// def speak(): +/// original_speak = super.speak() +/// return f"{original_speak} But as a dog, it barks!" /// ``` /// /// Use instead: /// ```python -/// class Soup: +/// class Animal: /// @staticmethod -/// def temp(): -/// print("Soup is hot!") -/// +/// def speak(): +/// return "This animal says something." /// -/// class TomatoSoup(Soup): +/// class Dog(Animal): /// @staticmethod -/// def temp(): -/// super().temp() -/// print("But tomato soup is even hotter!") +/// def speak(): +/// original_speak = super().speak() +/// return f"{original_speak} But as a dog, it barks!" /// ``` #[violation] pub struct SuperWithoutBrackets; @@ -48,7 +47,7 @@ pub struct SuperWithoutBrackets; impl AlwaysFixableViolation for SuperWithoutBrackets { #[derive_message_formats] fn message(&self) -> String { - format!("`super` call without parentheses") + format!("`super` call is missing parentheses") } fn fix_title(&self) -> String { @@ -58,49 +57,49 @@ impl AlwaysFixableViolation for SuperWithoutBrackets { /// PLW0245 pub(crate) fn super_without_brackets(checker: &mut Checker, func: &Expr) { - let ScopeKind::Function(ast::StmtFunctionDef { - name, - decorator_list, - .. - }) = checker.semantic().current_scope().kind - else { + // The call must be to `super` (without parentheses). + let Expr::Attribute(ast::ExprAttribute { value, .. }) = func else { return; }; - let Some(parent) = &checker - .semantic() - .first_non_type_parent_scope(checker.semantic().current_scope()) - else { + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { return; }; - match function_type::classify( - name, - decorator_list, - parent, - checker.semantic(), - &checker.settings.pep8_naming.classmethod_decorators, - &checker.settings.pep8_naming.staticmethod_decorators, - ) { - function_type::FunctionType::Method { .. } - | function_type::FunctionType::ClassMethod { .. } - | function_type::FunctionType::StaticMethod { .. } => {} - function_type::FunctionType::Function { .. } => return, + if id.as_str() != "super" { + return; } - let Expr::Attribute(ast::ExprAttribute { value, .. }) = func else { + if !checker.semantic().is_builtin(id.as_str()) { return; - }; + } - let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { + let scope = checker.semantic().current_scope(); + + // The current scope _must_ be a function. + let ScopeKind::Function(function_def) = scope.kind else { return; }; - if id.as_str() != "super" { + let Some(parent) = &checker.semantic().first_non_type_parent_scope(scope) else { return; - } + }; - if !checker.semantic().is_builtin(id.as_str()) { + // The function must be a method, class method, or static method. + let classification = function_type::classify( + &function_def.name, + &function_def.decorator_list, + parent, + checker.semantic(), + &checker.settings.pep8_naming.classmethod_decorators, + &checker.settings.pep8_naming.staticmethod_decorators, + ); + if !matches!( + classification, + function_type::FunctionType::Method { .. } + | function_type::FunctionType::ClassMethod { .. } + | function_type::FunctionType::StaticMethod { .. } + ) { return; } diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0245_super_without_brackets.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0245_super_without_brackets.py.snap index c4ca34b49e552e..d2abe86131b9de 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0245_super_without_brackets.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0245_super_without_brackets.py.snap @@ -1,24 +1,24 @@ --- source: crates/ruff_linter/src/rules/pylint/mod.rs --- -super_without_brackets.py:10:9: PLW0245 [*] `super` call without parentheses +super_without_brackets.py:10:26: PLW0245 [*] `super` call is missing parentheses | 8 | @staticmethod - 9 | def temp() -> None: -10 | super.temp() # PLW0245 - | ^^^^^ PLW0245 -11 | print("But tomato soup is even hotter!") + 9 | def speak(): +10 | original_speak = super.speak() # PLW0245 + | ^^^^^ PLW0245 +11 | return f"{original_speak} But as a dog, it barks!" | = help: Add parentheses to `super` call ℹ Safe fix -7 7 | class TomatoSoup(Soup): +7 7 | class BadDog(Animal): 8 8 | @staticmethod -9 9 | def temp() -> None: -10 |- super.temp() # PLW0245 - 10 |+ super().temp() # PLW0245 -11 11 | print("But tomato soup is even hotter!") +9 9 | def speak(): +10 |- original_speak = super.speak() # PLW0245 + 10 |+ original_speak = super().speak() # PLW0245 +11 11 | return f"{original_speak} But as a dog, it barks!" 12 12 | -13 13 | class ProperTomatoSoup(Soup): +13 13 |