diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a89a836b7d..a72d7f2031 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -156,10 +156,13 @@ At a high level, the steps involved in adding a new lint rule are as follows: (e.g., `pub(crate) fn assert_false`) based on whatever inputs are required for the rule (e.g., an `ast::StmtAssert` node). -1. Define the logic for triggering the violation in `crates/ruff/src/checkers/ast/mod.rs` (for - AST-based checks), `crates/ruff/src/checkers/tokens.rs` (for token-based checks), - `crates/ruff/src/checkers/lines.rs` (for text-based checks), or - `crates/ruff/src/checkers/filesystem.rs` (for filesystem-based checks). +1. Define the logic for invoking the diagnostic in `crates/ruff/src/checkers/ast/analyze` (for + AST-based rules), `crates/ruff/src/checkers/tokens.rs` (for token-based rules), + `crates/ruff/src/checkers/physical_lines.rs` (for text-based rules), + `crates/ruff/src/checkers/filesystem.rs` (for filesystem-based rules), etc. For AST-based rules, + you'll likely want to modify `analyze/statement.rs` (if your rule is based on analyzing + statements, like imports) or `analyze/expression.rs` (if your rule is based on analyzing + expressions, like function calls). 1. Map the violation struct to a rule code in `crates/ruff/src/codes.rs` (e.g., `B011`). diff --git a/crates/ruff/src/checkers/ast/analyze/argument.rs b/crates/ruff/src/checkers/ast/analyze/argument.rs new file mode 100644 index 0000000000..8e37e62e8c --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/argument.rs @@ -0,0 +1,27 @@ +use rustpython_parser::ast::{Arg, Ranged}; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::{flake8_builtins, pep8_naming, pycodestyle}; + +/// Run lint rules over an [`Stmt`] syntax node. +pub(crate) fn argument(arg: &Arg, checker: &mut Checker) { + if checker.enabled(Rule::AmbiguousVariableName) { + if let Some(diagnostic) = pycodestyle::rules::ambiguous_variable_name(&arg.arg, arg.range()) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::InvalidArgumentName) { + if let Some(diagnostic) = pep8_naming::rules::invalid_argument_name( + &arg.arg, + arg, + &checker.settings.pep8_naming.ignore_names, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::BuiltinArgumentShadowing) { + flake8_builtins::rules::builtin_argument_shadowing(checker, arg); + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/arguments.rs b/crates/ruff/src/checkers/ast/analyze/arguments.rs new file mode 100644 index 0000000000..87e6203a68 --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/arguments.rs @@ -0,0 +1,26 @@ +use rustpython_parser::ast::Arguments; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::{flake8_bugbear, flake8_pyi, ruff}; + +/// Run lint rules over a [`Arguments`] syntax node. +pub(crate) fn arguments(arguments: &Arguments, checker: &mut Checker) { + if checker.enabled(Rule::MutableArgumentDefault) { + flake8_bugbear::rules::mutable_argument_default(checker, arguments); + } + if checker.enabled(Rule::FunctionCallInDefaultArgument) { + flake8_bugbear::rules::function_call_in_argument_default(checker, arguments); + } + if checker.settings.rules.enabled(Rule::ImplicitOptional) { + ruff::rules::implicit_optional(checker, arguments); + } + if checker.is_stub { + if checker.enabled(Rule::TypedArgumentDefaultInStub) { + flake8_pyi::rules::typed_argument_simple_defaults(checker, arguments); + } + if checker.enabled(Rule::ArgumentDefaultInStub) { + flake8_pyi::rules::argument_simple_defaults(checker, arguments); + } + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/bindings.rs b/crates/ruff/src/checkers/ast/analyze/bindings.rs new file mode 100644 index 0000000000..0d6d096114 --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/bindings.rs @@ -0,0 +1,68 @@ +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::{flake8_import_conventions, flake8_pyi, pyflakes, pylint}; +use ruff_diagnostics::{Diagnostic, Fix}; + +/// Run lint rules over the [`Binding`]s. +pub(crate) fn bindings(checker: &mut Checker) { + if !checker.any_enabled(&[ + Rule::InvalidAllFormat, + Rule::InvalidAllObject, + Rule::UnaliasedCollectionsAbcSetImport, + Rule::UnconventionalImportAlias, + Rule::UnusedVariable, + ]) { + return; + } + + for binding in checker.semantic.bindings.iter() { + if checker.enabled(Rule::UnusedVariable) { + if binding.kind.is_bound_exception() && !binding.is_used() { + let mut diagnostic = Diagnostic::new( + pyflakes::rules::UnusedVariable { + name: binding.name(checker.locator).to_string(), + }, + binding.range, + ); + if checker.patch(Rule::UnusedVariable) { + diagnostic.try_set_fix(|| { + pyflakes::fixes::remove_exception_handler_assignment( + binding, + checker.locator, + ) + .map(Fix::automatic) + }); + } + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::InvalidAllFormat) { + if let Some(diagnostic) = pylint::rules::invalid_all_format(binding) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::InvalidAllObject) { + if let Some(diagnostic) = pylint::rules::invalid_all_object(binding) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::UnconventionalImportAlias) { + if let Some(diagnostic) = flake8_import_conventions::rules::unconventional_import_alias( + checker, + binding, + &checker.settings.flake8_import_conventions.aliases, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.is_stub { + if checker.enabled(Rule::UnaliasedCollectionsAbcSetImport) { + if let Some(diagnostic) = + flake8_pyi::rules::unaliased_collections_abc_set_import(checker, binding) + { + checker.diagnostics.push(diagnostic); + } + } + } + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/deferred_for_loops.rs b/crates/ruff/src/checkers/ast/analyze/deferred_for_loops.rs new file mode 100644 index 0000000000..e98625746b --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/deferred_for_loops.rs @@ -0,0 +1,33 @@ +use rustpython_parser::ast::{self, Stmt}; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::{flake8_bugbear, perflint}; + +/// Run lint rules over all deferred for-loops in the [`SemanticModel`]. +pub(crate) fn deferred_for_loops(checker: &mut Checker) { + while !checker.deferred.for_loops.is_empty() { + let for_loops = std::mem::take(&mut checker.deferred.for_loops); + + for snapshot in for_loops { + checker.semantic.restore(snapshot); + + if let Stmt::For(ast::StmtFor { + target, iter, body, .. + }) + | Stmt::AsyncFor(ast::StmtAsyncFor { + target, iter, body, .. + }) = &checker.semantic.stmt() + { + if checker.enabled(Rule::UnusedLoopControlVariable) { + flake8_bugbear::rules::unused_loop_control_variable(checker, target, body); + } + if checker.enabled(Rule::IncorrectDictIterator) { + perflint::rules::incorrect_dict_iterator(checker, target, iter); + } + } else { + unreachable!("Expected Expr::For | Expr::AsyncFor"); + } + } + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs b/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs new file mode 100644 index 0000000000..1d0f2a5ba0 --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs @@ -0,0 +1,287 @@ +use ruff_diagnostics::Diagnostic; +use ruff_python_ast::cast; +use ruff_python_semantic::analyze::{branch_detection, visibility}; +use ruff_python_semantic::{Binding, BindingKind, ScopeKind}; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::{flake8_type_checking, flake8_unused_arguments, pyflakes, pylint}; + +/// Run lint rules over all deferred scopes in the [`SemanticModel`]. +pub(crate) fn deferred_scopes(checker: &mut Checker) { + if !checker.any_enabled(&[ + Rule::GlobalVariableNotAssigned, + Rule::ImportShadowedByLoopVar, + Rule::RedefinedWhileUnused, + Rule::RuntimeImportInTypeCheckingBlock, + Rule::TypingOnlyFirstPartyImport, + Rule::TypingOnlyStandardLibraryImport, + Rule::TypingOnlyThirdPartyImport, + Rule::UndefinedLocal, + Rule::UnusedAnnotation, + Rule::UnusedClassMethodArgument, + Rule::UnusedFunctionArgument, + Rule::UnusedImport, + Rule::UnusedLambdaArgument, + Rule::UnusedMethodArgument, + Rule::UnusedStaticMethodArgument, + Rule::UnusedVariable, + ]) { + return; + } + + // Identify any valid runtime imports. If a module is imported at runtime, and + // used at runtime, then by default, we avoid flagging any other + // imports from that model as typing-only. + let enforce_typing_imports = !checker.is_stub + && checker.any_enabled(&[ + Rule::RuntimeImportInTypeCheckingBlock, + Rule::TypingOnlyFirstPartyImport, + Rule::TypingOnlyStandardLibraryImport, + Rule::TypingOnlyThirdPartyImport, + ]); + let runtime_imports: Vec> = if enforce_typing_imports { + checker + .semantic + .scopes + .iter() + .map(|scope| { + scope + .binding_ids() + .map(|binding_id| checker.semantic.binding(binding_id)) + .filter(|binding| { + flake8_type_checking::helpers::is_valid_runtime_import( + binding, + &checker.semantic, + ) + }) + .collect() + }) + .collect::>() + } else { + vec![] + }; + + let mut diagnostics: Vec = vec![]; + for scope_id in checker.deferred.scopes.iter().rev().copied() { + let scope = &checker.semantic.scopes[scope_id]; + + if checker.enabled(Rule::UndefinedLocal) { + pyflakes::rules::undefined_local(checker, scope_id, scope, &mut diagnostics); + } + + if checker.enabled(Rule::GlobalVariableNotAssigned) { + for (name, binding_id) in scope.bindings() { + let binding = checker.semantic.binding(binding_id); + if binding.kind.is_global() { + diagnostics.push(Diagnostic::new( + pylint::rules::GlobalVariableNotAssigned { + name: (*name).to_string(), + }, + binding.range, + )); + } + } + } + + if checker.enabled(Rule::ImportShadowedByLoopVar) { + for (name, binding_id) in scope.bindings() { + for shadow in checker.semantic.shadowed_bindings(scope_id, binding_id) { + // If the shadowing binding isn't a loop variable, abort. + let binding = &checker.semantic.bindings[shadow.binding_id()]; + if !binding.kind.is_loop_var() { + continue; + } + + // If the shadowed binding isn't an import, abort. + let shadowed = &checker.semantic.bindings[shadow.shadowed_id()]; + if !matches!( + shadowed.kind, + BindingKind::Import(..) + | BindingKind::FromImport(..) + | BindingKind::SubmoduleImport(..) + | BindingKind::FutureImport + ) { + continue; + } + + // If the bindings are in different forks, abort. + if shadowed.source.map_or(true, |left| { + binding.source.map_or(true, |right| { + branch_detection::different_forks(left, right, &checker.semantic.stmts) + }) + }) { + continue; + } + + #[allow(deprecated)] + let line = checker.locator.compute_line_index(shadowed.range.start()); + + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::ImportShadowedByLoopVar { + name: name.to_string(), + line, + }, + binding.range, + )); + } + } + } + + if checker.enabled(Rule::RedefinedWhileUnused) { + for (name, binding_id) in scope.bindings() { + for shadow in checker.semantic.shadowed_bindings(scope_id, binding_id) { + // If the shadowing binding is a loop variable, abort, to avoid overlap + // with F402. + let binding = &checker.semantic.bindings[shadow.binding_id()]; + if binding.kind.is_loop_var() { + continue; + } + + // If the shadowed binding is used, abort. + let shadowed = &checker.semantic.bindings[shadow.shadowed_id()]; + if shadowed.is_used() { + continue; + } + + // If the shadowing binding isn't considered a "redefinition" of the + // shadowed binding, abort. + if !binding.redefines(shadowed) { + continue; + } + + if shadow.same_scope() { + // If the symbol is a dummy variable, abort, unless the shadowed + // binding is an import. + if !matches!( + shadowed.kind, + BindingKind::Import(..) + | BindingKind::FromImport(..) + | BindingKind::SubmoduleImport(..) + | BindingKind::FutureImport + ) && checker.settings.dummy_variable_rgx.is_match(name) + { + continue; + } + + // If this is an overloaded function, abort. + if shadowed.kind.is_function_definition() + && visibility::is_overload( + cast::decorator_list( + checker.semantic.stmts[shadowed.source.unwrap()], + ), + &checker.semantic, + ) + { + continue; + } + } else { + // Only enforce cross-scope shadowing for imports. + if !matches!( + shadowed.kind, + BindingKind::Import(..) + | BindingKind::FromImport(..) + | BindingKind::SubmoduleImport(..) + | BindingKind::FutureImport + ) { + continue; + } + } + + // If the bindings are in different forks, abort. + if shadowed.source.map_or(true, |left| { + binding.source.map_or(true, |right| { + branch_detection::different_forks(left, right, &checker.semantic.stmts) + }) + }) { + continue; + } + + #[allow(deprecated)] + let line = checker.locator.compute_line_index(shadowed.range.start()); + let mut diagnostic = Diagnostic::new( + pyflakes::rules::RedefinedWhileUnused { + name: (*name).to_string(), + line, + }, + binding.range, + ); + if let Some(range) = binding.parent_range(&checker.semantic) { + diagnostic.set_parent(range.start()); + } + diagnostics.push(diagnostic); + } + } + } + + if matches!( + scope.kind, + ScopeKind::Function(_) | ScopeKind::AsyncFunction(_) | ScopeKind::Lambda(_) + ) { + if checker.enabled(Rule::UnusedVariable) { + pyflakes::rules::unused_variable(checker, scope, &mut diagnostics); + } + + if checker.enabled(Rule::UnusedAnnotation) { + pyflakes::rules::unused_annotation(checker, scope, &mut diagnostics); + } + + if !checker.is_stub { + if checker.any_enabled(&[ + Rule::UnusedClassMethodArgument, + Rule::UnusedFunctionArgument, + Rule::UnusedLambdaArgument, + Rule::UnusedMethodArgument, + Rule::UnusedStaticMethodArgument, + ]) { + flake8_unused_arguments::rules::unused_arguments( + checker, + scope, + &mut diagnostics, + ); + } + } + } + + if matches!( + scope.kind, + ScopeKind::Function(_) | ScopeKind::AsyncFunction(_) | ScopeKind::Module + ) { + if enforce_typing_imports { + let runtime_imports: Vec<&Binding> = checker + .semantic + .scopes + .ancestor_ids(scope_id) + .flat_map(|scope_id| runtime_imports[scope_id.as_usize()].iter()) + .copied() + .collect(); + + if checker.enabled(Rule::RuntimeImportInTypeCheckingBlock) { + flake8_type_checking::rules::runtime_import_in_type_checking_block( + checker, + scope, + &mut diagnostics, + ); + } + + if checker.any_enabled(&[ + Rule::TypingOnlyFirstPartyImport, + Rule::TypingOnlyStandardLibraryImport, + Rule::TypingOnlyThirdPartyImport, + ]) { + flake8_type_checking::rules::typing_only_runtime_import( + checker, + scope, + &runtime_imports, + &mut diagnostics, + ); + } + } + + if checker.enabled(Rule::UnusedImport) { + pyflakes::rules::unused_import(checker, scope, &mut diagnostics); + } + } + } + checker.diagnostics.extend(diagnostics); +} diff --git a/crates/ruff/src/checkers/ast/analyze/definitions.rs b/crates/ruff/src/checkers/ast/analyze/definitions.rs new file mode 100644 index 0000000000..fe32800278 --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/definitions.rs @@ -0,0 +1,291 @@ +use ruff_python_ast::str::raw_contents_range; +use ruff_text_size::TextRange; +use rustpython_parser::ast::Ranged; + +use ruff_python_semantic::{BindingKind, ContextualizedDefinition, Export}; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::docstrings::Docstring; +use crate::fs::relativize_path; +use crate::rules::{flake8_annotations, flake8_pyi, pydocstyle}; +use crate::{docstrings, warn_user}; + +/// Run lint rules over all [`Definition`] nodes in the [`SemanticModel`]. +/// +/// This phase is expected to run after the AST has been traversed in its entirety; as such, +/// it is expected that all [`Definition`] nodes have been visited by the time, and that this +/// method will not recurse into any other nodes. +pub(crate) fn definitions(checker: &mut Checker) { + let enforce_annotations = checker.any_enabled(&[ + Rule::AnyType, + Rule::MissingReturnTypeClassMethod, + Rule::MissingReturnTypePrivateFunction, + Rule::MissingReturnTypeSpecialMethod, + Rule::MissingReturnTypeStaticMethod, + Rule::MissingReturnTypeUndocumentedPublicFunction, + Rule::MissingTypeArgs, + Rule::MissingTypeCls, + Rule::MissingTypeFunctionArgument, + Rule::MissingTypeKwargs, + Rule::MissingTypeSelf, + ]); + let enforce_stubs = checker.is_stub + && checker.any_enabled(&[Rule::DocstringInStub, Rule::IterMethodReturnIterable]); + let enforce_docstrings = checker.any_enabled(&[ + Rule::BlankLineAfterLastSection, + Rule::BlankLineAfterSummary, + Rule::BlankLineBeforeClass, + Rule::BlankLinesBetweenHeaderAndContent, + Rule::CapitalizeSectionName, + Rule::DashedUnderlineAfterSection, + Rule::DocstringStartsWithThis, + Rule::EmptyDocstring, + Rule::EmptyDocstringSection, + Rule::EndsInPeriod, + Rule::EndsInPunctuation, + Rule::EscapeSequenceInDocstring, + Rule::FirstLineCapitalized, + Rule::FitsOnOneLine, + Rule::IndentWithSpaces, + Rule::MultiLineSummaryFirstLine, + Rule::MultiLineSummarySecondLine, + Rule::NewLineAfterLastParagraph, + Rule::NewLineAfterSectionName, + Rule::NoBlankLineAfterFunction, + Rule::NoBlankLineAfterSection, + Rule::NoBlankLineBeforeFunction, + Rule::NoBlankLineBeforeSection, + Rule::NoSignature, + Rule::NonImperativeMood, + Rule::OneBlankLineAfterClass, + Rule::OneBlankLineBeforeClass, + Rule::OverIndentation, + Rule::OverloadWithDocstring, + Rule::SectionNameEndsInColon, + Rule::SectionNotOverIndented, + Rule::SectionUnderlineAfterName, + Rule::SectionUnderlineMatchesSectionLength, + Rule::SectionUnderlineNotOverIndented, + Rule::SurroundingWhitespace, + Rule::TripleSingleQuotes, + Rule::UnderIndentation, + Rule::UndocumentedMagicMethod, + Rule::UndocumentedParam, + Rule::UndocumentedPublicClass, + Rule::UndocumentedPublicFunction, + Rule::UndocumentedPublicInit, + Rule::UndocumentedPublicMethod, + Rule::UndocumentedPublicModule, + Rule::UndocumentedPublicNestedClass, + Rule::UndocumentedPublicPackage, + ]); + + if !enforce_annotations && !enforce_docstrings && !enforce_stubs { + return; + } + + // Compute visibility of all definitions. + let exports: Option> = { + checker + .semantic + .global_scope() + .get_all("__all__") + .map(|binding_id| &checker.semantic.bindings[binding_id]) + .filter_map(|binding| match &binding.kind { + BindingKind::Export(Export { names }) => Some(names.iter().copied()), + _ => None, + }) + .fold(None, |acc, names| { + Some(acc.into_iter().flatten().chain(names).collect()) + }) + }; + + let definitions = std::mem::take(&mut checker.semantic.definitions); + let mut overloaded_name: Option = None; + for ContextualizedDefinition { + definition, + visibility, + } in definitions.resolve(exports.as_deref()).iter() + { + let docstring = docstrings::extraction::extract_docstring(definition); + + // flake8-annotations + if enforce_annotations { + // TODO(charlie): This should be even stricter, in that an overload + // implementation should come immediately after the overloaded + // interfaces, without any AST nodes in between. Right now, we + // only error when traversing definition boundaries (functions, + // classes, etc.). + if !overloaded_name.map_or(false, |overloaded_name| { + flake8_annotations::helpers::is_overload_impl( + definition, + &overloaded_name, + &checker.semantic, + ) + }) { + checker + .diagnostics + .extend(flake8_annotations::rules::definition( + checker, + definition, + *visibility, + )); + } + overloaded_name = + flake8_annotations::helpers::overloaded_name(definition, &checker.semantic); + } + + // flake8-pyi + if enforce_stubs { + if checker.enabled(Rule::DocstringInStub) { + flake8_pyi::rules::docstring_in_stubs(checker, docstring); + } + if checker.enabled(Rule::IterMethodReturnIterable) { + flake8_pyi::rules::iter_method_return_iterable(checker, definition); + } + } + + // pydocstyle + if enforce_docstrings { + if pydocstyle::helpers::should_ignore_definition( + definition, + &checker.settings.pydocstyle.ignore_decorators, + &checker.semantic, + ) { + continue; + } + + // Extract a `Docstring` from a `Definition`. + let Some(expr) = docstring else { + pydocstyle::rules::not_missing(checker, definition, *visibility); + continue; + }; + + let contents = checker.locator.slice(expr.range()); + + let indentation = checker.locator.slice(TextRange::new( + checker.locator.line_start(expr.start()), + expr.start(), + )); + + if pydocstyle::helpers::should_ignore_docstring(contents) { + #[allow(deprecated)] + let location = checker.locator.compute_source_location(expr.start()); + warn_user!( + "Docstring at {}:{}:{} contains implicit string concatenation; ignoring...", + relativize_path(checker.path), + location.row, + location.column + ); + continue; + } + + // SAFETY: Safe for docstrings that pass `should_ignore_docstring`. + let body_range = raw_contents_range(contents).unwrap(); + let docstring = Docstring { + definition, + expr, + contents, + body_range, + indentation, + }; + + if !pydocstyle::rules::not_empty(checker, &docstring) { + continue; + } + if checker.enabled(Rule::FitsOnOneLine) { + pydocstyle::rules::one_liner(checker, &docstring); + } + if checker.any_enabled(&[ + Rule::NoBlankLineAfterFunction, + Rule::NoBlankLineBeforeFunction, + ]) { + pydocstyle::rules::blank_before_after_function(checker, &docstring); + } + if checker.any_enabled(&[ + Rule::BlankLineBeforeClass, + Rule::OneBlankLineAfterClass, + Rule::OneBlankLineBeforeClass, + ]) { + pydocstyle::rules::blank_before_after_class(checker, &docstring); + } + if checker.enabled(Rule::BlankLineAfterSummary) { + pydocstyle::rules::blank_after_summary(checker, &docstring); + } + if checker.any_enabled(&[ + Rule::IndentWithSpaces, + Rule::OverIndentation, + Rule::UnderIndentation, + ]) { + pydocstyle::rules::indent(checker, &docstring); + } + if checker.enabled(Rule::NewLineAfterLastParagraph) { + pydocstyle::rules::newline_after_last_paragraph(checker, &docstring); + } + if checker.enabled(Rule::SurroundingWhitespace) { + pydocstyle::rules::no_surrounding_whitespace(checker, &docstring); + } + if checker.any_enabled(&[ + Rule::MultiLineSummaryFirstLine, + Rule::MultiLineSummarySecondLine, + ]) { + pydocstyle::rules::multi_line_summary_start(checker, &docstring); + } + if checker.enabled(Rule::TripleSingleQuotes) { + pydocstyle::rules::triple_quotes(checker, &docstring); + } + if checker.enabled(Rule::EscapeSequenceInDocstring) { + pydocstyle::rules::backslashes(checker, &docstring); + } + if checker.enabled(Rule::EndsInPeriod) { + pydocstyle::rules::ends_with_period(checker, &docstring); + } + if checker.enabled(Rule::NonImperativeMood) { + pydocstyle::rules::non_imperative_mood( + checker, + &docstring, + &checker.settings.pydocstyle.property_decorators, + ); + } + if checker.enabled(Rule::NoSignature) { + pydocstyle::rules::no_signature(checker, &docstring); + } + if checker.enabled(Rule::FirstLineCapitalized) { + pydocstyle::rules::capitalized(checker, &docstring); + } + if checker.enabled(Rule::DocstringStartsWithThis) { + pydocstyle::rules::starts_with_this(checker, &docstring); + } + if checker.enabled(Rule::EndsInPunctuation) { + pydocstyle::rules::ends_with_punctuation(checker, &docstring); + } + if checker.enabled(Rule::OverloadWithDocstring) { + pydocstyle::rules::if_needed(checker, &docstring); + } + if checker.any_enabled(&[ + Rule::BlankLineAfterLastSection, + Rule::BlankLinesBetweenHeaderAndContent, + Rule::CapitalizeSectionName, + Rule::DashedUnderlineAfterSection, + Rule::EmptyDocstringSection, + Rule::MultiLineSummaryFirstLine, + Rule::NewLineAfterSectionName, + Rule::NoBlankLineAfterSection, + Rule::NoBlankLineBeforeSection, + Rule::SectionNameEndsInColon, + Rule::SectionNotOverIndented, + Rule::SectionUnderlineAfterName, + Rule::SectionUnderlineMatchesSectionLength, + Rule::SectionUnderlineNotOverIndented, + Rule::UndocumentedParam, + ]) { + pydocstyle::rules::sections( + checker, + &docstring, + checker.settings.pydocstyle.convention.as_ref(), + ); + } + } + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/except_handler.rs b/crates/ruff/src/checkers/ast/analyze/except_handler.rs new file mode 100644 index 0000000000..5dad39a60c --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/except_handler.rs @@ -0,0 +1,88 @@ +use rustpython_parser::ast::{self, ExceptHandler, Ranged}; + +use crate::checkers::ast::Checker; +use crate::registry::Rule; +use crate::rules::{ + flake8_bandit, flake8_blind_except, flake8_bugbear, flake8_builtins, pycodestyle, pylint, + tryceratops, +}; + +/// Run lint rules over an [`ExceptHandler`] syntax node. +pub(crate) fn except_handler(except_handler: &ExceptHandler, checker: &mut Checker) { + match except_handler { + ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { + type_, + name, + body, + range: _, + }) => { + if checker.enabled(Rule::BareExcept) { + if let Some(diagnostic) = pycodestyle::rules::bare_except( + type_.as_deref(), + body, + except_handler, + checker.locator, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::RaiseWithoutFromInsideExcept) { + flake8_bugbear::rules::raise_without_from_inside_except( + checker, + name.as_deref(), + body, + ); + } + if checker.enabled(Rule::BlindExcept) { + flake8_blind_except::rules::blind_except( + checker, + type_.as_deref(), + name.as_deref(), + body, + ); + } + if checker.enabled(Rule::TryExceptPass) { + flake8_bandit::rules::try_except_pass( + checker, + except_handler, + type_.as_deref(), + body, + checker.settings.flake8_bandit.check_typed_exception, + ); + } + if checker.enabled(Rule::TryExceptContinue) { + flake8_bandit::rules::try_except_continue( + checker, + except_handler, + type_.as_deref(), + body, + checker.settings.flake8_bandit.check_typed_exception, + ); + } + if checker.enabled(Rule::ExceptWithEmptyTuple) { + flake8_bugbear::rules::except_with_empty_tuple(checker, except_handler); + } + if checker.enabled(Rule::ExceptWithNonExceptionClasses) { + flake8_bugbear::rules::except_with_non_exception_classes(checker, except_handler); + } + if checker.enabled(Rule::ReraiseNoCause) { + tryceratops::rules::reraise_no_cause(checker, body); + } + if checker.enabled(Rule::BinaryOpException) { + pylint::rules::binary_op_exception(checker, except_handler); + } + if let Some(name) = name { + if checker.enabled(Rule::AmbiguousVariableName) { + if let Some(diagnostic) = + pycodestyle::rules::ambiguous_variable_name(name.as_str(), name.range()) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::BuiltinVariableShadowing) { + flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range()); + } + } + } + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/expression.rs b/crates/ruff/src/checkers/ast/analyze/expression.rs new file mode 100644 index 0000000000..81dc460f3d --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/expression.rs @@ -0,0 +1,1415 @@ +use rustpython_format::cformat::{CFormatError, CFormatErrorType}; +use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Operator, Ranged}; + +use ruff_diagnostics::Diagnostic; + +use ruff_python_ast::types::Node; +use ruff_python_semantic::analyze::typing; +use ruff_python_semantic::ScopeKind; + +use crate::checkers::ast::Checker; +use crate::registry::Rule; +use crate::rules::{ + flake8_2020, flake8_async, flake8_bandit, flake8_boolean_trap, flake8_bugbear, flake8_builtins, + flake8_comprehensions, flake8_datetimez, flake8_debugger, flake8_django, + flake8_future_annotations, flake8_gettext, flake8_implicit_str_concat, flake8_logging_format, + flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_self, flake8_simplify, + flake8_tidy_imports, flake8_use_pathlib, flynt, numpy, pandas_vet, pep8_naming, pycodestyle, + pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, +}; +use crate::settings::types::PythonVersion; + +/// Run lint rules over an [`Expr`] syntax node. +pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { + match expr { + Expr::Subscript(subscript @ ast::ExprSubscript { value, slice, .. }) => { + // Ex) Optional[...], Union[...] + if checker.any_enabled(&[ + Rule::FutureRewritableTypeAnnotation, + Rule::NonPEP604Annotation, + ]) { + if let Some(operator) = typing::to_pep604_operator(value, slice, &checker.semantic) + { + if checker.enabled(Rule::FutureRewritableTypeAnnotation) { + if !checker.is_stub + && checker.settings.target_version < PythonVersion::Py310 + && checker.settings.target_version >= PythonVersion::Py37 + && !checker.semantic.future_annotations() + && checker.semantic.in_annotation() + && !checker.settings.pyupgrade.keep_runtime_typing + { + flake8_future_annotations::rules::future_rewritable_type_annotation( + checker, value, + ); + } + } + if checker.enabled(Rule::NonPEP604Annotation) { + if checker.is_stub + || checker.settings.target_version >= PythonVersion::Py310 + || (checker.settings.target_version >= PythonVersion::Py37 + && checker.semantic.future_annotations() + && checker.semantic.in_annotation() + && !checker.settings.pyupgrade.keep_runtime_typing) + { + pyupgrade::rules::use_pep604_annotation(checker, expr, slice, operator); + } + } + } + } + + // Ex) list[...] + if checker.enabled(Rule::FutureRequiredTypeAnnotation) { + if !checker.is_stub + && checker.settings.target_version < PythonVersion::Py39 + && !checker.semantic.future_annotations() + && checker.semantic.in_annotation() + && typing::is_pep585_generic(value, &checker.semantic) + { + flake8_future_annotations::rules::future_required_type_annotation( + checker, + expr, + flake8_future_annotations::rules::Reason::PEP585, + ); + } + } + + // Ex) Union[...] + if checker.any_enabled(&[Rule::UnnecessaryLiteralUnion, Rule::DuplicateUnionMember]) { + // Determine if the current expression is an union + // Avoid duplicate checks if the parent is an `Union[...]` since these rules traverse nested unions + let is_unchecked_union = checker + .semantic + .expr_grandparent() + .and_then(Expr::as_subscript_expr) + .map_or(true, |parent| { + !checker.semantic.match_typing_expr(&parent.value, "Union") + }); + + if is_unchecked_union { + if checker.enabled(Rule::UnnecessaryLiteralUnion) { + flake8_pyi::rules::unnecessary_literal_union(checker, expr); + } + if checker.enabled(Rule::DuplicateUnionMember) { + flake8_pyi::rules::duplicate_union_member(checker, expr); + } + } + } + + if checker.any_enabled(&[ + Rule::SysVersionSlice3, + Rule::SysVersion2, + Rule::SysVersion0, + Rule::SysVersionSlice1, + ]) { + flake8_2020::rules::subscript(checker, value, slice); + } + if checker.enabled(Rule::UncapitalizedEnvironmentVariables) { + flake8_simplify::rules::use_capital_environment_variables(checker, expr); + } + if checker.enabled(Rule::UnnecessaryIterableAllocationForFirstElement) { + ruff::rules::unnecessary_iterable_allocation_for_first_element(checker, subscript); + } + + if checker.enabled(Rule::InvalidIndexType) { + ruff::rules::invalid_index_type(checker, subscript); + } + + pandas_vet::rules::subscript(checker, value, expr); + } + Expr::Tuple(ast::ExprTuple { + elts, + ctx, + range: _, + }) + | Expr::List(ast::ExprList { + elts, + ctx, + range: _, + }) => { + if ctx.is_store() { + let check_too_many_expressions = checker.enabled(Rule::ExpressionsInStarAssignment); + let check_two_starred_expressions = + checker.enabled(Rule::MultipleStarredExpressions); + if let Some(diagnostic) = pyflakes::rules::starred_expressions( + elts, + check_too_many_expressions, + check_two_starred_expressions, + expr.range(), + ) { + checker.diagnostics.push(diagnostic); + } + } + } + Expr::Name(ast::ExprName { id, ctx, range }) => { + match ctx { + ExprContext::Load => { + if checker.enabled(Rule::TypingTextStrAlias) { + pyupgrade::rules::typing_text_str_alias(checker, expr); + } + if checker.enabled(Rule::NumpyDeprecatedTypeAlias) { + numpy::rules::deprecated_type_alias(checker, expr); + } + if checker.enabled(Rule::NumpyDeprecatedFunction) { + numpy::rules::deprecated_function(checker, expr); + } + if checker.is_stub { + if checker.enabled(Rule::CollectionsNamedTuple) { + flake8_pyi::rules::collections_named_tuple(checker, expr); + } + } + + // Ex) List[...] + if checker.any_enabled(&[ + Rule::FutureRewritableTypeAnnotation, + Rule::NonPEP585Annotation, + ]) { + if let Some(replacement) = + typing::to_pep585_generic(expr, &checker.semantic) + { + if checker.enabled(Rule::FutureRewritableTypeAnnotation) { + if !checker.is_stub + && checker.settings.target_version < PythonVersion::Py39 + && checker.settings.target_version >= PythonVersion::Py37 + && !checker.semantic.future_annotations() + && checker.semantic.in_annotation() + && !checker.settings.pyupgrade.keep_runtime_typing + { + flake8_future_annotations::rules::future_rewritable_type_annotation( + checker, expr, + ); + } + } + if checker.enabled(Rule::NonPEP585Annotation) { + if checker.is_stub + || checker.settings.target_version >= PythonVersion::Py39 + || (checker.settings.target_version >= PythonVersion::Py37 + && checker.semantic.future_annotations() + && checker.semantic.in_annotation() + && !checker.settings.pyupgrade.keep_runtime_typing) + { + pyupgrade::rules::use_pep585_annotation( + checker, + expr, + &replacement, + ); + } + } + } + } + } + ExprContext::Store => { + if checker.enabled(Rule::NonLowercaseVariableInFunction) { + if checker.semantic.scope().kind.is_any_function() { + // Ignore globals. + if !checker + .semantic + .scope() + .get(id) + .map_or(false, |binding_id| { + checker.semantic.binding(binding_id).is_global() + }) + { + pep8_naming::rules::non_lowercase_variable_in_function( + checker, expr, id, + ); + } + } + } + if checker.enabled(Rule::MixedCaseVariableInClassScope) { + if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) = + &checker.semantic.scope().kind + { + pep8_naming::rules::mixed_case_variable_in_class_scope( + checker, expr, id, bases, + ); + } + } + if checker.enabled(Rule::MixedCaseVariableInGlobalScope) { + if matches!(checker.semantic.scope().kind, ScopeKind::Module) { + pep8_naming::rules::mixed_case_variable_in_global_scope( + checker, expr, id, + ); + } + } + if checker.enabled(Rule::AmbiguousVariableName) { + if let Some(diagnostic) = + pycodestyle::rules::ambiguous_variable_name(id, expr.range()) + { + checker.diagnostics.push(diagnostic); + } + } + if let ScopeKind::Class(class_def) = checker.semantic.scope().kind { + if checker.enabled(Rule::BuiltinAttributeShadowing) { + flake8_builtins::rules::builtin_attribute_shadowing( + checker, class_def, id, *range, + ); + } + } else { + if checker.enabled(Rule::BuiltinVariableShadowing) { + flake8_builtins::rules::builtin_variable_shadowing(checker, id, *range); + } + } + } + ExprContext::Del => {} + } + if checker.enabled(Rule::SixPY3) { + flake8_2020::rules::name_or_attribute(checker, expr); + } + if checker.enabled(Rule::LoadBeforeGlobalDeclaration) { + pylint::rules::load_before_global_declaration(checker, id, expr); + } + } + Expr::Attribute(ast::ExprAttribute { attr, value, .. }) => { + // Ex) typing.List[...] + if checker.any_enabled(&[ + Rule::FutureRewritableTypeAnnotation, + Rule::NonPEP585Annotation, + ]) { + if let Some(replacement) = typing::to_pep585_generic(expr, &checker.semantic) { + if checker.enabled(Rule::FutureRewritableTypeAnnotation) { + if !checker.is_stub + && checker.settings.target_version < PythonVersion::Py39 + && checker.settings.target_version >= PythonVersion::Py37 + && !checker.semantic.future_annotations() + && checker.semantic.in_annotation() + && !checker.settings.pyupgrade.keep_runtime_typing + { + flake8_future_annotations::rules::future_rewritable_type_annotation( + checker, expr, + ); + } + } + if checker.enabled(Rule::NonPEP585Annotation) { + if checker.is_stub + || checker.settings.target_version >= PythonVersion::Py39 + || (checker.settings.target_version >= PythonVersion::Py37 + && checker.semantic.future_annotations() + && checker.semantic.in_annotation() + && !checker.settings.pyupgrade.keep_runtime_typing) + { + pyupgrade::rules::use_pep585_annotation(checker, expr, &replacement); + } + } + } + } + if checker.enabled(Rule::DatetimeTimezoneUTC) { + if checker.settings.target_version >= PythonVersion::Py311 { + pyupgrade::rules::datetime_utc_alias(checker, expr); + } + } + if checker.enabled(Rule::TypingTextStrAlias) { + pyupgrade::rules::typing_text_str_alias(checker, expr); + } + if checker.enabled(Rule::NumpyDeprecatedTypeAlias) { + numpy::rules::deprecated_type_alias(checker, expr); + } + if checker.enabled(Rule::NumpyDeprecatedFunction) { + numpy::rules::deprecated_function(checker, expr); + } + if checker.enabled(Rule::DeprecatedMockImport) { + pyupgrade::rules::deprecated_mock_attribute(checker, expr); + } + if checker.enabled(Rule::SixPY3) { + flake8_2020::rules::name_or_attribute(checker, expr); + } + if checker.enabled(Rule::BannedApi) { + flake8_tidy_imports::rules::banned_attribute_access(checker, expr); + } + if checker.enabled(Rule::PrivateMemberAccess) { + flake8_self::rules::private_member_access(checker, expr); + } + if checker.is_stub { + if checker.enabled(Rule::CollectionsNamedTuple) { + flake8_pyi::rules::collections_named_tuple(checker, expr); + } + } + pandas_vet::rules::attr(checker, attr, value, expr); + } + Expr::Call( + call @ ast::ExprCall { + func, + args, + keywords, + range: _, + }, + ) => { + if checker.any_enabled(&[ + // pyflakes + Rule::StringDotFormatInvalidFormat, + Rule::StringDotFormatExtraNamedArguments, + Rule::StringDotFormatExtraPositionalArguments, + Rule::StringDotFormatMissingArguments, + Rule::StringDotFormatMixingAutomatic, + // pyupgrade + Rule::FormatLiterals, + Rule::FString, + // flynt + Rule::StaticJoinToFString, + ]) { + if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() { + let attr = attr.as_str(); + if let Expr::Constant(ast::ExprConstant { + value: Constant::Str(val), + .. + }) = value.as_ref() + { + if attr == "join" { + // "...".join(...) call + if checker.enabled(Rule::StaticJoinToFString) { + flynt::rules::static_join_to_fstring(checker, expr, val); + } + } else if attr == "format" { + // "...".format(...) call + let location = expr.range(); + match pyflakes::format::FormatSummary::try_from(val.as_ref()) { + Err(e) => { + if checker.enabled(Rule::StringDotFormatInvalidFormat) { + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::StringDotFormatInvalidFormat { + message: pyflakes::format::error_to_string(&e), + }, + location, + )); + } + } + Ok(summary) => { + if checker.enabled(Rule::StringDotFormatExtraNamedArguments) { + pyflakes::rules::string_dot_format_extra_named_arguments( + checker, &summary, keywords, location, + ); + } + if checker + .enabled(Rule::StringDotFormatExtraPositionalArguments) + { + pyflakes::rules::string_dot_format_extra_positional_arguments( + checker, + &summary, args, location, + ); + } + if checker.enabled(Rule::StringDotFormatMissingArguments) { + pyflakes::rules::string_dot_format_missing_argument( + checker, &summary, args, keywords, location, + ); + } + if checker.enabled(Rule::StringDotFormatMixingAutomatic) { + pyflakes::rules::string_dot_format_mixing_automatic( + checker, &summary, location, + ); + } + if checker.enabled(Rule::FormatLiterals) { + pyupgrade::rules::format_literals(checker, &summary, expr); + } + if checker.enabled(Rule::FString) { + pyupgrade::rules::f_strings( + checker, + &summary, + expr, + value, + checker.settings.line_length, + ); + } + } + } + } + } + } + } + if checker.enabled(Rule::TypeOfPrimitive) { + pyupgrade::rules::type_of_primitive(checker, expr, func, args); + } + if checker.enabled(Rule::DeprecatedUnittestAlias) { + pyupgrade::rules::deprecated_unittest_alias(checker, func); + } + if checker.enabled(Rule::SuperCallWithParameters) { + pyupgrade::rules::super_call_with_parameters(checker, expr, func, args); + } + if checker.enabled(Rule::UnnecessaryEncodeUTF8) { + pyupgrade::rules::unnecessary_encode_utf8(checker, expr, func, args, keywords); + } + if checker.enabled(Rule::RedundantOpenModes) { + pyupgrade::rules::redundant_open_modes(checker, expr); + } + if checker.enabled(Rule::NativeLiterals) { + pyupgrade::rules::native_literals(checker, expr, func, args, keywords); + } + if checker.enabled(Rule::OpenAlias) { + pyupgrade::rules::open_alias(checker, expr, func); + } + if checker.enabled(Rule::ReplaceUniversalNewlines) { + pyupgrade::rules::replace_universal_newlines(checker, func, keywords); + } + if checker.enabled(Rule::ReplaceStdoutStderr) { + pyupgrade::rules::replace_stdout_stderr(checker, expr, func, args, keywords); + } + if checker.enabled(Rule::OSErrorAlias) { + pyupgrade::rules::os_error_alias_call(checker, func); + } + if checker.enabled(Rule::NonPEP604Isinstance) { + if checker.settings.target_version >= PythonVersion::Py310 { + pyupgrade::rules::use_pep604_isinstance(checker, expr, func, args); + } + } + if checker.enabled(Rule::BlockingHttpCallInAsyncFunction) { + flake8_async::rules::blocking_http_call(checker, expr); + } + if checker.enabled(Rule::OpenSleepOrSubprocessInAsyncFunction) { + flake8_async::rules::open_sleep_or_subprocess_call(checker, expr); + } + if checker.enabled(Rule::BlockingOsCallInAsyncFunction) { + flake8_async::rules::blocking_os_call(checker, expr); + } + if checker.any_enabled(&[Rule::Print, Rule::PPrint]) { + flake8_print::rules::print_call(checker, func, keywords); + } + if checker.any_enabled(&[ + Rule::SuspiciousPickleUsage, + Rule::SuspiciousMarshalUsage, + Rule::SuspiciousInsecureHashUsage, + Rule::SuspiciousInsecureCipherUsage, + Rule::SuspiciousInsecureCipherModeUsage, + Rule::SuspiciousMktempUsage, + Rule::SuspiciousEvalUsage, + Rule::SuspiciousMarkSafeUsage, + Rule::SuspiciousURLOpenUsage, + Rule::SuspiciousNonCryptographicRandomUsage, + Rule::SuspiciousXMLCElementTreeUsage, + Rule::SuspiciousXMLElementTreeUsage, + Rule::SuspiciousXMLExpatReaderUsage, + Rule::SuspiciousXMLExpatBuilderUsage, + Rule::SuspiciousXMLSaxUsage, + Rule::SuspiciousXMLMiniDOMUsage, + Rule::SuspiciousXMLPullDOMUsage, + Rule::SuspiciousXMLETreeUsage, + Rule::SuspiciousUnverifiedContextUsage, + Rule::SuspiciousTelnetUsage, + Rule::SuspiciousFTPLibUsage, + ]) { + flake8_bandit::rules::suspicious_function_call(checker, expr); + } + if checker.enabled(Rule::ReSubPositionalArgs) { + flake8_bugbear::rules::re_sub_positional_args(checker, call); + } + if checker.enabled(Rule::UnreliableCallableCheck) { + flake8_bugbear::rules::unreliable_callable_check(checker, expr, func, args); + } + if checker.enabled(Rule::StripWithMultiCharacters) { + flake8_bugbear::rules::strip_with_multi_characters(checker, expr, func, args); + } + if checker.enabled(Rule::GetAttrWithConstant) { + flake8_bugbear::rules::getattr_with_constant(checker, expr, func, args); + } + if checker.enabled(Rule::SetAttrWithConstant) { + flake8_bugbear::rules::setattr_with_constant(checker, expr, func, args); + } + if checker.enabled(Rule::UselessContextlibSuppress) { + flake8_bugbear::rules::useless_contextlib_suppress(checker, expr, func, args); + } + if checker.enabled(Rule::StarArgUnpackingAfterKeywordArg) { + flake8_bugbear::rules::star_arg_unpacking_after_keyword_arg( + checker, args, keywords, + ); + } + if checker.enabled(Rule::ZipWithoutExplicitStrict) { + if checker.settings.target_version >= PythonVersion::Py310 { + flake8_bugbear::rules::zip_without_explicit_strict( + checker, expr, func, args, keywords, + ); + } + } + if checker.enabled(Rule::NoExplicitStacklevel) { + flake8_bugbear::rules::no_explicit_stacklevel(checker, func, keywords); + } + if checker.enabled(Rule::UnnecessaryDictKwargs) { + flake8_pie::rules::unnecessary_dict_kwargs(checker, expr, keywords); + } + if checker.enabled(Rule::ExecBuiltin) { + flake8_bandit::rules::exec_used(checker, func); + } + if checker.enabled(Rule::BadFilePermissions) { + flake8_bandit::rules::bad_file_permissions(checker, func, args, keywords); + } + if checker.enabled(Rule::RequestWithNoCertValidation) { + flake8_bandit::rules::request_with_no_cert_validation(checker, func, keywords); + } + if checker.enabled(Rule::UnsafeYAMLLoad) { + flake8_bandit::rules::unsafe_yaml_load(checker, func, args, keywords); + } + if checker.enabled(Rule::SnmpInsecureVersion) { + flake8_bandit::rules::snmp_insecure_version(checker, func, keywords); + } + if checker.enabled(Rule::SnmpWeakCryptography) { + flake8_bandit::rules::snmp_weak_cryptography(checker, func, args, keywords); + } + if checker.enabled(Rule::Jinja2AutoescapeFalse) { + flake8_bandit::rules::jinja2_autoescape_false(checker, func, keywords); + } + if checker.enabled(Rule::HardcodedPasswordFuncArg) { + flake8_bandit::rules::hardcoded_password_func_arg(checker, keywords); + } + if checker.enabled(Rule::HardcodedSQLExpression) { + flake8_bandit::rules::hardcoded_sql_expression(checker, expr); + } + if checker.enabled(Rule::HashlibInsecureHashFunction) { + flake8_bandit::rules::hashlib_insecure_hash_functions( + checker, func, args, keywords, + ); + } + if checker.enabled(Rule::RequestWithoutTimeout) { + flake8_bandit::rules::request_without_timeout(checker, func, keywords); + } + if checker.enabled(Rule::ParamikoCall) { + flake8_bandit::rules::paramiko_call(checker, func); + } + if checker.enabled(Rule::LoggingConfigInsecureListen) { + flake8_bandit::rules::logging_config_insecure_listen(checker, func, keywords); + } + if checker.any_enabled(&[ + Rule::SubprocessWithoutShellEqualsTrue, + Rule::SubprocessPopenWithShellEqualsTrue, + Rule::CallWithShellEqualsTrue, + Rule::StartProcessWithAShell, + Rule::StartProcessWithNoShell, + Rule::StartProcessWithPartialPath, + Rule::UnixCommandWildcardInjection, + ]) { + flake8_bandit::rules::shell_injection(checker, func, args, keywords); + } + if checker.enabled(Rule::UnnecessaryGeneratorList) { + flake8_comprehensions::rules::unnecessary_generator_list( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryGeneratorSet) { + flake8_comprehensions::rules::unnecessary_generator_set( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryGeneratorDict) { + flake8_comprehensions::rules::unnecessary_generator_dict( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryListComprehensionSet) { + flake8_comprehensions::rules::unnecessary_list_comprehension_set( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryListComprehensionDict) { + flake8_comprehensions::rules::unnecessary_list_comprehension_dict( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryLiteralSet) { + flake8_comprehensions::rules::unnecessary_literal_set( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryLiteralDict) { + flake8_comprehensions::rules::unnecessary_literal_dict( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryCollectionCall) { + flake8_comprehensions::rules::unnecessary_collection_call( + checker, + expr, + func, + args, + keywords, + &checker.settings.flake8_comprehensions, + ); + } + if checker.enabled(Rule::UnnecessaryLiteralWithinTupleCall) { + flake8_comprehensions::rules::unnecessary_literal_within_tuple_call( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryLiteralWithinListCall) { + flake8_comprehensions::rules::unnecessary_literal_within_list_call( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryLiteralWithinDictCall) { + flake8_comprehensions::rules::unnecessary_literal_within_dict_call( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessaryListCall) { + flake8_comprehensions::rules::unnecessary_list_call(checker, expr, func, args); + } + if checker.enabled(Rule::UnnecessaryCallAroundSorted) { + flake8_comprehensions::rules::unnecessary_call_around_sorted( + checker, expr, func, args, + ); + } + if checker.enabled(Rule::UnnecessaryDoubleCastOrProcess) { + flake8_comprehensions::rules::unnecessary_double_cast_or_process( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::UnnecessarySubscriptReversal) { + flake8_comprehensions::rules::unnecessary_subscript_reversal( + checker, expr, func, args, + ); + } + if checker.enabled(Rule::UnnecessaryMap) { + flake8_comprehensions::rules::unnecessary_map( + checker, + expr, + checker.semantic.expr_parent(), + func, + args, + ); + } + if checker.enabled(Rule::UnnecessaryComprehensionAnyAll) { + flake8_comprehensions::rules::unnecessary_comprehension_any_all( + checker, expr, func, args, keywords, + ); + } + if checker.enabled(Rule::BooleanPositionalValueInFunctionCall) { + flake8_boolean_trap::rules::check_boolean_positional_value_in_function_call( + checker, args, func, + ); + } + if checker.enabled(Rule::Debugger) { + flake8_debugger::rules::debugger_call(checker, expr, func); + } + if checker.enabled(Rule::PandasUseOfInplaceArgument) { + pandas_vet::rules::inplace_argument(checker, expr, func, args, keywords); + } + pandas_vet::rules::call(checker, func); + if checker.enabled(Rule::PandasUseOfDotReadTable) { + pandas_vet::rules::use_of_read_table(checker, func, keywords); + } + if checker.enabled(Rule::PandasUseOfPdMerge) { + pandas_vet::rules::use_of_pd_merge(checker, func); + } + if checker.enabled(Rule::CallDatetimeWithoutTzinfo) { + flake8_datetimez::rules::call_datetime_without_tzinfo( + checker, + func, + args, + keywords, + expr.range(), + ); + } + if checker.enabled(Rule::CallDatetimeToday) { + flake8_datetimez::rules::call_datetime_today(checker, func, expr.range()); + } + if checker.enabled(Rule::CallDatetimeUtcnow) { + flake8_datetimez::rules::call_datetime_utcnow(checker, func, expr.range()); + } + if checker.enabled(Rule::CallDatetimeUtcfromtimestamp) { + flake8_datetimez::rules::call_datetime_utcfromtimestamp( + checker, + func, + expr.range(), + ); + } + if checker.enabled(Rule::CallDatetimeNowWithoutTzinfo) { + flake8_datetimez::rules::call_datetime_now_without_tzinfo( + checker, + func, + args, + keywords, + expr.range(), + ); + } + if checker.enabled(Rule::CallDatetimeFromtimestamp) { + flake8_datetimez::rules::call_datetime_fromtimestamp( + checker, + func, + args, + keywords, + expr.range(), + ); + } + if checker.enabled(Rule::CallDatetimeStrptimeWithoutZone) { + flake8_datetimez::rules::call_datetime_strptime_without_zone( + checker, + func, + args, + expr.range(), + ); + } + if checker.enabled(Rule::CallDateToday) { + flake8_datetimez::rules::call_date_today(checker, func, expr.range()); + } + if checker.enabled(Rule::CallDateFromtimestamp) { + flake8_datetimez::rules::call_date_fromtimestamp(checker, func, expr.range()); + } + if checker.enabled(Rule::Eval) { + pygrep_hooks::rules::no_eval(checker, func); + } + if checker.enabled(Rule::DeprecatedLogWarn) { + pygrep_hooks::rules::deprecated_log_warn(checker, func); + } + if checker.enabled(Rule::UnnecessaryDirectLambdaCall) { + pylint::rules::unnecessary_direct_lambda_call(checker, expr, func); + } + if checker.enabled(Rule::SysExitAlias) { + pylint::rules::sys_exit_alias(checker, func); + } + if checker.enabled(Rule::BadStrStripCall) { + pylint::rules::bad_str_strip_call(checker, func, args); + } + if checker.enabled(Rule::InvalidEnvvarDefault) { + pylint::rules::invalid_envvar_default(checker, func, args, keywords); + } + if checker.enabled(Rule::InvalidEnvvarValue) { + pylint::rules::invalid_envvar_value(checker, func, args, keywords); + } + if checker.enabled(Rule::NestedMinMax) { + pylint::rules::nested_min_max(checker, expr, func, args, keywords); + } + if checker.enabled(Rule::PytestPatchWithLambda) { + if let Some(diagnostic) = + flake8_pytest_style::rules::patch_with_lambda(func, args, keywords) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::PytestUnittestAssertion) { + if let Some(diagnostic) = flake8_pytest_style::rules::unittest_assertion( + checker, expr, func, args, keywords, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::SubprocessPopenPreexecFn) { + pylint::rules::subprocess_popen_preexec_fn(checker, func, keywords); + } + if checker.any_enabled(&[ + Rule::PytestRaisesWithoutException, + Rule::PytestRaisesTooBroad, + ]) { + flake8_pytest_style::rules::raises_call(checker, func, args, keywords); + } + if checker.enabled(Rule::PytestFailWithoutMessage) { + flake8_pytest_style::rules::fail_call(checker, func, args, keywords); + } + if checker.enabled(Rule::PairwiseOverZipped) { + if checker.settings.target_version >= PythonVersion::Py310 { + ruff::rules::pairwise_over_zipped(checker, func, args); + } + } + if checker.any_enabled(&[ + Rule::FStringInGetTextFuncCall, + Rule::FormatInGetTextFuncCall, + Rule::PrintfInGetTextFuncCall, + ]) && flake8_gettext::is_gettext_func_call( + func, + &checker.settings.flake8_gettext.functions_names, + ) { + if checker.enabled(Rule::FStringInGetTextFuncCall) { + flake8_gettext::rules::f_string_in_gettext_func_call(checker, args); + } + if checker.enabled(Rule::FormatInGetTextFuncCall) { + flake8_gettext::rules::format_in_gettext_func_call(checker, args); + } + if checker.enabled(Rule::PrintfInGetTextFuncCall) { + flake8_gettext::rules::printf_in_gettext_func_call(checker, args); + } + } + if checker.enabled(Rule::UncapitalizedEnvironmentVariables) { + flake8_simplify::rules::use_capital_environment_variables(checker, expr); + } + if checker.enabled(Rule::OpenFileWithContextHandler) { + flake8_simplify::rules::open_file_with_context_handler(checker, func); + } + if checker.enabled(Rule::DictGetWithNoneDefault) { + flake8_simplify::rules::dict_get_with_none_default(checker, expr); + } + if checker.any_enabled(&[ + Rule::OsPathAbspath, + Rule::OsChmod, + Rule::OsMkdir, + Rule::OsMakedirs, + Rule::OsRename, + Rule::OsReplace, + Rule::OsRmdir, + Rule::OsRemove, + Rule::OsUnlink, + Rule::OsGetcwd, + Rule::OsPathExists, + Rule::OsPathExpanduser, + Rule::OsPathIsdir, + Rule::OsPathIsfile, + Rule::OsPathIslink, + Rule::OsReadlink, + Rule::OsStat, + Rule::OsPathIsabs, + Rule::OsPathJoin, + Rule::OsPathBasename, + Rule::OsPathSamefile, + Rule::OsPathSplitext, + Rule::BuiltinOpen, + Rule::PyPath, + Rule::OsPathGetsize, + Rule::OsPathGetatime, + Rule::OsPathGetmtime, + Rule::OsPathGetctime, + ]) { + flake8_use_pathlib::rules::replaceable_by_pathlib(checker, func); + } + if checker.enabled(Rule::PathConstructorCurrentDirectory) { + flake8_use_pathlib::rules::path_constructor_current_directory(checker, expr, func); + } + if checker.enabled(Rule::OsSepSplit) { + flake8_use_pathlib::rules::os_sep_split(checker, func, args, keywords); + } + if checker.enabled(Rule::NumpyLegacyRandom) { + numpy::rules::legacy_random(checker, func); + } + if checker.any_enabled(&[ + Rule::LoggingStringFormat, + Rule::LoggingPercentFormat, + Rule::LoggingStringConcat, + Rule::LoggingFString, + Rule::LoggingWarn, + Rule::LoggingExtraAttrClash, + Rule::LoggingExcInfo, + Rule::LoggingRedundantExcInfo, + ]) { + flake8_logging_format::rules::logging_call(checker, func, args, keywords); + } + if checker.any_enabled(&[Rule::LoggingTooFewArgs, Rule::LoggingTooManyArgs]) { + pylint::rules::logging_call(checker, func, args, keywords); + } + if checker.enabled(Rule::DjangoLocalsInRenderFunction) { + flake8_django::rules::locals_in_render_function(checker, func, args, keywords); + } + if checker.is_stub && checker.enabled(Rule::UnsupportedMethodCallOnAll) { + flake8_pyi::rules::unsupported_method_call_on_all(checker, func); + } + } + Expr::Dict(ast::ExprDict { + keys, + values, + range: _, + }) => { + if checker.any_enabled(&[ + Rule::MultiValueRepeatedKeyLiteral, + Rule::MultiValueRepeatedKeyVariable, + ]) { + pyflakes::rules::repeated_keys(checker, keys, values); + } + if checker.enabled(Rule::UnnecessarySpread) { + flake8_pie::rules::unnecessary_spread(checker, keys, values); + } + } + Expr::Set(ast::ExprSet { elts, range: _ }) => { + if checker.enabled(Rule::DuplicateValue) { + flake8_bugbear::rules::duplicate_value(checker, elts); + } + } + Expr::Yield(_) => { + if checker.enabled(Rule::YieldOutsideFunction) { + pyflakes::rules::yield_outside_function(checker, expr); + } + if checker.enabled(Rule::YieldInInit) { + pylint::rules::yield_in_init(checker, expr); + } + } + Expr::YieldFrom(yield_from) => { + if checker.enabled(Rule::YieldOutsideFunction) { + pyflakes::rules::yield_outside_function(checker, expr); + } + if checker.enabled(Rule::YieldInInit) { + pylint::rules::yield_in_init(checker, expr); + } + if checker.enabled(Rule::YieldFromInAsyncFunction) { + pylint::rules::yield_from_in_async_function(checker, yield_from); + } + } + Expr::Await(_) => { + if checker.enabled(Rule::YieldOutsideFunction) { + pyflakes::rules::yield_outside_function(checker, expr); + } + if checker.enabled(Rule::AwaitOutsideAsync) { + pylint::rules::await_outside_async(checker, expr); + } + } + Expr::JoinedStr(ast::ExprJoinedStr { values, range: _ }) => { + if checker.enabled(Rule::FStringMissingPlaceholders) { + pyflakes::rules::f_string_missing_placeholders(expr, values, checker); + } + if checker.enabled(Rule::HardcodedSQLExpression) { + flake8_bandit::rules::hardcoded_sql_expression(checker, expr); + } + if checker.enabled(Rule::ExplicitFStringTypeConversion) { + ruff::rules::explicit_f_string_type_conversion(checker, expr, values); + } + } + Expr::BinOp(ast::ExprBinOp { + left, + op: Operator::RShift, + .. + }) => { + if checker.enabled(Rule::InvalidPrintSyntax) { + pyflakes::rules::invalid_print_syntax(checker, left); + } + } + Expr::BinOp(ast::ExprBinOp { + left, + op: Operator::Mod, + right, + range: _, + }) => { + if let Expr::Constant(ast::ExprConstant { + value: Constant::Str(value), + .. + }) = left.as_ref() + { + if checker.any_enabled(&[ + Rule::PercentFormatInvalidFormat, + Rule::PercentFormatExpectedMapping, + Rule::PercentFormatExpectedSequence, + Rule::PercentFormatExtraNamedArguments, + Rule::PercentFormatMissingArgument, + Rule::PercentFormatMixedPositionalAndNamed, + Rule::PercentFormatPositionalCountMismatch, + Rule::PercentFormatStarRequiresSequence, + Rule::PercentFormatUnsupportedFormatCharacter, + ]) { + let location = expr.range(); + match pyflakes::cformat::CFormatSummary::try_from(value.as_str()) { + Err(CFormatError { + typ: CFormatErrorType::UnsupportedFormatChar(c), + .. + }) => { + if checker.enabled(Rule::PercentFormatUnsupportedFormatCharacter) { + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::PercentFormatUnsupportedFormatCharacter { + char: c, + }, + location, + )); + } + } + Err(e) => { + if checker.enabled(Rule::PercentFormatInvalidFormat) { + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::PercentFormatInvalidFormat { + message: e.to_string(), + }, + location, + )); + } + } + Ok(summary) => { + if checker.enabled(Rule::PercentFormatExpectedMapping) { + pyflakes::rules::percent_format_expected_mapping( + checker, &summary, right, location, + ); + } + if checker.enabled(Rule::PercentFormatExpectedSequence) { + pyflakes::rules::percent_format_expected_sequence( + checker, &summary, right, location, + ); + } + if checker.enabled(Rule::PercentFormatExtraNamedArguments) { + pyflakes::rules::percent_format_extra_named_arguments( + checker, &summary, right, location, + ); + } + if checker.enabled(Rule::PercentFormatMissingArgument) { + pyflakes::rules::percent_format_missing_arguments( + checker, &summary, right, location, + ); + } + if checker.enabled(Rule::PercentFormatMixedPositionalAndNamed) { + pyflakes::rules::percent_format_mixed_positional_and_named( + checker, &summary, location, + ); + } + if checker.enabled(Rule::PercentFormatPositionalCountMismatch) { + pyflakes::rules::percent_format_positional_count_mismatch( + checker, &summary, right, location, + ); + } + if checker.enabled(Rule::PercentFormatStarRequiresSequence) { + pyflakes::rules::percent_format_star_requires_sequence( + checker, &summary, right, location, + ); + } + } + } + } + if checker.enabled(Rule::PrintfStringFormatting) { + pyupgrade::rules::printf_string_formatting( + checker, + expr, + right, + checker.locator, + ); + } + if checker.enabled(Rule::BadStringFormatType) { + pylint::rules::bad_string_format_type(checker, expr, right); + } + if checker.enabled(Rule::HardcodedSQLExpression) { + flake8_bandit::rules::hardcoded_sql_expression(checker, expr); + } + } + } + Expr::BinOp(ast::ExprBinOp { + op: Operator::Add, .. + }) => { + if checker.enabled(Rule::ExplicitStringConcatenation) { + if let Some(diagnostic) = flake8_implicit_str_concat::rules::explicit(expr) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::CollectionLiteralConcatenation) { + ruff::rules::collection_literal_concatenation(checker, expr); + } + if checker.enabled(Rule::HardcodedSQLExpression) { + flake8_bandit::rules::hardcoded_sql_expression(checker, expr); + } + } + Expr::BinOp(ast::ExprBinOp { + op: Operator::BitOr, + .. + }) => { + // Ex) `str | None` + if checker.enabled(Rule::FutureRequiredTypeAnnotation) { + if !checker.is_stub + && checker.settings.target_version < PythonVersion::Py310 + && !checker.semantic.future_annotations() + && checker.semantic.in_annotation() + { + flake8_future_annotations::rules::future_required_type_annotation( + checker, + expr, + flake8_future_annotations::rules::Reason::PEP604, + ); + } + } + if checker.is_stub { + if checker.enabled(Rule::DuplicateUnionMember) + && checker.semantic.in_type_definition() + // Avoid duplicate checks if the parent is an `|` + && !matches!( + checker.semantic.expr_parent(), + Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) + ) + { + flake8_pyi::rules::duplicate_union_member(checker, expr); + } + if checker.enabled(Rule::UnnecessaryLiteralUnion) + // Avoid duplicate checks if the parent is an `|` + && !matches!( + checker.semantic.expr_parent(), + Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) + ) + { + flake8_pyi::rules::unnecessary_literal_union(checker, expr); + } + } + } + Expr::UnaryOp(ast::ExprUnaryOp { + op, + operand, + range: _, + }) => { + let check_not_in = checker.enabled(Rule::NotInTest); + let check_not_is = checker.enabled(Rule::NotIsTest); + if check_not_in || check_not_is { + pycodestyle::rules::not_tests( + checker, + expr, + *op, + operand, + check_not_in, + check_not_is, + ); + } + if checker.enabled(Rule::UnaryPrefixIncrementDecrement) { + flake8_bugbear::rules::unary_prefix_increment_decrement( + checker, expr, *op, operand, + ); + } + if checker.enabled(Rule::NegateEqualOp) { + flake8_simplify::rules::negation_with_equal_op(checker, expr, *op, operand); + } + if checker.enabled(Rule::NegateNotEqualOp) { + flake8_simplify::rules::negation_with_not_equal_op(checker, expr, *op, operand); + } + if checker.enabled(Rule::DoubleNegation) { + flake8_simplify::rules::double_negation(checker, expr, *op, operand); + } + } + Expr::Compare(ast::ExprCompare { + left, + ops, + comparators, + range: _, + }) => { + let check_none_comparisons = checker.enabled(Rule::NoneComparison); + let check_true_false_comparisons = checker.enabled(Rule::TrueFalseComparison); + if check_none_comparisons || check_true_false_comparisons { + pycodestyle::rules::literal_comparisons( + checker, + expr, + left, + ops, + comparators, + check_none_comparisons, + check_true_false_comparisons, + ); + } + if checker.enabled(Rule::IsLiteral) { + pyflakes::rules::invalid_literal_comparison(checker, left, ops, comparators, expr); + } + if checker.enabled(Rule::TypeComparison) { + pycodestyle::rules::type_comparison(checker, expr, ops, comparators); + } + if checker.any_enabled(&[ + Rule::SysVersionCmpStr3, + Rule::SysVersionInfo0Eq3, + Rule::SysVersionInfo1CmpInt, + Rule::SysVersionInfoMinorCmpInt, + Rule::SysVersionCmpStr10, + ]) { + flake8_2020::rules::compare(checker, left, ops, comparators); + } + if checker.enabled(Rule::HardcodedPasswordString) { + flake8_bandit::rules::compare_to_hardcoded_password_string( + checker, + left, + comparators, + ); + } + if checker.enabled(Rule::ComparisonWithItself) { + pylint::rules::comparison_with_itself(checker, left, ops, comparators); + } + if checker.enabled(Rule::ComparisonOfConstant) { + pylint::rules::comparison_of_constant(checker, left, ops, comparators); + } + if checker.enabled(Rule::CompareToEmptyString) { + pylint::rules::compare_to_empty_string(checker, left, ops, comparators); + } + if checker.enabled(Rule::MagicValueComparison) { + pylint::rules::magic_value_comparison(checker, left, comparators); + } + if checker.enabled(Rule::InDictKeys) { + flake8_simplify::rules::key_in_dict_compare(checker, expr, left, ops, comparators); + } + if checker.enabled(Rule::YodaConditions) { + flake8_simplify::rules::yoda_conditions(checker, expr, left, ops, comparators); + } + if checker.enabled(Rule::PandasNuniqueConstantSeriesCheck) { + pandas_vet::rules::nunique_constant_series_check( + checker, + expr, + left, + ops, + comparators, + ); + } + } + Expr::Constant(ast::ExprConstant { + value: Constant::Int(_) | Constant::Float(_) | Constant::Complex { .. }, + kind: _, + range: _, + }) => { + if checker.is_stub && checker.enabled(Rule::NumericLiteralTooLong) { + flake8_pyi::rules::numeric_literal_too_long(checker, expr); + } + } + Expr::Constant(ast::ExprConstant { + value: Constant::Bytes(_), + kind: _, + range: _, + }) => { + if checker.is_stub && checker.enabled(Rule::StringOrBytesTooLong) { + flake8_pyi::rules::string_or_bytes_too_long(checker, expr); + } + } + Expr::Constant(ast::ExprConstant { + value: Constant::Str(value), + kind, + range: _, + }) => { + if checker.enabled(Rule::HardcodedBindAllInterfaces) { + if let Some(diagnostic) = + flake8_bandit::rules::hardcoded_bind_all_interfaces(value, expr.range()) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::HardcodedTempFile) { + if let Some(diagnostic) = flake8_bandit::rules::hardcoded_tmp_directory( + expr, + value, + &checker.settings.flake8_bandit.hardcoded_tmp_directory, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::UnicodeKindPrefix) { + pyupgrade::rules::unicode_kind_prefix(checker, expr, kind.as_deref()); + } + if checker.is_stub { + if checker.enabled(Rule::StringOrBytesTooLong) { + flake8_pyi::rules::string_or_bytes_too_long(checker, expr); + } + } + } + Expr::Lambda( + lambda @ ast::ExprLambda { + args: _, + body: _, + range: _, + }, + ) => { + if checker.enabled(Rule::ReimplementedListBuiltin) { + flake8_pie::rules::reimplemented_list_builtin(checker, lambda); + } + } + Expr::IfExp(ast::ExprIfExp { + test, + body, + orelse, + range: _, + }) => { + if checker.enabled(Rule::IfExprWithTrueFalse) { + flake8_simplify::rules::explicit_true_false_in_ifexpr( + checker, expr, test, body, orelse, + ); + } + if checker.enabled(Rule::IfExprWithFalseTrue) { + flake8_simplify::rules::explicit_false_true_in_ifexpr( + checker, expr, test, body, orelse, + ); + } + if checker.enabled(Rule::IfExprWithTwistedArms) { + flake8_simplify::rules::twisted_arms_in_ifexpr(checker, expr, test, body, orelse); + } + } + Expr::ListComp(ast::ExprListComp { + elt, + generators, + range: _, + }) + | Expr::SetComp(ast::ExprSetComp { + elt, + generators, + range: _, + }) => { + if checker.enabled(Rule::UnnecessaryComprehension) { + flake8_comprehensions::rules::unnecessary_list_set_comprehension( + checker, expr, elt, generators, + ); + } + if checker.enabled(Rule::FunctionUsesLoopVariable) { + flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Expr(expr)); + } + if checker.enabled(Rule::InDictKeys) { + for generator in generators { + flake8_simplify::rules::key_in_dict_for( + checker, + &generator.target, + &generator.iter, + ); + } + } + if checker.enabled(Rule::IterationOverSet) { + for generator in generators { + pylint::rules::iteration_over_set(checker, &generator.iter); + } + } + } + Expr::DictComp(ast::ExprDictComp { + key, + value, + generators, + range: _, + }) => { + if checker.enabled(Rule::UnnecessaryComprehension) { + flake8_comprehensions::rules::unnecessary_dict_comprehension( + checker, expr, key, value, generators, + ); + } + if checker.enabled(Rule::FunctionUsesLoopVariable) { + flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Expr(expr)); + } + if checker.enabled(Rule::InDictKeys) { + for generator in generators { + flake8_simplify::rules::key_in_dict_for( + checker, + &generator.target, + &generator.iter, + ); + } + } + if checker.enabled(Rule::IterationOverSet) { + for generator in generators { + pylint::rules::iteration_over_set(checker, &generator.iter); + } + } + if checker.enabled(Rule::StaticKeyDictComprehension) { + ruff::rules::static_key_dict_comprehension(checker, key); + } + } + Expr::GeneratorExp(ast::ExprGeneratorExp { + generators, + elt: _, + range: _, + }) => { + if checker.enabled(Rule::FunctionUsesLoopVariable) { + flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Expr(expr)); + } + if checker.enabled(Rule::InDictKeys) { + for generator in generators { + flake8_simplify::rules::key_in_dict_for( + checker, + &generator.target, + &generator.iter, + ); + } + } + if checker.enabled(Rule::IterationOverSet) { + for generator in generators { + pylint::rules::iteration_over_set(checker, &generator.iter); + } + } + } + Expr::BoolOp( + bool_op @ ast::ExprBoolOp { + op, + values, + range: _, + }, + ) => { + if checker.enabled(Rule::RepeatedIsinstanceCalls) { + pylint::rules::repeated_isinstance_calls(checker, expr, *op, values); + } + if checker.enabled(Rule::MultipleStartsEndsWith) { + flake8_pie::rules::multiple_starts_ends_with(checker, expr); + } + if checker.enabled(Rule::DuplicateIsinstanceCall) { + flake8_simplify::rules::duplicate_isinstance_call(checker, expr); + } + if checker.enabled(Rule::CompareWithTuple) { + flake8_simplify::rules::compare_with_tuple(checker, expr); + } + if checker.enabled(Rule::ExprAndNotExpr) { + flake8_simplify::rules::expr_and_not_expr(checker, expr); + } + if checker.enabled(Rule::ExprOrNotExpr) { + flake8_simplify::rules::expr_or_not_expr(checker, expr); + } + if checker.enabled(Rule::ExprOrTrue) { + flake8_simplify::rules::expr_or_true(checker, expr); + } + if checker.enabled(Rule::ExprAndFalse) { + flake8_simplify::rules::expr_and_false(checker, expr); + } + if checker.enabled(Rule::RepeatedEqualityComparisonTarget) { + pylint::rules::repeated_equality_comparison_target(checker, bool_op); + } + } + _ => {} + }; +} diff --git a/crates/ruff/src/checkers/ast/analyze/mod.rs b/crates/ruff/src/checkers/ast/analyze/mod.rs new file mode 100644 index 0000000000..08798f990d --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/mod.rs @@ -0,0 +1,25 @@ +pub(super) use argument::argument; +pub(super) use arguments::arguments; +pub(super) use bindings::bindings; +pub(super) use deferred_for_loops::deferred_for_loops; +pub(super) use deferred_scopes::deferred_scopes; +pub(super) use definitions::definitions; +pub(super) use except_handler::except_handler; +pub(super) use expression::expression; +pub(super) use module::module; +pub(super) use statement::statement; +pub(super) use suite::suite; +pub(super) use unresolved_references::unresolved_references; + +mod argument; +mod arguments; +mod bindings; +mod deferred_for_loops; +mod deferred_scopes; +mod definitions; +mod except_handler; +mod expression; +mod module; +mod statement; +mod suite; +mod unresolved_references; diff --git a/crates/ruff/src/checkers/ast/analyze/module.rs b/crates/ruff/src/checkers/ast/analyze/module.rs new file mode 100644 index 0000000000..6d678961d7 --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/module.rs @@ -0,0 +1,12 @@ +use rustpython_parser::ast::Suite; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::flake8_bugbear; + +/// Run lint rules over a module. +pub(crate) fn module(suite: &Suite, checker: &mut Checker) { + if checker.enabled(Rule::FStringDocstring) { + flake8_bugbear::rules::f_string_docstring(checker, suite); + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/statement.rs b/crates/ruff/src/checkers/ast/analyze/statement.rs new file mode 100644 index 0000000000..23faed4f22 --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/statement.rs @@ -0,0 +1,1424 @@ +use rustpython_parser::ast::{self, Expr, Ranged, Stmt}; + +use ruff_diagnostics::Diagnostic; +use ruff_python_ast::helpers; + +use ruff_python_ast::types::Node; +use ruff_python_semantic::analyze::typing; +use ruff_python_semantic::ScopeKind; + +use crate::checkers::ast::Checker; +use crate::registry::Rule; +use crate::rules::{ + airflow, flake8_bandit, flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_debugger, + flake8_django, flake8_errmsg, flake8_import_conventions, flake8_pie, flake8_pyi, + flake8_pytest_style, flake8_raise, flake8_return, flake8_simplify, flake8_slots, + flake8_tidy_imports, flake8_type_checking, mccabe, pandas_vet, pep8_naming, perflint, + pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, tryceratops, +}; +use crate::settings::types::PythonVersion; + +/// Run lint rules over a [`Stmt`] syntax node. +pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { + match stmt { + Stmt::Global(ast::StmtGlobal { names, range: _ }) => { + if checker.enabled(Rule::AmbiguousVariableName) { + checker.diagnostics.extend(names.iter().filter_map(|name| { + pycodestyle::rules::ambiguous_variable_name(name, name.range()) + })); + } + } + Stmt::Nonlocal(ast::StmtNonlocal { names, range: _ }) => { + if checker.enabled(Rule::AmbiguousVariableName) { + checker.diagnostics.extend(names.iter().filter_map(|name| { + pycodestyle::rules::ambiguous_variable_name(name, name.range()) + })); + } + + if checker.enabled(Rule::NonlocalWithoutBinding) { + if !checker.semantic.scope_id.is_global() { + for name in names { + if checker.semantic.nonlocal(name).is_none() { + checker.diagnostics.push(Diagnostic::new( + pylint::rules::NonlocalWithoutBinding { + name: name.to_string(), + }, + name.range(), + )); + } + } + } + } + } + Stmt::Break(_) => { + if checker.enabled(Rule::BreakOutsideLoop) { + if let Some(diagnostic) = pyflakes::rules::break_outside_loop( + stmt, + &mut checker.semantic.parents().skip(1), + ) { + checker.diagnostics.push(diagnostic); + } + } + } + Stmt::Continue(_) => { + if checker.enabled(Rule::ContinueOutsideLoop) { + if let Some(diagnostic) = pyflakes::rules::continue_outside_loop( + stmt, + &mut checker.semantic.parents().skip(1), + ) { + checker.diagnostics.push(diagnostic); + } + } + } + Stmt::FunctionDef(ast::StmtFunctionDef { + name, + decorator_list, + returns, + args, + body, + .. + }) + | Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef { + name, + decorator_list, + returns, + args, + body, + .. + }) => { + if checker.enabled(Rule::DjangoNonLeadingReceiverDecorator) { + flake8_django::rules::non_leading_receiver_decorator(checker, decorator_list); + } + if checker.enabled(Rule::AmbiguousFunctionName) { + if let Some(diagnostic) = pycodestyle::rules::ambiguous_function_name(name) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::InvalidStrReturnType) { + pylint::rules::invalid_str_return(checker, name, body); + } + if checker.enabled(Rule::InvalidFunctionName) { + if let Some(diagnostic) = pep8_naming::rules::invalid_function_name( + stmt, + name, + decorator_list, + &checker.settings.pep8_naming.ignore_names, + &checker.semantic, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::InvalidFirstArgumentNameForClassMethod) { + if let Some(diagnostic) = + pep8_naming::rules::invalid_first_argument_name_for_class_method( + checker, + checker.semantic.scope(), + name, + decorator_list, + args, + ) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::InvalidFirstArgumentNameForMethod) { + if let Some(diagnostic) = pep8_naming::rules::invalid_first_argument_name_for_method( + checker, + checker.semantic.scope(), + name, + decorator_list, + args, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.is_stub { + if checker.enabled(Rule::PassStatementStubBody) { + flake8_pyi::rules::pass_statement_stub_body(checker, body); + } + if checker.enabled(Rule::NonEmptyStubBody) { + flake8_pyi::rules::non_empty_stub_body(checker, body); + } + if checker.enabled(Rule::StubBodyMultipleStatements) { + flake8_pyi::rules::stub_body_multiple_statements(checker, stmt, body); + } + if checker.enabled(Rule::AnyEqNeAnnotation) { + flake8_pyi::rules::any_eq_ne_annotation(checker, name, args); + } + if checker.enabled(Rule::NonSelfReturnType) { + flake8_pyi::rules::non_self_return_type( + checker, + stmt, + name, + decorator_list, + returns.as_ref().map(AsRef::as_ref), + args, + stmt.is_async_function_def_stmt(), + ); + } + if checker.enabled(Rule::StrOrReprDefinedInStub) { + flake8_pyi::rules::str_or_repr_defined_in_stub(checker, stmt); + } + if checker.enabled(Rule::NoReturnArgumentAnnotationInStub) { + flake8_pyi::rules::no_return_argument_annotation(checker, args); + } + if checker.enabled(Rule::BadExitAnnotation) { + flake8_pyi::rules::bad_exit_annotation( + checker, + stmt.is_async_function_def_stmt(), + name, + args, + ); + } + if checker.enabled(Rule::RedundantNumericUnion) { + flake8_pyi::rules::redundant_numeric_union(checker, args); + } + } + if checker.enabled(Rule::DunderFunctionName) { + if let Some(diagnostic) = pep8_naming::rules::dunder_function_name( + checker.semantic.scope(), + stmt, + name, + &checker.settings.pep8_naming.ignore_names, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::GlobalStatement) { + pylint::rules::global_statement(checker, name); + } + if checker.enabled(Rule::LRUCacheWithoutParameters) { + if checker.settings.target_version >= PythonVersion::Py38 { + pyupgrade::rules::lru_cache_without_parameters(checker, decorator_list); + } + } + if checker.enabled(Rule::LRUCacheWithMaxsizeNone) { + if checker.settings.target_version >= PythonVersion::Py39 { + pyupgrade::rules::lru_cache_with_maxsize_none(checker, decorator_list); + } + } + if checker.enabled(Rule::CachedInstanceMethod) { + flake8_bugbear::rules::cached_instance_method(checker, decorator_list); + } + if checker.any_enabled(&[ + Rule::UnnecessaryReturnNone, + Rule::ImplicitReturnValue, + Rule::ImplicitReturn, + Rule::UnnecessaryAssign, + Rule::SuperfluousElseReturn, + Rule::SuperfluousElseRaise, + Rule::SuperfluousElseContinue, + Rule::SuperfluousElseBreak, + ]) { + flake8_return::rules::function(checker, body, returns.as_ref().map(AsRef::as_ref)); + } + if checker.enabled(Rule::UselessReturn) { + pylint::rules::useless_return( + checker, + stmt, + body, + returns.as_ref().map(AsRef::as_ref), + ); + } + if checker.enabled(Rule::ComplexStructure) { + if let Some(diagnostic) = mccabe::rules::function_is_too_complex( + stmt, + name, + body, + checker.settings.mccabe.max_complexity, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::HardcodedPasswordDefault) { + flake8_bandit::rules::hardcoded_password_default(checker, args); + } + if checker.enabled(Rule::PropertyWithParameters) { + pylint::rules::property_with_parameters(checker, stmt, decorator_list, args); + } + if checker.enabled(Rule::TooManyArguments) { + pylint::rules::too_many_arguments(checker, args, stmt); + } + if checker.enabled(Rule::TooManyReturnStatements) { + if let Some(diagnostic) = pylint::rules::too_many_return_statements( + stmt, + body, + checker.settings.pylint.max_returns, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::TooManyBranches) { + if let Some(diagnostic) = pylint::rules::too_many_branches( + stmt, + body, + checker.settings.pylint.max_branches, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::TooManyStatements) { + if let Some(diagnostic) = pylint::rules::too_many_statements( + stmt, + body, + checker.settings.pylint.max_statements, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.any_enabled(&[ + Rule::PytestFixtureIncorrectParenthesesStyle, + Rule::PytestFixturePositionalArgs, + Rule::PytestExtraneousScopeFunction, + Rule::PytestMissingFixtureNameUnderscore, + Rule::PytestIncorrectFixtureNameUnderscore, + Rule::PytestFixtureParamWithoutValue, + Rule::PytestDeprecatedYieldFixture, + Rule::PytestFixtureFinalizerCallback, + Rule::PytestUselessYieldFixture, + Rule::PytestUnnecessaryAsyncioMarkOnFixture, + Rule::PytestErroneousUseFixturesOnFixture, + ]) { + flake8_pytest_style::rules::fixture( + checker, + stmt, + name, + args, + decorator_list, + body, + ); + } + if checker.any_enabled(&[ + Rule::PytestParametrizeNamesWrongType, + Rule::PytestParametrizeValuesWrongType, + ]) { + flake8_pytest_style::rules::parametrize(checker, decorator_list); + } + if checker.any_enabled(&[ + Rule::PytestIncorrectMarkParenthesesStyle, + Rule::PytestUseFixturesWithoutParameters, + ]) { + flake8_pytest_style::rules::marks(checker, decorator_list); + } + if checker.enabled(Rule::BooleanPositionalArgInFunctionDefinition) { + flake8_boolean_trap::rules::check_positional_boolean_in_def( + checker, + name, + decorator_list, + args, + ); + } + if checker.enabled(Rule::BooleanDefaultValueInFunctionDefinition) { + flake8_boolean_trap::rules::check_boolean_default_value_in_function_definition( + checker, + name, + decorator_list, + args, + ); + } + if checker.enabled(Rule::UnexpectedSpecialMethodSignature) { + pylint::rules::unexpected_special_method_signature( + checker, + stmt, + name, + decorator_list, + args, + ); + } + if checker.enabled(Rule::FStringDocstring) { + flake8_bugbear::rules::f_string_docstring(checker, body); + } + if checker.enabled(Rule::YieldInForLoop) { + pyupgrade::rules::yield_in_for_loop(checker, stmt); + } + if let ScopeKind::Class(class_def) = checker.semantic.scope().kind { + if checker.enabled(Rule::BuiltinAttributeShadowing) { + flake8_builtins::rules::builtin_attribute_shadowing( + checker, + class_def, + name, + name.range(), + ); + } + } else { + if checker.enabled(Rule::BuiltinVariableShadowing) { + flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range()); + } + } + #[cfg(feature = "unreachable-code")] + if checker.enabled(Rule::UnreachableCode) { + checker + .diagnostics + .extend(ruff::rules::unreachable::in_function(name, body)); + } + } + Stmt::Return(_) => { + if checker.enabled(Rule::ReturnOutsideFunction) { + pyflakes::rules::return_outside_function(checker, stmt); + } + if checker.enabled(Rule::ReturnInInit) { + pylint::rules::return_in_init(checker, stmt); + } + } + Stmt::ClassDef( + class_def @ ast::StmtClassDef { + name, + bases, + keywords, + type_params: _, + decorator_list, + body, + range: _, + }, + ) => { + if checker.enabled(Rule::DjangoNullableModelStringField) { + flake8_django::rules::nullable_model_string_field(checker, body); + } + if checker.enabled(Rule::DjangoExcludeWithModelForm) { + if let Some(diagnostic) = + flake8_django::rules::exclude_with_model_form(checker, bases, body) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::DjangoAllWithModelForm) { + if let Some(diagnostic) = + flake8_django::rules::all_with_model_form(checker, bases, body) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::DjangoUnorderedBodyContentInModel) { + flake8_django::rules::unordered_body_content_in_model(checker, bases, body); + } + if !checker.is_stub { + if checker.enabled(Rule::DjangoModelWithoutDunderStr) { + flake8_django::rules::model_without_dunder_str(checker, class_def); + } + } + if checker.enabled(Rule::GlobalStatement) { + pylint::rules::global_statement(checker, name); + } + if checker.enabled(Rule::UselessObjectInheritance) { + pyupgrade::rules::useless_object_inheritance(checker, class_def); + } + if checker.enabled(Rule::UnnecessaryClassParentheses) { + pyupgrade::rules::unnecessary_class_parentheses(checker, class_def); + } + if checker.enabled(Rule::AmbiguousClassName) { + if let Some(diagnostic) = pycodestyle::rules::ambiguous_class_name(name) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::InvalidClassName) { + if let Some(diagnostic) = pep8_naming::rules::invalid_class_name( + stmt, + name, + &checker.settings.pep8_naming.ignore_names, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::ErrorSuffixOnExceptionName) { + if let Some(diagnostic) = pep8_naming::rules::error_suffix_on_exception_name( + stmt, + bases, + name, + &checker.settings.pep8_naming.ignore_names, + ) { + checker.diagnostics.push(diagnostic); + } + } + if !checker.is_stub { + if checker.any_enabled(&[ + Rule::AbstractBaseClassWithoutAbstractMethod, + Rule::EmptyMethodWithoutAbstractDecorator, + ]) { + flake8_bugbear::rules::abstract_base_class( + checker, stmt, name, bases, keywords, body, + ); + } + } + if checker.is_stub { + if checker.enabled(Rule::PassStatementStubBody) { + flake8_pyi::rules::pass_statement_stub_body(checker, body); + } + if checker.enabled(Rule::PassInClassBody) { + flake8_pyi::rules::pass_in_class_body(checker, stmt, body); + } + if checker.enabled(Rule::EllipsisInNonEmptyClassBody) { + flake8_pyi::rules::ellipsis_in_non_empty_class_body(checker, stmt, body); + } + } + if checker.enabled(Rule::PytestIncorrectMarkParenthesesStyle) { + flake8_pytest_style::rules::marks(checker, decorator_list); + } + if checker.enabled(Rule::DuplicateClassFieldDefinition) { + flake8_pie::rules::duplicate_class_field_definition(checker, stmt, body); + } + if checker.enabled(Rule::NonUniqueEnums) { + flake8_pie::rules::non_unique_enums(checker, stmt, body); + } + if checker.enabled(Rule::MutableClassDefault) { + ruff::rules::mutable_class_default(checker, class_def); + } + if checker.enabled(Rule::MutableDataclassDefault) { + ruff::rules::mutable_dataclass_default(checker, class_def); + } + if checker.enabled(Rule::FunctionCallInDataclassDefaultArgument) { + ruff::rules::function_call_in_dataclass_default(checker, class_def); + } + if checker.enabled(Rule::FStringDocstring) { + flake8_bugbear::rules::f_string_docstring(checker, body); + } + if checker.enabled(Rule::BuiltinVariableShadowing) { + flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range()); + } + if checker.enabled(Rule::DuplicateBases) { + pylint::rules::duplicate_bases(checker, name, bases); + } + if checker.enabled(Rule::NoSlotsInStrSubclass) { + flake8_slots::rules::no_slots_in_str_subclass(checker, stmt, class_def); + } + if checker.enabled(Rule::NoSlotsInTupleSubclass) { + flake8_slots::rules::no_slots_in_tuple_subclass(checker, stmt, class_def); + } + if checker.enabled(Rule::NoSlotsInNamedtupleSubclass) { + flake8_slots::rules::no_slots_in_namedtuple_subclass(checker, stmt, class_def); + } + if checker.enabled(Rule::SingleStringSlots) { + pylint::rules::single_string_slots(checker, class_def); + } + } + Stmt::Import(ast::StmtImport { names, range: _ }) => { + if checker.enabled(Rule::MultipleImportsOnOneLine) { + pycodestyle::rules::multiple_imports_on_one_line(checker, stmt, names); + } + if checker.enabled(Rule::ModuleImportNotAtTopOfFile) { + pycodestyle::rules::module_import_not_at_top_of_file( + checker, + stmt, + checker.locator, + ); + } + if checker.enabled(Rule::GlobalStatement) { + for name in names { + if let Some(asname) = name.asname.as_ref() { + pylint::rules::global_statement(checker, asname); + } else { + pylint::rules::global_statement(checker, &name.name); + } + } + } + if checker.enabled(Rule::DeprecatedCElementTree) { + pyupgrade::rules::deprecated_c_element_tree(checker, stmt); + } + if checker.enabled(Rule::DeprecatedMockImport) { + pyupgrade::rules::deprecated_mock_import(checker, stmt); + } + + for alias in names { + if let Some(asname) = &alias.asname { + if checker.enabled(Rule::BuiltinVariableShadowing) { + flake8_builtins::rules::builtin_variable_shadowing( + checker, + asname, + asname.range(), + ); + } + } + if checker.enabled(Rule::Debugger) { + if let Some(diagnostic) = + flake8_debugger::rules::debugger_import(stmt, None, &alias.name) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::BannedApi) { + flake8_tidy_imports::rules::name_or_parent_is_banned( + checker, + &alias.name, + alias, + ); + } + if !checker.is_stub { + if checker.enabled(Rule::UselessImportAlias) { + pylint::rules::useless_import_alias(checker, alias); + } + } + if checker.enabled(Rule::ManualFromImport) { + pylint::rules::manual_from_import(checker, stmt, alias, names); + } + if checker.enabled(Rule::ImportSelf) { + if let Some(diagnostic) = pylint::rules::import_self(alias, checker.module_path) + { + checker.diagnostics.push(diagnostic); + } + } + if let Some(asname) = &alias.asname { + let name = alias.name.split('.').last().unwrap(); + if checker.enabled(Rule::ConstantImportedAsNonConstant) { + if let Some(diagnostic) = + pep8_naming::rules::constant_imported_as_non_constant( + name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::LowercaseImportedAsNonLowercase) { + if let Some(diagnostic) = + pep8_naming::rules::lowercase_imported_as_non_lowercase( + name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::CamelcaseImportedAsLowercase) { + if let Some(diagnostic) = + pep8_naming::rules::camelcase_imported_as_lowercase( + name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::CamelcaseImportedAsConstant) { + if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_constant( + name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::CamelcaseImportedAsAcronym) { + if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_acronym( + name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) { + checker.diagnostics.push(diagnostic); + } + } + } + if checker.enabled(Rule::BannedImportAlias) { + if let Some(asname) = &alias.asname { + if let Some(diagnostic) = + flake8_import_conventions::rules::banned_import_alias( + stmt, + &alias.name, + asname, + &checker.settings.flake8_import_conventions.banned_aliases, + ) + { + checker.diagnostics.push(diagnostic); + } + } + } + if checker.enabled(Rule::PytestIncorrectPytestImport) { + if let Some(diagnostic) = flake8_pytest_style::rules::import( + stmt, + &alias.name, + alias.asname.as_deref(), + ) { + checker.diagnostics.push(diagnostic); + } + } + } + } + Stmt::ImportFrom( + import_from @ ast::StmtImportFrom { + names, + module, + level, + range: _, + }, + ) => { + let module = module.as_deref(); + let level = level.map(|level| level.to_u32()); + if checker.enabled(Rule::ModuleImportNotAtTopOfFile) { + pycodestyle::rules::module_import_not_at_top_of_file( + checker, + stmt, + checker.locator, + ); + } + if checker.enabled(Rule::GlobalStatement) { + for name in names { + if let Some(asname) = name.asname.as_ref() { + pylint::rules::global_statement(checker, asname); + } else { + pylint::rules::global_statement(checker, &name.name); + } + } + } + if checker.enabled(Rule::UnnecessaryFutureImport) { + if checker.settings.target_version >= PythonVersion::Py37 { + if let Some("__future__") = module { + pyupgrade::rules::unnecessary_future_import(checker, stmt, names); + } + } + } + if checker.enabled(Rule::DeprecatedMockImport) { + pyupgrade::rules::deprecated_mock_import(checker, stmt); + } + if checker.enabled(Rule::DeprecatedCElementTree) { + pyupgrade::rules::deprecated_c_element_tree(checker, stmt); + } + if checker.enabled(Rule::DeprecatedImport) { + pyupgrade::rules::deprecated_import(checker, stmt, names, module, level); + } + if checker.enabled(Rule::UnnecessaryBuiltinImport) { + if let Some(module) = module { + pyupgrade::rules::unnecessary_builtin_import(checker, stmt, module, names); + } + } + if checker.enabled(Rule::BannedApi) { + if let Some(module) = + helpers::resolve_imported_module_path(level, module, checker.module_path) + { + flake8_tidy_imports::rules::name_or_parent_is_banned(checker, &module, stmt); + + for alias in names { + if &alias.name == "*" { + continue; + } + flake8_tidy_imports::rules::name_is_banned( + checker, + format!("{module}.{}", alias.name), + alias, + ); + } + } + } + if checker.enabled(Rule::PytestIncorrectPytestImport) { + if let Some(diagnostic) = + flake8_pytest_style::rules::import_from(stmt, module, level) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.is_stub { + if checker.enabled(Rule::FutureAnnotationsInStub) { + flake8_pyi::rules::from_future_import(checker, import_from); + } + } + for alias in names { + if let Some("__future__") = module { + if checker.enabled(Rule::FutureFeatureNotDefined) { + pyflakes::rules::future_feature_not_defined(checker, alias); + } + if checker.enabled(Rule::LateFutureImport) { + if checker.semantic.seen_futures_boundary() { + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::LateFutureImport, + stmt.range(), + )); + } + } + } else if &alias.name == "*" { + if checker.enabled(Rule::UndefinedLocalWithNestedImportStarUsage) { + if !matches!(checker.semantic.scope().kind, ScopeKind::Module) { + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::UndefinedLocalWithNestedImportStarUsage { + name: helpers::format_import_from(level, module), + }, + stmt.range(), + )); + } + } + if checker.enabled(Rule::UndefinedLocalWithImportStar) { + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::UndefinedLocalWithImportStar { + name: helpers::format_import_from(level, module), + }, + stmt.range(), + )); + } + } else { + if let Some(asname) = &alias.asname { + if checker.enabled(Rule::BuiltinVariableShadowing) { + flake8_builtins::rules::builtin_variable_shadowing( + checker, + asname, + asname.range(), + ); + } + } + } + if checker.enabled(Rule::RelativeImports) { + if let Some(diagnostic) = flake8_tidy_imports::rules::banned_relative_import( + checker, + stmt, + level, + module, + checker.module_path, + checker.settings.flake8_tidy_imports.ban_relative_imports, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::Debugger) { + if let Some(diagnostic) = + flake8_debugger::rules::debugger_import(stmt, module, &alias.name) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::BannedImportAlias) { + if let Some(asname) = &alias.asname { + let qualified_name = + helpers::format_import_from_member(level, module, &alias.name); + if let Some(diagnostic) = + flake8_import_conventions::rules::banned_import_alias( + stmt, + &qualified_name, + asname, + &checker.settings.flake8_import_conventions.banned_aliases, + ) + { + checker.diagnostics.push(diagnostic); + } + } + } + if let Some(asname) = &alias.asname { + if checker.enabled(Rule::ConstantImportedAsNonConstant) { + if let Some(diagnostic) = + pep8_naming::rules::constant_imported_as_non_constant( + &alias.name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::LowercaseImportedAsNonLowercase) { + if let Some(diagnostic) = + pep8_naming::rules::lowercase_imported_as_non_lowercase( + &alias.name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::CamelcaseImportedAsLowercase) { + if let Some(diagnostic) = + pep8_naming::rules::camelcase_imported_as_lowercase( + &alias.name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::CamelcaseImportedAsConstant) { + if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_constant( + &alias.name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::CamelcaseImportedAsAcronym) { + if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_acronym( + &alias.name, + asname, + alias, + stmt, + &checker.settings.pep8_naming.ignore_names, + ) { + checker.diagnostics.push(diagnostic); + } + } + if !checker.is_stub { + if checker.enabled(Rule::UselessImportAlias) { + pylint::rules::useless_import_alias(checker, alias); + } + } + } + } + if checker.enabled(Rule::ImportSelf) { + if let Some(diagnostic) = + pylint::rules::import_from_self(level, module, names, checker.module_path) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::BannedImportFrom) { + if let Some(diagnostic) = flake8_import_conventions::rules::banned_import_from( + stmt, + &helpers::format_import_from(level, module), + &checker.settings.flake8_import_conventions.banned_from, + ) { + checker.diagnostics.push(diagnostic); + } + } + } + Stmt::Raise(ast::StmtRaise { exc, .. }) => { + if checker.enabled(Rule::RaiseNotImplemented) { + if let Some(expr) = exc { + pyflakes::rules::raise_not_implemented(checker, expr); + } + } + if checker.enabled(Rule::RaiseLiteral) { + if let Some(exc) = exc { + flake8_bugbear::rules::raise_literal(checker, exc); + } + } + if checker.any_enabled(&[ + Rule::RawStringInException, + Rule::FStringInException, + Rule::DotFormatInException, + ]) { + if let Some(exc) = exc { + flake8_errmsg::rules::string_in_exception(checker, stmt, exc); + } + } + if checker.enabled(Rule::OSErrorAlias) { + if let Some(item) = exc { + pyupgrade::rules::os_error_alias_raise(checker, item); + } + } + if checker.enabled(Rule::RaiseVanillaClass) { + if let Some(expr) = exc { + tryceratops::rules::raise_vanilla_class(checker, expr); + } + } + if checker.enabled(Rule::RaiseVanillaArgs) { + if let Some(expr) = exc { + tryceratops::rules::raise_vanilla_args(checker, expr); + } + } + if checker.enabled(Rule::UnnecessaryParenOnRaiseException) { + if let Some(expr) = exc { + flake8_raise::rules::unnecessary_paren_on_raise_exception(checker, expr); + } + } + } + Stmt::AugAssign(ast::StmtAugAssign { target, .. }) => { + if checker.enabled(Rule::GlobalStatement) { + if let Expr::Name(ast::ExprName { id, .. }) = target.as_ref() { + pylint::rules::global_statement(checker, id); + } + } + } + Stmt::If( + if_ @ ast::StmtIf { + test, + elif_else_clauses, + .. + }, + ) => { + if checker.enabled(Rule::EmptyTypeCheckingBlock) { + if typing::is_type_checking_block(if_, &checker.semantic) { + flake8_type_checking::rules::empty_type_checking_block(checker, if_); + } + } + if checker.enabled(Rule::IfTuple) { + pyflakes::rules::if_tuple(checker, if_); + } + if checker.enabled(Rule::CollapsibleIf) { + flake8_simplify::rules::nested_if_statements( + checker, + if_, + checker.semantic.stmt_parent(), + ); + } + if checker.enabled(Rule::IfWithSameArms) { + flake8_simplify::rules::if_with_same_arms(checker, checker.locator, if_); + } + if checker.enabled(Rule::NeedlessBool) { + flake8_simplify::rules::needless_bool(checker, stmt); + } + if checker.enabled(Rule::IfElseBlockInsteadOfDictLookup) { + flake8_simplify::rules::manual_dict_lookup(checker, if_); + } + if checker.enabled(Rule::IfElseBlockInsteadOfIfExp) { + flake8_simplify::rules::use_ternary_operator(checker, stmt); + } + if checker.enabled(Rule::IfElseBlockInsteadOfDictGet) { + flake8_simplify::rules::use_dict_get_with_default(checker, if_); + } + if checker.enabled(Rule::TypeCheckWithoutTypeError) { + tryceratops::rules::type_check_without_type_error( + checker, + if_, + checker.semantic.stmt_parent(), + ); + } + if checker.enabled(Rule::OutdatedVersionBlock) { + pyupgrade::rules::outdated_version_block(checker, if_); + } + if checker.enabled(Rule::CollapsibleElseIf) { + if let Some(diagnostic) = pylint::rules::collapsible_else_if(elif_else_clauses) { + checker.diagnostics.push(diagnostic); + } + } + if checker.is_stub { + if checker.any_enabled(&[ + Rule::UnrecognizedVersionInfoCheck, + Rule::PatchVersionComparison, + Rule::WrongTupleLengthVersionComparison, + ]) { + if let Expr::BoolOp(ast::ExprBoolOp { values, .. }) = test.as_ref() { + for value in values { + flake8_pyi::rules::unrecognized_version_info(checker, value); + } + } else { + flake8_pyi::rules::unrecognized_version_info(checker, test); + } + } + if checker.any_enabled(&[ + Rule::UnrecognizedPlatformCheck, + Rule::UnrecognizedPlatformName, + ]) { + if let Expr::BoolOp(ast::ExprBoolOp { values, .. }) = test.as_ref() { + for value in values { + flake8_pyi::rules::unrecognized_platform(checker, value); + } + } else { + flake8_pyi::rules::unrecognized_platform(checker, test); + } + } + if checker.enabled(Rule::BadVersionInfoComparison) { + if let Expr::BoolOp(ast::ExprBoolOp { values, .. }) = test.as_ref() { + for value in values { + flake8_pyi::rules::bad_version_info_comparison(checker, value); + } + } else { + flake8_pyi::rules::bad_version_info_comparison(checker, test); + } + } + if checker.enabled(Rule::ComplexIfStatementInStub) { + if let Expr::BoolOp(ast::ExprBoolOp { values, .. }) = test.as_ref() { + for value in values { + flake8_pyi::rules::complex_if_statement_in_stub(checker, value); + } + } else { + flake8_pyi::rules::complex_if_statement_in_stub(checker, test); + } + } + } + } + Stmt::Assert(ast::StmtAssert { + test, + msg, + range: _, + }) => { + if !checker.semantic.in_type_checking_block() { + if checker.enabled(Rule::Assert) { + checker + .diagnostics + .push(flake8_bandit::rules::assert_used(stmt)); + } + } + if checker.enabled(Rule::AssertTuple) { + pyflakes::rules::assert_tuple(checker, stmt, test); + } + if checker.enabled(Rule::AssertFalse) { + flake8_bugbear::rules::assert_false(checker, stmt, test, msg.as_deref()); + } + if checker.enabled(Rule::PytestAssertAlwaysFalse) { + flake8_pytest_style::rules::assert_falsy(checker, stmt, test); + } + if checker.enabled(Rule::PytestCompositeAssertion) { + flake8_pytest_style::rules::composite_condition( + checker, + stmt, + test, + msg.as_deref(), + ); + } + if checker.enabled(Rule::AssertOnStringLiteral) { + pylint::rules::assert_on_string_literal(checker, test); + } + if checker.enabled(Rule::InvalidMockAccess) { + pygrep_hooks::rules::non_existent_mock_method(checker, test); + } + } + Stmt::With(ast::StmtWith { items, body, .. }) + | Stmt::AsyncWith(ast::StmtAsyncWith { items, body, .. }) => { + if checker.enabled(Rule::AssertRaisesException) { + flake8_bugbear::rules::assert_raises_exception(checker, items); + } + if checker.enabled(Rule::PytestRaisesWithMultipleStatements) { + flake8_pytest_style::rules::complex_raises(checker, stmt, items, body); + } + if checker.enabled(Rule::MultipleWithStatements) { + flake8_simplify::rules::multiple_with_statements( + checker, + stmt, + body, + checker.semantic.stmt_parent(), + ); + } + if checker.enabled(Rule::RedefinedLoopName) { + pylint::rules::redefined_loop_name(checker, stmt); + } + } + Stmt::While(ast::StmtWhile { body, orelse, .. }) => { + if checker.enabled(Rule::FunctionUsesLoopVariable) { + flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Stmt(stmt)); + } + if checker.enabled(Rule::UselessElseOnLoop) { + pylint::rules::useless_else_on_loop(checker, stmt, body, orelse); + } + if checker.enabled(Rule::TryExceptInLoop) { + perflint::rules::try_except_in_loop(checker, body); + } + } + Stmt::For(ast::StmtFor { + target, + body, + iter, + orelse, + .. + }) + | Stmt::AsyncFor(ast::StmtAsyncFor { + target, + body, + iter, + orelse, + .. + }) => { + if checker.any_enabled(&[Rule::UnusedLoopControlVariable, Rule::IncorrectDictIterator]) + { + checker.deferred.for_loops.push(checker.semantic.snapshot()); + } + if checker.enabled(Rule::LoopVariableOverridesIterator) { + flake8_bugbear::rules::loop_variable_overrides_iterator(checker, target, iter); + } + if checker.enabled(Rule::FunctionUsesLoopVariable) { + flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Stmt(stmt)); + } + if checker.enabled(Rule::ReuseOfGroupbyGenerator) { + flake8_bugbear::rules::reuse_of_groupby_generator(checker, target, body, iter); + } + if checker.enabled(Rule::UselessElseOnLoop) { + pylint::rules::useless_else_on_loop(checker, stmt, body, orelse); + } + if checker.enabled(Rule::RedefinedLoopName) { + pylint::rules::redefined_loop_name(checker, stmt); + } + if checker.enabled(Rule::IterationOverSet) { + pylint::rules::iteration_over_set(checker, iter); + } + if stmt.is_for_stmt() { + if checker.enabled(Rule::ReimplementedBuiltin) { + flake8_simplify::rules::convert_for_loop_to_any_all(checker, stmt); + } + if checker.enabled(Rule::InDictKeys) { + flake8_simplify::rules::key_in_dict_for(checker, target, iter); + } + if checker.enabled(Rule::TryExceptInLoop) { + perflint::rules::try_except_in_loop(checker, body); + } + } + if checker.enabled(Rule::ManualListComprehension) { + perflint::rules::manual_list_comprehension(checker, target, body); + } + if checker.enabled(Rule::ManualListCopy) { + perflint::rules::manual_list_copy(checker, target, body); + } + if checker.enabled(Rule::UnnecessaryListCast) { + perflint::rules::unnecessary_list_cast(checker, iter); + } + } + Stmt::Try(ast::StmtTry { + body, + handlers, + orelse, + finalbody, + range: _, + }) + | Stmt::TryStar(ast::StmtTryStar { + body, + handlers, + orelse, + finalbody, + range: _, + }) => { + if checker.enabled(Rule::JumpStatementInFinally) { + flake8_bugbear::rules::jump_statement_in_finally(checker, finalbody); + } + if checker.enabled(Rule::ContinueInFinally) { + if checker.settings.target_version <= PythonVersion::Py38 { + pylint::rules::continue_in_finally(checker, finalbody); + } + } + if checker.enabled(Rule::DefaultExceptNotLast) { + if let Some(diagnostic) = + pyflakes::rules::default_except_not_last(handlers, checker.locator) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.any_enabled(&[ + Rule::DuplicateHandlerException, + Rule::DuplicateTryBlockException, + ]) { + flake8_bugbear::rules::duplicate_exceptions(checker, handlers); + } + if checker.enabled(Rule::RedundantTupleInExceptionHandler) { + flake8_bugbear::rules::redundant_tuple_in_exception_handler(checker, handlers); + } + if checker.enabled(Rule::OSErrorAlias) { + pyupgrade::rules::os_error_alias_handlers(checker, handlers); + } + if checker.enabled(Rule::PytestAssertInExcept) { + flake8_pytest_style::rules::assert_in_exception_handler(checker, handlers); + } + if checker.enabled(Rule::SuppressibleException) { + flake8_simplify::rules::suppressible_exception( + checker, stmt, body, handlers, orelse, finalbody, + ); + } + if checker.enabled(Rule::ReturnInTryExceptFinally) { + flake8_simplify::rules::return_in_try_except_finally( + checker, body, handlers, finalbody, + ); + } + if checker.enabled(Rule::TryConsiderElse) { + tryceratops::rules::try_consider_else(checker, body, orelse, handlers); + } + if checker.enabled(Rule::VerboseRaise) { + tryceratops::rules::verbose_raise(checker, handlers); + } + if checker.enabled(Rule::VerboseLogMessage) { + tryceratops::rules::verbose_log_message(checker, handlers); + } + if checker.enabled(Rule::RaiseWithinTry) { + tryceratops::rules::raise_within_try(checker, body, handlers); + } + if checker.enabled(Rule::UselessTryExcept) { + tryceratops::rules::useless_try_except(checker, handlers); + } + if checker.enabled(Rule::ErrorInsteadOfException) { + tryceratops::rules::error_instead_of_exception(checker, handlers); + } + } + Stmt::Assign(assign @ ast::StmtAssign { targets, value, .. }) => { + if checker.enabled(Rule::LambdaAssignment) { + if let [target] = &targets[..] { + pycodestyle::rules::lambda_assignment(checker, target, value, None, stmt); + } + } + if checker.enabled(Rule::AssignmentToOsEnviron) { + flake8_bugbear::rules::assignment_to_os_environ(checker, targets); + } + if checker.enabled(Rule::HardcodedPasswordString) { + flake8_bandit::rules::assign_hardcoded_password_string(checker, value, targets); + } + if checker.enabled(Rule::GlobalStatement) { + for target in targets { + if let Expr::Name(ast::ExprName { id, .. }) = target { + pylint::rules::global_statement(checker, id); + } + } + } + if checker.enabled(Rule::UselessMetaclassType) { + pyupgrade::rules::useless_metaclass_type(checker, stmt, value, targets); + } + if checker.enabled(Rule::ConvertTypedDictFunctionalToClass) { + pyupgrade::rules::convert_typed_dict_functional_to_class( + checker, stmt, targets, value, + ); + } + if checker.enabled(Rule::ConvertNamedTupleFunctionalToClass) { + pyupgrade::rules::convert_named_tuple_functional_to_class( + checker, stmt, targets, value, + ); + } + if checker.enabled(Rule::UnpackedListComprehension) { + pyupgrade::rules::unpacked_list_comprehension(checker, targets, value); + } + if checker.enabled(Rule::PandasDfVariableName) { + if let Some(diagnostic) = pandas_vet::rules::assignment_to_df(targets) { + checker.diagnostics.push(diagnostic); + } + } + if checker + .settings + .rules + .enabled(Rule::AirflowVariableNameTaskIdMismatch) + { + if let Some(diagnostic) = + airflow::rules::variable_name_task_id(checker, targets, value) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.settings.rules.enabled(Rule::SelfAssigningVariable) { + if let [target] = targets.as_slice() { + pylint::rules::self_assigning_variable(checker, target, value); + } + } + if checker.settings.rules.enabled(Rule::TypeParamNameMismatch) { + pylint::rules::type_param_name_mismatch(checker, value, targets); + } + if checker + .settings + .rules + .enabled(Rule::TypeNameIncorrectVariance) + { + pylint::rules::type_name_incorrect_variance(checker, value); + } + if checker.settings.rules.enabled(Rule::TypeBivariance) { + pylint::rules::type_bivariance(checker, value); + } + if checker.is_stub { + if checker.any_enabled(&[ + Rule::UnprefixedTypeParam, + Rule::AssignmentDefaultInStub, + Rule::UnannotatedAssignmentInStub, + Rule::ComplexAssignmentInStub, + Rule::TypeAliasWithoutAnnotation, + ]) { + // Ignore assignments in function bodies; those are covered by other rules. + if !checker + .semantic + .scopes() + .any(|scope| scope.kind.is_any_function()) + { + if checker.enabled(Rule::UnprefixedTypeParam) { + flake8_pyi::rules::prefix_type_params(checker, value, targets); + } + if checker.enabled(Rule::AssignmentDefaultInStub) { + flake8_pyi::rules::assignment_default_in_stub(checker, targets, value); + } + if checker.enabled(Rule::UnannotatedAssignmentInStub) { + flake8_pyi::rules::unannotated_assignment_in_stub( + checker, targets, value, + ); + } + if checker.enabled(Rule::ComplexAssignmentInStub) { + flake8_pyi::rules::complex_assignment_in_stub(checker, assign); + } + if checker.enabled(Rule::TypeAliasWithoutAnnotation) { + flake8_pyi::rules::type_alias_without_annotation( + checker, value, targets, + ); + } + } + } + } + } + Stmt::AnnAssign(ast::StmtAnnAssign { + target, + value, + annotation, + .. + }) => { + if let Some(value) = value { + if checker.enabled(Rule::LambdaAssignment) { + pycodestyle::rules::lambda_assignment( + checker, + target, + value, + Some(annotation), + stmt, + ); + } + if checker.enabled(Rule::SelfAssigningVariable) { + pylint::rules::self_assigning_variable(checker, target, value); + } + } + if checker.enabled(Rule::UnintentionalTypeAnnotation) { + flake8_bugbear::rules::unintentional_type_annotation( + checker, + target, + value.as_deref(), + stmt, + ); + } + if checker.is_stub { + if let Some(value) = value { + if checker.enabled(Rule::AssignmentDefaultInStub) { + // Ignore assignments in function bodies; those are covered by other rules. + if !checker + .semantic + .scopes() + .any(|scope| scope.kind.is_any_function()) + { + flake8_pyi::rules::annotated_assignment_default_in_stub( + checker, target, value, annotation, + ); + } + } + } else { + if checker.enabled(Rule::UnassignedSpecialVariableInStub) { + flake8_pyi::rules::unassigned_special_variable_in_stub( + checker, target, stmt, + ); + } + } + if checker.semantic.match_typing_expr(annotation, "TypeAlias") { + if checker.enabled(Rule::SnakeCaseTypeAlias) { + flake8_pyi::rules::snake_case_type_alias(checker, target); + } + if checker.enabled(Rule::TSuffixedTypeAlias) { + flake8_pyi::rules::t_suffixed_type_alias(checker, target); + } + } + } + } + Stmt::Delete(ast::StmtDelete { targets, range: _ }) => { + if checker.enabled(Rule::GlobalStatement) { + for target in targets { + if let Expr::Name(ast::ExprName { id, .. }) = target { + pylint::rules::global_statement(checker, id); + } + } + } + } + Stmt::Expr(ast::StmtExpr { value, range: _ }) => { + if checker.enabled(Rule::UselessComparison) { + flake8_bugbear::rules::useless_comparison(checker, value); + } + if checker.enabled(Rule::UselessExpression) { + flake8_bugbear::rules::useless_expression(checker, value); + } + if checker.enabled(Rule::InvalidMockAccess) { + pygrep_hooks::rules::uncalled_mock_method(checker, value); + } + if checker.enabled(Rule::NamedExprWithoutContext) { + pylint::rules::named_expr_without_context(checker, value); + } + if checker.enabled(Rule::AsyncioDanglingTask) { + ruff::rules::asyncio_dangling_task(checker, value); + } + } + _ => {} + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/suite.rs b/crates/ruff/src/checkers/ast/analyze/suite.rs new file mode 100644 index 0000000000..f24b4525eb --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/suite.rs @@ -0,0 +1,12 @@ +use rustpython_parser::ast::Stmt; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::flake8_pie; + +/// Run lint rules over a suite of [`Stmt`] syntax nodes. +pub(crate) fn suite(suite: &[Stmt], checker: &mut Checker) { + if checker.enabled(Rule::UnnecessaryPass) { + flake8_pie::rules::no_unnecessary_pass(checker, suite); + } +} diff --git a/crates/ruff/src/checkers/ast/analyze/unresolved_references.rs b/crates/ruff/src/checkers/ast/analyze/unresolved_references.rs new file mode 100644 index 0000000000..c4d6cc65ab --- /dev/null +++ b/crates/ruff/src/checkers/ast/analyze/unresolved_references.rs @@ -0,0 +1,47 @@ +use ruff_diagnostics::Diagnostic; +use ruff_python_semantic::Exceptions; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::pyflakes; + +/// Run lint rules over all [`UnresolvedReference`] entities in the [`SemanticModel`]. +pub(crate) fn unresolved_references(checker: &mut Checker) { + if !checker.any_enabled(&[Rule::UndefinedLocalWithImportStarUsage, Rule::UndefinedName]) { + return; + } + + for reference in checker.semantic.unresolved_references() { + if reference.is_wildcard_import() { + if checker.enabled(Rule::UndefinedLocalWithImportStarUsage) { + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::UndefinedLocalWithImportStarUsage { + name: reference.name(checker.locator).to_string(), + }, + reference.range(), + )); + } + } else { + if checker.enabled(Rule::UndefinedName) { + // Avoid flagging if `NameError` is handled. + if reference.exceptions().contains(Exceptions::NAME_ERROR) { + continue; + } + + // Allow __path__. + if checker.path.ends_with("__init__.py") { + if reference.name(checker.locator) == "__path__" { + continue; + } + } + + checker.diagnostics.push(Diagnostic::new( + pyflakes::rules::UndefinedName { + name: reference.name(checker.locator).to_string(), + }, + reference.range(), + )); + } + } + } +} diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 812401e61e..168e26b769 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -31,54 +31,38 @@ use std::path::Path; use itertools::Itertools; use log::error; use ruff_text_size::{TextRange, TextSize}; -use rustpython_format::cformat::{CFormatError, CFormatErrorType}; use rustpython_parser::ast::{ self, Arg, ArgWithDefault, Arguments, Comprehension, Constant, ElifElseClause, ExceptHandler, - Expr, ExprContext, Keyword, Operator, Pattern, Ranged, Stmt, Suite, UnaryOp, + Expr, ExprContext, Keyword, Pattern, Ranged, Stmt, Suite, UnaryOp, }; -use ruff_diagnostics::{Diagnostic, Fix, IsolationLevel}; +use ruff_diagnostics::{Diagnostic, IsolationLevel}; use ruff_python_ast::all::{extract_all_names, DunderAllFlags}; use ruff_python_ast::helpers::{extract_handled_exceptions, to_module_path}; use ruff_python_ast::identifier::Identifier; use ruff_python_ast::source_code::{Generator, Indexer, Locator, Quote, Stylist}; use ruff_python_ast::str::trailing_quote; -use ruff_python_ast::types::Node; use ruff_python_ast::typing::{parse_type_annotation, AnnotationKind}; use ruff_python_ast::visitor::{walk_except_handler, walk_pattern, Visitor}; -use ruff_python_ast::{cast, helpers, str, visitor}; -use ruff_python_semantic::analyze::{branch_detection, typing, visibility}; +use ruff_python_ast::{helpers, str, visitor}; +use ruff_python_semantic::analyze::{typing, visibility}; use ruff_python_semantic::{ - Binding, BindingFlags, BindingId, BindingKind, ContextualizedDefinition, Exceptions, Export, - FromImport, Globals, Import, Module, ModuleKind, ScopeId, ScopeKind, SemanticModel, - SemanticModelFlags, StarImport, SubmoduleImport, + BindingFlags, BindingId, BindingKind, Exceptions, Export, FromImport, Globals, Import, Module, + ModuleKind, ScopeId, ScopeKind, SemanticModel, SemanticModelFlags, StarImport, SubmoduleImport, }; use ruff_python_stdlib::builtins::{BUILTINS, MAGIC_GLOBALS}; use ruff_python_stdlib::path::is_python_stub_file; use crate::checkers::ast::deferred::Deferred; use crate::docstrings::extraction::ExtractionTarget; -use crate::docstrings::Docstring; -use crate::fs::relativize_path; use crate::importer::Importer; use crate::noqa::NoqaMapping; use crate::registry::Rule; - -use crate::rules::{ - airflow, flake8_2020, flake8_annotations, flake8_async, flake8_bandit, flake8_blind_except, - flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, - flake8_debugger, flake8_django, flake8_errmsg, flake8_future_annotations, flake8_gettext, - flake8_implicit_str_concat, flake8_import_conventions, flake8_logging_format, flake8_pie, - flake8_print, flake8_pyi, flake8_pytest_style, flake8_raise, flake8_return, flake8_self, - flake8_simplify, flake8_slots, flake8_tidy_imports, flake8_type_checking, - flake8_unused_arguments, flake8_use_pathlib, flynt, mccabe, numpy, pandas_vet, pep8_naming, - perflint, pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, - tryceratops, -}; -use crate::settings::types::PythonVersion; +use crate::rules::{flake8_pyi, flake8_type_checking, pyflakes, pyupgrade}; use crate::settings::{flags, Settings}; -use crate::{docstrings, noqa, warn_user}; +use crate::{docstrings, noqa}; +mod analyze; mod deferred; pub(crate) struct Checker<'a> { @@ -115,7 +99,7 @@ pub(crate) struct Checker<'a> { /// The cumulative set of diagnostics computed across all lint rules. pub(crate) diagnostics: Vec, /// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations.. - pub(crate) flake8_bugbear_seen: Vec<&'a ast::ExprName>, + pub(crate) flake8_bugbear_seen: Vec, } impl<'a> Checker<'a> { @@ -318,1409 +302,7 @@ where let flags_snapshot = self.semantic.flags; // Step 1: Analysis - match stmt { - Stmt::Global(ast::StmtGlobal { names, range: _ }) => { - if self.enabled(Rule::AmbiguousVariableName) { - self.diagnostics.extend(names.iter().filter_map(|name| { - pycodestyle::rules::ambiguous_variable_name(name, name.range()) - })); - } - } - Stmt::Nonlocal(ast::StmtNonlocal { names, range: _ }) => { - if self.enabled(Rule::AmbiguousVariableName) { - self.diagnostics.extend(names.iter().filter_map(|name| { - pycodestyle::rules::ambiguous_variable_name(name, name.range()) - })); - } - - if self.enabled(Rule::NonlocalWithoutBinding) { - if !self.semantic.scope_id.is_global() { - for name in names { - if self.semantic.nonlocal(name).is_none() { - self.diagnostics.push(Diagnostic::new( - pylint::rules::NonlocalWithoutBinding { - name: name.to_string(), - }, - name.range(), - )); - } - } - } - } - } - Stmt::Break(_) => { - if self.enabled(Rule::BreakOutsideLoop) { - if let Some(diagnostic) = pyflakes::rules::break_outside_loop( - stmt, - &mut self.semantic.parents().skip(1), - ) { - self.diagnostics.push(diagnostic); - } - } - } - Stmt::Continue(_) => { - if self.enabled(Rule::ContinueOutsideLoop) { - if let Some(diagnostic) = pyflakes::rules::continue_outside_loop( - stmt, - &mut self.semantic.parents().skip(1), - ) { - self.diagnostics.push(diagnostic); - } - } - } - Stmt::FunctionDef(ast::StmtFunctionDef { - name, - decorator_list, - returns, - args, - body, - .. - }) - | Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef { - name, - decorator_list, - returns, - args, - body, - .. - }) => { - if self.enabled(Rule::DjangoNonLeadingReceiverDecorator) { - flake8_django::rules::non_leading_receiver_decorator(self, decorator_list); - } - if self.enabled(Rule::AmbiguousFunctionName) { - if let Some(diagnostic) = pycodestyle::rules::ambiguous_function_name(name) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::InvalidStrReturnType) { - pylint::rules::invalid_str_return(self, name, body); - } - if self.enabled(Rule::InvalidFunctionName) { - if let Some(diagnostic) = pep8_naming::rules::invalid_function_name( - stmt, - name, - decorator_list, - &self.settings.pep8_naming.ignore_names, - &self.semantic, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::InvalidFirstArgumentNameForClassMethod) { - if let Some(diagnostic) = - pep8_naming::rules::invalid_first_argument_name_for_class_method( - self, - self.semantic.scope(), - name, - decorator_list, - args, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::InvalidFirstArgumentNameForMethod) { - if let Some(diagnostic) = - pep8_naming::rules::invalid_first_argument_name_for_method( - self, - self.semantic.scope(), - name, - decorator_list, - args, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.is_stub { - if self.enabled(Rule::PassStatementStubBody) { - flake8_pyi::rules::pass_statement_stub_body(self, body); - } - if self.enabled(Rule::NonEmptyStubBody) { - flake8_pyi::rules::non_empty_stub_body(self, body); - } - if self.enabled(Rule::StubBodyMultipleStatements) { - flake8_pyi::rules::stub_body_multiple_statements(self, stmt, body); - } - if self.enabled(Rule::AnyEqNeAnnotation) { - flake8_pyi::rules::any_eq_ne_annotation(self, name, args); - } - if self.enabled(Rule::NonSelfReturnType) { - flake8_pyi::rules::non_self_return_type( - self, - stmt, - name, - decorator_list, - returns.as_ref().map(AsRef::as_ref), - args, - stmt.is_async_function_def_stmt(), - ); - } - if self.enabled(Rule::StrOrReprDefinedInStub) { - flake8_pyi::rules::str_or_repr_defined_in_stub(self, stmt); - } - if self.enabled(Rule::NoReturnArgumentAnnotationInStub) { - flake8_pyi::rules::no_return_argument_annotation(self, args); - } - if self.enabled(Rule::BadExitAnnotation) { - flake8_pyi::rules::bad_exit_annotation( - self, - stmt.is_async_function_def_stmt(), - name, - args, - ); - } - if self.enabled(Rule::RedundantNumericUnion) { - flake8_pyi::rules::redundant_numeric_union(self, args); - } - } - if self.enabled(Rule::DunderFunctionName) { - if let Some(diagnostic) = pep8_naming::rules::dunder_function_name( - self.semantic.scope(), - stmt, - name, - &self.settings.pep8_naming.ignore_names, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::GlobalStatement) { - pylint::rules::global_statement(self, name); - } - if self.enabled(Rule::LRUCacheWithoutParameters) { - if self.settings.target_version >= PythonVersion::Py38 { - pyupgrade::rules::lru_cache_without_parameters(self, decorator_list); - } - } - if self.enabled(Rule::LRUCacheWithMaxsizeNone) { - if self.settings.target_version >= PythonVersion::Py39 { - pyupgrade::rules::lru_cache_with_maxsize_none(self, decorator_list); - } - } - if self.enabled(Rule::CachedInstanceMethod) { - flake8_bugbear::rules::cached_instance_method(self, decorator_list); - } - if self.any_enabled(&[ - Rule::UnnecessaryReturnNone, - Rule::ImplicitReturnValue, - Rule::ImplicitReturn, - Rule::UnnecessaryAssign, - Rule::SuperfluousElseReturn, - Rule::SuperfluousElseRaise, - Rule::SuperfluousElseContinue, - Rule::SuperfluousElseBreak, - ]) { - flake8_return::rules::function(self, body, returns.as_ref().map(AsRef::as_ref)); - } - if self.enabled(Rule::UselessReturn) { - pylint::rules::useless_return( - self, - stmt, - body, - returns.as_ref().map(AsRef::as_ref), - ); - } - if self.enabled(Rule::ComplexStructure) { - if let Some(diagnostic) = mccabe::rules::function_is_too_complex( - stmt, - name, - body, - self.settings.mccabe.max_complexity, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::HardcodedPasswordDefault) { - flake8_bandit::rules::hardcoded_password_default(self, args); - } - if self.enabled(Rule::PropertyWithParameters) { - pylint::rules::property_with_parameters(self, stmt, decorator_list, args); - } - if self.enabled(Rule::TooManyArguments) { - pylint::rules::too_many_arguments(self, args, stmt); - } - if self.enabled(Rule::TooManyReturnStatements) { - if let Some(diagnostic) = pylint::rules::too_many_return_statements( - stmt, - body, - self.settings.pylint.max_returns, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::TooManyBranches) { - if let Some(diagnostic) = pylint::rules::too_many_branches( - stmt, - body, - self.settings.pylint.max_branches, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::TooManyStatements) { - if let Some(diagnostic) = pylint::rules::too_many_statements( - stmt, - body, - self.settings.pylint.max_statements, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.any_enabled(&[ - Rule::PytestFixtureIncorrectParenthesesStyle, - Rule::PytestFixturePositionalArgs, - Rule::PytestExtraneousScopeFunction, - Rule::PytestMissingFixtureNameUnderscore, - Rule::PytestIncorrectFixtureNameUnderscore, - Rule::PytestFixtureParamWithoutValue, - Rule::PytestDeprecatedYieldFixture, - Rule::PytestFixtureFinalizerCallback, - Rule::PytestUselessYieldFixture, - Rule::PytestUnnecessaryAsyncioMarkOnFixture, - Rule::PytestErroneousUseFixturesOnFixture, - ]) { - flake8_pytest_style::rules::fixture( - self, - stmt, - name, - args, - decorator_list, - body, - ); - } - if self.any_enabled(&[ - Rule::PytestParametrizeNamesWrongType, - Rule::PytestParametrizeValuesWrongType, - ]) { - flake8_pytest_style::rules::parametrize(self, decorator_list); - } - if self.any_enabled(&[ - Rule::PytestIncorrectMarkParenthesesStyle, - Rule::PytestUseFixturesWithoutParameters, - ]) { - flake8_pytest_style::rules::marks(self, decorator_list); - } - if self.enabled(Rule::BooleanPositionalArgInFunctionDefinition) { - flake8_boolean_trap::rules::check_positional_boolean_in_def( - self, - name, - decorator_list, - args, - ); - } - if self.enabled(Rule::BooleanDefaultValueInFunctionDefinition) { - flake8_boolean_trap::rules::check_boolean_default_value_in_function_definition( - self, - name, - decorator_list, - args, - ); - } - if self.enabled(Rule::UnexpectedSpecialMethodSignature) { - pylint::rules::unexpected_special_method_signature( - self, - stmt, - name, - decorator_list, - args, - ); - } - if self.enabled(Rule::FStringDocstring) { - flake8_bugbear::rules::f_string_docstring(self, body); - } - if self.enabled(Rule::YieldInForLoop) { - pyupgrade::rules::yield_in_for_loop(self, stmt); - } - if let ScopeKind::Class(class_def) = self.semantic.scope().kind { - if self.enabled(Rule::BuiltinAttributeShadowing) { - flake8_builtins::rules::builtin_attribute_shadowing( - self, - class_def, - name, - name.range(), - ); - } - } else { - if self.enabled(Rule::BuiltinVariableShadowing) { - flake8_builtins::rules::builtin_variable_shadowing( - self, - name, - name.range(), - ); - } - } - #[cfg(feature = "unreachable-code")] - if self.enabled(Rule::UnreachableCode) { - self.diagnostics - .extend(ruff::rules::unreachable::in_function(name, body)); - } - } - Stmt::Return(_) => { - if self.enabled(Rule::ReturnOutsideFunction) { - pyflakes::rules::return_outside_function(self, stmt); - } - if self.enabled(Rule::ReturnInInit) { - pylint::rules::return_in_init(self, stmt); - } - } - Stmt::ClassDef( - class_def @ ast::StmtClassDef { - name, - bases, - keywords, - type_params: _, - decorator_list, - body, - range: _, - }, - ) => { - if self.enabled(Rule::DjangoNullableModelStringField) { - flake8_django::rules::nullable_model_string_field(self, body); - } - if self.enabled(Rule::DjangoExcludeWithModelForm) { - if let Some(diagnostic) = - flake8_django::rules::exclude_with_model_form(self, bases, body) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::DjangoAllWithModelForm) { - if let Some(diagnostic) = - flake8_django::rules::all_with_model_form(self, bases, body) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::DjangoUnorderedBodyContentInModel) { - flake8_django::rules::unordered_body_content_in_model(self, bases, body); - } - if !self.is_stub { - if self.enabled(Rule::DjangoModelWithoutDunderStr) { - flake8_django::rules::model_without_dunder_str(self, class_def); - } - } - if self.enabled(Rule::GlobalStatement) { - pylint::rules::global_statement(self, name); - } - if self.enabled(Rule::UselessObjectInheritance) { - pyupgrade::rules::useless_object_inheritance(self, class_def); - } - if self.enabled(Rule::UnnecessaryClassParentheses) { - pyupgrade::rules::unnecessary_class_parentheses(self, class_def); - } - if self.enabled(Rule::AmbiguousClassName) { - if let Some(diagnostic) = pycodestyle::rules::ambiguous_class_name(name) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::InvalidClassName) { - if let Some(diagnostic) = pep8_naming::rules::invalid_class_name( - stmt, - name, - &self.settings.pep8_naming.ignore_names, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::ErrorSuffixOnExceptionName) { - if let Some(diagnostic) = pep8_naming::rules::error_suffix_on_exception_name( - stmt, - bases, - name, - &self.settings.pep8_naming.ignore_names, - ) { - self.diagnostics.push(diagnostic); - } - } - if !self.is_stub { - if self.any_enabled(&[ - Rule::AbstractBaseClassWithoutAbstractMethod, - Rule::EmptyMethodWithoutAbstractDecorator, - ]) { - flake8_bugbear::rules::abstract_base_class( - self, stmt, name, bases, keywords, body, - ); - } - } - if self.is_stub { - if self.enabled(Rule::PassStatementStubBody) { - flake8_pyi::rules::pass_statement_stub_body(self, body); - } - if self.enabled(Rule::PassInClassBody) { - flake8_pyi::rules::pass_in_class_body(self, stmt, body); - } - if self.enabled(Rule::EllipsisInNonEmptyClassBody) { - flake8_pyi::rules::ellipsis_in_non_empty_class_body(self, stmt, body); - } - } - if self.enabled(Rule::PytestIncorrectMarkParenthesesStyle) { - flake8_pytest_style::rules::marks(self, decorator_list); - } - if self.enabled(Rule::DuplicateClassFieldDefinition) { - flake8_pie::rules::duplicate_class_field_definition(self, stmt, body); - } - if self.enabled(Rule::NonUniqueEnums) { - flake8_pie::rules::non_unique_enums(self, stmt, body); - } - if self.enabled(Rule::MutableClassDefault) { - ruff::rules::mutable_class_default(self, class_def); - } - if self.enabled(Rule::MutableDataclassDefault) { - ruff::rules::mutable_dataclass_default(self, class_def); - } - if self.enabled(Rule::FunctionCallInDataclassDefaultArgument) { - ruff::rules::function_call_in_dataclass_default(self, class_def); - } - if self.enabled(Rule::FStringDocstring) { - flake8_bugbear::rules::f_string_docstring(self, body); - } - if self.enabled(Rule::BuiltinVariableShadowing) { - flake8_builtins::rules::builtin_variable_shadowing(self, name, name.range()); - } - if self.enabled(Rule::DuplicateBases) { - pylint::rules::duplicate_bases(self, name, bases); - } - if self.enabled(Rule::NoSlotsInStrSubclass) { - flake8_slots::rules::no_slots_in_str_subclass(self, stmt, class_def); - } - if self.enabled(Rule::NoSlotsInTupleSubclass) { - flake8_slots::rules::no_slots_in_tuple_subclass(self, stmt, class_def); - } - if self.enabled(Rule::NoSlotsInNamedtupleSubclass) { - flake8_slots::rules::no_slots_in_namedtuple_subclass(self, stmt, class_def); - } - if self.enabled(Rule::SingleStringSlots) { - pylint::rules::single_string_slots(self, class_def); - } - } - Stmt::Import(ast::StmtImport { names, range: _ }) => { - if self.enabled(Rule::MultipleImportsOnOneLine) { - pycodestyle::rules::multiple_imports_on_one_line(self, stmt, names); - } - if self.enabled(Rule::ModuleImportNotAtTopOfFile) { - pycodestyle::rules::module_import_not_at_top_of_file(self, stmt, self.locator); - } - if self.enabled(Rule::GlobalStatement) { - for name in names { - if let Some(asname) = name.asname.as_ref() { - pylint::rules::global_statement(self, asname); - } else { - pylint::rules::global_statement(self, &name.name); - } - } - } - if self.enabled(Rule::DeprecatedCElementTree) { - pyupgrade::rules::deprecated_c_element_tree(self, stmt); - } - if self.enabled(Rule::DeprecatedMockImport) { - pyupgrade::rules::deprecated_mock_import(self, stmt); - } - - for alias in names { - if let Some(asname) = &alias.asname { - if self.enabled(Rule::BuiltinVariableShadowing) { - flake8_builtins::rules::builtin_variable_shadowing( - self, - asname, - asname.range(), - ); - } - } - if self.enabled(Rule::Debugger) { - if let Some(diagnostic) = - flake8_debugger::rules::debugger_import(stmt, None, &alias.name) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::BannedApi) { - flake8_tidy_imports::rules::name_or_parent_is_banned( - self, - &alias.name, - alias, - ); - } - if !self.is_stub { - if self.enabled(Rule::UselessImportAlias) { - pylint::rules::useless_import_alias(self, alias); - } - } - if self.enabled(Rule::ManualFromImport) { - pylint::rules::manual_from_import(self, stmt, alias, names); - } - if self.enabled(Rule::ImportSelf) { - if let Some(diagnostic) = - pylint::rules::import_self(alias, self.module_path) - { - self.diagnostics.push(diagnostic); - } - } - if let Some(asname) = &alias.asname { - let name = alias.name.split('.').last().unwrap(); - if self.enabled(Rule::ConstantImportedAsNonConstant) { - if let Some(diagnostic) = - pep8_naming::rules::constant_imported_as_non_constant( - name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::LowercaseImportedAsNonLowercase) { - if let Some(diagnostic) = - pep8_naming::rules::lowercase_imported_as_non_lowercase( - name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::CamelcaseImportedAsLowercase) { - if let Some(diagnostic) = - pep8_naming::rules::camelcase_imported_as_lowercase( - name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::CamelcaseImportedAsConstant) { - if let Some(diagnostic) = - pep8_naming::rules::camelcase_imported_as_constant( - name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::CamelcaseImportedAsAcronym) { - if let Some(diagnostic) = - pep8_naming::rules::camelcase_imported_as_acronym( - name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - } - if self.enabled(Rule::BannedImportAlias) { - if let Some(asname) = &alias.asname { - if let Some(diagnostic) = - flake8_import_conventions::rules::banned_import_alias( - stmt, - &alias.name, - asname, - &self.settings.flake8_import_conventions.banned_aliases, - ) - { - self.diagnostics.push(diagnostic); - } - } - } - if self.enabled(Rule::PytestIncorrectPytestImport) { - if let Some(diagnostic) = flake8_pytest_style::rules::import( - stmt, - &alias.name, - alias.asname.as_deref(), - ) { - self.diagnostics.push(diagnostic); - } - } - } - } - Stmt::ImportFrom( - import_from @ ast::StmtImportFrom { - names, - module, - level, - range: _, - }, - ) => { - let module = module.as_deref(); - let level = level.map(|level| level.to_u32()); - if self.enabled(Rule::ModuleImportNotAtTopOfFile) { - pycodestyle::rules::module_import_not_at_top_of_file(self, stmt, self.locator); - } - if self.enabled(Rule::GlobalStatement) { - for name in names { - if let Some(asname) = name.asname.as_ref() { - pylint::rules::global_statement(self, asname); - } else { - pylint::rules::global_statement(self, &name.name); - } - } - } - if self.enabled(Rule::UnnecessaryFutureImport) { - if self.settings.target_version >= PythonVersion::Py37 { - if let Some("__future__") = module { - pyupgrade::rules::unnecessary_future_import(self, stmt, names); - } - } - } - if self.enabled(Rule::DeprecatedMockImport) { - pyupgrade::rules::deprecated_mock_import(self, stmt); - } - if self.enabled(Rule::DeprecatedCElementTree) { - pyupgrade::rules::deprecated_c_element_tree(self, stmt); - } - if self.enabled(Rule::DeprecatedImport) { - pyupgrade::rules::deprecated_import(self, stmt, names, module, level); - } - if self.enabled(Rule::UnnecessaryBuiltinImport) { - if let Some(module) = module { - pyupgrade::rules::unnecessary_builtin_import(self, stmt, module, names); - } - } - if self.enabled(Rule::BannedApi) { - if let Some(module) = - helpers::resolve_imported_module_path(level, module, self.module_path) - { - flake8_tidy_imports::rules::name_or_parent_is_banned(self, &module, stmt); - - for alias in names { - if &alias.name == "*" { - continue; - } - flake8_tidy_imports::rules::name_is_banned( - self, - format!("{module}.{}", alias.name), - alias, - ); - } - } - } - if self.enabled(Rule::PytestIncorrectPytestImport) { - if let Some(diagnostic) = - flake8_pytest_style::rules::import_from(stmt, module, level) - { - self.diagnostics.push(diagnostic); - } - } - if self.is_stub { - if self.enabled(Rule::FutureAnnotationsInStub) { - flake8_pyi::rules::from_future_import(self, import_from); - } - } - for alias in names { - if let Some("__future__") = module { - if self.enabled(Rule::FutureFeatureNotDefined) { - pyflakes::rules::future_feature_not_defined(self, alias); - } - if self.enabled(Rule::LateFutureImport) { - if self.semantic.seen_futures_boundary() { - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::LateFutureImport, - stmt.range(), - )); - } - } - } else if &alias.name == "*" { - if self.enabled(Rule::UndefinedLocalWithNestedImportStarUsage) { - if !matches!(self.semantic.scope().kind, ScopeKind::Module) { - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::UndefinedLocalWithNestedImportStarUsage { - name: helpers::format_import_from(level, module), - }, - stmt.range(), - )); - } - } - if self.enabled(Rule::UndefinedLocalWithImportStar) { - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::UndefinedLocalWithImportStar { - name: helpers::format_import_from(level, module), - }, - stmt.range(), - )); - } - } else { - if let Some(asname) = &alias.asname { - if self.enabled(Rule::BuiltinVariableShadowing) { - flake8_builtins::rules::builtin_variable_shadowing( - self, - asname, - asname.range(), - ); - } - } - } - if self.enabled(Rule::RelativeImports) { - if let Some(diagnostic) = flake8_tidy_imports::rules::banned_relative_import( - self, - stmt, - level, - module, - self.module_path, - self.settings.flake8_tidy_imports.ban_relative_imports, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::Debugger) { - if let Some(diagnostic) = - flake8_debugger::rules::debugger_import(stmt, module, &alias.name) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::BannedImportAlias) { - if let Some(asname) = &alias.asname { - let qualified_name = - helpers::format_import_from_member(level, module, &alias.name); - if let Some(diagnostic) = - flake8_import_conventions::rules::banned_import_alias( - stmt, - &qualified_name, - asname, - &self.settings.flake8_import_conventions.banned_aliases, - ) - { - self.diagnostics.push(diagnostic); - } - } - } - if let Some(asname) = &alias.asname { - if self.enabled(Rule::ConstantImportedAsNonConstant) { - if let Some(diagnostic) = - pep8_naming::rules::constant_imported_as_non_constant( - &alias.name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::LowercaseImportedAsNonLowercase) { - if let Some(diagnostic) = - pep8_naming::rules::lowercase_imported_as_non_lowercase( - &alias.name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::CamelcaseImportedAsLowercase) { - if let Some(diagnostic) = - pep8_naming::rules::camelcase_imported_as_lowercase( - &alias.name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::CamelcaseImportedAsConstant) { - if let Some(diagnostic) = - pep8_naming::rules::camelcase_imported_as_constant( - &alias.name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::CamelcaseImportedAsAcronym) { - if let Some(diagnostic) = - pep8_naming::rules::camelcase_imported_as_acronym( - &alias.name, - asname, - alias, - stmt, - &self.settings.pep8_naming.ignore_names, - ) - { - self.diagnostics.push(diagnostic); - } - } - if !self.is_stub { - if self.enabled(Rule::UselessImportAlias) { - pylint::rules::useless_import_alias(self, alias); - } - } - } - } - if self.enabled(Rule::ImportSelf) { - if let Some(diagnostic) = - pylint::rules::import_from_self(level, module, names, self.module_path) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::BannedImportFrom) { - if let Some(diagnostic) = flake8_import_conventions::rules::banned_import_from( - stmt, - &helpers::format_import_from(level, module), - &self.settings.flake8_import_conventions.banned_from, - ) { - self.diagnostics.push(diagnostic); - } - } - } - Stmt::Raise(ast::StmtRaise { exc, .. }) => { - if self.enabled(Rule::RaiseNotImplemented) { - if let Some(expr) = exc { - pyflakes::rules::raise_not_implemented(self, expr); - } - } - if self.enabled(Rule::RaiseLiteral) { - if let Some(exc) = exc { - flake8_bugbear::rules::raise_literal(self, exc); - } - } - if self.any_enabled(&[ - Rule::RawStringInException, - Rule::FStringInException, - Rule::DotFormatInException, - ]) { - if let Some(exc) = exc { - flake8_errmsg::rules::string_in_exception(self, stmt, exc); - } - } - if self.enabled(Rule::OSErrorAlias) { - if let Some(item) = exc { - pyupgrade::rules::os_error_alias_raise(self, item); - } - } - if self.enabled(Rule::RaiseVanillaClass) { - if let Some(expr) = exc { - tryceratops::rules::raise_vanilla_class(self, expr); - } - } - if self.enabled(Rule::RaiseVanillaArgs) { - if let Some(expr) = exc { - tryceratops::rules::raise_vanilla_args(self, expr); - } - } - if self.enabled(Rule::UnnecessaryParenOnRaiseException) { - if let Some(expr) = exc { - flake8_raise::rules::unnecessary_paren_on_raise_exception(self, expr); - } - } - } - Stmt::AugAssign(ast::StmtAugAssign { target, .. }) => { - if self.enabled(Rule::GlobalStatement) { - if let Expr::Name(ast::ExprName { id, .. }) = target.as_ref() { - pylint::rules::global_statement(self, id); - } - } - } - Stmt::If( - stmt_if @ ast::StmtIf { - test, - elif_else_clauses, - .. - }, - ) => { - if self.enabled(Rule::EmptyTypeCheckingBlock) { - if typing::is_type_checking_block(stmt_if, &self.semantic) { - flake8_type_checking::rules::empty_type_checking_block(self, stmt_if); - } - } - if self.enabled(Rule::IfTuple) { - pyflakes::rules::if_tuple(self, stmt_if); - } - if self.enabled(Rule::CollapsibleIf) { - flake8_simplify::rules::nested_if_statements( - self, - stmt_if, - self.semantic.stmt_parent(), - ); - } - if self.enabled(Rule::IfWithSameArms) { - flake8_simplify::rules::if_with_same_arms(self, self.locator, stmt_if); - } - if self.enabled(Rule::NeedlessBool) { - flake8_simplify::rules::needless_bool(self, stmt); - } - if self.enabled(Rule::IfElseBlockInsteadOfDictLookup) { - flake8_simplify::rules::manual_dict_lookup(self, stmt_if); - } - if self.enabled(Rule::IfElseBlockInsteadOfIfExp) { - flake8_simplify::rules::use_ternary_operator(self, stmt); - } - if self.enabled(Rule::IfElseBlockInsteadOfDictGet) { - flake8_simplify::rules::use_dict_get_with_default(self, stmt_if); - } - if self.enabled(Rule::TypeCheckWithoutTypeError) { - tryceratops::rules::type_check_without_type_error( - self, - stmt_if, - self.semantic.stmt_parent(), - ); - } - if self.enabled(Rule::OutdatedVersionBlock) { - pyupgrade::rules::outdated_version_block(self, stmt_if); - } - if self.enabled(Rule::CollapsibleElseIf) { - if let Some(diagnostic) = pylint::rules::collapsible_else_if(elif_else_clauses) - { - self.diagnostics.push(diagnostic); - } - } - if self.is_stub { - if self.any_enabled(&[ - Rule::UnrecognizedVersionInfoCheck, - Rule::PatchVersionComparison, - Rule::WrongTupleLengthVersionComparison, - ]) { - if let Expr::BoolOp(ast::ExprBoolOp { values, .. }) = test.as_ref() { - for value in values { - flake8_pyi::rules::unrecognized_version_info(self, value); - } - } else { - flake8_pyi::rules::unrecognized_version_info(self, test); - } - } - if self.any_enabled(&[ - Rule::UnrecognizedPlatformCheck, - Rule::UnrecognizedPlatformName, - ]) { - if let Expr::BoolOp(ast::ExprBoolOp { values, .. }) = test.as_ref() { - for value in values { - flake8_pyi::rules::unrecognized_platform(self, value); - } - } else { - flake8_pyi::rules::unrecognized_platform(self, test); - } - } - if self.enabled(Rule::BadVersionInfoComparison) { - if let Expr::BoolOp(ast::ExprBoolOp { values, .. }) = test.as_ref() { - for value in values { - flake8_pyi::rules::bad_version_info_comparison(self, value); - } - } else { - flake8_pyi::rules::bad_version_info_comparison(self, test); - } - } - if self.enabled(Rule::ComplexIfStatementInStub) { - if let Expr::BoolOp(ast::ExprBoolOp { values, .. }) = test.as_ref() { - for value in values { - flake8_pyi::rules::complex_if_statement_in_stub(self, value); - } - } else { - flake8_pyi::rules::complex_if_statement_in_stub(self, test); - } - } - } - } - Stmt::Assert(ast::StmtAssert { - test, - msg, - range: _, - }) => { - if !self.semantic.in_type_checking_block() { - if self.enabled(Rule::Assert) { - self.diagnostics - .push(flake8_bandit::rules::assert_used(stmt)); - } - } - if self.enabled(Rule::AssertTuple) { - pyflakes::rules::assert_tuple(self, stmt, test); - } - if self.enabled(Rule::AssertFalse) { - flake8_bugbear::rules::assert_false(self, stmt, test, msg.as_deref()); - } - if self.enabled(Rule::PytestAssertAlwaysFalse) { - flake8_pytest_style::rules::assert_falsy(self, stmt, test); - } - if self.enabled(Rule::PytestCompositeAssertion) { - flake8_pytest_style::rules::composite_condition( - self, - stmt, - test, - msg.as_deref(), - ); - } - if self.enabled(Rule::AssertOnStringLiteral) { - pylint::rules::assert_on_string_literal(self, test); - } - if self.enabled(Rule::InvalidMockAccess) { - pygrep_hooks::rules::non_existent_mock_method(self, test); - } - } - Stmt::With(ast::StmtWith { items, body, .. }) - | Stmt::AsyncWith(ast::StmtAsyncWith { items, body, .. }) => { - if self.enabled(Rule::AssertRaisesException) { - flake8_bugbear::rules::assert_raises_exception(self, items); - } - if self.enabled(Rule::PytestRaisesWithMultipleStatements) { - flake8_pytest_style::rules::complex_raises(self, stmt, items, body); - } - if self.enabled(Rule::MultipleWithStatements) { - flake8_simplify::rules::multiple_with_statements( - self, - stmt, - body, - self.semantic.stmt_parent(), - ); - } - if self.enabled(Rule::RedefinedLoopName) { - pylint::rules::redefined_loop_name(self, stmt); - } - } - Stmt::While(ast::StmtWhile { body, orelse, .. }) => { - if self.enabled(Rule::FunctionUsesLoopVariable) { - flake8_bugbear::rules::function_uses_loop_variable(self, &Node::Stmt(stmt)); - } - if self.enabled(Rule::UselessElseOnLoop) { - pylint::rules::useless_else_on_loop(self, stmt, body, orelse); - } - if self.enabled(Rule::TryExceptInLoop) { - perflint::rules::try_except_in_loop(self, body); - } - } - Stmt::For(ast::StmtFor { - target, - body, - iter, - orelse, - .. - }) - | Stmt::AsyncFor(ast::StmtAsyncFor { - target, - body, - iter, - orelse, - .. - }) => { - if self.any_enabled(&[Rule::UnusedLoopControlVariable, Rule::IncorrectDictIterator]) - { - self.deferred.for_loops.push(self.semantic.snapshot()); - } - if self.enabled(Rule::LoopVariableOverridesIterator) { - flake8_bugbear::rules::loop_variable_overrides_iterator(self, target, iter); - } - if self.enabled(Rule::FunctionUsesLoopVariable) { - flake8_bugbear::rules::function_uses_loop_variable(self, &Node::Stmt(stmt)); - } - if self.enabled(Rule::ReuseOfGroupbyGenerator) { - flake8_bugbear::rules::reuse_of_groupby_generator(self, target, body, iter); - } - if self.enabled(Rule::UselessElseOnLoop) { - pylint::rules::useless_else_on_loop(self, stmt, body, orelse); - } - if self.enabled(Rule::RedefinedLoopName) { - pylint::rules::redefined_loop_name(self, stmt); - } - if self.enabled(Rule::IterationOverSet) { - pylint::rules::iteration_over_set(self, iter); - } - if stmt.is_for_stmt() { - if self.enabled(Rule::ReimplementedBuiltin) { - flake8_simplify::rules::convert_for_loop_to_any_all(self, stmt); - } - if self.enabled(Rule::InDictKeys) { - flake8_simplify::rules::key_in_dict_for(self, target, iter); - } - if self.enabled(Rule::TryExceptInLoop) { - perflint::rules::try_except_in_loop(self, body); - } - } - if self.enabled(Rule::ManualListComprehension) { - perflint::rules::manual_list_comprehension(self, target, body); - } - if self.enabled(Rule::ManualListCopy) { - perflint::rules::manual_list_copy(self, target, body); - } - if self.enabled(Rule::UnnecessaryListCast) { - perflint::rules::unnecessary_list_cast(self, iter); - } - } - Stmt::Try(ast::StmtTry { - body, - handlers, - orelse, - finalbody, - range: _, - }) - | Stmt::TryStar(ast::StmtTryStar { - body, - handlers, - orelse, - finalbody, - range: _, - }) => { - if self.enabled(Rule::JumpStatementInFinally) { - flake8_bugbear::rules::jump_statement_in_finally(self, finalbody); - } - if self.enabled(Rule::ContinueInFinally) { - if self.settings.target_version <= PythonVersion::Py38 { - pylint::rules::continue_in_finally(self, finalbody); - } - } - if self.enabled(Rule::DefaultExceptNotLast) { - if let Some(diagnostic) = - pyflakes::rules::default_except_not_last(handlers, self.locator) - { - self.diagnostics.push(diagnostic); - } - } - if self.any_enabled(&[ - Rule::DuplicateHandlerException, - Rule::DuplicateTryBlockException, - ]) { - flake8_bugbear::rules::duplicate_exceptions(self, handlers); - } - if self.enabled(Rule::RedundantTupleInExceptionHandler) { - flake8_bugbear::rules::redundant_tuple_in_exception_handler(self, handlers); - } - if self.enabled(Rule::OSErrorAlias) { - pyupgrade::rules::os_error_alias_handlers(self, handlers); - } - if self.enabled(Rule::PytestAssertInExcept) { - flake8_pytest_style::rules::assert_in_exception_handler(self, handlers); - } - if self.enabled(Rule::SuppressibleException) { - flake8_simplify::rules::suppressible_exception( - self, stmt, body, handlers, orelse, finalbody, - ); - } - if self.enabled(Rule::ReturnInTryExceptFinally) { - flake8_simplify::rules::return_in_try_except_finally( - self, body, handlers, finalbody, - ); - } - if self.enabled(Rule::TryConsiderElse) { - tryceratops::rules::try_consider_else(self, body, orelse, handlers); - } - if self.enabled(Rule::VerboseRaise) { - tryceratops::rules::verbose_raise(self, handlers); - } - if self.enabled(Rule::VerboseLogMessage) { - tryceratops::rules::verbose_log_message(self, handlers); - } - if self.enabled(Rule::RaiseWithinTry) { - tryceratops::rules::raise_within_try(self, body, handlers); - } - if self.enabled(Rule::UselessTryExcept) { - tryceratops::rules::useless_try_except(self, handlers); - } - if self.enabled(Rule::ErrorInsteadOfException) { - tryceratops::rules::error_instead_of_exception(self, handlers); - } - } - Stmt::Assign(stmt_assign @ ast::StmtAssign { targets, value, .. }) => { - if self.enabled(Rule::LambdaAssignment) { - if let [target] = &targets[..] { - pycodestyle::rules::lambda_assignment(self, target, value, None, stmt); - } - } - if self.enabled(Rule::AssignmentToOsEnviron) { - flake8_bugbear::rules::assignment_to_os_environ(self, targets); - } - if self.enabled(Rule::HardcodedPasswordString) { - flake8_bandit::rules::assign_hardcoded_password_string(self, value, targets); - } - if self.enabled(Rule::GlobalStatement) { - for target in targets { - if let Expr::Name(ast::ExprName { id, .. }) = target { - pylint::rules::global_statement(self, id); - } - } - } - if self.enabled(Rule::UselessMetaclassType) { - pyupgrade::rules::useless_metaclass_type(self, stmt, value, targets); - } - if self.enabled(Rule::ConvertTypedDictFunctionalToClass) { - pyupgrade::rules::convert_typed_dict_functional_to_class( - self, stmt, targets, value, - ); - } - if self.enabled(Rule::ConvertNamedTupleFunctionalToClass) { - pyupgrade::rules::convert_named_tuple_functional_to_class( - self, stmt, targets, value, - ); - } - if self.enabled(Rule::UnpackedListComprehension) { - pyupgrade::rules::unpacked_list_comprehension(self, targets, value); - } - if self.enabled(Rule::PandasDfVariableName) { - if let Some(diagnostic) = pandas_vet::rules::assignment_to_df(targets) { - self.diagnostics.push(diagnostic); - } - } - if self - .settings - .rules - .enabled(Rule::AirflowVariableNameTaskIdMismatch) - { - if let Some(diagnostic) = - airflow::rules::variable_name_task_id(self, targets, value) - { - self.diagnostics.push(diagnostic); - } - } - if self.settings.rules.enabled(Rule::SelfAssigningVariable) { - if let [target] = targets.as_slice() { - pylint::rules::self_assigning_variable(self, target, value); - } - } - if self.settings.rules.enabled(Rule::TypeParamNameMismatch) { - pylint::rules::type_param_name_mismatch(self, value, targets); - } - if self.settings.rules.enabled(Rule::TypeNameIncorrectVariance) { - pylint::rules::type_name_incorrect_variance(self, value); - } - if self.settings.rules.enabled(Rule::TypeBivariance) { - pylint::rules::type_bivariance(self, value); - } - if self.is_stub { - if self.any_enabled(&[ - Rule::UnprefixedTypeParam, - Rule::AssignmentDefaultInStub, - Rule::UnannotatedAssignmentInStub, - Rule::ComplexAssignmentInStub, - Rule::TypeAliasWithoutAnnotation, - ]) { - // Ignore assignments in function bodies; those are covered by other rules. - if !self - .semantic - .scopes() - .any(|scope| scope.kind.is_any_function()) - { - if self.enabled(Rule::UnprefixedTypeParam) { - flake8_pyi::rules::prefix_type_params(self, value, targets); - } - if self.enabled(Rule::AssignmentDefaultInStub) { - flake8_pyi::rules::assignment_default_in_stub(self, targets, value); - } - if self.enabled(Rule::UnannotatedAssignmentInStub) { - flake8_pyi::rules::unannotated_assignment_in_stub( - self, targets, value, - ); - } - if self.enabled(Rule::ComplexAssignmentInStub) { - flake8_pyi::rules::complex_assignment_in_stub(self, stmt_assign); - } - if self.enabled(Rule::TypeAliasWithoutAnnotation) { - flake8_pyi::rules::type_alias_without_annotation( - self, value, targets, - ); - } - } - } - } - } - Stmt::AnnAssign(ast::StmtAnnAssign { - target, - value, - annotation, - .. - }) => { - if let Some(value) = value { - if self.enabled(Rule::LambdaAssignment) { - pycodestyle::rules::lambda_assignment( - self, - target, - value, - Some(annotation), - stmt, - ); - } - if self.enabled(Rule::SelfAssigningVariable) { - pylint::rules::self_assigning_variable(self, target, value); - } - } - if self.enabled(Rule::UnintentionalTypeAnnotation) { - flake8_bugbear::rules::unintentional_type_annotation( - self, - target, - value.as_deref(), - stmt, - ); - } - if self.is_stub { - if let Some(value) = value { - if self.enabled(Rule::AssignmentDefaultInStub) { - // Ignore assignments in function bodies; those are covered by other rules. - if !self - .semantic - .scopes() - .any(|scope| scope.kind.is_any_function()) - { - flake8_pyi::rules::annotated_assignment_default_in_stub( - self, target, value, annotation, - ); - } - } - } else { - if self.enabled(Rule::UnassignedSpecialVariableInStub) { - flake8_pyi::rules::unassigned_special_variable_in_stub( - self, target, stmt, - ); - } - } - if self.semantic.match_typing_expr(annotation, "TypeAlias") { - if self.enabled(Rule::SnakeCaseTypeAlias) { - flake8_pyi::rules::snake_case_type_alias(self, target); - } - if self.enabled(Rule::TSuffixedTypeAlias) { - flake8_pyi::rules::t_suffixed_type_alias(self, target); - } - } - } - } - Stmt::Delete(ast::StmtDelete { targets, range: _ }) => { - if self.enabled(Rule::GlobalStatement) { - for target in targets { - if let Expr::Name(ast::ExprName { id, .. }) = target { - pylint::rules::global_statement(self, id); - } - } - } - } - Stmt::Expr(ast::StmtExpr { value, range: _ }) => { - if self.enabled(Rule::UselessComparison) { - flake8_bugbear::rules::useless_comparison(self, value); - } - if self.enabled(Rule::UselessExpression) { - flake8_bugbear::rules::useless_expression(self, value); - } - if self.enabled(Rule::InvalidMockAccess) { - pygrep_hooks::rules::uncalled_mock_method(self, value); - } - if self.enabled(Rule::NamedExprWithoutContext) { - pylint::rules::named_expr_without_context(self, value); - } - if self.enabled(Rule::AsyncioDanglingTask) { - ruff::rules::asyncio_dangling_task(self, value); - } - } - _ => {} - } + analyze::statement(stmt, self); // Step 2: Binding match stmt { @@ -2215,1392 +797,7 @@ where } // Step 1: Analysis - match expr { - Expr::Subscript(subscript @ ast::ExprSubscript { value, slice, .. }) => { - // Ex) Optional[...], Union[...] - if self.any_enabled(&[ - Rule::FutureRewritableTypeAnnotation, - Rule::NonPEP604Annotation, - ]) { - if let Some(operator) = typing::to_pep604_operator(value, slice, &self.semantic) - { - if self.enabled(Rule::FutureRewritableTypeAnnotation) { - if !self.is_stub - && self.settings.target_version < PythonVersion::Py310 - && self.settings.target_version >= PythonVersion::Py37 - && !self.semantic.future_annotations() - && self.semantic.in_annotation() - && !self.settings.pyupgrade.keep_runtime_typing - { - flake8_future_annotations::rules::future_rewritable_type_annotation( - self, value, - ); - } - } - if self.enabled(Rule::NonPEP604Annotation) { - if self.is_stub - || self.settings.target_version >= PythonVersion::Py310 - || (self.settings.target_version >= PythonVersion::Py37 - && self.semantic.future_annotations() - && self.semantic.in_annotation() - && !self.settings.pyupgrade.keep_runtime_typing) - { - pyupgrade::rules::use_pep604_annotation( - self, expr, slice, operator, - ); - } - } - } - } - - // Ex) list[...] - if self.enabled(Rule::FutureRequiredTypeAnnotation) { - if !self.is_stub - && self.settings.target_version < PythonVersion::Py39 - && !self.semantic.future_annotations() - && self.semantic.in_annotation() - && typing::is_pep585_generic(value, &self.semantic) - { - flake8_future_annotations::rules::future_required_type_annotation( - self, - expr, - flake8_future_annotations::rules::Reason::PEP585, - ); - } - } - - // Ex) Union[...] - if self.any_enabled(&[Rule::UnnecessaryLiteralUnion, Rule::DuplicateUnionMember]) { - // Determine if the current expression is an union - // Avoid duplicate checks if the parent is an `Union[...]` since these rules traverse nested unions - let is_unchecked_union = self - .semantic - .expr_grandparent() - .and_then(Expr::as_subscript_expr) - .map_or(true, |parent| { - !self.semantic.match_typing_expr(&parent.value, "Union") - }); - - if is_unchecked_union { - if self.enabled(Rule::UnnecessaryLiteralUnion) { - flake8_pyi::rules::unnecessary_literal_union(self, expr); - } - if self.enabled(Rule::DuplicateUnionMember) { - flake8_pyi::rules::duplicate_union_member(self, expr); - } - } - } - - if self.any_enabled(&[ - Rule::SysVersionSlice3, - Rule::SysVersion2, - Rule::SysVersion0, - Rule::SysVersionSlice1, - ]) { - flake8_2020::rules::subscript(self, value, slice); - } - if self.enabled(Rule::UncapitalizedEnvironmentVariables) { - flake8_simplify::rules::use_capital_environment_variables(self, expr); - } - if self.enabled(Rule::UnnecessaryIterableAllocationForFirstElement) { - ruff::rules::unnecessary_iterable_allocation_for_first_element(self, subscript); - } - - if self.enabled(Rule::InvalidIndexType) { - ruff::rules::invalid_index_type(self, subscript); - } - - pandas_vet::rules::subscript(self, value, expr); - } - Expr::Tuple(ast::ExprTuple { - elts, - ctx, - range: _, - }) - | Expr::List(ast::ExprList { - elts, - ctx, - range: _, - }) => { - if ctx.is_store() { - let check_too_many_expressions = - self.enabled(Rule::ExpressionsInStarAssignment); - let check_two_starred_expressions = - self.enabled(Rule::MultipleStarredExpressions); - if let Some(diagnostic) = pyflakes::rules::starred_expressions( - elts, - check_too_many_expressions, - check_two_starred_expressions, - expr.range(), - ) { - self.diagnostics.push(diagnostic); - } - } - } - Expr::Name(ast::ExprName { id, ctx, range }) => { - match ctx { - ExprContext::Load => { - if self.enabled(Rule::TypingTextStrAlias) { - pyupgrade::rules::typing_text_str_alias(self, expr); - } - if self.enabled(Rule::NumpyDeprecatedTypeAlias) { - numpy::rules::deprecated_type_alias(self, expr); - } - if self.enabled(Rule::NumpyDeprecatedFunction) { - numpy::rules::deprecated_function(self, expr); - } - if self.is_stub { - if self.enabled(Rule::CollectionsNamedTuple) { - flake8_pyi::rules::collections_named_tuple(self, expr); - } - } - - // Ex) List[...] - if self.any_enabled(&[ - Rule::FutureRewritableTypeAnnotation, - Rule::NonPEP585Annotation, - ]) { - if let Some(replacement) = - typing::to_pep585_generic(expr, &self.semantic) - { - if self.enabled(Rule::FutureRewritableTypeAnnotation) { - if !self.is_stub - && self.settings.target_version < PythonVersion::Py39 - && self.settings.target_version >= PythonVersion::Py37 - && !self.semantic.future_annotations() - && self.semantic.in_annotation() - && !self.settings.pyupgrade.keep_runtime_typing - { - flake8_future_annotations::rules::future_rewritable_type_annotation( - self, expr, - ); - } - } - if self.enabled(Rule::NonPEP585Annotation) { - if self.is_stub - || self.settings.target_version >= PythonVersion::Py39 - || (self.settings.target_version >= PythonVersion::Py37 - && self.semantic.future_annotations() - && self.semantic.in_annotation() - && !self.settings.pyupgrade.keep_runtime_typing) - { - pyupgrade::rules::use_pep585_annotation( - self, - expr, - &replacement, - ); - } - } - } - } - } - ExprContext::Store => { - if self.enabled(Rule::NonLowercaseVariableInFunction) { - if self.semantic.scope().kind.is_any_function() { - // Ignore globals. - if !self.semantic.scope().get(id).map_or(false, |binding_id| { - self.semantic.binding(binding_id).is_global() - }) { - pep8_naming::rules::non_lowercase_variable_in_function( - self, expr, id, - ); - } - } - } - if self.enabled(Rule::MixedCaseVariableInClassScope) { - if let ScopeKind::Class(ast::StmtClassDef { bases, .. }) = - &self.semantic.scope().kind - { - pep8_naming::rules::mixed_case_variable_in_class_scope( - self, expr, id, bases, - ); - } - } - if self.enabled(Rule::MixedCaseVariableInGlobalScope) { - if matches!(self.semantic.scope().kind, ScopeKind::Module) { - pep8_naming::rules::mixed_case_variable_in_global_scope( - self, expr, id, - ); - } - } - if self.enabled(Rule::AmbiguousVariableName) { - if let Some(diagnostic) = - pycodestyle::rules::ambiguous_variable_name(id, expr.range()) - { - self.diagnostics.push(diagnostic); - } - } - if let ScopeKind::Class(class_def) = self.semantic.scope().kind { - if self.enabled(Rule::BuiltinAttributeShadowing) { - flake8_builtins::rules::builtin_attribute_shadowing( - self, class_def, id, *range, - ); - } - } else { - if self.enabled(Rule::BuiltinVariableShadowing) { - flake8_builtins::rules::builtin_variable_shadowing( - self, id, *range, - ); - } - } - } - ExprContext::Del => {} - } - if self.enabled(Rule::SixPY3) { - flake8_2020::rules::name_or_attribute(self, expr); - } - if self.enabled(Rule::LoadBeforeGlobalDeclaration) { - pylint::rules::load_before_global_declaration(self, id, expr); - } - } - Expr::Attribute(ast::ExprAttribute { attr, value, .. }) => { - // Ex) typing.List[...] - if self.any_enabled(&[ - Rule::FutureRewritableTypeAnnotation, - Rule::NonPEP585Annotation, - ]) { - if let Some(replacement) = typing::to_pep585_generic(expr, &self.semantic) { - if self.enabled(Rule::FutureRewritableTypeAnnotation) { - if !self.is_stub - && self.settings.target_version < PythonVersion::Py39 - && self.settings.target_version >= PythonVersion::Py37 - && !self.semantic.future_annotations() - && self.semantic.in_annotation() - && !self.settings.pyupgrade.keep_runtime_typing - { - flake8_future_annotations::rules::future_rewritable_type_annotation( - self, expr, - ); - } - } - if self.enabled(Rule::NonPEP585Annotation) { - if self.is_stub - || self.settings.target_version >= PythonVersion::Py39 - || (self.settings.target_version >= PythonVersion::Py37 - && self.semantic.future_annotations() - && self.semantic.in_annotation() - && !self.settings.pyupgrade.keep_runtime_typing) - { - pyupgrade::rules::use_pep585_annotation(self, expr, &replacement); - } - } - } - } - if self.enabled(Rule::DatetimeTimezoneUTC) { - if self.settings.target_version >= PythonVersion::Py311 { - pyupgrade::rules::datetime_utc_alias(self, expr); - } - } - if self.enabled(Rule::TypingTextStrAlias) { - pyupgrade::rules::typing_text_str_alias(self, expr); - } - if self.enabled(Rule::NumpyDeprecatedTypeAlias) { - numpy::rules::deprecated_type_alias(self, expr); - } - if self.enabled(Rule::NumpyDeprecatedFunction) { - numpy::rules::deprecated_function(self, expr); - } - if self.enabled(Rule::DeprecatedMockImport) { - pyupgrade::rules::deprecated_mock_attribute(self, expr); - } - if self.enabled(Rule::SixPY3) { - flake8_2020::rules::name_or_attribute(self, expr); - } - if self.enabled(Rule::BannedApi) { - flake8_tidy_imports::rules::banned_attribute_access(self, expr); - } - if self.enabled(Rule::PrivateMemberAccess) { - flake8_self::rules::private_member_access(self, expr); - } - if self.is_stub { - if self.enabled(Rule::CollectionsNamedTuple) { - flake8_pyi::rules::collections_named_tuple(self, expr); - } - } - pandas_vet::rules::attr(self, attr, value, expr); - } - Expr::Call( - call @ ast::ExprCall { - func, - args, - keywords, - range: _, - }, - ) => { - if self.any_enabled(&[ - // pyflakes - Rule::StringDotFormatInvalidFormat, - Rule::StringDotFormatExtraNamedArguments, - Rule::StringDotFormatExtraPositionalArguments, - Rule::StringDotFormatMissingArguments, - Rule::StringDotFormatMixingAutomatic, - // pyupgrade - Rule::FormatLiterals, - Rule::FString, - // flynt - Rule::StaticJoinToFString, - ]) { - if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() { - let attr = attr.as_str(); - if let Expr::Constant(ast::ExprConstant { - value: Constant::Str(val), - .. - }) = value.as_ref() - { - if attr == "join" { - // "...".join(...) call - if self.enabled(Rule::StaticJoinToFString) { - flynt::rules::static_join_to_fstring(self, expr, val); - } - } else if attr == "format" { - // "...".format(...) call - let location = expr.range(); - match pyflakes::format::FormatSummary::try_from(val.as_ref()) { - Err(e) => { - if self.enabled(Rule::StringDotFormatInvalidFormat) { - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::StringDotFormatInvalidFormat { - message: pyflakes::format::error_to_string(&e), - }, - location, - )); - } - } - Ok(summary) => { - if self.enabled(Rule::StringDotFormatExtraNamedArguments) { - pyflakes::rules::string_dot_format_extra_named_arguments( - self, &summary, keywords, location, - ); - } - if self - .enabled(Rule::StringDotFormatExtraPositionalArguments) - { - pyflakes::rules::string_dot_format_extra_positional_arguments( - self, - &summary, args, location, - ); - } - if self.enabled(Rule::StringDotFormatMissingArguments) { - pyflakes::rules::string_dot_format_missing_argument( - self, &summary, args, keywords, location, - ); - } - if self.enabled(Rule::StringDotFormatMixingAutomatic) { - pyflakes::rules::string_dot_format_mixing_automatic( - self, &summary, location, - ); - } - if self.enabled(Rule::FormatLiterals) { - pyupgrade::rules::format_literals(self, &summary, expr); - } - if self.enabled(Rule::FString) { - pyupgrade::rules::f_strings( - self, - &summary, - expr, - value, - self.settings.line_length, - ); - } - } - } - } - } - } - } - if self.enabled(Rule::TypeOfPrimitive) { - pyupgrade::rules::type_of_primitive(self, expr, func, args); - } - if self.enabled(Rule::DeprecatedUnittestAlias) { - pyupgrade::rules::deprecated_unittest_alias(self, func); - } - if self.enabled(Rule::SuperCallWithParameters) { - pyupgrade::rules::super_call_with_parameters(self, expr, func, args); - } - if self.enabled(Rule::UnnecessaryEncodeUTF8) { - pyupgrade::rules::unnecessary_encode_utf8(self, expr, func, args, keywords); - } - if self.enabled(Rule::RedundantOpenModes) { - pyupgrade::rules::redundant_open_modes(self, expr); - } - if self.enabled(Rule::NativeLiterals) { - pyupgrade::rules::native_literals(self, expr, func, args, keywords); - } - if self.enabled(Rule::OpenAlias) { - pyupgrade::rules::open_alias(self, expr, func); - } - if self.enabled(Rule::ReplaceUniversalNewlines) { - pyupgrade::rules::replace_universal_newlines(self, func, keywords); - } - if self.enabled(Rule::ReplaceStdoutStderr) { - pyupgrade::rules::replace_stdout_stderr(self, expr, func, args, keywords); - } - if self.enabled(Rule::OSErrorAlias) { - pyupgrade::rules::os_error_alias_call(self, func); - } - if self.enabled(Rule::NonPEP604Isinstance) { - if self.settings.target_version >= PythonVersion::Py310 { - pyupgrade::rules::use_pep604_isinstance(self, expr, func, args); - } - } - if self.enabled(Rule::BlockingHttpCallInAsyncFunction) { - flake8_async::rules::blocking_http_call(self, expr); - } - if self.enabled(Rule::OpenSleepOrSubprocessInAsyncFunction) { - flake8_async::rules::open_sleep_or_subprocess_call(self, expr); - } - if self.enabled(Rule::BlockingOsCallInAsyncFunction) { - flake8_async::rules::blocking_os_call(self, expr); - } - if self.any_enabled(&[Rule::Print, Rule::PPrint]) { - flake8_print::rules::print_call(self, func, keywords); - } - if self.any_enabled(&[ - Rule::SuspiciousPickleUsage, - Rule::SuspiciousMarshalUsage, - Rule::SuspiciousInsecureHashUsage, - Rule::SuspiciousInsecureCipherUsage, - Rule::SuspiciousInsecureCipherModeUsage, - Rule::SuspiciousMktempUsage, - Rule::SuspiciousEvalUsage, - Rule::SuspiciousMarkSafeUsage, - Rule::SuspiciousURLOpenUsage, - Rule::SuspiciousNonCryptographicRandomUsage, - Rule::SuspiciousXMLCElementTreeUsage, - Rule::SuspiciousXMLElementTreeUsage, - Rule::SuspiciousXMLExpatReaderUsage, - Rule::SuspiciousXMLExpatBuilderUsage, - Rule::SuspiciousXMLSaxUsage, - Rule::SuspiciousXMLMiniDOMUsage, - Rule::SuspiciousXMLPullDOMUsage, - Rule::SuspiciousXMLETreeUsage, - Rule::SuspiciousUnverifiedContextUsage, - Rule::SuspiciousTelnetUsage, - Rule::SuspiciousFTPLibUsage, - ]) { - flake8_bandit::rules::suspicious_function_call(self, expr); - } - if self.enabled(Rule::ReSubPositionalArgs) { - flake8_bugbear::rules::re_sub_positional_args(self, call); - } - if self.enabled(Rule::UnreliableCallableCheck) { - flake8_bugbear::rules::unreliable_callable_check(self, expr, func, args); - } - if self.enabled(Rule::StripWithMultiCharacters) { - flake8_bugbear::rules::strip_with_multi_characters(self, expr, func, args); - } - if self.enabled(Rule::GetAttrWithConstant) { - flake8_bugbear::rules::getattr_with_constant(self, expr, func, args); - } - if self.enabled(Rule::SetAttrWithConstant) { - flake8_bugbear::rules::setattr_with_constant(self, expr, func, args); - } - if self.enabled(Rule::UselessContextlibSuppress) { - flake8_bugbear::rules::useless_contextlib_suppress(self, expr, func, args); - } - if self.enabled(Rule::StarArgUnpackingAfterKeywordArg) { - flake8_bugbear::rules::star_arg_unpacking_after_keyword_arg( - self, args, keywords, - ); - } - if self.enabled(Rule::ZipWithoutExplicitStrict) { - if self.settings.target_version >= PythonVersion::Py310 { - flake8_bugbear::rules::zip_without_explicit_strict( - self, expr, func, args, keywords, - ); - } - } - if self.enabled(Rule::NoExplicitStacklevel) { - flake8_bugbear::rules::no_explicit_stacklevel(self, func, keywords); - } - if self.enabled(Rule::UnnecessaryDictKwargs) { - flake8_pie::rules::unnecessary_dict_kwargs(self, expr, keywords); - } - if self.enabled(Rule::ExecBuiltin) { - flake8_bandit::rules::exec_used(self, func); - } - if self.enabled(Rule::BadFilePermissions) { - flake8_bandit::rules::bad_file_permissions(self, func, args, keywords); - } - if self.enabled(Rule::RequestWithNoCertValidation) { - flake8_bandit::rules::request_with_no_cert_validation(self, func, keywords); - } - if self.enabled(Rule::UnsafeYAMLLoad) { - flake8_bandit::rules::unsafe_yaml_load(self, func, args, keywords); - } - if self.enabled(Rule::SnmpInsecureVersion) { - flake8_bandit::rules::snmp_insecure_version(self, func, keywords); - } - if self.enabled(Rule::SnmpWeakCryptography) { - flake8_bandit::rules::snmp_weak_cryptography(self, func, args, keywords); - } - if self.enabled(Rule::Jinja2AutoescapeFalse) { - flake8_bandit::rules::jinja2_autoescape_false(self, func, keywords); - } - if self.enabled(Rule::HardcodedPasswordFuncArg) { - flake8_bandit::rules::hardcoded_password_func_arg(self, keywords); - } - if self.enabled(Rule::HardcodedSQLExpression) { - flake8_bandit::rules::hardcoded_sql_expression(self, expr); - } - if self.enabled(Rule::HashlibInsecureHashFunction) { - flake8_bandit::rules::hashlib_insecure_hash_functions( - self, func, args, keywords, - ); - } - if self.enabled(Rule::RequestWithoutTimeout) { - flake8_bandit::rules::request_without_timeout(self, func, keywords); - } - if self.enabled(Rule::ParamikoCall) { - flake8_bandit::rules::paramiko_call(self, func); - } - if self.enabled(Rule::LoggingConfigInsecureListen) { - flake8_bandit::rules::logging_config_insecure_listen(self, func, keywords); - } - if self.any_enabled(&[ - Rule::SubprocessWithoutShellEqualsTrue, - Rule::SubprocessPopenWithShellEqualsTrue, - Rule::CallWithShellEqualsTrue, - Rule::StartProcessWithAShell, - Rule::StartProcessWithNoShell, - Rule::StartProcessWithPartialPath, - Rule::UnixCommandWildcardInjection, - ]) { - flake8_bandit::rules::shell_injection(self, func, args, keywords); - } - if self.enabled(Rule::UnnecessaryGeneratorList) { - flake8_comprehensions::rules::unnecessary_generator_list( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryGeneratorSet) { - flake8_comprehensions::rules::unnecessary_generator_set( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryGeneratorDict) { - flake8_comprehensions::rules::unnecessary_generator_dict( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryListComprehensionSet) { - flake8_comprehensions::rules::unnecessary_list_comprehension_set( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryListComprehensionDict) { - flake8_comprehensions::rules::unnecessary_list_comprehension_dict( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryLiteralSet) { - flake8_comprehensions::rules::unnecessary_literal_set( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryLiteralDict) { - flake8_comprehensions::rules::unnecessary_literal_dict( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryCollectionCall) { - flake8_comprehensions::rules::unnecessary_collection_call( - self, - expr, - func, - args, - keywords, - &self.settings.flake8_comprehensions, - ); - } - if self.enabled(Rule::UnnecessaryLiteralWithinTupleCall) { - flake8_comprehensions::rules::unnecessary_literal_within_tuple_call( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryLiteralWithinListCall) { - flake8_comprehensions::rules::unnecessary_literal_within_list_call( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryLiteralWithinDictCall) { - flake8_comprehensions::rules::unnecessary_literal_within_dict_call( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessaryListCall) { - flake8_comprehensions::rules::unnecessary_list_call(self, expr, func, args); - } - if self.enabled(Rule::UnnecessaryCallAroundSorted) { - flake8_comprehensions::rules::unnecessary_call_around_sorted( - self, expr, func, args, - ); - } - if self.enabled(Rule::UnnecessaryDoubleCastOrProcess) { - flake8_comprehensions::rules::unnecessary_double_cast_or_process( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::UnnecessarySubscriptReversal) { - flake8_comprehensions::rules::unnecessary_subscript_reversal( - self, expr, func, args, - ); - } - if self.enabled(Rule::UnnecessaryMap) { - flake8_comprehensions::rules::unnecessary_map( - self, - expr, - self.semantic.expr_parent(), - func, - args, - ); - } - if self.enabled(Rule::UnnecessaryComprehensionAnyAll) { - flake8_comprehensions::rules::unnecessary_comprehension_any_all( - self, expr, func, args, keywords, - ); - } - if self.enabled(Rule::BooleanPositionalValueInFunctionCall) { - flake8_boolean_trap::rules::check_boolean_positional_value_in_function_call( - self, args, func, - ); - } - if self.enabled(Rule::Debugger) { - flake8_debugger::rules::debugger_call(self, expr, func); - } - if self.enabled(Rule::PandasUseOfInplaceArgument) { - pandas_vet::rules::inplace_argument(self, expr, func, args, keywords); - } - pandas_vet::rules::call(self, func); - if self.enabled(Rule::PandasUseOfDotReadTable) { - pandas_vet::rules::use_of_read_table(self, func, keywords); - } - if self.enabled(Rule::PandasUseOfPdMerge) { - pandas_vet::rules::use_of_pd_merge(self, func); - } - if self.enabled(Rule::CallDatetimeWithoutTzinfo) { - flake8_datetimez::rules::call_datetime_without_tzinfo( - self, - func, - args, - keywords, - expr.range(), - ); - } - if self.enabled(Rule::CallDatetimeToday) { - flake8_datetimez::rules::call_datetime_today(self, func, expr.range()); - } - if self.enabled(Rule::CallDatetimeUtcnow) { - flake8_datetimez::rules::call_datetime_utcnow(self, func, expr.range()); - } - if self.enabled(Rule::CallDatetimeUtcfromtimestamp) { - flake8_datetimez::rules::call_datetime_utcfromtimestamp( - self, - func, - expr.range(), - ); - } - if self.enabled(Rule::CallDatetimeNowWithoutTzinfo) { - flake8_datetimez::rules::call_datetime_now_without_tzinfo( - self, - func, - args, - keywords, - expr.range(), - ); - } - if self.enabled(Rule::CallDatetimeFromtimestamp) { - flake8_datetimez::rules::call_datetime_fromtimestamp( - self, - func, - args, - keywords, - expr.range(), - ); - } - if self.enabled(Rule::CallDatetimeStrptimeWithoutZone) { - flake8_datetimez::rules::call_datetime_strptime_without_zone( - self, - func, - args, - expr.range(), - ); - } - if self.enabled(Rule::CallDateToday) { - flake8_datetimez::rules::call_date_today(self, func, expr.range()); - } - if self.enabled(Rule::CallDateFromtimestamp) { - flake8_datetimez::rules::call_date_fromtimestamp(self, func, expr.range()); - } - if self.enabled(Rule::Eval) { - pygrep_hooks::rules::no_eval(self, func); - } - if self.enabled(Rule::DeprecatedLogWarn) { - pygrep_hooks::rules::deprecated_log_warn(self, func); - } - if self.enabled(Rule::UnnecessaryDirectLambdaCall) { - pylint::rules::unnecessary_direct_lambda_call(self, expr, func); - } - if self.enabled(Rule::SysExitAlias) { - pylint::rules::sys_exit_alias(self, func); - } - if self.enabled(Rule::BadStrStripCall) { - pylint::rules::bad_str_strip_call(self, func, args); - } - if self.enabled(Rule::InvalidEnvvarDefault) { - pylint::rules::invalid_envvar_default(self, func, args, keywords); - } - if self.enabled(Rule::InvalidEnvvarValue) { - pylint::rules::invalid_envvar_value(self, func, args, keywords); - } - if self.enabled(Rule::NestedMinMax) { - pylint::rules::nested_min_max(self, expr, func, args, keywords); - } - if self.enabled(Rule::PytestPatchWithLambda) { - if let Some(diagnostic) = - flake8_pytest_style::rules::patch_with_lambda(func, args, keywords) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::PytestUnittestAssertion) { - if let Some(diagnostic) = flake8_pytest_style::rules::unittest_assertion( - self, expr, func, args, keywords, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::SubprocessPopenPreexecFn) { - pylint::rules::subprocess_popen_preexec_fn(self, func, keywords); - } - if self.any_enabled(&[ - Rule::PytestRaisesWithoutException, - Rule::PytestRaisesTooBroad, - ]) { - flake8_pytest_style::rules::raises_call(self, func, args, keywords); - } - if self.enabled(Rule::PytestFailWithoutMessage) { - flake8_pytest_style::rules::fail_call(self, func, args, keywords); - } - if self.enabled(Rule::PairwiseOverZipped) { - if self.settings.target_version >= PythonVersion::Py310 { - ruff::rules::pairwise_over_zipped(self, func, args); - } - } - if self.any_enabled(&[ - Rule::FStringInGetTextFuncCall, - Rule::FormatInGetTextFuncCall, - Rule::PrintfInGetTextFuncCall, - ]) && flake8_gettext::is_gettext_func_call( - func, - &self.settings.flake8_gettext.functions_names, - ) { - if self.enabled(Rule::FStringInGetTextFuncCall) { - flake8_gettext::rules::f_string_in_gettext_func_call(self, args); - } - if self.enabled(Rule::FormatInGetTextFuncCall) { - flake8_gettext::rules::format_in_gettext_func_call(self, args); - } - if self.enabled(Rule::PrintfInGetTextFuncCall) { - flake8_gettext::rules::printf_in_gettext_func_call(self, args); - } - } - if self.enabled(Rule::UncapitalizedEnvironmentVariables) { - flake8_simplify::rules::use_capital_environment_variables(self, expr); - } - if self.enabled(Rule::OpenFileWithContextHandler) { - flake8_simplify::rules::open_file_with_context_handler(self, func); - } - if self.enabled(Rule::DictGetWithNoneDefault) { - flake8_simplify::rules::dict_get_with_none_default(self, expr); - } - if self.any_enabled(&[ - Rule::OsPathAbspath, - Rule::OsChmod, - Rule::OsMkdir, - Rule::OsMakedirs, - Rule::OsRename, - Rule::OsReplace, - Rule::OsRmdir, - Rule::OsRemove, - Rule::OsUnlink, - Rule::OsGetcwd, - Rule::OsPathExists, - Rule::OsPathExpanduser, - Rule::OsPathIsdir, - Rule::OsPathIsfile, - Rule::OsPathIslink, - Rule::OsReadlink, - Rule::OsStat, - Rule::OsPathIsabs, - Rule::OsPathJoin, - Rule::OsPathBasename, - Rule::OsPathSamefile, - Rule::OsPathSplitext, - Rule::BuiltinOpen, - Rule::PyPath, - Rule::OsPathGetsize, - Rule::OsPathGetatime, - Rule::OsPathGetmtime, - Rule::OsPathGetctime, - ]) { - flake8_use_pathlib::rules::replaceable_by_pathlib(self, func); - } - if self.enabled(Rule::PathConstructorCurrentDirectory) { - flake8_use_pathlib::rules::path_constructor_current_directory(self, expr, func); - } - if self.enabled(Rule::OsSepSplit) { - flake8_use_pathlib::rules::os_sep_split(self, func, args, keywords); - } - if self.enabled(Rule::NumpyLegacyRandom) { - numpy::rules::legacy_random(self, func); - } - if self.any_enabled(&[ - Rule::LoggingStringFormat, - Rule::LoggingPercentFormat, - Rule::LoggingStringConcat, - Rule::LoggingFString, - Rule::LoggingWarn, - Rule::LoggingExtraAttrClash, - Rule::LoggingExcInfo, - Rule::LoggingRedundantExcInfo, - ]) { - flake8_logging_format::rules::logging_call(self, func, args, keywords); - } - if self.any_enabled(&[Rule::LoggingTooFewArgs, Rule::LoggingTooManyArgs]) { - pylint::rules::logging_call(self, func, args, keywords); - } - if self.enabled(Rule::DjangoLocalsInRenderFunction) { - flake8_django::rules::locals_in_render_function(self, func, args, keywords); - } - if self.is_stub && self.enabled(Rule::UnsupportedMethodCallOnAll) { - flake8_pyi::rules::unsupported_method_call_on_all(self, func); - } - } - Expr::Dict(ast::ExprDict { - keys, - values, - range: _, - }) => { - if self.any_enabled(&[ - Rule::MultiValueRepeatedKeyLiteral, - Rule::MultiValueRepeatedKeyVariable, - ]) { - pyflakes::rules::repeated_keys(self, keys, values); - } - if self.enabled(Rule::UnnecessarySpread) { - flake8_pie::rules::unnecessary_spread(self, keys, values); - } - } - Expr::Set(ast::ExprSet { elts, range: _ }) => { - if self.enabled(Rule::DuplicateValue) { - flake8_bugbear::rules::duplicate_value(self, elts); - } - } - Expr::Yield(_) => { - if self.enabled(Rule::YieldOutsideFunction) { - pyflakes::rules::yield_outside_function(self, expr); - } - if self.enabled(Rule::YieldInInit) { - pylint::rules::yield_in_init(self, expr); - } - } - Expr::YieldFrom(yield_from) => { - if self.enabled(Rule::YieldOutsideFunction) { - pyflakes::rules::yield_outside_function(self, expr); - } - if self.enabled(Rule::YieldInInit) { - pylint::rules::yield_in_init(self, expr); - } - if self.enabled(Rule::YieldFromInAsyncFunction) { - pylint::rules::yield_from_in_async_function(self, yield_from); - } - } - Expr::Await(_) => { - if self.enabled(Rule::YieldOutsideFunction) { - pyflakes::rules::yield_outside_function(self, expr); - } - if self.enabled(Rule::AwaitOutsideAsync) { - pylint::rules::await_outside_async(self, expr); - } - } - Expr::JoinedStr(ast::ExprJoinedStr { values, range: _ }) => { - if self.enabled(Rule::FStringMissingPlaceholders) { - pyflakes::rules::f_string_missing_placeholders(expr, values, self); - } - if self.enabled(Rule::HardcodedSQLExpression) { - flake8_bandit::rules::hardcoded_sql_expression(self, expr); - } - if self.enabled(Rule::ExplicitFStringTypeConversion) { - ruff::rules::explicit_f_string_type_conversion(self, expr, values); - } - } - Expr::BinOp(ast::ExprBinOp { - left, - op: Operator::RShift, - .. - }) => { - if self.enabled(Rule::InvalidPrintSyntax) { - pyflakes::rules::invalid_print_syntax(self, left); - } - } - Expr::BinOp(ast::ExprBinOp { - left, - op: Operator::Mod, - right, - range: _, - }) => { - if let Expr::Constant(ast::ExprConstant { - value: Constant::Str(value), - .. - }) = left.as_ref() - { - if self.any_enabled(&[ - Rule::PercentFormatInvalidFormat, - Rule::PercentFormatExpectedMapping, - Rule::PercentFormatExpectedSequence, - Rule::PercentFormatExtraNamedArguments, - Rule::PercentFormatMissingArgument, - Rule::PercentFormatMixedPositionalAndNamed, - Rule::PercentFormatPositionalCountMismatch, - Rule::PercentFormatStarRequiresSequence, - Rule::PercentFormatUnsupportedFormatCharacter, - ]) { - let location = expr.range(); - match pyflakes::cformat::CFormatSummary::try_from(value.as_str()) { - Err(CFormatError { - typ: CFormatErrorType::UnsupportedFormatChar(c), - .. - }) => { - if self.enabled(Rule::PercentFormatUnsupportedFormatCharacter) { - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::PercentFormatUnsupportedFormatCharacter { - char: c, - }, - location, - )); - } - } - Err(e) => { - if self.enabled(Rule::PercentFormatInvalidFormat) { - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::PercentFormatInvalidFormat { - message: e.to_string(), - }, - location, - )); - } - } - Ok(summary) => { - if self.enabled(Rule::PercentFormatExpectedMapping) { - pyflakes::rules::percent_format_expected_mapping( - self, &summary, right, location, - ); - } - if self.enabled(Rule::PercentFormatExpectedSequence) { - pyflakes::rules::percent_format_expected_sequence( - self, &summary, right, location, - ); - } - if self.enabled(Rule::PercentFormatExtraNamedArguments) { - pyflakes::rules::percent_format_extra_named_arguments( - self, &summary, right, location, - ); - } - if self.enabled(Rule::PercentFormatMissingArgument) { - pyflakes::rules::percent_format_missing_arguments( - self, &summary, right, location, - ); - } - if self.enabled(Rule::PercentFormatMixedPositionalAndNamed) { - pyflakes::rules::percent_format_mixed_positional_and_named( - self, &summary, location, - ); - } - if self.enabled(Rule::PercentFormatPositionalCountMismatch) { - pyflakes::rules::percent_format_positional_count_mismatch( - self, &summary, right, location, - ); - } - if self.enabled(Rule::PercentFormatStarRequiresSequence) { - pyflakes::rules::percent_format_star_requires_sequence( - self, &summary, right, location, - ); - } - } - } - } - if self.enabled(Rule::PrintfStringFormatting) { - pyupgrade::rules::printf_string_formatting(self, expr, right, self.locator); - } - if self.enabled(Rule::BadStringFormatType) { - pylint::rules::bad_string_format_type(self, expr, right); - } - if self.enabled(Rule::HardcodedSQLExpression) { - flake8_bandit::rules::hardcoded_sql_expression(self, expr); - } - } - } - Expr::BinOp(ast::ExprBinOp { - op: Operator::Add, .. - }) => { - if self.enabled(Rule::ExplicitStringConcatenation) { - if let Some(diagnostic) = flake8_implicit_str_concat::rules::explicit(expr) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::CollectionLiteralConcatenation) { - ruff::rules::collection_literal_concatenation(self, expr); - } - if self.enabled(Rule::HardcodedSQLExpression) { - flake8_bandit::rules::hardcoded_sql_expression(self, expr); - } - } - Expr::BinOp(ast::ExprBinOp { - op: Operator::BitOr, - .. - }) => { - // Ex) `str | None` - if self.enabled(Rule::FutureRequiredTypeAnnotation) { - if !self.is_stub - && self.settings.target_version < PythonVersion::Py310 - && !self.semantic.future_annotations() - && self.semantic.in_annotation() - { - flake8_future_annotations::rules::future_required_type_annotation( - self, - expr, - flake8_future_annotations::rules::Reason::PEP604, - ); - } - } - if self.is_stub { - if self.enabled(Rule::DuplicateUnionMember) - && self.semantic.in_type_definition() - // Avoid duplicate checks if the parent is an `|` - && !matches!( - self.semantic.expr_parent(), - Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) - ) - { - flake8_pyi::rules::duplicate_union_member(self, expr); - } - if self.enabled(Rule::UnnecessaryLiteralUnion) - // Avoid duplicate checks if the parent is an `|` - && !matches!( - self.semantic.expr_parent(), - Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) - ) - { - flake8_pyi::rules::unnecessary_literal_union(self, expr); - } - } - } - Expr::UnaryOp(ast::ExprUnaryOp { - op, - operand, - range: _, - }) => { - let check_not_in = self.enabled(Rule::NotInTest); - let check_not_is = self.enabled(Rule::NotIsTest); - if check_not_in || check_not_is { - pycodestyle::rules::not_tests( - self, - expr, - *op, - operand, - check_not_in, - check_not_is, - ); - } - if self.enabled(Rule::UnaryPrefixIncrementDecrement) { - flake8_bugbear::rules::unary_prefix_increment_decrement( - self, expr, *op, operand, - ); - } - if self.enabled(Rule::NegateEqualOp) { - flake8_simplify::rules::negation_with_equal_op(self, expr, *op, operand); - } - if self.enabled(Rule::NegateNotEqualOp) { - flake8_simplify::rules::negation_with_not_equal_op(self, expr, *op, operand); - } - if self.enabled(Rule::DoubleNegation) { - flake8_simplify::rules::double_negation(self, expr, *op, operand); - } - } - Expr::Compare(ast::ExprCompare { - left, - ops, - comparators, - range: _, - }) => { - let check_none_comparisons = self.enabled(Rule::NoneComparison); - let check_true_false_comparisons = self.enabled(Rule::TrueFalseComparison); - if check_none_comparisons || check_true_false_comparisons { - pycodestyle::rules::literal_comparisons( - self, - expr, - left, - ops, - comparators, - check_none_comparisons, - check_true_false_comparisons, - ); - } - if self.enabled(Rule::IsLiteral) { - pyflakes::rules::invalid_literal_comparison(self, left, ops, comparators, expr); - } - if self.enabled(Rule::TypeComparison) { - pycodestyle::rules::type_comparison(self, expr, ops, comparators); - } - if self.any_enabled(&[ - Rule::SysVersionCmpStr3, - Rule::SysVersionInfo0Eq3, - Rule::SysVersionInfo1CmpInt, - Rule::SysVersionInfoMinorCmpInt, - Rule::SysVersionCmpStr10, - ]) { - flake8_2020::rules::compare(self, left, ops, comparators); - } - if self.enabled(Rule::HardcodedPasswordString) { - flake8_bandit::rules::compare_to_hardcoded_password_string( - self, - left, - comparators, - ); - } - if self.enabled(Rule::ComparisonWithItself) { - pylint::rules::comparison_with_itself(self, left, ops, comparators); - } - if self.enabled(Rule::ComparisonOfConstant) { - pylint::rules::comparison_of_constant(self, left, ops, comparators); - } - if self.enabled(Rule::CompareToEmptyString) { - pylint::rules::compare_to_empty_string(self, left, ops, comparators); - } - if self.enabled(Rule::MagicValueComparison) { - pylint::rules::magic_value_comparison(self, left, comparators); - } - if self.enabled(Rule::InDictKeys) { - flake8_simplify::rules::key_in_dict_compare(self, expr, left, ops, comparators); - } - if self.enabled(Rule::YodaConditions) { - flake8_simplify::rules::yoda_conditions(self, expr, left, ops, comparators); - } - if self.enabled(Rule::PandasNuniqueConstantSeriesCheck) { - pandas_vet::rules::nunique_constant_series_check( - self, - expr, - left, - ops, - comparators, - ); - } - } - Expr::Constant(ast::ExprConstant { - value: Constant::Int(_) | Constant::Float(_) | Constant::Complex { .. }, - kind: _, - range: _, - }) => { - if self.is_stub && self.enabled(Rule::NumericLiteralTooLong) { - flake8_pyi::rules::numeric_literal_too_long(self, expr); - } - } - Expr::Constant(ast::ExprConstant { - value: Constant::Bytes(_), - kind: _, - range: _, - }) => { - if self.is_stub && self.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long(self, expr); - } - } - Expr::Constant(ast::ExprConstant { - value: Constant::Str(value), - kind, - range: _, - }) => { - if self.enabled(Rule::HardcodedBindAllInterfaces) { - if let Some(diagnostic) = - flake8_bandit::rules::hardcoded_bind_all_interfaces(value, expr.range()) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::HardcodedTempFile) { - if let Some(diagnostic) = flake8_bandit::rules::hardcoded_tmp_directory( - expr, - value, - &self.settings.flake8_bandit.hardcoded_tmp_directory, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::UnicodeKindPrefix) { - pyupgrade::rules::unicode_kind_prefix(self, expr, kind.as_deref()); - } - if self.is_stub { - if self.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long(self, expr); - } - } - } - Expr::Lambda( - lambda @ ast::ExprLambda { - args: _, - body: _, - range: _, - }, - ) => { - if self.enabled(Rule::ReimplementedListBuiltin) { - flake8_pie::rules::reimplemented_list_builtin(self, lambda); - } - } - Expr::IfExp(ast::ExprIfExp { - test, - body, - orelse, - range: _, - }) => { - if self.enabled(Rule::IfExprWithTrueFalse) { - flake8_simplify::rules::explicit_true_false_in_ifexpr( - self, expr, test, body, orelse, - ); - } - if self.enabled(Rule::IfExprWithFalseTrue) { - flake8_simplify::rules::explicit_false_true_in_ifexpr( - self, expr, test, body, orelse, - ); - } - if self.enabled(Rule::IfExprWithTwistedArms) { - flake8_simplify::rules::twisted_arms_in_ifexpr(self, expr, test, body, orelse); - } - } - Expr::ListComp(ast::ExprListComp { - elt, - generators, - range: _, - }) - | Expr::SetComp(ast::ExprSetComp { - elt, - generators, - range: _, - }) => { - if self.enabled(Rule::UnnecessaryComprehension) { - flake8_comprehensions::rules::unnecessary_list_set_comprehension( - self, expr, elt, generators, - ); - } - if self.enabled(Rule::FunctionUsesLoopVariable) { - flake8_bugbear::rules::function_uses_loop_variable(self, &Node::Expr(expr)); - } - if self.enabled(Rule::InDictKeys) { - for generator in generators { - flake8_simplify::rules::key_in_dict_for( - self, - &generator.target, - &generator.iter, - ); - } - } - if self.enabled(Rule::IterationOverSet) { - for generator in generators { - pylint::rules::iteration_over_set(self, &generator.iter); - } - } - } - Expr::DictComp(ast::ExprDictComp { - key, - value, - generators, - range: _, - }) => { - if self.enabled(Rule::UnnecessaryComprehension) { - flake8_comprehensions::rules::unnecessary_dict_comprehension( - self, expr, key, value, generators, - ); - } - if self.enabled(Rule::FunctionUsesLoopVariable) { - flake8_bugbear::rules::function_uses_loop_variable(self, &Node::Expr(expr)); - } - if self.enabled(Rule::InDictKeys) { - for generator in generators { - flake8_simplify::rules::key_in_dict_for( - self, - &generator.target, - &generator.iter, - ); - } - } - if self.enabled(Rule::IterationOverSet) { - for generator in generators { - pylint::rules::iteration_over_set(self, &generator.iter); - } - } - if self.enabled(Rule::StaticKeyDictComprehension) { - ruff::rules::static_key_dict_comprehension(self, key); - } - } - Expr::GeneratorExp(ast::ExprGeneratorExp { - generators, - elt: _, - range: _, - }) => { - if self.enabled(Rule::FunctionUsesLoopVariable) { - flake8_bugbear::rules::function_uses_loop_variable(self, &Node::Expr(expr)); - } - if self.enabled(Rule::InDictKeys) { - for generator in generators { - flake8_simplify::rules::key_in_dict_for( - self, - &generator.target, - &generator.iter, - ); - } - } - if self.enabled(Rule::IterationOverSet) { - for generator in generators { - pylint::rules::iteration_over_set(self, &generator.iter); - } - } - } - Expr::BoolOp( - bool_op @ ast::ExprBoolOp { - op, - values, - range: _, - }, - ) => { - if self.enabled(Rule::RepeatedIsinstanceCalls) { - pylint::rules::repeated_isinstance_calls(self, expr, *op, values); - } - if self.enabled(Rule::MultipleStartsEndsWith) { - flake8_pie::rules::multiple_starts_ends_with(self, expr); - } - if self.enabled(Rule::DuplicateIsinstanceCall) { - flake8_simplify::rules::duplicate_isinstance_call(self, expr); - } - if self.enabled(Rule::CompareWithTuple) { - flake8_simplify::rules::compare_with_tuple(self, expr); - } - if self.enabled(Rule::ExprAndNotExpr) { - flake8_simplify::rules::expr_and_not_expr(self, expr); - } - if self.enabled(Rule::ExprOrNotExpr) { - flake8_simplify::rules::expr_or_not_expr(self, expr); - } - if self.enabled(Rule::ExprOrTrue) { - flake8_simplify::rules::expr_or_true(self, expr); - } - if self.enabled(Rule::ExprAndFalse) { - flake8_simplify::rules::expr_and_false(self, expr); - } - if self.enabled(Rule::RepeatedEqualityComparisonTarget) { - pylint::rules::repeated_equality_comparison_target(self, bool_op); - } - } - _ => {} - }; + analyze::expression(expr, self); // Step 2: Binding match expr { @@ -4003,86 +1200,7 @@ where self.semantic.flags |= SemanticModelFlags::EXCEPTION_HANDLER; // Step 1: Analysis - match except_handler { - ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { - type_, - name, - body, - range: _, - }) => { - if self.enabled(Rule::BareExcept) { - if let Some(diagnostic) = pycodestyle::rules::bare_except( - type_.as_deref(), - body, - except_handler, - self.locator, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::RaiseWithoutFromInsideExcept) { - flake8_bugbear::rules::raise_without_from_inside_except( - self, - name.as_deref(), - body, - ); - } - if self.enabled(Rule::BlindExcept) { - flake8_blind_except::rules::blind_except( - self, - type_.as_deref(), - name.as_deref(), - body, - ); - } - if self.enabled(Rule::TryExceptPass) { - flake8_bandit::rules::try_except_pass( - self, - except_handler, - type_.as_deref(), - body, - self.settings.flake8_bandit.check_typed_exception, - ); - } - if self.enabled(Rule::TryExceptContinue) { - flake8_bandit::rules::try_except_continue( - self, - except_handler, - type_.as_deref(), - body, - self.settings.flake8_bandit.check_typed_exception, - ); - } - if self.enabled(Rule::ExceptWithEmptyTuple) { - flake8_bugbear::rules::except_with_empty_tuple(self, except_handler); - } - if self.enabled(Rule::ExceptWithNonExceptionClasses) { - flake8_bugbear::rules::except_with_non_exception_classes(self, except_handler); - } - if self.enabled(Rule::ReraiseNoCause) { - tryceratops::rules::reraise_no_cause(self, body); - } - if self.enabled(Rule::BinaryOpException) { - pylint::rules::binary_op_exception(self, except_handler); - } - if let Some(name) = name { - if self.enabled(Rule::AmbiguousVariableName) { - if let Some(diagnostic) = - pycodestyle::rules::ambiguous_variable_name(name.as_str(), name.range()) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::BuiltinVariableShadowing) { - flake8_builtins::rules::builtin_variable_shadowing( - self, - name, - name.range(), - ); - } - } - } - } + analyze::except_handler(except_handler, self); // Step 2: Binding let binding = match except_handler { @@ -4140,23 +1258,7 @@ where fn visit_arguments(&mut self, arguments: &'b Arguments) { // Step 1: Analysis - if self.enabled(Rule::MutableArgumentDefault) { - flake8_bugbear::rules::mutable_argument_default(self, arguments); - } - if self.enabled(Rule::FunctionCallInDefaultArgument) { - flake8_bugbear::rules::function_call_in_argument_default(self, arguments); - } - if self.settings.rules.enabled(Rule::ImplicitOptional) { - ruff::rules::implicit_optional(self, arguments); - } - if self.is_stub { - if self.enabled(Rule::TypedArgumentDefaultInStub) { - flake8_pyi::rules::typed_argument_simple_defaults(self, arguments); - } - if self.enabled(Rule::ArgumentDefaultInStub) { - flake8_pyi::rules::argument_simple_defaults(self, arguments); - } - } + analyze::arguments(arguments, self); // Step 2: Binding. // Bind, but intentionally avoid walking default expressions, as we handle them @@ -4180,25 +1282,7 @@ where fn visit_arg(&mut self, arg: &'b Arg) { // Step 1: Analysis - if self.enabled(Rule::AmbiguousVariableName) { - if let Some(diagnostic) = - pycodestyle::rules::ambiguous_variable_name(&arg.arg, arg.range()) - { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::InvalidArgumentName) { - if let Some(diagnostic) = pep8_naming::rules::invalid_argument_name( - &arg.arg, - arg, - &self.settings.pep8_naming.ignore_names, - ) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::BuiltinArgumentShadowing) { - flake8_builtins::rules::builtin_argument_shadowing(self, arg); - } + analyze::argument(arg, self); // Step 2: Binding. // Bind, but intentionally avoid walking the annotation, as we handle it @@ -4238,9 +1322,7 @@ where fn visit_body(&mut self, body: &'b [Stmt]) { // Step 1: Analysis - if self.enabled(Rule::UnnecessaryPass) { - flake8_pie::rules::no_unnecessary_pass(self, body); - } + analyze::suite(body, self); // Step 3: Traversal for stmt in body { @@ -4252,9 +1334,8 @@ where impl<'a> Checker<'a> { /// Visit a [`Module`]. Returns `true` if the module contains a module-level docstring. fn visit_module(&mut self, python_ast: &'a Suite) -> bool { - if self.enabled(Rule::FStringDocstring) { - flake8_bugbear::rules::f_string_docstring(self, python_ast); - } + analyze::module(python_ast, self); + let docstring = docstrings::extraction::docstring_from(python_ast); docstring.is_some() } @@ -4587,7 +1668,7 @@ impl<'a> Checker<'a> { scope.add(id, binding_id); } - fn check_deferred_future_type_definitions(&mut self) { + fn visit_deferred_future_type_definitions(&mut self) { while !self.deferred.future_type_definitions.is_empty() { let type_definitions = std::mem::take(&mut self.deferred.future_type_definitions); for (expr, snapshot) in type_definitions { @@ -4600,7 +1681,7 @@ impl<'a> Checker<'a> { } } - fn check_deferred_string_type_definitions(&mut self, allocator: &'a typed_arena::Arena) { + fn visit_deferred_string_type_definitions(&mut self, allocator: &'a typed_arena::Arena) { while !self.deferred.string_type_definitions.is_empty() { let type_definitions = std::mem::take(&mut self.deferred.string_type_definitions); for (range, value, snapshot) in type_definitions { @@ -4644,7 +1725,7 @@ impl<'a> Checker<'a> { } } - fn check_deferred_functions(&mut self) { + fn visit_deferred_functions(&mut self) { while !self.deferred.functions.is_empty() { let deferred_functions = std::mem::take(&mut self.deferred.functions); for snapshot in deferred_functions { @@ -4664,7 +1745,7 @@ impl<'a> Checker<'a> { } } - fn check_deferred_lambdas(&mut self) { + fn visit_deferred_lambdas(&mut self) { while !self.deferred.lambdas.is_empty() { let lambdas = std::mem::take(&mut self.deferred.lambdas); for (expr, snapshot) in lambdas { @@ -4685,141 +1766,8 @@ impl<'a> Checker<'a> { } } - fn check_deferred_for_loops(&mut self) { - while !self.deferred.for_loops.is_empty() { - let for_loops = std::mem::take(&mut self.deferred.for_loops); - for snapshot in for_loops { - self.semantic.restore(snapshot); - - if let Stmt::For(ast::StmtFor { - target, iter, body, .. - }) - | Stmt::AsyncFor(ast::StmtAsyncFor { - target, iter, body, .. - }) = &self.semantic.stmt() - { - if self.enabled(Rule::UnusedLoopControlVariable) { - flake8_bugbear::rules::unused_loop_control_variable(self, target, body); - } - if self.enabled(Rule::IncorrectDictIterator) { - perflint::rules::incorrect_dict_iterator(self, target, iter); - } - } else { - unreachable!("Expected Expr::For | Expr::AsyncFor"); - } - } - } - } - - /// Run any lint rules that operate over a single [`UnresolvedReference`]. - fn check_unresolved_references(&mut self) { - if !self.any_enabled(&[Rule::UndefinedLocalWithImportStarUsage, Rule::UndefinedName]) { - return; - } - - for reference in self.semantic.unresolved_references() { - if reference.is_wildcard_import() { - if self.enabled(Rule::UndefinedLocalWithImportStarUsage) { - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::UndefinedLocalWithImportStarUsage { - name: reference.name(self.locator).to_string(), - }, - reference.range(), - )); - } - } else { - if self.enabled(Rule::UndefinedName) { - // Avoid flagging if `NameError` is handled. - if reference.exceptions().contains(Exceptions::NAME_ERROR) { - continue; - } - - // Allow __path__. - if self.path.ends_with("__init__.py") { - if reference.name(self.locator) == "__path__" { - continue; - } - } - - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::UndefinedName { - name: reference.name(self.locator).to_string(), - }, - reference.range(), - )); - } - } - } - } - - /// Run any lint rules that operate over a single [`Binding`]. - fn check_bindings(&mut self) { - if !self.any_enabled(&[ - Rule::InvalidAllFormat, - Rule::InvalidAllObject, - Rule::UnaliasedCollectionsAbcSetImport, - Rule::UnconventionalImportAlias, - Rule::UnusedVariable, - ]) { - return; - } - - for binding in self.semantic.bindings.iter() { - if self.enabled(Rule::UnusedVariable) { - if binding.kind.is_bound_exception() && !binding.is_used() { - let mut diagnostic = Diagnostic::new( - pyflakes::rules::UnusedVariable { - name: binding.name(self.locator).to_string(), - }, - binding.range, - ); - if self.patch(Rule::UnusedVariable) { - diagnostic.try_set_fix(|| { - pyflakes::fixes::remove_exception_handler_assignment( - binding, - self.locator, - ) - .map(Fix::automatic) - }); - } - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::InvalidAllFormat) { - if let Some(diagnostic) = pylint::rules::invalid_all_format(binding) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::InvalidAllObject) { - if let Some(diagnostic) = pylint::rules::invalid_all_object(binding) { - self.diagnostics.push(diagnostic); - } - } - if self.enabled(Rule::UnconventionalImportAlias) { - if let Some(diagnostic) = - flake8_import_conventions::rules::unconventional_import_alias( - self, - binding, - &self.settings.flake8_import_conventions.aliases, - ) - { - self.diagnostics.push(diagnostic); - } - } - if self.is_stub { - if self.enabled(Rule::UnaliasedCollectionsAbcSetImport) { - if let Some(diagnostic) = - flake8_pyi::rules::unaliased_collections_abc_set_import(self, binding) - { - self.diagnostics.push(diagnostic); - } - } - } - } - } - /// Run any lint rules that operate over the module exports (i.e., members of `__all__`). - fn check_exports(&mut self) { + fn visit_exports(&mut self) { let exports: Vec<(&str, TextRange)> = self .semantic .global_scope() @@ -4863,565 +1811,6 @@ impl<'a> Checker<'a> { } } } - - fn check_deferred_scopes(&mut self) { - if !self.any_enabled(&[ - Rule::GlobalVariableNotAssigned, - Rule::ImportShadowedByLoopVar, - Rule::RedefinedWhileUnused, - Rule::RuntimeImportInTypeCheckingBlock, - Rule::TypingOnlyFirstPartyImport, - Rule::TypingOnlyStandardLibraryImport, - Rule::TypingOnlyThirdPartyImport, - Rule::UndefinedLocal, - Rule::UnusedAnnotation, - Rule::UnusedClassMethodArgument, - Rule::UnusedFunctionArgument, - Rule::UnusedImport, - Rule::UnusedLambdaArgument, - Rule::UnusedMethodArgument, - Rule::UnusedStaticMethodArgument, - Rule::UnusedVariable, - ]) { - return; - } - - // Identify any valid runtime imports. If a module is imported at runtime, and - // used at runtime, then by default, we avoid flagging any other - // imports from that model as typing-only. - let enforce_typing_imports = if self.is_stub { - false - } else { - self.any_enabled(&[ - Rule::RuntimeImportInTypeCheckingBlock, - Rule::TypingOnlyFirstPartyImport, - Rule::TypingOnlyThirdPartyImport, - Rule::TypingOnlyStandardLibraryImport, - ]) - }; - let runtime_imports: Vec> = if enforce_typing_imports { - self.semantic - .scopes - .iter() - .map(|scope| { - scope - .binding_ids() - .map(|binding_id| self.semantic.binding(binding_id)) - .filter(|binding| { - flake8_type_checking::helpers::is_valid_runtime_import( - binding, - &self.semantic, - ) - }) - .collect() - }) - .collect::>() - } else { - vec![] - }; - - let mut diagnostics: Vec = vec![]; - for scope_id in self.deferred.scopes.iter().rev().copied() { - let scope = &self.semantic.scopes[scope_id]; - - if self.enabled(Rule::UndefinedLocal) { - pyflakes::rules::undefined_local(self, scope_id, scope, &mut diagnostics); - } - - if self.enabled(Rule::GlobalVariableNotAssigned) { - for (name, binding_id) in scope.bindings() { - let binding = self.semantic.binding(binding_id); - if binding.kind.is_global() { - diagnostics.push(Diagnostic::new( - pylint::rules::GlobalVariableNotAssigned { - name: (*name).to_string(), - }, - binding.range, - )); - } - } - } - - if self.enabled(Rule::ImportShadowedByLoopVar) { - for (name, binding_id) in scope.bindings() { - for shadow in self.semantic.shadowed_bindings(scope_id, binding_id) { - // If the shadowing binding isn't a loop variable, abort. - let binding = &self.semantic.bindings[shadow.binding_id()]; - if !binding.kind.is_loop_var() { - continue; - } - - // If the shadowed binding isn't an import, abort. - let shadowed = &self.semantic.bindings[shadow.shadowed_id()]; - if !matches!( - shadowed.kind, - BindingKind::Import(..) - | BindingKind::FromImport(..) - | BindingKind::SubmoduleImport(..) - | BindingKind::FutureImport - ) { - continue; - } - - // If the bindings are in different forks, abort. - if shadowed.source.map_or(true, |left| { - binding.source.map_or(true, |right| { - branch_detection::different_forks(left, right, &self.semantic.stmts) - }) - }) { - continue; - } - - #[allow(deprecated)] - let line = self.locator.compute_line_index(shadowed.range.start()); - - self.diagnostics.push(Diagnostic::new( - pyflakes::rules::ImportShadowedByLoopVar { - name: name.to_string(), - line, - }, - binding.range, - )); - } - } - } - - if self.enabled(Rule::RedefinedWhileUnused) { - for (name, binding_id) in scope.bindings() { - for shadow in self.semantic.shadowed_bindings(scope_id, binding_id) { - // If the shadowing binding is a loop variable, abort, to avoid overlap - // with F402. - let binding = &self.semantic.bindings[shadow.binding_id()]; - if binding.kind.is_loop_var() { - continue; - } - - // If the shadowed binding is used, abort. - let shadowed = &self.semantic.bindings[shadow.shadowed_id()]; - if shadowed.is_used() { - continue; - } - - // If the shadowing binding isn't considered a "redefinition" of the - // shadowed binding, abort. - if !binding.redefines(shadowed) { - continue; - } - - if shadow.same_scope() { - // If the symbol is a dummy variable, abort, unless the shadowed - // binding is an import. - if !matches!( - shadowed.kind, - BindingKind::Import(..) - | BindingKind::FromImport(..) - | BindingKind::SubmoduleImport(..) - | BindingKind::FutureImport - ) && self.settings.dummy_variable_rgx.is_match(name) - { - continue; - } - - // If this is an overloaded function, abort. - if shadowed.kind.is_function_definition() - && visibility::is_overload( - cast::decorator_list( - self.semantic.stmts[shadowed.source.unwrap()], - ), - &self.semantic, - ) - { - continue; - } - } else { - // Only enforce cross-scope shadowing for imports. - if !matches!( - shadowed.kind, - BindingKind::Import(..) - | BindingKind::FromImport(..) - | BindingKind::SubmoduleImport(..) - | BindingKind::FutureImport - ) { - continue; - } - } - - // If the bindings are in different forks, abort. - if shadowed.source.map_or(true, |left| { - binding.source.map_or(true, |right| { - branch_detection::different_forks(left, right, &self.semantic.stmts) - }) - }) { - continue; - } - - #[allow(deprecated)] - let line = self.locator.compute_line_index(shadowed.range.start()); - let mut diagnostic = Diagnostic::new( - pyflakes::rules::RedefinedWhileUnused { - name: (*name).to_string(), - line, - }, - binding.range, - ); - if let Some(range) = binding.parent_range(&self.semantic) { - diagnostic.set_parent(range.start()); - } - diagnostics.push(diagnostic); - } - } - } - - if matches!( - scope.kind, - ScopeKind::Function(_) | ScopeKind::AsyncFunction(_) | ScopeKind::Lambda(_) - ) { - if self.enabled(Rule::UnusedVariable) { - pyflakes::rules::unused_variable(self, scope, &mut diagnostics); - } - - if self.enabled(Rule::UnusedAnnotation) { - pyflakes::rules::unused_annotation(self, scope, &mut diagnostics); - } - - if !self.is_stub { - if self.any_enabled(&[ - Rule::UnusedFunctionArgument, - Rule::UnusedMethodArgument, - Rule::UnusedClassMethodArgument, - Rule::UnusedStaticMethodArgument, - Rule::UnusedLambdaArgument, - ]) { - flake8_unused_arguments::rules::unused_arguments( - self, - scope, - &mut diagnostics, - ); - } - } - } - - if matches!( - scope.kind, - ScopeKind::Function(_) | ScopeKind::AsyncFunction(_) | ScopeKind::Module - ) { - if enforce_typing_imports { - let runtime_imports: Vec<&Binding> = self - .semantic - .scopes - .ancestor_ids(scope_id) - .flat_map(|scope_id| runtime_imports[scope_id.as_usize()].iter()) - .copied() - .collect(); - - if self.enabled(Rule::RuntimeImportInTypeCheckingBlock) { - flake8_type_checking::rules::runtime_import_in_type_checking_block( - self, - scope, - &mut diagnostics, - ); - } - - if self.any_enabled(&[ - Rule::TypingOnlyFirstPartyImport, - Rule::TypingOnlyThirdPartyImport, - Rule::TypingOnlyStandardLibraryImport, - ]) { - flake8_type_checking::rules::typing_only_runtime_import( - self, - scope, - &runtime_imports, - &mut diagnostics, - ); - } - } - - if self.enabled(Rule::UnusedImport) { - pyflakes::rules::unused_import(self, scope, &mut diagnostics); - } - } - } - self.diagnostics.extend(diagnostics); - } - - /// Visit all the [`Definition`] nodes in the AST. - /// - /// This phase is expected to run after the AST has been traversed in its entirety; as such, - /// it is expected that all [`Definition`] nodes have been visited by the time, and that this - /// method will not recurse into any other nodes. - fn check_definitions(&mut self) { - let enforce_annotations = self.any_enabled(&[ - Rule::MissingTypeFunctionArgument, - Rule::MissingTypeArgs, - Rule::MissingTypeKwargs, - Rule::MissingTypeSelf, - Rule::MissingTypeCls, - Rule::MissingReturnTypeUndocumentedPublicFunction, - Rule::MissingReturnTypePrivateFunction, - Rule::MissingReturnTypeSpecialMethod, - Rule::MissingReturnTypeStaticMethod, - Rule::MissingReturnTypeClassMethod, - Rule::AnyType, - ]); - let enforce_stubs = self.is_stub - && self.any_enabled(&[Rule::DocstringInStub, Rule::IterMethodReturnIterable]); - let enforce_docstrings = self.any_enabled(&[ - Rule::UndocumentedPublicModule, - Rule::UndocumentedPublicClass, - Rule::UndocumentedPublicMethod, - Rule::UndocumentedPublicFunction, - Rule::UndocumentedPublicPackage, - Rule::UndocumentedMagicMethod, - Rule::UndocumentedPublicNestedClass, - Rule::UndocumentedPublicInit, - Rule::FitsOnOneLine, - Rule::NoBlankLineBeforeFunction, - Rule::NoBlankLineAfterFunction, - Rule::OneBlankLineBeforeClass, - Rule::OneBlankLineAfterClass, - Rule::BlankLineAfterSummary, - Rule::IndentWithSpaces, - Rule::UnderIndentation, - Rule::OverIndentation, - Rule::NewLineAfterLastParagraph, - Rule::SurroundingWhitespace, - Rule::BlankLineBeforeClass, - Rule::MultiLineSummaryFirstLine, - Rule::MultiLineSummarySecondLine, - Rule::SectionNotOverIndented, - Rule::SectionUnderlineNotOverIndented, - Rule::TripleSingleQuotes, - Rule::EscapeSequenceInDocstring, - Rule::EndsInPeriod, - Rule::NonImperativeMood, - Rule::NoSignature, - Rule::FirstLineCapitalized, - Rule::DocstringStartsWithThis, - Rule::CapitalizeSectionName, - Rule::NewLineAfterSectionName, - Rule::DashedUnderlineAfterSection, - Rule::SectionUnderlineAfterName, - Rule::SectionUnderlineMatchesSectionLength, - Rule::NoBlankLineAfterSection, - Rule::NoBlankLineBeforeSection, - Rule::BlankLinesBetweenHeaderAndContent, - Rule::BlankLineAfterLastSection, - Rule::EmptyDocstringSection, - Rule::EndsInPunctuation, - Rule::SectionNameEndsInColon, - Rule::UndocumentedParam, - Rule::OverloadWithDocstring, - Rule::EmptyDocstring, - ]); - - if !enforce_annotations && !enforce_docstrings && !enforce_stubs { - return; - } - - // Compute visibility of all definitions. - let exports: Option> = { - self.semantic - .global_scope() - .get_all("__all__") - .map(|binding_id| &self.semantic.bindings[binding_id]) - .filter_map(|binding| match &binding.kind { - BindingKind::Export(Export { names }) => Some(names.iter().copied()), - _ => None, - }) - .fold(None, |acc, names| { - Some(acc.into_iter().flatten().chain(names).collect()) - }) - }; - - let definitions = std::mem::take(&mut self.semantic.definitions); - let mut overloaded_name: Option = None; - for ContextualizedDefinition { - definition, - visibility, - } in definitions.resolve(exports.as_deref()).iter() - { - let docstring = docstrings::extraction::extract_docstring(definition); - - // flake8-annotations - if enforce_annotations { - // TODO(charlie): This should be even stricter, in that an overload - // implementation should come immediately after the overloaded - // interfaces, without any AST nodes in between. Right now, we - // only error when traversing definition boundaries (functions, - // classes, etc.). - if !overloaded_name.map_or(false, |overloaded_name| { - flake8_annotations::helpers::is_overload_impl( - definition, - &overloaded_name, - &self.semantic, - ) - }) { - self.diagnostics - .extend(flake8_annotations::rules::definition( - self, - definition, - *visibility, - )); - } - overloaded_name = - flake8_annotations::helpers::overloaded_name(definition, &self.semantic); - } - - // flake8-pyi - if enforce_stubs { - if self.is_stub { - if self.enabled(Rule::DocstringInStub) { - flake8_pyi::rules::docstring_in_stubs(self, docstring); - } - if self.enabled(Rule::IterMethodReturnIterable) { - flake8_pyi::rules::iter_method_return_iterable(self, definition); - } - } - } - - // pydocstyle - if enforce_docstrings { - if pydocstyle::helpers::should_ignore_definition( - definition, - &self.settings.pydocstyle.ignore_decorators, - &self.semantic, - ) { - continue; - } - - // Extract a `Docstring` from a `Definition`. - let Some(expr) = docstring else { - pydocstyle::rules::not_missing(self, definition, *visibility); - continue; - }; - - let contents = self.locator.slice(expr.range()); - - let indentation = self.locator.slice(TextRange::new( - self.locator.line_start(expr.start()), - expr.start(), - )); - - if pydocstyle::helpers::should_ignore_docstring(contents) { - #[allow(deprecated)] - let location = self.locator.compute_source_location(expr.start()); - warn_user!( - "Docstring at {}:{}:{} contains implicit string concatenation; ignoring...", - relativize_path(self.path), - location.row, - location.column - ); - continue; - } - - // SAFETY: Safe for docstrings that pass `should_ignore_docstring`. - let body_range = str::raw_contents_range(contents).unwrap(); - let docstring = Docstring { - definition, - expr, - contents, - body_range, - indentation, - }; - - if !pydocstyle::rules::not_empty(self, &docstring) { - continue; - } - if self.enabled(Rule::FitsOnOneLine) { - pydocstyle::rules::one_liner(self, &docstring); - } - if self.any_enabled(&[ - Rule::NoBlankLineBeforeFunction, - Rule::NoBlankLineAfterFunction, - ]) { - pydocstyle::rules::blank_before_after_function(self, &docstring); - } - if self.any_enabled(&[ - Rule::OneBlankLineBeforeClass, - Rule::OneBlankLineAfterClass, - Rule::BlankLineBeforeClass, - ]) { - pydocstyle::rules::blank_before_after_class(self, &docstring); - } - if self.enabled(Rule::BlankLineAfterSummary) { - pydocstyle::rules::blank_after_summary(self, &docstring); - } - if self.any_enabled(&[ - Rule::IndentWithSpaces, - Rule::UnderIndentation, - Rule::OverIndentation, - ]) { - pydocstyle::rules::indent(self, &docstring); - } - if self.enabled(Rule::NewLineAfterLastParagraph) { - pydocstyle::rules::newline_after_last_paragraph(self, &docstring); - } - if self.enabled(Rule::SurroundingWhitespace) { - pydocstyle::rules::no_surrounding_whitespace(self, &docstring); - } - if self.any_enabled(&[ - Rule::MultiLineSummaryFirstLine, - Rule::MultiLineSummarySecondLine, - ]) { - pydocstyle::rules::multi_line_summary_start(self, &docstring); - } - if self.enabled(Rule::TripleSingleQuotes) { - pydocstyle::rules::triple_quotes(self, &docstring); - } - if self.enabled(Rule::EscapeSequenceInDocstring) { - pydocstyle::rules::backslashes(self, &docstring); - } - if self.enabled(Rule::EndsInPeriod) { - pydocstyle::rules::ends_with_period(self, &docstring); - } - if self.enabled(Rule::NonImperativeMood) { - pydocstyle::rules::non_imperative_mood( - self, - &docstring, - &self.settings.pydocstyle.property_decorators, - ); - } - if self.enabled(Rule::NoSignature) { - pydocstyle::rules::no_signature(self, &docstring); - } - if self.enabled(Rule::FirstLineCapitalized) { - pydocstyle::rules::capitalized(self, &docstring); - } - if self.enabled(Rule::DocstringStartsWithThis) { - pydocstyle::rules::starts_with_this(self, &docstring); - } - if self.enabled(Rule::EndsInPunctuation) { - pydocstyle::rules::ends_with_punctuation(self, &docstring); - } - if self.enabled(Rule::OverloadWithDocstring) { - pydocstyle::rules::if_needed(self, &docstring); - } - if self.any_enabled(&[ - Rule::MultiLineSummaryFirstLine, - Rule::SectionNotOverIndented, - Rule::SectionUnderlineNotOverIndented, - Rule::CapitalizeSectionName, - Rule::NewLineAfterSectionName, - Rule::DashedUnderlineAfterSection, - Rule::SectionUnderlineAfterName, - Rule::SectionUnderlineMatchesSectionLength, - Rule::NoBlankLineAfterSection, - Rule::NoBlankLineBeforeSection, - Rule::BlankLinesBetweenHeaderAndContent, - Rule::BlankLineAfterLastSection, - Rule::EmptyDocstringSection, - Rule::SectionNameEndsInColon, - Rule::UndocumentedParam, - ]) { - pydocstyle::rules::sections( - self, - &docstring, - self.settings.pydocstyle.convention.as_ref(), - ); - } - } - } - } } #[allow(clippy::too_many_arguments)] @@ -5475,24 +1864,24 @@ pub(crate) fn check_ast( // Iterate over the AST. checker.visit_body(python_ast); - // Check any deferred statements. - checker.check_deferred_functions(); - checker.check_deferred_lambdas(); - checker.check_deferred_future_type_definitions(); + // Visit any deferred syntax nodes. + checker.visit_deferred_functions(); + checker.visit_deferred_lambdas(); + checker.visit_deferred_future_type_definitions(); let allocator = typed_arena::Arena::new(); - checker.check_deferred_string_type_definitions(&allocator); - checker.check_deferred_for_loops(); + checker.visit_deferred_string_type_definitions(&allocator); + checker.visit_exports(); - // Check docstrings, exports, bindings, and unresolved references. - checker.check_definitions(); - checker.check_exports(); - checker.check_bindings(); - checker.check_unresolved_references(); + // Check docstrings, bindings, and unresolved references. + analyze::deferred_for_loops(&mut checker); + analyze::definitions(&mut checker); + analyze::bindings(&mut checker); + analyze::unresolved_references(&mut checker); // Reset the scope to module-level, and check all consumed scopes. checker.semantic.scope_id = ScopeId::global(); checker.deferred.scopes.push(ScopeId::global()); - checker.check_deferred_scopes(); + analyze::deferred_scopes(&mut checker); checker.diagnostics } diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/function_uses_loop_variable.rs b/crates/ruff/src/rules/flake8_bugbear/rules/function_uses_loop_variable.rs index edba6aa901..5900cab1e0 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/function_uses_loop_variable.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/function_uses_loop_variable.rs @@ -276,7 +276,7 @@ impl<'a> Visitor<'a> for AssignedNamesVisitor<'a> { } /// B023 -pub(crate) fn function_uses_loop_variable<'a>(checker: &mut Checker<'a>, node: &Node<'a>) { +pub(crate) fn function_uses_loop_variable(checker: &mut Checker, node: &Node) { // Identify any "suspicious" variables. These are defined as variables that are // referenced in a function or lambda body, but aren't bound as arguments. let suspicious_variables = { @@ -303,8 +303,8 @@ pub(crate) fn function_uses_loop_variable<'a>(checker: &mut Checker<'a>, node: & // loop, flag it. for name in suspicious_variables { if reassigned_in_loop.contains(&name.id.as_str()) { - if !checker.flake8_bugbear_seen.contains(&name) { - checker.flake8_bugbear_seen.push(name); + if !checker.flake8_bugbear_seen.contains(&name.range()) { + checker.flake8_bugbear_seen.push(name.range()); checker.diagnostics.push(Diagnostic::new( FunctionUsesLoopVariable { name: name.id.to_string(),