diff --git a/src/rules/pyupgrade/rules/mod.rs b/src/rules/pyupgrade/rules/mod.rs index 89117f6d08..a49cd9c975 100644 --- a/src/rules/pyupgrade/rules/mod.rs +++ b/src/rules/pyupgrade/rules/mod.rs @@ -9,24 +9,22 @@ pub(crate) use functools_cache::functools_cache; pub(crate) use import_replacements::{import_replacements, ImportReplacements}; pub(crate) use lru_cache_without_parameters::lru_cache_without_parameters; pub(crate) use native_literals::native_literals; -use once_cell::sync::Lazy; pub(crate) use open_alias::open_alias; pub(crate) use os_error_alias::os_error_alias; pub(crate) use printf_string_formatting::printf_string_formatting; pub(crate) use redundant_open_modes::redundant_open_modes; -use regex::Regex; pub(crate) use replace_stdout_stderr::replace_stdout_stderr; pub(crate) use replace_universal_newlines::replace_universal_newlines; pub(crate) use rewrite_c_element_tree::replace_c_element_tree; pub(crate) use rewrite_mock_import::{rewrite_mock_attribute, rewrite_mock_import}; pub(crate) use rewrite_unicode_literal::rewrite_unicode_literal; pub(crate) use rewrite_yield_from::rewrite_yield_from; -use rustpython_ast::Location; -use rustpython_parser::ast::{ArgData, Expr, ExprKind, Stmt, StmtKind}; +pub(crate) use super_args::super_args; pub(crate) use super_call_with_parameters::super_call_with_parameters; pub(crate) use type_of_primitive::type_of_primitive; pub(crate) use typing_text_str_alias::typing_text_str_alias; pub(crate) use unnecessary_builtin_import::unnecessary_builtin_import; +pub(crate) use unnecessary_coding_comment::unnecessary_coding_comment; pub(crate) use unnecessary_encode_utf8::unnecessary_encode_utf8; pub(crate) use unnecessary_future_import::unnecessary_future_import; pub(crate) use unpack_list_comprehension::unpack_list_comprehension; @@ -35,12 +33,6 @@ pub(crate) use use_pep604_annotation::use_pep604_annotation; pub(crate) use useless_metaclass_type::useless_metaclass_type; pub(crate) use useless_object_inheritance::useless_object_inheritance; -use crate::ast::helpers; -use crate::ast::types::{Range, Scope, ScopeKind}; -use crate::fix::Fix; -use crate::registry::Diagnostic; -use crate::violations; - mod convert_named_tuple_functional_to_class; mod convert_typed_dict_functional_to_class; mod datetime_utc_alias; @@ -62,10 +54,12 @@ mod rewrite_c_element_tree; mod rewrite_mock_import; mod rewrite_unicode_literal; mod rewrite_yield_from; +mod super_args; mod super_call_with_parameters; mod type_of_primitive; mod typing_text_str_alias; mod unnecessary_builtin_import; +mod unnecessary_coding_comment; mod unnecessary_encode_utf8; mod unnecessary_future_import; mod unpack_list_comprehension; @@ -73,99 +67,3 @@ mod use_pep585_annotation; mod use_pep604_annotation; mod useless_metaclass_type; mod useless_object_inheritance; - -/// UP008 -pub fn super_args( - scope: &Scope, - parents: &[&Stmt], - expr: &Expr, - func: &Expr, - args: &[Expr], -) -> Option { - if !helpers::is_super_call_with_arguments(func, args) { - return None; - } - - // Check: are we in a Function scope? - if !matches!(scope.kind, ScopeKind::Function { .. }) { - return None; - } - - let mut parents = parents.iter().rev(); - - // For a `super` invocation to be unnecessary, the first argument needs to match - // the enclosing class, and the second argument needs to match the first - // argument to the enclosing function. - let [first_arg, second_arg] = args else { - return None; - }; - - // Find the enclosing function definition (if any). - let Some(StmtKind::FunctionDef { - args: parent_args, .. - }) = parents - .find(|stmt| matches!(stmt.node, StmtKind::FunctionDef { .. })) - .map(|stmt| &stmt.node) else { - return None; - }; - - // Extract the name of the first argument to the enclosing function. - let Some(ArgData { - arg: parent_arg, .. - }) = parent_args.args.first().map(|expr| &expr.node) else { - return None; - }; - - // Find the enclosing class definition (if any). - let Some(StmtKind::ClassDef { - name: parent_name, .. - }) = parents - .find(|stmt| matches!(stmt.node, StmtKind::ClassDef { .. })) - .map(|stmt| &stmt.node) else { - return None; - }; - - let ( - ExprKind::Name { - id: first_arg_id, .. - }, - ExprKind::Name { - id: second_arg_id, .. - }, - ) = (&first_arg.node, &second_arg.node) else { - return None; - }; - - if first_arg_id == parent_name && second_arg_id == parent_arg { - return Some(Diagnostic::new( - violations::SuperCallWithParameters, - Range::from_located(expr), - )); - } - - None -} - -// Regex from PEP263. -static CODING_COMMENT_REGEX: Lazy = - Lazy::new(|| Regex::new(r"^[ \t\f]*#.*?coding[:=][ \t]*utf-?8").unwrap()); - -/// UP009 -pub fn unnecessary_coding_comment(lineno: usize, line: &str, autofix: bool) -> Option { - // PEP3120 makes utf-8 the default encoding. - if CODING_COMMENT_REGEX.is_match(line) { - let mut diagnostic = Diagnostic::new( - violations::PEP3120UnnecessaryCodingComment, - Range::new(Location::new(lineno + 1, 0), Location::new(lineno + 2, 0)), - ); - if autofix { - diagnostic.amend(Fix::deletion( - Location::new(lineno + 1, 0), - Location::new(lineno + 2, 0), - )); - } - Some(diagnostic) - } else { - None - } -} diff --git a/src/rules/pyupgrade/rules/super_args.rs b/src/rules/pyupgrade/rules/super_args.rs new file mode 100644 index 0000000000..850a326d48 --- /dev/null +++ b/src/rules/pyupgrade/rules/super_args.rs @@ -0,0 +1,77 @@ +use crate::ast::helpers; +use crate::ast::types::{Range, Scope, ScopeKind}; +use crate::registry::Diagnostic; +use crate::violations; +use rustpython_ast::{ArgData, Expr, ExprKind, Stmt, StmtKind}; + +/// UP008 +pub fn super_args( + scope: &Scope, + parents: &[&Stmt], + expr: &Expr, + func: &Expr, + args: &[Expr], +) -> Option { + if !helpers::is_super_call_with_arguments(func, args) { + return None; + } + + // Check: are we in a Function scope? + if !matches!(scope.kind, ScopeKind::Function { .. }) { + return None; + } + + let mut parents = parents.iter().rev(); + + // For a `super` invocation to be unnecessary, the first argument needs to match + // the enclosing class, and the second argument needs to match the first + // argument to the enclosing function. + let [first_arg, second_arg] = args else { + return None; + }; + + // Find the enclosing function definition (if any). + let Some(StmtKind::FunctionDef { + args: parent_args, .. + }) = parents + .find(|stmt| matches!(stmt.node, StmtKind::FunctionDef { .. })) + .map(|stmt| &stmt.node) else { + return None; + }; + + // Extract the name of the first argument to the enclosing function. + let Some(ArgData { + arg: parent_arg, .. + }) = parent_args.args.first().map(|expr| &expr.node) else { + return None; + }; + + // Find the enclosing class definition (if any). + let Some(StmtKind::ClassDef { + name: parent_name, .. + }) = parents + .find(|stmt| matches!(stmt.node, StmtKind::ClassDef { .. })) + .map(|stmt| &stmt.node) else { + return None; + }; + + let ( + ExprKind::Name { + id: first_arg_id, .. + }, + ExprKind::Name { + id: second_arg_id, .. + }, + ) = (&first_arg.node, &second_arg.node) else { + return None; + }; + + if first_arg_id == parent_name && second_arg_id == parent_arg { + return Some(Diagnostic::new( + violations::SuperCallWithParameters, + Range::from_located(expr), + )); + } + + None +} diff --git a/src/rules/pyupgrade/rules/unnecessary_coding_comment.rs b/src/rules/pyupgrade/rules/unnecessary_coding_comment.rs new file mode 100644 index 0000000000..bf2fd122fb --- /dev/null +++ b/src/rules/pyupgrade/rules/unnecessary_coding_comment.rs @@ -0,0 +1,31 @@ +use crate::ast::types::Range; +use crate::fix::Fix; +use crate::registry::Diagnostic; +use crate::violations; +use once_cell::sync::Lazy; +use regex::Regex; +use rustpython_ast::Location; + +// Regex from PEP263. +static CODING_COMMENT_REGEX: Lazy = + Lazy::new(|| Regex::new(r"^[ \t\f]*#.*?coding[:=][ \t]*utf-?8").unwrap()); + +/// UP009 +pub fn unnecessary_coding_comment(lineno: usize, line: &str, autofix: bool) -> Option { + // PEP3120 makes utf-8 the default encoding. + if CODING_COMMENT_REGEX.is_match(line) { + let mut diagnostic = Diagnostic::new( + violations::PEP3120UnnecessaryCodingComment, + Range::new(Location::new(lineno + 1, 0), Location::new(lineno + 2, 0)), + ); + if autofix { + diagnostic.amend(Fix::deletion( + Location::new(lineno + 1, 0), + Location::new(lineno + 2, 0), + )); + } + Some(diagnostic) + } else { + None + } +}