diff --git a/src/ast/helpers.rs b/src/ast/helpers.rs index f91ffbe1f6..d1364b463d 100644 --- a/src/ast/helpers.rs +++ b/src/ast/helpers.rs @@ -61,15 +61,6 @@ pub fn dealias_call_path<'a>( } } -/// Return `true` if the `Expr` is a name or attribute reference to `${target}`. -pub fn match_name_or_attr(expr: &Expr, target: &str) -> bool { - match &expr.node { - ExprKind::Attribute { attr, .. } => target == attr, - ExprKind::Name { id, .. } => target == id, - _ => false, - } -} - /// Return `true` if the `Expr` is a reference to `${module}.${target}`. /// /// Useful for, e.g., ensuring that a `Union` reference represents diff --git a/src/flake8_annotations/plugins.rs b/src/flake8_annotations/plugins.rs index ea627d5073..afd05d4cbe 100644 --- a/src/flake8_annotations/plugins.rs +++ b/src/flake8_annotations/plugins.rs @@ -211,7 +211,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V .chain(args.kwonlyargs.iter()) .skip( // If this is a non-static method, skip `cls` or `self`. - usize::from(!visibility::is_staticmethod(stmt)), + usize::from(!visibility::is_staticmethod(checker, stmt)), ) { // ANN401 for dynamically typed arguments @@ -283,10 +283,10 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V } // ANN101, ANN102 - if !visibility::is_staticmethod(stmt) { + if !visibility::is_staticmethod(checker, stmt) { if let Some(arg) = args.args.first() { if arg.node.annotation.is_none() { - if visibility::is_classmethod(stmt) { + if visibility::is_classmethod(checker, stmt) { if checker.settings.enabled.contains(&CheckCode::ANN102) { checker.add_check(Check::new( CheckKind::MissingTypeCls(arg.node.arg.to_string()), @@ -319,14 +319,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V return; } - if visibility::is_classmethod(stmt) { + if visibility::is_classmethod(checker, stmt) { if checker.settings.enabled.contains(&CheckCode::ANN206) { checker.add_check(Check::new( CheckKind::MissingReturnTypeClassMethod(name.to_string()), Range::from_located(stmt), )); } - } else if visibility::is_staticmethod(stmt) { + } else if visibility::is_staticmethod(checker, stmt) { if checker.settings.enabled.contains(&CheckCode::ANN205) { checker.add_check(Check::new( CheckKind::MissingReturnTypeStaticMethod(name.to_string()), diff --git a/src/flake8_bugbear/plugins/assert_raises_exception.rs b/src/flake8_bugbear/plugins/assert_raises_exception.rs index 7fd17d8274..c63f7c479d 100644 --- a/src/flake8_bugbear/plugins/assert_raises_exception.rs +++ b/src/flake8_bugbear/plugins/assert_raises_exception.rs @@ -1,6 +1,6 @@ use rustpython_ast::{ExprKind, Stmt, Withitem}; -use crate::ast::helpers::match_name_or_attr; +use crate::ast::helpers::match_module_member; use crate::ast::types::Range; use crate::check_ast::Checker; use crate::checks::{Check, CheckKind}; @@ -12,8 +12,14 @@ pub fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: &[With if let ExprKind::Call { func, args, .. } = &item_context.node { if args.len() == 1 && item.optional_vars.is_none() - && match_name_or_attr(func, "assertRaises") - && match_name_or_attr(args.first().unwrap(), "Exception") + && matches!(&func.node, ExprKind::Attribute { attr, .. } if attr == "assertRaises") + && match_module_member( + args.first().unwrap(), + "", + "Exception", + &checker.from_imports, + &checker.import_aliases, + ) { checker.add_check(Check::new( CheckKind::NoAssertRaisesException, diff --git a/src/pydocstyle/plugins.rs b/src/pydocstyle/plugins.rs index 9aeca34be7..30de1e976d 100644 --- a/src/pydocstyle/plugins.rs +++ b/src/pydocstyle/plugins.rs @@ -76,7 +76,7 @@ pub fn not_missing( false } DefinitionKind::Function(stmt) | DefinitionKind::NestedFunction(stmt) => { - if is_overload(stmt) { + if is_overload(checker, stmt) { true } else { if checker.settings.enabled.contains(&CheckCode::D103) { @@ -89,7 +89,7 @@ pub fn not_missing( } } DefinitionKind::Method(stmt) => { - if is_overload(stmt) || is_override(stmt) { + if is_overload(checker, stmt) || is_override(checker, stmt) { true } else if is_magic(stmt) { if checker.settings.enabled.contains(&CheckCode::D105) { @@ -835,7 +835,7 @@ pub fn if_needed(checker: &mut Checker, definition: &Definition) { | DefinitionKind::NestedFunction(stmt) | DefinitionKind::Method(stmt) = definition.kind { - if is_overload(stmt) { + if is_overload(checker, stmt) { checker.add_check(Check::new( CheckKind::SkipDocstring, Range::from_located(stmt), @@ -1319,7 +1319,7 @@ fn missing_args(checker: &mut Checker, definition: &Definition, docstrings_args: // If this is a non-static method, skip `cls` or `self`. usize::from( matches!(definition.kind, DefinitionKind::Method(_)) - && !is_staticmethod(parent), + && !is_staticmethod(checker, parent), ), ) { diff --git a/src/python/typing.rs b/src/python/typing.rs index 36c9df3c88..061e0bd71f 100644 --- a/src/python/typing.rs +++ b/src/python/typing.rs @@ -55,6 +55,7 @@ static TYPING_EXTENSIONS: Lazy> = Lazy::new(|| { "get_overloads", "is_typeddict", "overload", + "override", "reveal_type", "runtime_checkable", ]) diff --git a/src/pyupgrade/plugins/redundant_open_modes.rs b/src/pyupgrade/plugins/redundant_open_modes.rs index 3f5ed1cf13..1644a75dcd 100644 --- a/src/pyupgrade/plugins/redundant_open_modes.rs +++ b/src/pyupgrade/plugins/redundant_open_modes.rs @@ -6,7 +6,7 @@ use rustpython_ast::{Constant, Expr, ExprKind, Keyword, KeywordData, Location}; use rustpython_parser::lexer; use rustpython_parser::token::Tok; -use crate::ast::helpers::{self, match_name_or_attr}; +use crate::ast::helpers; use crate::ast::types::Range; use crate::autofix::Fix; use crate::check_ast::Checker; @@ -64,7 +64,7 @@ fn match_open(expr: &Expr) -> (Option<&Expr>, Vec) { keywords, } = &expr.node { - if match_name_or_attr(func, OPEN_FUNC_NAME) { + if matches!(&func.node, ExprKind::Name {id, ..} if id == OPEN_FUNC_NAME) { // Return the "open mode" parameter and keywords. return (args.get(1), keywords.clone()); } diff --git a/src/visibility.rs b/src/visibility.rs index 9c9f8e3634..7006a9cb42 100644 --- a/src/visibility.rs +++ b/src/visibility.rs @@ -5,7 +5,8 @@ use std::path::Path; use rustpython_ast::{Stmt, StmtKind}; -use crate::ast::helpers::match_name_or_attr; +use crate::ast::helpers::match_module_member; +use crate::check_ast::Checker; use crate::docstrings::definition::Documentable; #[derive(Debug, Clone)] @@ -28,45 +29,57 @@ pub struct VisibleScope { } /// Returns `true` if a function is a "static method". -pub fn is_staticmethod(stmt: &Stmt) -> bool { +pub fn is_staticmethod(checker: &Checker, stmt: &Stmt) -> bool { match &stmt.node { StmtKind::FunctionDef { decorator_list, .. } - | StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list - .iter() - .any(|expr| match_name_or_attr(expr, "staticmethod")), + | StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list.iter().any(|expr| { + match_module_member( + expr, + "", + "staticmethod", + &checker.from_imports, + &checker.import_aliases, + ) + }), _ => panic!("Found non-FunctionDef in is_staticmethod"), } } /// Returns `true` if a function is a "class method". -pub fn is_classmethod(stmt: &Stmt) -> bool { +pub fn is_classmethod(checker: &Checker, stmt: &Stmt) -> bool { match &stmt.node { StmtKind::FunctionDef { decorator_list, .. } - | StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list - .iter() - .any(|expr| match_name_or_attr(expr, "classmethod")), + | StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list.iter().any(|expr| { + match_module_member( + expr, + "", + "classmethod", + &checker.from_imports, + &checker.import_aliases, + ) + }), _ => panic!("Found non-FunctionDef in is_classmethod"), } } /// Returns `true` if a function definition is an `@overload`. -pub fn is_overload(stmt: &Stmt) -> bool { +pub fn is_overload(checker: &Checker, stmt: &Stmt) -> bool { match &stmt.node { StmtKind::FunctionDef { decorator_list, .. } | StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list .iter() - .any(|expr| match_name_or_attr(expr, "overload")), + .any(|expr| checker.match_typing_expr(expr, "overload")), _ => panic!("Found non-FunctionDef in is_overload"), } } /// Returns `true` if a function definition is an `@override` (PEP 698). -pub fn is_override(stmt: &Stmt) -> bool { +pub fn is_override(checker: &Checker, stmt: &Stmt) -> bool { match &stmt.node { StmtKind::FunctionDef { decorator_list, .. } | StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list .iter() - .any(|expr| match_name_or_attr(expr, "override")), + .any(|expr| checker.match_typing_expr(expr, "override")), _ => panic!("Found non-FunctionDef in is_override"), } }