Pass Checker by immutable reference to lint rules (#16012)

This very large PR changes the field `.diagnostics` in the `Checker`
from a `Vec<Diagnostic>` to a `RefCell<Vec<Diagnostic>>`, adds methods
to push new diagnostics to this cell, and then removes unnecessary
mutability throughout all of our lint rule implementations.

Consequently, the compiler may now enforce what was, till now, the
_convention_ that the only changes to the `Checker` that can happen
during a lint are the addition of diagnostics[^1].

The PR is best reviewed commit-by-commit. I have tried to keep the large
commits limited to "bulk actions that you can easily see are performing
the same find/replace on a large number of files", and separate anything
ad-hoc or with larger diffs. Please let me know if there's anything else
I can do to make this easier to review!

Many thanks to [`ast-grep`](https://github.com/ast-grep/ast-grep),
[`helix`](https://github.com/helix-editor/helix), and good ol'
fashioned`git` magic, without which this PR would have taken the rest of
my natural life.

[^1]: And randomly also the seen variables violating `flake8-bugbear`?
This commit is contained in:
Dylan 2025-02-07 09:05:50 -06:00 committed by GitHub
parent 1f7a29d347
commit 46fe17767d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
552 changed files with 1751 additions and 2288 deletions

View file

@ -9,7 +9,7 @@ use crate::rules::{
}; };
/// Run lint rules over the [`Binding`]s. /// Run lint rules over the [`Binding`]s.
pub(crate) fn bindings(checker: &mut Checker) { pub(crate) fn bindings(checker: &Checker) {
if !checker.any_enabled(&[ if !checker.any_enabled(&[
Rule::AssignmentInAssert, Rule::AssignmentInAssert,
Rule::InvalidAllFormat, Rule::InvalidAllFormat,
@ -48,22 +48,22 @@ pub(crate) fn bindings(checker: &mut Checker) {
pyflakes::fixes::remove_exception_handler_assignment(binding, checker.locator) pyflakes::fixes::remove_exception_handler_assignment(binding, checker.locator)
.map(Fix::safe_edit) .map(Fix::safe_edit)
}); });
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::InvalidAllFormat) { if checker.enabled(Rule::InvalidAllFormat) {
if let Some(diagnostic) = pylint::rules::invalid_all_format(binding) { if let Some(diagnostic) = pylint::rules::invalid_all_format(binding) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::InvalidAllObject) { if checker.enabled(Rule::InvalidAllObject) {
if let Some(diagnostic) = pylint::rules::invalid_all_object(binding) { if let Some(diagnostic) = pylint::rules::invalid_all_object(binding) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::NonAsciiName) { if checker.enabled(Rule::NonAsciiName) {
if let Some(diagnostic) = pylint::rules::non_ascii_name(binding, checker.locator) { if let Some(diagnostic) = pylint::rules::non_ascii_name(binding, checker.locator) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::UnconventionalImportAlias) { if checker.enabled(Rule::UnconventionalImportAlias) {
@ -72,61 +72,61 @@ pub(crate) fn bindings(checker: &mut Checker) {
binding, binding,
&checker.settings.flake8_import_conventions.aliases, &checker.settings.flake8_import_conventions.aliases,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::UnaliasedCollectionsAbcSetImport) { if checker.enabled(Rule::UnaliasedCollectionsAbcSetImport) {
if let Some(diagnostic) = if let Some(diagnostic) =
flake8_pyi::rules::unaliased_collections_abc_set_import(checker, binding) flake8_pyi::rules::unaliased_collections_abc_set_import(checker, binding)
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if !checker.source_type.is_stub() && checker.enabled(Rule::UnquotedTypeAlias) { if !checker.source_type.is_stub() && checker.enabled(Rule::UnquotedTypeAlias) {
if let Some(diagnostics) = if let Some(diagnostics) =
flake8_type_checking::rules::unquoted_type_alias(checker, binding) flake8_type_checking::rules::unquoted_type_alias(checker, binding)
{ {
checker.diagnostics.extend(diagnostics); checker.report_diagnostics(diagnostics);
} }
} }
if checker.enabled(Rule::UnsortedDunderSlots) { if checker.enabled(Rule::UnsortedDunderSlots) {
if let Some(diagnostic) = ruff::rules::sort_dunder_slots(checker, binding) { if let Some(diagnostic) = ruff::rules::sort_dunder_slots(checker, binding) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::UsedDummyVariable) { if checker.enabled(Rule::UsedDummyVariable) {
if let Some(diagnostic) = ruff::rules::used_dummy_variable(checker, binding, binding_id) if let Some(diagnostic) = ruff::rules::used_dummy_variable(checker, binding, binding_id)
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::AssignmentInAssert) { if checker.enabled(Rule::AssignmentInAssert) {
if let Some(diagnostic) = ruff::rules::assignment_in_assert(checker, binding) { if let Some(diagnostic) = ruff::rules::assignment_in_assert(checker, binding) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::PytestUnittestRaisesAssertion) { if checker.enabled(Rule::PytestUnittestRaisesAssertion) {
if let Some(diagnostic) = if let Some(diagnostic) =
flake8_pytest_style::rules::unittest_raises_assertion_binding(checker, binding) flake8_pytest_style::rules::unittest_raises_assertion_binding(checker, binding)
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::ForLoopWrites) { if checker.enabled(Rule::ForLoopWrites) {
if let Some(diagnostic) = refurb::rules::for_loop_writes_binding(checker, binding) { if let Some(diagnostic) = refurb::rules::for_loop_writes_binding(checker, binding) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::CustomTypeVarForSelf) { if checker.enabled(Rule::CustomTypeVarForSelf) {
if let Some(diagnostic) = if let Some(diagnostic) =
flake8_pyi::rules::custom_type_var_instead_of_self(checker, binding) flake8_pyi::rules::custom_type_var_instead_of_self(checker, binding)
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::PrivateTypeParameter) { if checker.enabled(Rule::PrivateTypeParameter) {
if let Some(diagnostic) = pyupgrade::rules::private_type_parameter(checker, binding) { if let Some(diagnostic) = pyupgrade::rules::private_type_parameter(checker, binding) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }

View file

@ -5,7 +5,7 @@ use crate::codes::Rule;
use crate::rules::{flake8_simplify, pylint, refurb}; use crate::rules::{flake8_simplify, pylint, refurb};
/// Run lint rules over a [`Comprehension`] syntax nodes. /// Run lint rules over a [`Comprehension`] syntax nodes.
pub(crate) fn comprehension(comprehension: &Comprehension, checker: &mut Checker) { pub(crate) fn comprehension(comprehension: &Comprehension, checker: &Checker) {
if checker.enabled(Rule::InDictKeys) { if checker.enabled(Rule::InDictKeys) {
flake8_simplify::rules::key_in_dict_comprehension(checker, comprehension); flake8_simplify::rules::key_in_dict_comprehension(checker, comprehension);
} }

View file

@ -13,7 +13,7 @@ use crate::rules::{
}; };
/// Run lint rules over all deferred scopes in the [`SemanticModel`]. /// Run lint rules over all deferred scopes in the [`SemanticModel`].
pub(crate) fn deferred_scopes(checker: &mut Checker) { pub(crate) fn deferred_scopes(checker: &Checker) {
if !checker.any_enabled(&[ if !checker.any_enabled(&[
Rule::AsyncioDanglingTask, Rule::AsyncioDanglingTask,
Rule::BadStaticmethodArgument, Rule::BadStaticmethodArgument,
@ -85,12 +85,11 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
vec![] vec![]
}; };
let mut diagnostics: Vec<Diagnostic> = vec![];
for scope_id in checker.analyze.scopes.iter().rev().copied() { for scope_id in checker.analyze.scopes.iter().rev().copied() {
let scope = &checker.semantic.scopes[scope_id]; let scope = &checker.semantic.scopes[scope_id];
if checker.enabled(Rule::UndefinedLocal) { if checker.enabled(Rule::UndefinedLocal) {
pyflakes::rules::undefined_local(checker, scope_id, scope, &mut diagnostics); pyflakes::rules::undefined_local(checker, scope_id, scope);
} }
if checker.enabled(Rule::GlobalVariableNotAssigned) { if checker.enabled(Rule::GlobalVariableNotAssigned) {
@ -112,7 +111,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
.map(|id| checker.semantic.reference(*id)) .map(|id| checker.semantic.reference(*id))
.all(ResolvedReference::is_load) .all(ResolvedReference::is_load)
{ {
diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pylint::rules::GlobalVariableNotAssigned { pylint::rules::GlobalVariableNotAssigned {
name: (*name).to_string(), name: (*name).to_string(),
}, },
@ -146,7 +145,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
if scope.kind.is_generator() { if scope.kind.is_generator() {
continue; continue;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pylint::rules::RedefinedArgumentFromLocal { pylint::rules::RedefinedArgumentFromLocal {
name: name.to_string(), name: name.to_string(),
}, },
@ -186,7 +185,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
continue; continue;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::ImportShadowedByLoopVar { pyflakes::rules::ImportShadowedByLoopVar {
name: name.to_string(), name: name.to_string(),
row: checker.compute_source_row(shadowed.start()), row: checker.compute_source_row(shadowed.start()),
@ -347,7 +346,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
diagnostic.set_fix(fix.clone()); diagnostic.set_fix(fix.clone());
} }
diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }
@ -356,55 +355,47 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
|| matches!(scope.kind, ScopeKind::Module | ScopeKind::Function(_)) || matches!(scope.kind, ScopeKind::Module | ScopeKind::Function(_))
{ {
if checker.enabled(Rule::UnusedPrivateTypeVar) { if checker.enabled(Rule::UnusedPrivateTypeVar) {
flake8_pyi::rules::unused_private_type_var(checker, scope, &mut diagnostics); flake8_pyi::rules::unused_private_type_var(checker, scope);
} }
if checker.enabled(Rule::UnusedPrivateProtocol) { if checker.enabled(Rule::UnusedPrivateProtocol) {
flake8_pyi::rules::unused_private_protocol(checker, scope, &mut diagnostics); flake8_pyi::rules::unused_private_protocol(checker, scope);
} }
if checker.enabled(Rule::UnusedPrivateTypeAlias) { if checker.enabled(Rule::UnusedPrivateTypeAlias) {
flake8_pyi::rules::unused_private_type_alias(checker, scope, &mut diagnostics); flake8_pyi::rules::unused_private_type_alias(checker, scope);
} }
if checker.enabled(Rule::UnusedPrivateTypedDict) { if checker.enabled(Rule::UnusedPrivateTypedDict) {
flake8_pyi::rules::unused_private_typed_dict(checker, scope, &mut diagnostics); flake8_pyi::rules::unused_private_typed_dict(checker, scope);
} }
} }
if checker.enabled(Rule::AsyncioDanglingTask) { if checker.enabled(Rule::AsyncioDanglingTask) {
ruff::rules::asyncio_dangling_binding(scope, &checker.semantic, &mut diagnostics); ruff::rules::asyncio_dangling_binding(scope, checker);
} }
if let Some(class_def) = scope.kind.as_class() { if let Some(class_def) = scope.kind.as_class() {
if checker.enabled(Rule::BuiltinAttributeShadowing) { if checker.enabled(Rule::BuiltinAttributeShadowing) {
flake8_builtins::rules::builtin_attribute_shadowing( flake8_builtins::rules::builtin_attribute_shadowing(
checker, checker, scope_id, scope, class_def,
scope_id,
scope,
class_def,
&mut diagnostics,
); );
} }
if checker.enabled(Rule::FunctionCallInDataclassDefaultArgument) { if checker.enabled(Rule::FunctionCallInDataclassDefaultArgument) {
ruff::rules::function_call_in_dataclass_default( ruff::rules::function_call_in_dataclass_default(checker, class_def);
checker,
class_def,
&mut diagnostics,
);
} }
if checker.enabled(Rule::MutableClassDefault) { if checker.enabled(Rule::MutableClassDefault) {
ruff::rules::mutable_class_default(checker, class_def, &mut diagnostics); ruff::rules::mutable_class_default(checker, class_def);
} }
if checker.enabled(Rule::MutableDataclassDefault) { if checker.enabled(Rule::MutableDataclassDefault) {
ruff::rules::mutable_dataclass_default(checker, class_def, &mut diagnostics); ruff::rules::mutable_dataclass_default(checker, class_def);
} }
} }
if matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Lambda(_)) { if matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Lambda(_)) {
if checker.enabled(Rule::UnusedVariable) { if checker.enabled(Rule::UnusedVariable) {
pyflakes::rules::unused_variable(checker, scope, &mut diagnostics); pyflakes::rules::unused_variable(checker, scope);
} }
if checker.enabled(Rule::UnusedAnnotation) { if checker.enabled(Rule::UnusedAnnotation) {
pyflakes::rules::unused_annotation(checker, scope, &mut diagnostics); pyflakes::rules::unused_annotation(checker, scope);
} }
if !checker.source_type.is_stub() { if !checker.source_type.is_stub() {
@ -415,11 +406,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
Rule::UnusedMethodArgument, Rule::UnusedMethodArgument,
Rule::UnusedStaticMethodArgument, Rule::UnusedStaticMethodArgument,
]) { ]) {
flake8_unused_arguments::rules::unused_arguments( flake8_unused_arguments::rules::unused_arguments(checker, scope);
checker,
scope,
&mut diagnostics,
);
} }
} }
} }
@ -428,11 +415,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
if !checker.source_type.is_stub() if !checker.source_type.is_stub()
&& checker.enabled(Rule::RuntimeImportInTypeCheckingBlock) && checker.enabled(Rule::RuntimeImportInTypeCheckingBlock)
{ {
flake8_type_checking::rules::runtime_import_in_type_checking_block( flake8_type_checking::rules::runtime_import_in_type_checking_block(checker, scope);
checker,
scope,
&mut diagnostics,
);
} }
if enforce_typing_only_imports { if enforce_typing_only_imports {
let runtime_imports: Vec<&Binding> = checker let runtime_imports: Vec<&Binding> = checker
@ -447,47 +430,45 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
checker, checker,
scope, scope,
&runtime_imports, &runtime_imports,
&mut diagnostics,
); );
} }
if checker.enabled(Rule::UnusedImport) { if checker.enabled(Rule::UnusedImport) {
pyflakes::rules::unused_import(checker, scope, &mut diagnostics); pyflakes::rules::unused_import(checker, scope);
} }
if checker.enabled(Rule::ImportPrivateName) { if checker.enabled(Rule::ImportPrivateName) {
pylint::rules::import_private_name(checker, scope, &mut diagnostics); pylint::rules::import_private_name(checker, scope);
} }
} }
if scope.kind.is_function() { if scope.kind.is_function() {
if checker.enabled(Rule::NoSelfUse) { if checker.enabled(Rule::NoSelfUse) {
pylint::rules::no_self_use(checker, scope_id, scope, &mut diagnostics); pylint::rules::no_self_use(checker, scope_id, scope);
} }
if checker.enabled(Rule::TooManyLocals) { if checker.enabled(Rule::TooManyLocals) {
pylint::rules::too_many_locals(checker, scope, &mut diagnostics); pylint::rules::too_many_locals(checker, scope);
} }
if checker.enabled(Rule::SingledispatchMethod) { if checker.enabled(Rule::SingledispatchMethod) {
pylint::rules::singledispatch_method(checker, scope, &mut diagnostics); pylint::rules::singledispatch_method(checker, scope);
} }
if checker.enabled(Rule::SingledispatchmethodFunction) { if checker.enabled(Rule::SingledispatchmethodFunction) {
pylint::rules::singledispatchmethod_function(checker, scope, &mut diagnostics); pylint::rules::singledispatchmethod_function(checker, scope);
} }
if checker.enabled(Rule::BadStaticmethodArgument) { if checker.enabled(Rule::BadStaticmethodArgument) {
pylint::rules::bad_staticmethod_argument(checker, scope, &mut diagnostics); pylint::rules::bad_staticmethod_argument(checker, scope);
} }
if checker.any_enabled(&[ if checker.any_enabled(&[
Rule::InvalidFirstArgumentNameForClassMethod, Rule::InvalidFirstArgumentNameForClassMethod,
Rule::InvalidFirstArgumentNameForMethod, Rule::InvalidFirstArgumentNameForMethod,
]) { ]) {
pep8_naming::rules::invalid_first_argument_name(checker, scope, &mut diagnostics); pep8_naming::rules::invalid_first_argument_name(checker, scope);
} }
} }
} }
checker.diagnostics.extend(diagnostics);
} }

View file

@ -139,13 +139,11 @@ pub(crate) fn definitions(checker: &mut Checker) {
&checker.semantic, &checker.semantic,
) )
}) { }) {
checker checker.report_diagnostics(flake8_annotations::rules::definition(
.diagnostics checker,
.extend(flake8_annotations::rules::definition( definition,
checker, *visibility,
definition, ));
*visibility,
));
} }
overloaded_name = overloaded_name =
flake8_annotations::helpers::overloaded_name(definition, &checker.semantic); flake8_annotations::helpers::overloaded_name(definition, &checker.semantic);

View file

@ -8,7 +8,7 @@ use crate::rules::{
}; };
/// Run lint rules over an [`ExceptHandler`] syntax node. /// Run lint rules over an [`ExceptHandler`] syntax node.
pub(crate) fn except_handler(except_handler: &ExceptHandler, checker: &mut Checker) { pub(crate) fn except_handler(except_handler: &ExceptHandler, checker: &Checker) {
match except_handler { match except_handler {
ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
type_, type_,
@ -23,7 +23,7 @@ pub(crate) fn except_handler(except_handler: &ExceptHandler, checker: &mut Check
except_handler, except_handler,
checker.locator, checker.locator,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::RaiseWithoutFromInsideExcept) { if checker.enabled(Rule::RaiseWithoutFromInsideExcept) {

View file

@ -21,7 +21,7 @@ use crate::rules::{
use crate::settings::types::PythonVersion; use crate::settings::types::PythonVersion;
/// Run lint rules over an [`Expr`] syntax node. /// Run lint rules over an [`Expr`] syntax node.
pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { pub(crate) fn expression(expr: &Expr, checker: &Checker) {
match expr { match expr {
Expr::Subscript(subscript @ ast::ExprSubscript { value, slice, .. }) => { Expr::Subscript(subscript @ ast::ExprSubscript { value, slice, .. }) => {
// Ex) Optional[...], Union[...] // Ex) Optional[...], Union[...]
@ -201,7 +201,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
check_two_starred_expressions, check_two_starred_expressions,
expr.range(), expr.range(),
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }
@ -515,7 +515,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
match pyflakes::format::FormatSummary::try_from(string_value.to_str()) { match pyflakes::format::FormatSummary::try_from(string_value.to_str()) {
Err(e) => { Err(e) => {
if checker.enabled(Rule::StringDotFormatInvalidFormat) { if checker.enabled(Rule::StringDotFormatInvalidFormat) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::StringDotFormatInvalidFormat { pyflakes::rules::StringDotFormatInvalidFormat {
message: pyflakes::format::error_to_string(&e), message: pyflakes::format::error_to_string(&e),
}, },
@ -925,7 +925,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
} }
if checker.enabled(Rule::PytestPatchWithLambda) { if checker.enabled(Rule::PytestPatchWithLambda) {
if let Some(diagnostic) = flake8_pytest_style::rules::patch_with_lambda(call) { if let Some(diagnostic) = flake8_pytest_style::rules::patch_with_lambda(call) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.any_enabled(&[ if checker.any_enabled(&[
@ -1281,7 +1281,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
.. ..
}) => { }) => {
if checker.enabled(Rule::PercentFormatUnsupportedFormatCharacter) { if checker.enabled(Rule::PercentFormatUnsupportedFormatCharacter) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::PercentFormatUnsupportedFormatCharacter { pyflakes::rules::PercentFormatUnsupportedFormatCharacter {
char: c, char: c,
}, },
@ -1291,7 +1291,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
} }
Err(e) => { Err(e) => {
if checker.enabled(Rule::PercentFormatInvalidFormat) { if checker.enabled(Rule::PercentFormatInvalidFormat) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::PercentFormatInvalidFormat { pyflakes::rules::PercentFormatInvalidFormat {
message: e.to_string(), message: e.to_string(),
}, },
@ -1365,7 +1365,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
checker.locator, checker.locator,
checker.settings, checker.settings,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::CollectionLiteralConcatenation) { if checker.enabled(Rule::CollectionLiteralConcatenation) {

View file

@ -5,7 +5,7 @@ use crate::codes::Rule;
use crate::rules::{flake8_bugbear, ruff}; use crate::rules::{flake8_bugbear, ruff};
/// Run lint rules over a module. /// Run lint rules over a module.
pub(crate) fn module(suite: &Suite, checker: &mut Checker) { pub(crate) fn module(suite: &Suite, checker: &Checker) {
if checker.enabled(Rule::FStringDocstring) { if checker.enabled(Rule::FStringDocstring) {
flake8_bugbear::rules::f_string_docstring(checker, suite); flake8_bugbear::rules::f_string_docstring(checker, suite);
} }

View file

@ -6,7 +6,7 @@ use crate::codes::Rule;
use crate::rules::{flake8_builtins, pycodestyle}; use crate::rules::{flake8_builtins, pycodestyle};
/// Run lint rules over a [`Parameter`] syntax node. /// Run lint rules over a [`Parameter`] syntax node.
pub(crate) fn parameter(parameter: &Parameter, checker: &mut Checker) { pub(crate) fn parameter(parameter: &Parameter, checker: &Checker) {
if checker.enabled(Rule::AmbiguousVariableName) { if checker.enabled(Rule::AmbiguousVariableName) {
pycodestyle::rules::ambiguous_variable_name( pycodestyle::rules::ambiguous_variable_name(
checker, checker,

View file

@ -5,7 +5,7 @@ use crate::codes::Rule;
use crate::rules::{flake8_bugbear, flake8_pyi, ruff}; use crate::rules::{flake8_bugbear, flake8_pyi, ruff};
/// Run lint rules over a [`Parameters`] syntax node. /// Run lint rules over a [`Parameters`] syntax node.
pub(crate) fn parameters(parameters: &Parameters, checker: &mut Checker) { pub(crate) fn parameters(parameters: &Parameters, checker: &Checker) {
if checker.enabled(Rule::FunctionCallInDefaultArgument) { if checker.enabled(Rule::FunctionCallInDefaultArgument) {
flake8_bugbear::rules::function_call_in_argument_default(checker, parameters); flake8_bugbear::rules::function_call_in_argument_default(checker, parameters);
} }

View file

@ -39,7 +39,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if !checker.semantic.scope_id.is_global() { if !checker.semantic.scope_id.is_global() {
for name in names { for name in names {
if checker.semantic.nonlocal(name).is_none() { if checker.semantic.nonlocal(name).is_none() {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pylint::rules::NonlocalWithoutBinding { pylint::rules::NonlocalWithoutBinding {
name: name.to_string(), name: name.to_string(),
}, },
@ -59,7 +59,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
stmt, stmt,
&mut checker.semantic.current_statements().skip(1), &mut checker.semantic.current_statements().skip(1),
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }
@ -69,7 +69,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
stmt, stmt,
&mut checker.semantic.current_statements().skip(1), &mut checker.semantic.current_statements().skip(1),
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }
@ -99,7 +99,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
if checker.enabled(Rule::AmbiguousFunctionName) { if checker.enabled(Rule::AmbiguousFunctionName) {
if let Some(diagnostic) = pycodestyle::rules::ambiguous_function_name(name) { if let Some(diagnostic) = pycodestyle::rules::ambiguous_function_name(name) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::InvalidBoolReturnType) { if checker.enabled(Rule::InvalidBoolReturnType) {
@ -128,7 +128,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
&checker.semantic, &checker.semantic,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.source_type.is_stub() { if checker.source_type.is_stub() {
@ -187,7 +187,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
name, name,
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::GlobalStatement) { if checker.enabled(Rule::GlobalStatement) {
@ -239,7 +239,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
body, body,
checker.settings.mccabe.max_complexity, checker.settings.mccabe.max_complexity,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::HardcodedPasswordDefault) { if checker.enabled(Rule::HardcodedPasswordDefault) {
@ -265,7 +265,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
body, body,
checker.settings.pylint.max_returns, checker.settings.pylint.max_returns,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::TooManyBranches) { if checker.enabled(Rule::TooManyBranches) {
@ -274,7 +274,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
body, body,
checker.settings.pylint.max_branches, checker.settings.pylint.max_branches,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::TooManyStatements) { if checker.enabled(Rule::TooManyStatements) {
@ -283,7 +283,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
body, body,
checker.settings.pylint.max_statements, checker.settings.pylint.max_statements,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.any_enabled(&[ if checker.any_enabled(&[
@ -351,9 +351,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
#[cfg(any(feature = "test-rules", test))] #[cfg(any(feature = "test-rules", test))]
if checker.enabled(Rule::UnreachableCode) { if checker.enabled(Rule::UnreachableCode) {
checker checker.report_diagnostics(pylint::rules::in_function(name, body));
.diagnostics
.extend(pylint::rules::in_function(name, body));
} }
if checker.enabled(Rule::ReimplementedOperator) { if checker.enabled(Rule::ReimplementedOperator) {
refurb::rules::reimplemented_operator(checker, &function_def.into()); refurb::rules::reimplemented_operator(checker, &function_def.into());
@ -456,7 +454,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
if checker.enabled(Rule::AmbiguousClassName) { if checker.enabled(Rule::AmbiguousClassName) {
if let Some(diagnostic) = pycodestyle::rules::ambiguous_class_name(name) { if let Some(diagnostic) = pycodestyle::rules::ambiguous_class_name(name) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::InvalidClassName) { if checker.enabled(Rule::InvalidClassName) {
@ -465,7 +463,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
name, name,
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::ErrorSuffixOnExceptionName) { if checker.enabled(Rule::ErrorSuffixOnExceptionName) {
@ -475,7 +473,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
name, name,
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if !checker.source_type.is_stub() { if !checker.source_type.is_stub() {
@ -615,7 +613,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if let Some(diagnostic) = if let Some(diagnostic) =
flake8_debugger::rules::debugger_import(stmt, None, &alias.name) flake8_debugger::rules::debugger_import(stmt, None, &alias.name)
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::BannedApi) { if checker.enabled(Rule::BannedApi) {
@ -642,7 +640,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if let Some(diagnostic) = if let Some(diagnostic) =
pylint::rules::import_self(alias, checker.module.qualified_name()) pylint::rules::import_self(alias, checker.module.qualified_name())
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if let Some(asname) = &alias.asname { if let Some(asname) = &alias.asname {
@ -657,7 +655,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) )
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::LowercaseImportedAsNonLowercase) { if checker.enabled(Rule::LowercaseImportedAsNonLowercase) {
@ -670,7 +668,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) )
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::CamelcaseImportedAsLowercase) { if checker.enabled(Rule::CamelcaseImportedAsLowercase) {
@ -683,7 +681,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) )
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::CamelcaseImportedAsConstant) { if checker.enabled(Rule::CamelcaseImportedAsConstant) {
@ -694,14 +692,14 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
stmt, stmt,
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::CamelcaseImportedAsAcronym) { if checker.enabled(Rule::CamelcaseImportedAsAcronym) {
if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_acronym( if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_acronym(
name, asname, alias, stmt, checker, name, asname, alias, stmt, checker,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }
@ -715,7 +713,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.flake8_import_conventions.banned_aliases, &checker.settings.flake8_import_conventions.banned_aliases,
) )
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }
@ -725,7 +723,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&alias.name, &alias.name,
alias.asname.as_deref(), alias.asname.as_deref(),
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::BuiltinImportShadowing) { if checker.enabled(Rule::BuiltinImportShadowing) {
@ -841,7 +839,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if let Some(diagnostic) = if let Some(diagnostic) =
flake8_pytest_style::rules::import_from(stmt, module, level) flake8_pytest_style::rules::import_from(stmt, module, level)
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.source_type.is_stub() { if checker.source_type.is_stub() {
@ -856,7 +854,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
if checker.enabled(Rule::LateFutureImport) { if checker.enabled(Rule::LateFutureImport) {
if checker.semantic.seen_futures_boundary() { if checker.semantic.seen_futures_boundary() {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::LateFutureImport, pyflakes::rules::LateFutureImport,
stmt.range(), stmt.range(),
)); ));
@ -865,7 +863,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} else if &alias.name == "*" { } else if &alias.name == "*" {
if checker.enabled(Rule::UndefinedLocalWithNestedImportStarUsage) { if checker.enabled(Rule::UndefinedLocalWithNestedImportStarUsage) {
if !matches!(checker.semantic.current_scope().kind, ScopeKind::Module) { if !matches!(checker.semantic.current_scope().kind, ScopeKind::Module) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::UndefinedLocalWithNestedImportStarUsage { pyflakes::rules::UndefinedLocalWithNestedImportStarUsage {
name: helpers::format_import_from(level, module).to_string(), name: helpers::format_import_from(level, module).to_string(),
}, },
@ -874,7 +872,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
} }
if checker.enabled(Rule::UndefinedLocalWithImportStar) { if checker.enabled(Rule::UndefinedLocalWithImportStar) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::UndefinedLocalWithImportStar { pyflakes::rules::UndefinedLocalWithImportStar {
name: helpers::format_import_from(level, module).to_string(), name: helpers::format_import_from(level, module).to_string(),
}, },
@ -891,14 +889,14 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
checker.module.qualified_name(), checker.module.qualified_name(),
checker.settings.flake8_tidy_imports.ban_relative_imports, checker.settings.flake8_tidy_imports.ban_relative_imports,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::Debugger) { if checker.enabled(Rule::Debugger) {
if let Some(diagnostic) = if let Some(diagnostic) =
flake8_debugger::rules::debugger_import(stmt, module, &alias.name) flake8_debugger::rules::debugger_import(stmt, module, &alias.name)
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::BannedImportAlias) { if checker.enabled(Rule::BannedImportAlias) {
@ -913,7 +911,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.flake8_import_conventions.banned_aliases, &checker.settings.flake8_import_conventions.banned_aliases,
) )
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }
@ -928,7 +926,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) )
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::LowercaseImportedAsNonLowercase) { if checker.enabled(Rule::LowercaseImportedAsNonLowercase) {
@ -941,7 +939,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) )
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::CamelcaseImportedAsLowercase) { if checker.enabled(Rule::CamelcaseImportedAsLowercase) {
@ -954,7 +952,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) )
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::CamelcaseImportedAsConstant) { if checker.enabled(Rule::CamelcaseImportedAsConstant) {
@ -965,7 +963,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
stmt, stmt,
&checker.settings.pep8_naming.ignore_names, &checker.settings.pep8_naming.ignore_names,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::CamelcaseImportedAsAcronym) { if checker.enabled(Rule::CamelcaseImportedAsAcronym) {
@ -976,7 +974,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
stmt, stmt,
checker, checker,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if !checker.source_type.is_stub() { if !checker.source_type.is_stub() {
@ -996,7 +994,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
names, names,
checker.module.qualified_name(), checker.module.qualified_name(),
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::BannedImportFrom) { if checker.enabled(Rule::BannedImportFrom) {
@ -1005,7 +1003,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
&helpers::format_import_from(level, module), &helpers::format_import_from(level, module),
&checker.settings.flake8_import_conventions.banned_from, &checker.settings.flake8_import_conventions.banned_from,
) { ) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::ByteStringUsage) { if checker.enabled(Rule::ByteStringUsage) {
@ -1174,7 +1172,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
if checker.any_enabled(&[Rule::BadVersionInfoComparison, Rule::BadVersionInfoOrder]) { if checker.any_enabled(&[Rule::BadVersionInfoComparison, Rule::BadVersionInfoOrder]) {
fn bad_version_info_comparison( fn bad_version_info_comparison(
checker: &mut Checker, checker: &Checker,
test: &Expr, test: &Expr,
has_else_clause: bool, has_else_clause: bool,
) { ) {
@ -1221,9 +1219,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
) => { ) => {
if !checker.semantic.in_type_checking_block() { if !checker.semantic.in_type_checking_block() {
if checker.enabled(Rule::Assert) { if checker.enabled(Rule::Assert) {
checker checker.report_diagnostic(flake8_bandit::rules::assert_used(stmt));
.diagnostics
.push(flake8_bandit::rules::assert_used(stmt));
} }
} }
if checker.enabled(Rule::AssertTuple) { if checker.enabled(Rule::AssertTuple) {
@ -1440,7 +1436,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if let Some(diagnostic) = if let Some(diagnostic) =
pyflakes::rules::default_except_not_last(handlers, checker.locator) pyflakes::rules::default_except_not_last(handlers, checker.locator)
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.any_enabled(&[ if checker.any_enabled(&[
@ -1537,7 +1533,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
if checker.enabled(Rule::PandasDfVariableName) { if checker.enabled(Rule::PandasDfVariableName) {
if let Some(diagnostic) = pandas_vet::rules::assignment_to_df(targets) { if let Some(diagnostic) = pandas_vet::rules::assignment_to_df(targets) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker if checker
@ -1735,7 +1731,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if let Some(diagnostic) = if let Some(diagnostic) =
ruff::rules::asyncio_dangling_task(value, checker.semantic()) ruff::rules::asyncio_dangling_task(value, checker.semantic())
{ {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
if checker.enabled(Rule::RepeatedAppend) { if checker.enabled(Rule::RepeatedAppend) {

View file

@ -5,7 +5,7 @@ use crate::codes::Rule;
use crate::rules::{flake8_bandit, flake8_pyi, flake8_quotes, pycodestyle, ruff}; use crate::rules::{flake8_bandit, flake8_pyi, flake8_quotes, pycodestyle, ruff};
/// Run lint rules over a [`StringLike`] syntax nodes. /// Run lint rules over a [`StringLike`] syntax nodes.
pub(crate) fn string_like(string_like: StringLike, checker: &mut Checker) { pub(crate) fn string_like(string_like: StringLike, checker: &Checker) {
if checker.any_enabled(&[ if checker.any_enabled(&[
Rule::AmbiguousUnicodeCharacterString, Rule::AmbiguousUnicodeCharacterString,
Rule::AmbiguousUnicodeCharacterDocstring, Rule::AmbiguousUnicodeCharacterDocstring,

View file

@ -6,7 +6,7 @@ use crate::rules::flake8_pie;
use crate::rules::refurb; use crate::rules::refurb;
/// Run lint rules over a suite of [`Stmt`] syntax nodes. /// Run lint rules over a suite of [`Stmt`] syntax nodes.
pub(crate) fn suite(suite: &[Stmt], checker: &mut Checker) { pub(crate) fn suite(suite: &[Stmt], checker: &Checker) {
if checker.enabled(Rule::UnnecessaryPlaceholder) { if checker.enabled(Rule::UnnecessaryPlaceholder) {
flake8_pie::rules::unnecessary_placeholder(checker, suite); flake8_pie::rules::unnecessary_placeholder(checker, suite);
} }

View file

@ -7,7 +7,7 @@ use crate::codes::Rule;
use crate::rules::pyflakes; use crate::rules::pyflakes;
/// Run lint rules over all [`UnresolvedReference`] entities in the [`SemanticModel`]. /// Run lint rules over all [`UnresolvedReference`] entities in the [`SemanticModel`].
pub(crate) fn unresolved_references(checker: &mut Checker) { pub(crate) fn unresolved_references(checker: &Checker) {
if !checker.any_enabled(&[Rule::UndefinedLocalWithImportStarUsage, Rule::UndefinedName]) { if !checker.any_enabled(&[Rule::UndefinedLocalWithImportStarUsage, Rule::UndefinedName]) {
return; return;
} }
@ -15,7 +15,7 @@ pub(crate) fn unresolved_references(checker: &mut Checker) {
for reference in checker.semantic.unresolved_references() { for reference in checker.semantic.unresolved_references() {
if reference.is_wildcard_import() { if reference.is_wildcard_import() {
if checker.enabled(Rule::UndefinedLocalWithImportStarUsage) { if checker.enabled(Rule::UndefinedLocalWithImportStarUsage) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::UndefinedLocalWithImportStarUsage { pyflakes::rules::UndefinedLocalWithImportStarUsage {
name: reference.name(checker.source()).to_string(), name: reference.name(checker.source()).to_string(),
}, },
@ -42,7 +42,7 @@ pub(crate) fn unresolved_references(checker: &mut Checker) {
let symbol_name = reference.name(checker.source()); let symbol_name = reference.name(checker.source());
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
pyflakes::rules::UndefinedName { pyflakes::rules::UndefinedName {
name: symbol_name.to_string(), name: symbol_name.to_string(),
minor_version_builtin_added: version_builtin_was_added(symbol_name), minor_version_builtin_added: version_builtin_was_added(symbol_name),

View file

@ -9,11 +9,6 @@
//! parent scopes have been fully traversed. Individual rules may also perform internal traversals //! parent scopes have been fully traversed. Individual rules may also perform internal traversals
//! of the AST. //! of the AST.
//! //!
//! While the [`Checker`] is typically passed by mutable reference to the individual lint rule
//! implementations, most of its constituent components are intended to be treated immutably, with
//! the exception of the [`Diagnostic`] vector, which is intended to be mutated by the individual
//! lint rules. In the future, this should be formalized in the API.
//!
//! The individual [`Visitor`] implementations within the [`Checker`] typically proceed in four //! The individual [`Visitor`] implementations within the [`Checker`] typically proceed in four
//! steps: //! steps:
//! //!
@ -31,7 +26,7 @@ use std::path::Path;
use itertools::Itertools; use itertools::Itertools;
use log::debug; use log::debug;
use rustc_hash::FxHashMap; use rustc_hash::{FxHashMap, FxHashSet};
use ruff_diagnostics::{Diagnostic, IsolationLevel}; use ruff_diagnostics::{Diagnostic, IsolationLevel};
use ruff_notebook::{CellOffsets, NotebookIndex}; use ruff_notebook::{CellOffsets, NotebookIndex};
@ -221,9 +216,9 @@ pub(crate) struct Checker<'a> {
/// A set of deferred nodes to be analyzed after the AST traversal (e.g., `for` loops). /// A set of deferred nodes to be analyzed after the AST traversal (e.g., `for` loops).
analyze: deferred::Analyze, analyze: deferred::Analyze,
/// The cumulative set of diagnostics computed across all lint rules. /// The cumulative set of diagnostics computed across all lint rules.
pub(crate) diagnostics: Vec<Diagnostic>, diagnostics: RefCell<Vec<Diagnostic>>,
/// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations. /// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations.
pub(crate) flake8_bugbear_seen: Vec<TextRange>, flake8_bugbear_seen: RefCell<FxHashSet<TextRange>>,
/// The end offset of the last visited statement. /// The end offset of the last visited statement.
last_stmt_end: TextSize, last_stmt_end: TextSize,
/// A state describing if a docstring is expected or not. /// A state describing if a docstring is expected or not.
@ -271,8 +266,8 @@ impl<'a> Checker<'a> {
semantic, semantic,
visit: deferred::Visit::default(), visit: deferred::Visit::default(),
analyze: deferred::Analyze::default(), analyze: deferred::Analyze::default(),
diagnostics: Vec::default(), diagnostics: RefCell::default(),
flake8_bugbear_seen: Vec::default(), flake8_bugbear_seen: RefCell::default(),
cell_offsets, cell_offsets,
notebook_index, notebook_index,
last_stmt_end: TextSize::default(), last_stmt_end: TextSize::default(),
@ -362,6 +357,30 @@ impl<'a> Checker<'a> {
self.indexer.comment_ranges() self.indexer.comment_ranges()
} }
/// Push a new [`Diagnostic`] to the collection in the [`Checker`]
pub(crate) fn report_diagnostic(&self, diagnostic: Diagnostic) {
let mut diagnostics = self.diagnostics.borrow_mut();
diagnostics.push(diagnostic);
}
/// Extend the collection of [`Diagnostic`] objects in the [`Checker`]
pub(crate) fn report_diagnostics<I>(&self, diagnostics: I)
where
I: IntoIterator<Item = Diagnostic>,
{
let mut checker_diagnostics = self.diagnostics.borrow_mut();
checker_diagnostics.extend(diagnostics);
}
/// Adds a [`TextRange`] to the set of ranges of variable names
/// flagged in `flake8-bugbear` violations so far.
///
/// Returns whether the value was newly inserted.
pub(crate) fn insert_flake8_bugbear_range(&self, range: TextRange) -> bool {
let mut ranges = self.flake8_bugbear_seen.borrow_mut();
ranges.insert(range)
}
/// Returns the [`Tokens`] for the parsed type annotation if the checker is in a typing context /// Returns the [`Tokens`] for the parsed type annotation if the checker is in a typing context
/// or the parsed source code. /// or the parsed source code.
pub(crate) fn tokens(&self) -> &'a Tokens { pub(crate) fn tokens(&self) -> &'a Tokens {
@ -476,9 +495,9 @@ impl<'a> Checker<'a> {
} }
/// Push `diagnostic` if the checker is not in a `@no_type_check` context. /// Push `diagnostic` if the checker is not in a `@no_type_check` context.
pub(crate) fn push_type_diagnostic(&mut self, diagnostic: Diagnostic) { pub(crate) fn report_type_diagnostic(&self, diagnostic: Diagnostic) {
if !self.semantic.in_no_type_check() { if !self.semantic.in_no_type_check() {
self.diagnostics.push(diagnostic); self.report_diagnostic(diagnostic);
} }
} }
} }
@ -2419,7 +2438,7 @@ impl<'a> Checker<'a> {
self.semantic.restore(snapshot); self.semantic.restore(snapshot);
if self.enabled(Rule::ForwardAnnotationSyntaxError) { if self.enabled(Rule::ForwardAnnotationSyntaxError) {
self.push_type_diagnostic(Diagnostic::new( self.report_type_diagnostic(Diagnostic::new(
pyflakes::rules::ForwardAnnotationSyntaxError { pyflakes::rules::ForwardAnnotationSyntaxError {
parse_error: parse_error.error.to_string(), parse_error: parse_error.error.to_string(),
}, },
@ -2561,7 +2580,7 @@ impl<'a> Checker<'a> {
} else { } else {
if self.semantic.global_scope().uses_star_imports() { if self.semantic.global_scope().uses_star_imports() {
if self.enabled(Rule::UndefinedLocalWithImportStarUsage) { if self.enabled(Rule::UndefinedLocalWithImportStarUsage) {
self.diagnostics.push( self.diagnostics.get_mut().push(
Diagnostic::new( Diagnostic::new(
pyflakes::rules::UndefinedLocalWithImportStarUsage { pyflakes::rules::UndefinedLocalWithImportStarUsage {
name: name.to_string(), name: name.to_string(),
@ -2576,7 +2595,7 @@ impl<'a> Checker<'a> {
if self.settings.preview.is_enabled() if self.settings.preview.is_enabled()
|| !self.path.ends_with("__init__.py") || !self.path.ends_with("__init__.py")
{ {
self.diagnostics.push( self.diagnostics.get_mut().push(
Diagnostic::new( Diagnostic::new(
pyflakes::rules::UndefinedExport { pyflakes::rules::UndefinedExport {
name: name.to_string(), name: name.to_string(),
@ -2700,13 +2719,13 @@ pub(crate) fn check_ast(
analyze::deferred_lambdas(&mut checker); analyze::deferred_lambdas(&mut checker);
analyze::deferred_for_loops(&mut checker); analyze::deferred_for_loops(&mut checker);
analyze::definitions(&mut checker); analyze::definitions(&mut checker);
analyze::bindings(&mut checker); analyze::bindings(&checker);
analyze::unresolved_references(&mut checker); analyze::unresolved_references(&checker);
// Reset the scope to module-level, and check all consumed scopes. // Reset the scope to module-level, and check all consumed scopes.
checker.semantic.scope_id = ScopeId::global(); checker.semantic.scope_id = ScopeId::global();
checker.analyze.scopes.push(ScopeId::global()); checker.analyze.scopes.push(ScopeId::global());
analyze::deferred_scopes(&mut checker); analyze::deferred_scopes(&checker);
checker.diagnostics checker.diagnostics.take()
} }

View file

@ -50,7 +50,7 @@ impl Violation for AirflowDagNoScheduleArgument {
} }
/// AIR301 /// AIR301
pub(crate) fn dag_no_schedule_argument(checker: &mut Checker, expr: &Expr) { pub(crate) fn dag_no_schedule_argument(checker: &Checker, expr: &Expr) {
if !checker.semantic().seen_module(Modules::AIRFLOW) { if !checker.semantic().seen_module(Modules::AIRFLOW) {
return; return;
} }
@ -86,5 +86,5 @@ pub(crate) fn dag_no_schedule_argument(checker: &mut Checker, expr: &Expr) {
// Produce a diagnostic when the `schedule` keyword argument is not found. // Produce a diagnostic when the `schedule` keyword argument is not found.
let diagnostic = Diagnostic::new(AirflowDagNoScheduleArgument, expr.range()); let diagnostic = Diagnostic::new(AirflowDagNoScheduleArgument, expr.range());
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }

View file

@ -83,7 +83,7 @@ impl Violation for Airflow3MovedToProvider {
} }
/// AIR303 /// AIR303
pub(crate) fn moved_to_provider_in_3(checker: &mut Checker, expr: &Expr) { pub(crate) fn moved_to_provider_in_3(checker: &Checker, expr: &Expr) {
if !checker.semantic().seen_module(Modules::AIRFLOW) { if !checker.semantic().seen_module(Modules::AIRFLOW) {
return; return;
} }
@ -112,7 +112,7 @@ enum Replacement {
}, },
} }
fn check_names_moved_to_provider(checker: &mut Checker, expr: &Expr, ranged: TextRange) { fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRange) {
let Some(qualified_name) = checker.semantic().resolve_qualified_name(expr) else { let Some(qualified_name) = checker.semantic().resolve_qualified_name(expr) else {
return; return;
}; };
@ -1018,7 +1018,7 @@ fn check_names_moved_to_provider(checker: &mut Checker, expr: &Expr, ranged: Tex
}, },
_ => return, _ => return,
}; };
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3MovedToProvider { Airflow3MovedToProvider {
deprecated: qualified_name.to_string(), deprecated: qualified_name.to_string(),
replacement, replacement,

View file

@ -80,7 +80,7 @@ enum Replacement {
} }
/// AIR302 /// AIR302
pub(crate) fn airflow_3_removal_expr(checker: &mut Checker, expr: &Expr) { pub(crate) fn airflow_3_removal_expr(checker: &Checker, expr: &Expr) {
if !checker.semantic().seen_module(Modules::AIRFLOW) { if !checker.semantic().seen_module(Modules::AIRFLOW) {
return; return;
} }
@ -117,10 +117,7 @@ pub(crate) fn airflow_3_removal_expr(checker: &mut Checker, expr: &Expr) {
} }
/// AIR302 /// AIR302
pub(crate) fn airflow_3_removal_function_def( pub(crate) fn airflow_3_removal_function_def(checker: &Checker, function_def: &StmtFunctionDef) {
checker: &mut Checker,
function_def: &StmtFunctionDef,
) {
if !checker.semantic().seen_module(Modules::AIRFLOW) { if !checker.semantic().seen_module(Modules::AIRFLOW) {
return; return;
} }
@ -156,7 +153,7 @@ const REMOVED_CONTEXT_KEYS: [&str; 12] = [
/// # 'execution_date' is removed in Airflow 3.0 /// # 'execution_date' is removed in Airflow 3.0
/// pass /// pass
/// ``` /// ```
fn check_function_parameters(checker: &mut Checker, function_def: &StmtFunctionDef) { fn check_function_parameters(checker: &Checker, function_def: &StmtFunctionDef) {
if !is_airflow_task(function_def, checker.semantic()) if !is_airflow_task(function_def, checker.semantic())
&& !is_execute_method_inherits_from_airflow_operator(function_def, checker.semantic()) && !is_execute_method_inherits_from_airflow_operator(function_def, checker.semantic())
{ {
@ -166,7 +163,7 @@ fn check_function_parameters(checker: &mut Checker, function_def: &StmtFunctionD
for param in function_def.parameters.iter_non_variadic_params() { for param in function_def.parameters.iter_non_variadic_params() {
let param_name = param.name(); let param_name = param.name();
if REMOVED_CONTEXT_KEYS.contains(&param_name.as_str()) { if REMOVED_CONTEXT_KEYS.contains(&param_name.as_str()) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3Removal { Airflow3Removal {
deprecated: param_name.to_string(), deprecated: param_name.to_string(),
replacement: Replacement::None, replacement: Replacement::None,
@ -186,29 +183,25 @@ fn check_function_parameters(checker: &mut Checker, function_def: &StmtFunctionD
/// ///
/// DAG(schedule_interval="@daily") /// DAG(schedule_interval="@daily")
/// ``` /// ```
fn check_call_arguments( fn check_call_arguments(checker: &Checker, qualified_name: &QualifiedName, arguments: &Arguments) {
checker: &mut Checker,
qualified_name: &QualifiedName,
arguments: &Arguments,
) {
match qualified_name.segments() { match qualified_name.segments() {
["airflow", .., "DAG" | "dag"] => { ["airflow", .., "DAG" | "dag"] => {
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"schedule_interval", "schedule_interval",
Some("schedule"), Some("schedule"),
)); ));
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"timetable", "timetable",
Some("schedule"), Some("schedule"),
)); ));
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"sla_miss_callback", "sla_miss_callback",
None, None,
)); ));
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"fail_stop", "fail_stop",
Some("fail_fast"), Some("fail_fast"),
@ -217,7 +210,7 @@ fn check_call_arguments(
_ => { _ => {
if is_airflow_auth_manager(qualified_name.segments()) { if is_airflow_auth_manager(qualified_name.segments()) {
if !arguments.is_empty() { if !arguments.is_empty() {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3Removal { Airflow3Removal {
deprecated: String::from("appbuilder"), deprecated: String::from("appbuilder"),
replacement: Replacement::Message( replacement: Replacement::Message(
@ -228,44 +221,42 @@ fn check_call_arguments(
)); ));
} }
} else if is_airflow_task_handler(qualified_name.segments()) { } else if is_airflow_task_handler(qualified_name.segments()) {
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"filename_template", "filename_template",
None, None,
)); ));
} else if is_airflow_operator(qualified_name.segments()) { } else if is_airflow_operator(qualified_name.segments()) {
checker checker.report_diagnostics(diagnostic_for_argument(arguments, "sla", None));
.diagnostics checker.report_diagnostics(diagnostic_for_argument(
.extend(diagnostic_for_argument(arguments, "sla", None));
checker.diagnostics.extend(diagnostic_for_argument(
arguments, arguments,
"task_concurrency", "task_concurrency",
Some("max_active_tis_per_dag"), Some("max_active_tis_per_dag"),
)); ));
match qualified_name.segments() { match qualified_name.segments() {
["airflow", .., "operators", "trigger_dagrun", "TriggerDagRunOperator"] => { ["airflow", .., "operators", "trigger_dagrun", "TriggerDagRunOperator"] => {
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"execution_date", "execution_date",
Some("logical_date"), Some("logical_date"),
)); ));
} }
["airflow", .., "operators", "datetime", "BranchDateTimeOperator"] => { ["airflow", .., "operators", "datetime", "BranchDateTimeOperator"] => {
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"use_task_execution_day", "use_task_execution_day",
Some("use_task_logical_date"), Some("use_task_logical_date"),
)); ));
} }
["airflow", .., "operators", "weekday", "DayOfWeekSensor"] => { ["airflow", .., "operators", "weekday", "DayOfWeekSensor"] => {
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"use_task_execution_day", "use_task_execution_day",
Some("use_task_logical_date"), Some("use_task_logical_date"),
)); ));
} }
["airflow", .., "operators", "weekday", "BranchDayOfWeekOperator"] => { ["airflow", .., "operators", "weekday", "BranchDayOfWeekOperator"] => {
checker.diagnostics.extend(diagnostic_for_argument( checker.report_diagnostics(diagnostic_for_argument(
arguments, arguments,
"use_task_execution_day", "use_task_execution_day",
Some("use_task_logical_date"), Some("use_task_logical_date"),
@ -288,7 +279,7 @@ fn check_call_arguments(
/// info = DatasetLineageInfo() /// info = DatasetLineageInfo()
/// info.dataset /// info.dataset
/// ``` /// ```
fn check_class_attribute(checker: &mut Checker, attribute_expr: &ExprAttribute) { fn check_class_attribute(checker: &Checker, attribute_expr: &ExprAttribute) {
let ExprAttribute { value, attr, .. } = attribute_expr; let ExprAttribute { value, attr, .. } = attribute_expr;
let Some(qualname) = typing::resolve_assignment(value, checker.semantic()) else { let Some(qualname) = typing::resolve_assignment(value, checker.semantic()) else {
@ -312,7 +303,7 @@ fn check_class_attribute(checker: &mut Checker, attribute_expr: &ExprAttribute)
}; };
if let Some(replacement) = replacement { if let Some(replacement) = replacement {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3Removal { Airflow3Removal {
deprecated: attr.to_string(), deprecated: attr.to_string(),
replacement, replacement,
@ -350,7 +341,7 @@ fn check_class_attribute(checker: &mut Checker, attribute_expr: &ExprAttribute)
/// def my_task(**context): /// def my_task(**context):
/// context.get("conf") # 'conf' is removed in Airflow 3.0 /// context.get("conf") # 'conf' is removed in Airflow 3.0
/// ``` /// ```
fn check_context_key_usage_in_call(checker: &mut Checker, call_expr: &ExprCall) { fn check_context_key_usage_in_call(checker: &Checker, call_expr: &ExprCall) {
if !in_airflow_task_function(checker.semantic()) { if !in_airflow_task_function(checker.semantic()) {
return; return;
} }
@ -386,7 +377,7 @@ fn check_context_key_usage_in_call(checker: &mut Checker, call_expr: &ExprCall)
continue; continue;
}; };
if value == removed_key { if value == removed_key {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3Removal { Airflow3Removal {
deprecated: removed_key.to_string(), deprecated: removed_key.to_string(),
replacement: Replacement::None, replacement: Replacement::None,
@ -399,7 +390,7 @@ fn check_context_key_usage_in_call(checker: &mut Checker, call_expr: &ExprCall)
/// Check if a subscript expression accesses a removed Airflow context variable. /// Check if a subscript expression accesses a removed Airflow context variable.
/// If a removed key is found, push a corresponding diagnostic. /// If a removed key is found, push a corresponding diagnostic.
fn check_context_key_usage_in_subscript(checker: &mut Checker, subscript: &ExprSubscript) { fn check_context_key_usage_in_subscript(checker: &Checker, subscript: &ExprSubscript) {
if !in_airflow_task_function(checker.semantic()) { if !in_airflow_task_function(checker.semantic()) {
return; return;
} }
@ -427,7 +418,7 @@ fn check_context_key_usage_in_subscript(checker: &mut Checker, subscript: &ExprS
} }
if REMOVED_CONTEXT_KEYS.contains(&key.to_str()) { if REMOVED_CONTEXT_KEYS.contains(&key.to_str()) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3Removal { Airflow3Removal {
deprecated: key.to_string(), deprecated: key.to_string(),
replacement: Replacement::None, replacement: Replacement::None,
@ -463,7 +454,7 @@ fn is_kwarg_parameter(semantic: &SemanticModel, name: &ExprName) -> bool {
/// manager = DatasetManager() /// manager = DatasetManager()
/// manager.register_datsaet_change() /// manager.register_datsaet_change()
/// ``` /// ```
fn check_method(checker: &mut Checker, call_expr: &ExprCall) { fn check_method(checker: &Checker, call_expr: &ExprCall) {
let Expr::Attribute(ExprAttribute { attr, value, .. }) = &*call_expr.func else { let Expr::Attribute(ExprAttribute { attr, value, .. }) = &*call_expr.func else {
return; return;
}; };
@ -528,7 +519,7 @@ fn check_method(checker: &mut Checker, call_expr: &ExprCall) {
} }
}; };
if let Some(replacement) = replacement { if let Some(replacement) = replacement {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3Removal { Airflow3Removal {
deprecated: attr.to_string(), deprecated: attr.to_string(),
replacement, replacement,
@ -552,7 +543,7 @@ fn check_method(checker: &mut Checker, call_expr: &ExprCall) {
/// # Or, directly /// # Or, directly
/// SubDagOperator() /// SubDagOperator()
/// ``` /// ```
fn check_name(checker: &mut Checker, expr: &Expr, range: TextRange) { fn check_name(checker: &Checker, expr: &Expr, range: TextRange) {
let Some(qualified_name) = checker.semantic().resolve_qualified_name(expr) else { let Some(qualified_name) = checker.semantic().resolve_qualified_name(expr) else {
return; return;
}; };
@ -876,7 +867,7 @@ fn check_name(checker: &mut Checker, expr: &Expr, range: TextRange) {
_ => return, _ => return,
}; };
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3Removal { Airflow3Removal {
deprecated: qualified_name.to_string(), deprecated: qualified_name.to_string(),
replacement, replacement,
@ -897,7 +888,7 @@ fn check_name(checker: &mut Checker, expr: &Expr, range: TextRange) {
/// executors = "some.third.party.executor" /// executors = "some.third.party.executor"
/// ``` /// ```
fn check_airflow_plugin_extension( fn check_airflow_plugin_extension(
checker: &mut Checker, checker: &Checker,
expr: &Expr, expr: &Expr,
name: &str, name: &str,
class_def: &StmtClassDef, class_def: &StmtClassDef,
@ -914,7 +905,7 @@ fn check_airflow_plugin_extension(
) )
}) })
}) { }) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Airflow3Removal { Airflow3Removal {
deprecated: name.to_string(), deprecated: name.to_string(),
replacement: Replacement::Message( replacement: Replacement::Message(

View file

@ -45,7 +45,7 @@ impl Violation for AirflowVariableNameTaskIdMismatch {
} }
/// AIR001 /// AIR001
pub(crate) fn variable_name_task_id(checker: &mut Checker, targets: &[Expr], value: &Expr) { pub(crate) fn variable_name_task_id(checker: &Checker, targets: &[Expr], value: &Expr) {
if !checker.semantic().seen_module(Modules::AIRFLOW) { if !checker.semantic().seen_module(Modules::AIRFLOW) {
return; return;
} }
@ -116,5 +116,5 @@ pub(crate) fn variable_name_task_id(checker: &mut Checker, targets: &[Expr], val
}, },
target.range(), target.range(),
); );
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }

View file

@ -88,7 +88,7 @@ impl Violation for FastApiNonAnnotatedDependency {
/// FAST002 /// FAST002
pub(crate) fn fastapi_non_annotated_dependency( pub(crate) fn fastapi_non_annotated_dependency(
checker: &mut Checker, checker: &Checker,
function_def: &ast::StmtFunctionDef, function_def: &ast::StmtFunctionDef,
) { ) {
if !checker.semantic().seen_module(Modules::FASTAPI) if !checker.semantic().seen_module(Modules::FASTAPI)
@ -219,7 +219,7 @@ impl<'a> DependencyCall<'a> {
/// necessary to determine this while generating the fix, thus the need to return an updated /// necessary to determine this while generating the fix, thus the need to return an updated
/// `seen_default` here. /// `seen_default` here.
fn create_diagnostic( fn create_diagnostic(
checker: &mut Checker, checker: &Checker,
parameter: &DependencyParameter, parameter: &DependencyParameter,
dependency_call: Option<DependencyCall>, dependency_call: Option<DependencyCall>,
mut seen_default: bool, mut seen_default: bool,
@ -304,7 +304,7 @@ fn create_diagnostic(
} }
diagnostic.try_set_optional_fix(|| fix); diagnostic.try_set_optional_fix(|| fix);
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
seen_default seen_default
} }

View file

@ -74,10 +74,7 @@ impl AlwaysFixableViolation for FastApiRedundantResponseModel {
} }
/// FAST001 /// FAST001
pub(crate) fn fastapi_redundant_response_model( pub(crate) fn fastapi_redundant_response_model(checker: &Checker, function_def: &StmtFunctionDef) {
checker: &mut Checker,
function_def: &StmtFunctionDef,
) {
if !checker.semantic().seen_module(Modules::FASTAPI) { if !checker.semantic().seen_module(Modules::FASTAPI) {
return; return;
} }
@ -98,7 +95,7 @@ pub(crate) fn fastapi_redundant_response_model(
) )
.map(Fix::unsafe_edit) .map(Fix::unsafe_edit)
}); });
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }

View file

@ -105,7 +105,7 @@ impl Violation for FastApiUnusedPathParameter {
/// FAST003 /// FAST003
pub(crate) fn fastapi_unused_path_parameter( pub(crate) fn fastapi_unused_path_parameter(
checker: &mut Checker, checker: &Checker,
function_def: &ast::StmtFunctionDef, function_def: &ast::StmtFunctionDef,
) { ) {
if !checker.semantic().seen_module(Modules::FASTAPI) { if !checker.semantic().seen_module(Modules::FASTAPI) {
@ -163,7 +163,6 @@ pub(crate) fn fastapi_unused_path_parameter(
} }
// Check if any of the path parameters are not in the function signature. // Check if any of the path parameters are not in the function signature.
let mut diagnostics = vec![];
for (path_param, range) in path_params { for (path_param, range) in path_params {
// Ignore invalid identifiers (e.g., `user-id`, as opposed to `user_id`) // Ignore invalid identifiers (e.g., `user-id`, as opposed to `user_id`)
if !is_identifier(path_param) { if !is_identifier(path_param) {
@ -203,10 +202,8 @@ pub(crate) fn fastapi_unused_path_parameter(
checker.locator().contents(), checker.locator().contents(),
))); )));
} }
diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
checker.diagnostics.extend(diagnostics);
} }
/// Returns an iterator over the non-positional-only, non-variadic parameters of a function. /// Returns an iterator over the non-positional-only, non-variadic parameters of a function.

View file

@ -223,7 +223,7 @@ impl Violation for SysVersionCmpStr10 {
} }
/// YTT103, YTT201, YTT203, YTT204, YTT302 /// YTT103, YTT201, YTT203, YTT204, YTT302
pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], comparators: &[Expr]) { pub(crate) fn compare(checker: &Checker, left: &Expr, ops: &[CmpOp], comparators: &[Expr]) {
match left { match left {
Expr::Subscript(ast::ExprSubscript { value, slice, .. }) Expr::Subscript(ast::ExprSubscript { value, slice, .. })
if is_sys(value, "version_info", checker.semantic()) => if is_sys(value, "version_info", checker.semantic()) =>
@ -243,9 +243,10 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
) = (ops, comparators) ) = (ops, comparators)
{ {
if *n == 3 && checker.enabled(Rule::SysVersionInfo0Eq3) { if *n == 3 && checker.enabled(Rule::SysVersionInfo0Eq3) {
checker checker.report_diagnostic(Diagnostic::new(
.diagnostics SysVersionInfo0Eq3,
.push(Diagnostic::new(SysVersionInfo0Eq3, left.range())); left.range(),
));
} }
} }
} else if *i == 1 { } else if *i == 1 {
@ -258,9 +259,10 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
) = (ops, comparators) ) = (ops, comparators)
{ {
if checker.enabled(Rule::SysVersionInfo1CmpInt) { if checker.enabled(Rule::SysVersionInfo1CmpInt) {
checker checker.report_diagnostic(Diagnostic::new(
.diagnostics SysVersionInfo1CmpInt,
.push(Diagnostic::new(SysVersionInfo1CmpInt, left.range())); left.range(),
));
} }
} }
} }
@ -279,9 +281,10 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
) = (ops, comparators) ) = (ops, comparators)
{ {
if checker.enabled(Rule::SysVersionInfoMinorCmpInt) { if checker.enabled(Rule::SysVersionInfoMinorCmpInt) {
checker checker.report_diagnostic(Diagnostic::new(
.diagnostics SysVersionInfoMinorCmpInt,
.push(Diagnostic::new(SysVersionInfoMinorCmpInt, left.range())); left.range(),
));
} }
} }
} }
@ -297,14 +300,10 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
{ {
if value.len() == 1 { if value.len() == 1 {
if checker.enabled(Rule::SysVersionCmpStr10) { if checker.enabled(Rule::SysVersionCmpStr10) {
checker checker.report_diagnostic(Diagnostic::new(SysVersionCmpStr10, left.range()));
.diagnostics
.push(Diagnostic::new(SysVersionCmpStr10, left.range()));
} }
} else if checker.enabled(Rule::SysVersionCmpStr3) { } else if checker.enabled(Rule::SysVersionCmpStr3) {
checker checker.report_diagnostic(Diagnostic::new(SysVersionCmpStr3, left.range()));
.diagnostics
.push(Diagnostic::new(SysVersionCmpStr3, left.range()));
} }
} }
} }

View file

@ -46,7 +46,7 @@ impl Violation for SixPY3 {
} }
/// YTT202 /// YTT202
pub(crate) fn name_or_attribute(checker: &mut Checker, expr: &Expr) { pub(crate) fn name_or_attribute(checker: &Checker, expr: &Expr) {
if !checker.semantic().seen_module(Modules::SIX) { if !checker.semantic().seen_module(Modules::SIX) {
return; return;
} }
@ -56,8 +56,6 @@ pub(crate) fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
.resolve_qualified_name(expr) .resolve_qualified_name(expr)
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["six", "PY3"])) .is_some_and(|qualified_name| matches!(qualified_name.segments(), ["six", "PY3"]))
{ {
checker checker.report_diagnostic(Diagnostic::new(SixPY3, expr.range()));
.diagnostics
.push(Diagnostic::new(SixPY3, expr.range()));
} }
} }

View file

@ -168,7 +168,7 @@ impl Violation for SysVersionSlice1 {
} }
/// YTT101, YTT102, YTT301, YTT303 /// YTT101, YTT102, YTT301, YTT303
pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) { pub(crate) fn subscript(checker: &Checker, value: &Expr, slice: &Expr) {
if is_sys(value, "version", checker.semantic()) { if is_sys(value, "version", checker.semantic()) {
match slice { match slice {
Expr::Slice(ast::ExprSlice { Expr::Slice(ast::ExprSlice {
@ -183,13 +183,9 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
}) = upper.as_ref() }) = upper.as_ref()
{ {
if *i == 1 && checker.enabled(Rule::SysVersionSlice1) { if *i == 1 && checker.enabled(Rule::SysVersionSlice1) {
checker checker.report_diagnostic(Diagnostic::new(SysVersionSlice1, value.range()));
.diagnostics
.push(Diagnostic::new(SysVersionSlice1, value.range()));
} else if *i == 3 && checker.enabled(Rule::SysVersionSlice3) { } else if *i == 3 && checker.enabled(Rule::SysVersionSlice3) {
checker checker.report_diagnostic(Diagnostic::new(SysVersionSlice3, value.range()));
.diagnostics
.push(Diagnostic::new(SysVersionSlice3, value.range()));
} }
} }
} }
@ -199,13 +195,9 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
.. ..
}) => { }) => {
if *i == 2 && checker.enabled(Rule::SysVersion2) { if *i == 2 && checker.enabled(Rule::SysVersion2) {
checker checker.report_diagnostic(Diagnostic::new(SysVersion2, value.range()));
.diagnostics
.push(Diagnostic::new(SysVersion2, value.range()));
} else if *i == 0 && checker.enabled(Rule::SysVersion0) { } else if *i == 0 && checker.enabled(Rule::SysVersion0) {
checker checker.report_diagnostic(Diagnostic::new(SysVersion0, value.range()));
.diagnostics
.push(Diagnostic::new(SysVersion0, value.range()));
} }
} }

View file

@ -51,7 +51,7 @@ impl Violation for AsyncBusyWait {
} }
/// ASYNC110 /// ASYNC110
pub(crate) fn async_busy_wait(checker: &mut Checker, while_stmt: &ast::StmtWhile) { pub(crate) fn async_busy_wait(checker: &Checker, while_stmt: &ast::StmtWhile) {
// The body should be a single `await` call. // The body should be a single `await` call.
let [stmt] = while_stmt.body.as_slice() else { let [stmt] = while_stmt.body.as_slice() else {
return; return;
@ -74,7 +74,7 @@ pub(crate) fn async_busy_wait(checker: &mut Checker, while_stmt: &ast::StmtWhile
qualified_name.segments(), qualified_name.segments(),
["trio" | "anyio", "sleep" | "sleep_until"] | ["asyncio", "sleep"] ["trio" | "anyio", "sleep" | "sleep_until"] | ["asyncio", "sleep"]
) { ) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
AsyncBusyWait { AsyncBusyWait {
module: AsyncModule::try_from(&qualified_name).unwrap(), module: AsyncModule::try_from(&qualified_name).unwrap(),
}, },

View file

@ -87,10 +87,7 @@ impl Violation for AsyncFunctionWithTimeout {
} }
/// ASYNC109 /// ASYNC109
pub(crate) fn async_function_with_timeout( pub(crate) fn async_function_with_timeout(checker: &Checker, function_def: &ast::StmtFunctionDef) {
checker: &mut Checker,
function_def: &ast::StmtFunctionDef,
) {
// Detect `async` calls with a `timeout` argument. // Detect `async` calls with a `timeout` argument.
if !function_def.is_async { if !function_def.is_async {
return; return;
@ -115,7 +112,7 @@ pub(crate) fn async_function_with_timeout(
return; return;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
AsyncFunctionWithTimeout { module }, AsyncFunctionWithTimeout { module },
timeout.range(), timeout.range(),
)); ));

View file

@ -51,7 +51,7 @@ impl AlwaysFixableViolation for AsyncZeroSleep {
} }
/// ASYNC115 /// ASYNC115
pub(crate) fn async_zero_sleep(checker: &mut Checker, call: &ExprCall) { pub(crate) fn async_zero_sleep(checker: &Checker, call: &ExprCall) {
if !(checker.semantic().seen_module(Modules::TRIO) if !(checker.semantic().seen_module(Modules::TRIO)
|| checker.semantic().seen_module(Modules::ANYIO)) || checker.semantic().seen_module(Modules::ANYIO))
{ {
@ -103,6 +103,6 @@ pub(crate) fn async_zero_sleep(checker: &mut Checker, call: &ExprCall) {
let arg_edit = Edit::range_replacement("()".to_string(), call.arguments.range()); let arg_edit = Edit::range_replacement("()".to_string(), call.arguments.range());
Ok(Fix::safe_edits(import_edit, [reference_edit, arg_edit])) Ok(Fix::safe_edits(import_edit, [reference_edit, arg_edit]))
}); });
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }

View file

@ -62,7 +62,7 @@ fn is_blocking_http_call(qualified_name: &QualifiedName) -> bool {
} }
/// ASYNC210 /// ASYNC210
pub(crate) fn blocking_http_call(checker: &mut Checker, call: &ExprCall) { pub(crate) fn blocking_http_call(checker: &Checker, call: &ExprCall) {
if checker.semantic().in_async_context() { if checker.semantic().in_async_context() {
if checker if checker
.semantic() .semantic()
@ -70,7 +70,7 @@ pub(crate) fn blocking_http_call(checker: &mut Checker, call: &ExprCall) {
.as_ref() .as_ref()
.is_some_and(is_blocking_http_call) .is_some_and(is_blocking_http_call)
{ {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
BlockingHttpCallInAsyncFunction, BlockingHttpCallInAsyncFunction,
call.func.range(), call.func.range(),
)); ));

View file

@ -44,7 +44,7 @@ impl Violation for BlockingOpenCallInAsyncFunction {
} }
/// ASYNC230 /// ASYNC230
pub(crate) fn blocking_open_call(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn blocking_open_call(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().in_async_context() { if !checker.semantic().in_async_context() {
return; return;
} }
@ -52,7 +52,7 @@ pub(crate) fn blocking_open_call(checker: &mut Checker, call: &ast::ExprCall) {
if is_open_call(&call.func, checker.semantic()) if is_open_call(&call.func, checker.semantic())
|| is_open_call_from_pathlib(call.func.as_ref(), checker.semantic()) || is_open_call_from_pathlib(call.func.as_ref(), checker.semantic())
{ {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
BlockingOpenCallInAsyncFunction, BlockingOpenCallInAsyncFunction,
call.func.range(), call.func.range(),
)); ));

View file

@ -112,7 +112,7 @@ impl Violation for WaitForProcessInAsyncFunction {
} }
/// ASYNC220, ASYNC221, ASYNC222 /// ASYNC220, ASYNC221, ASYNC222
pub(crate) fn blocking_process_invocation(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn blocking_process_invocation(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().in_async_context() { if !checker.semantic().in_async_context() {
return; return;
} }
@ -146,7 +146,7 @@ pub(crate) fn blocking_process_invocation(checker: &mut Checker, call: &ast::Exp
}; };
let diagnostic = Diagnostic::new::<DiagnosticKind>(diagnostic_kind, call.func.range()); let diagnostic = Diagnostic::new::<DiagnosticKind>(diagnostic_kind, call.func.range());
if checker.enabled(diagnostic.kind.rule()) { if checker.enabled(diagnostic.kind.rule()) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }

View file

@ -43,7 +43,7 @@ fn is_blocking_sleep(qualified_name: &QualifiedName) -> bool {
} }
/// ASYNC251 /// ASYNC251
pub(crate) fn blocking_sleep(checker: &mut Checker, call: &ExprCall) { pub(crate) fn blocking_sleep(checker: &Checker, call: &ExprCall) {
if checker.semantic().in_async_context() { if checker.semantic().in_async_context() {
if checker if checker
.semantic() .semantic()
@ -51,7 +51,7 @@ pub(crate) fn blocking_sleep(checker: &mut Checker, call: &ExprCall) {
.as_ref() .as_ref()
.is_some_and(is_blocking_sleep) .is_some_and(is_blocking_sleep)
{ {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
BlockingSleepInAsyncFunction, BlockingSleepInAsyncFunction,
call.func.range(), call.func.range(),
)); ));

View file

@ -53,7 +53,7 @@ impl Violation for CancelScopeNoCheckpoint {
/// ASYNC100 /// ASYNC100
pub(crate) fn cancel_scope_no_checkpoint( pub(crate) fn cancel_scope_no_checkpoint(
checker: &mut Checker, checker: &Checker,
with_stmt: &StmtWith, with_stmt: &StmtWith,
with_items: &[WithItem], with_items: &[WithItem],
) { ) {
@ -98,7 +98,7 @@ pub(crate) fn cancel_scope_no_checkpoint(
return; return;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
CancelScopeNoCheckpoint { method_name }, CancelScopeNoCheckpoint { method_name },
with_stmt.range, with_stmt.range,
)); ));

View file

@ -56,7 +56,7 @@ impl Violation for LongSleepNotForever {
} }
/// ASYNC116 /// ASYNC116
pub(crate) fn long_sleep_not_forever(checker: &mut Checker, call: &ExprCall) { pub(crate) fn long_sleep_not_forever(checker: &Checker, call: &ExprCall) {
if !(checker.semantic().seen_module(Modules::TRIO) if !(checker.semantic().seen_module(Modules::TRIO)
|| checker.semantic().seen_module(Modules::ANYIO)) || checker.semantic().seen_module(Modules::ANYIO))
{ {
@ -127,5 +127,5 @@ pub(crate) fn long_sleep_not_forever(checker: &mut Checker, call: &ExprCall) {
let arg_edit = Edit::range_replacement("()".to_string(), call.arguments.range()); let arg_edit = Edit::range_replacement("()".to_string(), call.arguments.range());
Ok(Fix::unsafe_edits(import_edit, [reference_edit, arg_edit])) Ok(Fix::unsafe_edits(import_edit, [reference_edit, arg_edit]))
}); });
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }

View file

@ -51,7 +51,7 @@ impl Violation for TrioSyncCall {
} }
/// ASYNC105 /// ASYNC105
pub(crate) fn sync_call(checker: &mut Checker, call: &ExprCall) { pub(crate) fn sync_call(checker: &Checker, call: &ExprCall) {
if !checker.semantic().seen_module(Modules::TRIO) { if !checker.semantic().seen_module(Modules::TRIO) {
return; return;
} }
@ -91,5 +91,5 @@ pub(crate) fn sync_call(checker: &mut Checker, call: &ExprCall) {
call.func.start(), call.func.start(),
))); )));
} }
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }

View file

@ -61,7 +61,7 @@ enum Reason {
} }
/// S103 /// S103
pub(crate) fn bad_file_permissions(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn bad_file_permissions(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::OS) { if !checker.semantic().seen_module(Modules::OS) {
return; return;
} }
@ -78,7 +78,7 @@ pub(crate) fn bad_file_permissions(checker: &mut Checker, call: &ast::ExprCall)
// The mask is a valid integer value -- check for overly permissive permissions. // The mask is a valid integer value -- check for overly permissive permissions.
Ok(Some(mask)) => { Ok(Some(mask)) => {
if (mask & WRITE_WORLD > 0) || (mask & EXECUTE_GROUP > 0) { if (mask & WRITE_WORLD > 0) || (mask & EXECUTE_GROUP > 0) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
BadFilePermissions { BadFilePermissions {
reason: Reason::Permissive(mask), reason: Reason::Permissive(mask),
}, },
@ -88,7 +88,7 @@ pub(crate) fn bad_file_permissions(checker: &mut Checker, call: &ast::ExprCall)
} }
// The mask is an invalid integer value (i.e., it's out of range). // The mask is an invalid integer value (i.e., it's out of range).
Err(_) => { Err(_) => {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
BadFilePermissions { BadFilePermissions {
reason: Reason::Invalid, reason: Reason::Invalid,
}, },

View file

@ -44,7 +44,7 @@ impl Violation for DjangoExtra {
} }
/// S610 /// S610
pub(crate) fn django_extra(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn django_extra(checker: &Checker, call: &ast::ExprCall) {
let Expr::Attribute(ExprAttribute { attr, .. }) = call.func.as_ref() else { let Expr::Attribute(ExprAttribute { attr, .. }) = call.func.as_ref() else {
return; return;
}; };
@ -54,9 +54,7 @@ pub(crate) fn django_extra(checker: &mut Checker, call: &ast::ExprCall) {
} }
if is_call_insecure(call) { if is_call_insecure(call) {
checker checker.report_diagnostic(Diagnostic::new(DjangoExtra, call.arguments.range()));
.diagnostics
.push(Diagnostic::new(DjangoExtra, call.arguments.range()));
} }
} }

View file

@ -35,7 +35,7 @@ impl Violation for DjangoRawSql {
} }
/// S611 /// S611
pub(crate) fn django_raw_sql(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn django_raw_sql(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::DJANGO) { if !checker.semantic().seen_module(Modules::DJANGO) {
return; return;
} }
@ -55,9 +55,7 @@ pub(crate) fn django_raw_sql(checker: &mut Checker, call: &ast::ExprCall) {
.find_argument_value("sql", 0) .find_argument_value("sql", 0)
.is_some_and(Expr::is_string_literal_expr) .is_some_and(Expr::is_string_literal_expr)
{ {
checker checker.report_diagnostic(Diagnostic::new(DjangoRawSql, call.func.range()));
.diagnostics
.push(Diagnostic::new(DjangoRawSql, call.func.range()));
} }
} }
} }

View file

@ -32,10 +32,8 @@ impl Violation for ExecBuiltin {
} }
/// S102 /// S102
pub(crate) fn exec_used(checker: &mut Checker, func: &Expr) { pub(crate) fn exec_used(checker: &Checker, func: &Expr) {
if checker.semantic().match_builtin_expr(func, "exec") { if checker.semantic().match_builtin_expr(func, "exec") {
checker checker.report_diagnostic(Diagnostic::new(ExecBuiltin, func.range()));
.diagnostics
.push(Diagnostic::new(ExecBuiltin, func.range()));
} }
} }

View file

@ -47,7 +47,7 @@ impl Violation for FlaskDebugTrue {
} }
/// S201 /// S201
pub(crate) fn flask_debug_true(checker: &mut Checker, call: &ExprCall) { pub(crate) fn flask_debug_true(checker: &Checker, call: &ExprCall) {
let Expr::Attribute(ExprAttribute { attr, value, .. }) = call.func.as_ref() else { let Expr::Attribute(ExprAttribute { attr, value, .. }) = call.func.as_ref() else {
return; return;
}; };
@ -67,8 +67,6 @@ pub(crate) fn flask_debug_true(checker: &mut Checker, call: &ExprCall) {
if typing::resolve_assignment(value, checker.semantic()) if typing::resolve_assignment(value, checker.semantic())
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["flask", "Flask"])) .is_some_and(|qualified_name| matches!(qualified_name.segments(), ["flask", "Flask"]))
{ {
checker checker.report_diagnostic(Diagnostic::new(FlaskDebugTrue, debug_argument.range()));
.diagnostics
.push(Diagnostic::new(FlaskDebugTrue, debug_argument.range()));
} }
} }

View file

@ -37,13 +37,12 @@ impl Violation for HardcodedBindAllInterfaces {
} }
/// S104 /// S104
pub(crate) fn hardcoded_bind_all_interfaces(checker: &mut Checker, string: StringLike) { pub(crate) fn hardcoded_bind_all_interfaces(checker: &Checker, string: StringLike) {
match string { match string {
StringLike::String(ast::ExprStringLiteral { value, .. }) => { StringLike::String(ast::ExprStringLiteral { value, .. }) => {
if value == "0.0.0.0" { if value == "0.0.0.0" {
checker checker
.diagnostics .report_diagnostic(Diagnostic::new(HardcodedBindAllInterfaces, string.range()));
.push(Diagnostic::new(HardcodedBindAllInterfaces, string.range()));
} }
} }
StringLike::FString(ast::ExprFString { value, .. }) => { StringLike::FString(ast::ExprFString { value, .. }) => {
@ -51,15 +50,16 @@ pub(crate) fn hardcoded_bind_all_interfaces(checker: &mut Checker, string: Strin
match part { match part {
ast::FStringPart::Literal(literal) => { ast::FStringPart::Literal(literal) => {
if &**literal == "0.0.0.0" { if &**literal == "0.0.0.0" {
checker checker.report_diagnostic(Diagnostic::new(
.diagnostics HardcodedBindAllInterfaces,
.push(Diagnostic::new(HardcodedBindAllInterfaces, literal.range())); literal.range(),
));
} }
} }
ast::FStringPart::FString(f_string) => { ast::FStringPart::FString(f_string) => {
for literal in f_string.elements.literals() { for literal in f_string.elements.literals() {
if &**literal == "0.0.0.0" { if &**literal == "0.0.0.0" {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
HardcodedBindAllInterfaces, HardcodedBindAllInterfaces,
literal.range(), literal.range(),
)); ));

View file

@ -69,13 +69,13 @@ fn check_password_kwarg(parameter: &Parameter, default: &Expr) -> Option<Diagnos
} }
/// S107 /// S107
pub(crate) fn hardcoded_password_default(checker: &mut Checker, parameters: &Parameters) { pub(crate) fn hardcoded_password_default(checker: &Checker, parameters: &Parameters) {
for parameter in parameters.iter_non_variadic_params() { for parameter in parameters.iter_non_variadic_params() {
let Some(default) = parameter.default() else { let Some(default) = parameter.default() else {
continue; continue;
}; };
if let Some(diagnostic) = check_password_kwarg(&parameter.parameter, default) { if let Some(diagnostic) = check_password_kwarg(&parameter.parameter, default) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }

View file

@ -51,20 +51,18 @@ impl Violation for HardcodedPasswordFuncArg {
} }
/// S106 /// S106
pub(crate) fn hardcoded_password_func_arg(checker: &mut Checker, keywords: &[Keyword]) { pub(crate) fn hardcoded_password_func_arg(checker: &Checker, keywords: &[Keyword]) {
checker checker.report_diagnostics(keywords.iter().filter_map(|keyword| {
.diagnostics string_literal(&keyword.value).filter(|string| !string.is_empty())?;
.extend(keywords.iter().filter_map(|keyword| { let arg = keyword.arg.as_ref()?;
string_literal(&keyword.value).filter(|string| !string.is_empty())?; if !matches_password_name(arg) {
let arg = keyword.arg.as_ref()?; return None;
if !matches_password_name(arg) { }
return None; Some(Diagnostic::new(
} HardcodedPasswordFuncArg {
Some(Diagnostic::new( name: arg.to_string(),
HardcodedPasswordFuncArg { },
name: arg.to_string(), keyword.range(),
}, ))
keyword.range(), }));
))
}));
} }

View file

@ -72,37 +72,31 @@ fn password_target(target: &Expr) -> Option<&str> {
/// S105 /// S105
pub(crate) fn compare_to_hardcoded_password_string( pub(crate) fn compare_to_hardcoded_password_string(
checker: &mut Checker, checker: &Checker,
left: &Expr, left: &Expr,
comparators: &[Expr], comparators: &[Expr],
) { ) {
checker checker.report_diagnostics(comparators.iter().filter_map(|comp| {
.diagnostics string_literal(comp).filter(|string| !string.is_empty())?;
.extend(comparators.iter().filter_map(|comp| { let name = password_target(left)?;
string_literal(comp).filter(|string| !string.is_empty())?; Some(Diagnostic::new(
let name = password_target(left)?; HardcodedPasswordString {
Some(Diagnostic::new( name: name.to_string(),
HardcodedPasswordString { },
name: name.to_string(), comp.range(),
}, ))
comp.range(), }));
))
}));
} }
/// S105 /// S105
pub(crate) fn assign_hardcoded_password_string( pub(crate) fn assign_hardcoded_password_string(checker: &Checker, value: &Expr, targets: &[Expr]) {
checker: &mut Checker,
value: &Expr,
targets: &[Expr],
) {
if string_literal(value) if string_literal(value)
.filter(|string| !string.is_empty()) .filter(|string| !string.is_empty())
.is_some() .is_some()
{ {
for target in targets { for target in targets {
if let Some(name) = password_target(target) { if let Some(name) = password_target(target) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
HardcodedPasswordString { HardcodedPasswordString {
name: name.to_string(), name: name.to_string(),
}, },

View file

@ -55,7 +55,7 @@ impl Violation for HardcodedSQLExpression {
} }
/// S608 /// S608
pub(crate) fn hardcoded_sql_expression(checker: &mut Checker, expr: &Expr) { pub(crate) fn hardcoded_sql_expression(checker: &Checker, expr: &Expr) {
let content = match expr { let content = match expr {
// "select * from table where val = " + "str" + ... // "select * from table where val = " + "str" + ...
Expr::BinOp(ast::ExprBinOp { Expr::BinOp(ast::ExprBinOp {
@ -105,9 +105,7 @@ pub(crate) fn hardcoded_sql_expression(checker: &mut Checker, expr: &Expr) {
}; };
if SQL_REGEX.is_match(&content) { if SQL_REGEX.is_match(&content) {
checker checker.report_diagnostic(Diagnostic::new(HardcodedSQLExpression, expr.range()));
.diagnostics
.push(Diagnostic::new(HardcodedSQLExpression, expr.range()));
} }
} }

View file

@ -56,7 +56,7 @@ impl Violation for HardcodedTempFile {
} }
/// S108 /// S108
pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: StringLike) { pub(crate) fn hardcoded_tmp_directory(checker: &Checker, string: StringLike) {
match string { match string {
StringLike::String(ast::ExprStringLiteral { value, .. }) => { StringLike::String(ast::ExprStringLiteral { value, .. }) => {
check(checker, value.to_str(), string.range()); check(checker, value.to_str(), string.range());
@ -79,7 +79,7 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: StringLike)
} }
} }
fn check(checker: &mut Checker, value: &str, range: TextRange) { fn check(checker: &Checker, value: &str, range: TextRange) {
if !checker if !checker
.settings .settings
.flake8_bandit .flake8_bandit
@ -102,7 +102,7 @@ fn check(checker: &mut Checker, value: &str, range: TextRange) {
} }
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
HardcodedTempFile { HardcodedTempFile {
string: value.to_string(), string: value.to_string(),
}, },

View file

@ -64,7 +64,7 @@ impl Violation for HashlibInsecureHashFunction {
} }
/// S324 /// S324
pub(crate) fn hashlib_insecure_hash_functions(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn hashlib_insecure_hash_functions(checker: &Checker, call: &ast::ExprCall) {
if !checker if !checker
.semantic() .semantic()
.seen_module(Modules::HASHLIB | Modules::CRYPT) .seen_module(Modules::HASHLIB | Modules::CRYPT)
@ -105,7 +105,7 @@ pub(crate) fn hashlib_insecure_hash_functions(checker: &mut Checker, call: &ast:
} }
fn detect_insecure_hashlib_calls( fn detect_insecure_hashlib_calls(
checker: &mut Checker, checker: &Checker,
call: &ast::ExprCall, call: &ast::ExprCall,
hashlib_call: HashlibCall, hashlib_call: HashlibCall,
) { ) {
@ -128,7 +128,7 @@ fn detect_insecure_hashlib_calls(
hash_func_name, hash_func_name,
"md4" | "md5" | "sha" | "sha1" | "MD4" | "MD5" | "SHA" | "SHA1" "md4" | "md5" | "sha" | "sha1" | "MD4" | "MD5" | "SHA" | "SHA1"
) { ) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
HashlibInsecureHashFunction { HashlibInsecureHashFunction {
library: "hashlib".to_string(), library: "hashlib".to_string(),
string: hash_func_name.to_string(), string: hash_func_name.to_string(),
@ -138,7 +138,7 @@ fn detect_insecure_hashlib_calls(
} }
} }
HashlibCall::WeakHash(func_name) => { HashlibCall::WeakHash(func_name) => {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
HashlibInsecureHashFunction { HashlibInsecureHashFunction {
library: "hashlib".to_string(), library: "hashlib".to_string(),
string: (*func_name).to_string(), string: (*func_name).to_string(),
@ -149,7 +149,7 @@ fn detect_insecure_hashlib_calls(
} }
} }
fn detect_insecure_crypt_calls(checker: &mut Checker, call: &ast::ExprCall) { fn detect_insecure_crypt_calls(checker: &Checker, call: &ast::ExprCall) {
let Some(method) = checker let Some(method) = checker
.semantic() .semantic()
.resolve_qualified_name(&call.func) .resolve_qualified_name(&call.func)
@ -173,7 +173,7 @@ fn detect_insecure_crypt_calls(checker: &mut Checker, call: &ast::ExprCall) {
qualified_name.segments(), qualified_name.segments(),
["crypt", "METHOD_CRYPT" | "METHOD_MD5" | "METHOD_BLOWFISH"] ["crypt", "METHOD_CRYPT" | "METHOD_MD5" | "METHOD_BLOWFISH"]
) { ) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
HashlibInsecureHashFunction { HashlibInsecureHashFunction {
library: "crypt".to_string(), library: "crypt".to_string(),
string: qualified_name.to_string(), string: qualified_name.to_string(),

View file

@ -56,7 +56,7 @@ impl Violation for Jinja2AutoescapeFalse {
} }
/// S701 /// S701
pub(crate) fn jinja2_autoescape_false(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn jinja2_autoescape_false(checker: &Checker, call: &ast::ExprCall) {
if checker if checker
.semantic() .semantic()
.resolve_qualified_name(&call.func) .resolve_qualified_name(&call.func)
@ -70,20 +70,20 @@ pub(crate) fn jinja2_autoescape_false(checker: &mut Checker, call: &ast::ExprCal
Expr::Call(ast::ExprCall { func, .. }) => { Expr::Call(ast::ExprCall { func, .. }) => {
if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() { if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
if id != "select_autoescape" { if id != "select_autoescape" {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Jinja2AutoescapeFalse { value: true }, Jinja2AutoescapeFalse { value: true },
keyword.range(), keyword.range(),
)); ));
} }
} }
} }
_ => checker.diagnostics.push(Diagnostic::new( _ => checker.report_diagnostic(Diagnostic::new(
Jinja2AutoescapeFalse { value: true }, Jinja2AutoescapeFalse { value: true },
keyword.range(), keyword.range(),
)), )),
} }
} else { } else {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
Jinja2AutoescapeFalse { value: false }, Jinja2AutoescapeFalse { value: false },
call.func.range(), call.func.range(),
)); ));

View file

@ -35,7 +35,7 @@ impl Violation for LoggingConfigInsecureListen {
} }
/// S612 /// S612
pub(crate) fn logging_config_insecure_listen(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn logging_config_insecure_listen(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::LOGGING) { if !checker.semantic().seen_module(Modules::LOGGING) {
return; return;
} }
@ -51,7 +51,7 @@ pub(crate) fn logging_config_insecure_listen(checker: &mut Checker, call: &ast::
return; return;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
LoggingConfigInsecureListen, LoggingConfigInsecureListen,
call.func.range(), call.func.range(),
)); ));

View file

@ -42,7 +42,7 @@ impl Violation for MakoTemplates {
} }
/// S702 /// S702
pub(crate) fn mako_templates(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn mako_templates(checker: &Checker, call: &ast::ExprCall) {
if checker if checker
.semantic() .semantic()
.resolve_qualified_name(&call.func) .resolve_qualified_name(&call.func)
@ -50,8 +50,6 @@ pub(crate) fn mako_templates(checker: &mut Checker, call: &ast::ExprCall) {
matches!(qualified_name.segments(), ["mako", "template", "Template"]) matches!(qualified_name.segments(), ["mako", "template", "Template"])
}) })
{ {
checker checker.report_diagnostic(Diagnostic::new(MakoTemplates, call.func.range()));
.diagnostics
.push(Diagnostic::new(MakoTemplates, call.func.range()));
} }
} }

View file

@ -37,7 +37,7 @@ impl Violation for ParamikoCall {
} }
/// S601 /// S601
pub(crate) fn paramiko_call(checker: &mut Checker, func: &Expr) { pub(crate) fn paramiko_call(checker: &Checker, func: &Expr) {
if checker if checker
.semantic() .semantic()
.resolve_qualified_name(func) .resolve_qualified_name(func)
@ -45,8 +45,6 @@ pub(crate) fn paramiko_call(checker: &mut Checker, func: &Expr) {
matches!(qualified_name.segments(), ["paramiko", "exec_command"]) matches!(qualified_name.segments(), ["paramiko", "exec_command"])
}) })
{ {
checker checker.report_diagnostic(Diagnostic::new(ParamikoCall, func.range()));
.diagnostics
.push(Diagnostic::new(ParamikoCall, func.range()));
} }
} }

View file

@ -46,7 +46,7 @@ impl Violation for RequestWithNoCertValidation {
} }
/// S501 /// S501
pub(crate) fn request_with_no_cert_validation(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn request_with_no_cert_validation(checker: &Checker, call: &ast::ExprCall) {
if let Some(target) = checker if let Some(target) = checker
.semantic() .semantic()
.resolve_qualified_name(&call.func) .resolve_qualified_name(&call.func)
@ -61,7 +61,7 @@ pub(crate) fn request_with_no_cert_validation(checker: &mut Checker, call: &ast:
{ {
if let Some(keyword) = call.arguments.find_keyword("verify") { if let Some(keyword) = call.arguments.find_keyword("verify") {
if is_const_false(&keyword.value) { if is_const_false(&keyword.value) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
RequestWithNoCertValidation { RequestWithNoCertValidation {
string: target.to_string(), string: target.to_string(),
}, },

View file

@ -51,7 +51,7 @@ impl Violation for RequestWithoutTimeout {
} }
/// S113 /// S113
pub(crate) fn request_without_timeout(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn request_without_timeout(checker: &Checker, call: &ast::ExprCall) {
if let Some(module) = checker if let Some(module) = checker
.semantic() .semantic()
.resolve_qualified_name(&call.func) .resolve_qualified_name(&call.func)
@ -67,13 +67,13 @@ pub(crate) fn request_without_timeout(checker: &mut Checker, call: &ast::ExprCal
{ {
if let Some(keyword) = call.arguments.find_keyword("timeout") { if let Some(keyword) = call.arguments.find_keyword("timeout") {
if keyword.value.is_none_literal_expr() { if keyword.value.is_none_literal_expr() {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
RequestWithoutTimeout { implicit: false, module: module.to_string() }, RequestWithoutTimeout { implicit: false, module: module.to_string() },
keyword.range(), keyword.range(),
)); ));
} }
} else if module == "requests" { } else if module == "requests" {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
RequestWithoutTimeout { implicit: true, module: module.to_string() }, RequestWithoutTimeout { implicit: true, module: module.to_string() },
call.func.range(), call.func.range(),
)); ));

View file

@ -288,7 +288,7 @@ impl Violation for UnixCommandWildcardInjection {
} }
/// S602, S603, S604, S605, S606, S607, S609 /// S602, S603, S604, S605, S606, S607, S609
pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn shell_injection(checker: &Checker, call: &ast::ExprCall) {
let call_kind = get_call_kind(&call.func, checker.semantic()); let call_kind = get_call_kind(&call.func, checker.semantic());
let shell_keyword = find_shell_keyword(&call.arguments, checker.semantic()); let shell_keyword = find_shell_keyword(&call.arguments, checker.semantic());
@ -300,7 +300,7 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
truthiness: truthiness @ (Truthiness::True | Truthiness::Truthy), truthiness: truthiness @ (Truthiness::True | Truthiness::Truthy),
}) => { }) => {
if checker.enabled(Rule::SubprocessPopenWithShellEqualsTrue) { if checker.enabled(Rule::SubprocessPopenWithShellEqualsTrue) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
SubprocessPopenWithShellEqualsTrue { SubprocessPopenWithShellEqualsTrue {
safety: Safety::from(arg), safety: Safety::from(arg),
is_exact: matches!(truthiness, Truthiness::True), is_exact: matches!(truthiness, Truthiness::True),
@ -315,7 +315,7 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
Truthiness::False | Truthiness::Falsey | Truthiness::None | Truthiness::Unknown, Truthiness::False | Truthiness::Falsey | Truthiness::None | Truthiness::Unknown,
}) => { }) => {
if checker.enabled(Rule::SubprocessWithoutShellEqualsTrue) { if checker.enabled(Rule::SubprocessWithoutShellEqualsTrue) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
SubprocessWithoutShellEqualsTrue, SubprocessWithoutShellEqualsTrue,
call.func.range(), call.func.range(),
)); ));
@ -324,7 +324,7 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
// S603 // S603
None => { None => {
if checker.enabled(Rule::SubprocessWithoutShellEqualsTrue) { if checker.enabled(Rule::SubprocessWithoutShellEqualsTrue) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
SubprocessWithoutShellEqualsTrue, SubprocessWithoutShellEqualsTrue,
call.func.range(), call.func.range(),
)); ));
@ -338,7 +338,7 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
{ {
// S604 // S604
if checker.enabled(Rule::CallWithShellEqualsTrue) { if checker.enabled(Rule::CallWithShellEqualsTrue) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
CallWithShellEqualsTrue { CallWithShellEqualsTrue {
is_exact: matches!(truthiness, Truthiness::True), is_exact: matches!(truthiness, Truthiness::True),
}, },
@ -351,7 +351,7 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
if checker.enabled(Rule::StartProcessWithAShell) { if checker.enabled(Rule::StartProcessWithAShell) {
if matches!(call_kind, Some(CallKind::Shell)) { if matches!(call_kind, Some(CallKind::Shell)) {
if let Some(arg) = call.arguments.args.first() { if let Some(arg) = call.arguments.args.first() {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
StartProcessWithAShell { StartProcessWithAShell {
safety: Safety::from(arg), safety: Safety::from(arg),
}, },
@ -364,9 +364,7 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
// S606 // S606
if checker.enabled(Rule::StartProcessWithNoShell) { if checker.enabled(Rule::StartProcessWithNoShell) {
if matches!(call_kind, Some(CallKind::NoShell)) { if matches!(call_kind, Some(CallKind::NoShell)) {
checker checker.report_diagnostic(Diagnostic::new(StartProcessWithNoShell, call.func.range()));
.diagnostics
.push(Diagnostic::new(StartProcessWithNoShell, call.func.range()));
} }
} }
@ -375,9 +373,10 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
if call_kind.is_some() { if call_kind.is_some() {
if let Some(arg) = call.arguments.args.first() { if let Some(arg) = call.arguments.args.first() {
if is_partial_path(arg) { if is_partial_path(arg) {
checker checker.report_diagnostic(Diagnostic::new(
.diagnostics StartProcessWithPartialPath,
.push(Diagnostic::new(StartProcessWithPartialPath, arg.range())); arg.range(),
));
} }
} }
} }
@ -398,9 +397,10 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
{ {
if let Some(arg) = call.arguments.args.first() { if let Some(arg) = call.arguments.args.first() {
if is_wildcard_command(arg) { if is_wildcard_command(arg) {
checker checker.report_diagnostic(Diagnostic::new(
.diagnostics UnixCommandWildcardInjection,
.push(Diagnostic::new(UnixCommandWildcardInjection, arg.range())); arg.range(),
));
} }
} }
} }

View file

@ -41,7 +41,7 @@ impl Violation for SnmpInsecureVersion {
} }
/// S508 /// S508
pub(crate) fn snmp_insecure_version(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn snmp_insecure_version(checker: &Checker, call: &ast::ExprCall) {
if checker if checker
.semantic() .semantic()
.resolve_qualified_name(&call.func) .resolve_qualified_name(&call.func)
@ -60,9 +60,7 @@ pub(crate) fn snmp_insecure_version(checker: &mut Checker, call: &ast::ExprCall)
.. ..
}) })
) { ) {
checker checker.report_diagnostic(Diagnostic::new(SnmpInsecureVersion, keyword.range()));
.diagnostics
.push(Diagnostic::new(SnmpInsecureVersion, keyword.range()));
} }
} }
} }

View file

@ -40,7 +40,7 @@ impl Violation for SnmpWeakCryptography {
} }
/// S509 /// S509
pub(crate) fn snmp_weak_cryptography(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn snmp_weak_cryptography(checker: &Checker, call: &ast::ExprCall) {
if call.arguments.len() < 3 { if call.arguments.len() < 3 {
if checker if checker
.semantic() .semantic()
@ -52,9 +52,7 @@ pub(crate) fn snmp_weak_cryptography(checker: &mut Checker, call: &ast::ExprCall
) )
}) })
{ {
checker checker.report_diagnostic(Diagnostic::new(SnmpWeakCryptography, call.func.range()));
.diagnostics
.push(Diagnostic::new(SnmpWeakCryptography, call.func.range()));
} }
} }
} }

View file

@ -44,7 +44,7 @@ impl Violation for SSHNoHostKeyVerification {
} }
/// S507 /// S507
pub(crate) fn ssh_no_host_key_verification(checker: &mut Checker, call: &ExprCall) { pub(crate) fn ssh_no_host_key_verification(checker: &Checker, call: &ExprCall) {
let Expr::Attribute(ExprAttribute { attr, value, .. }) = call.func.as_ref() else { let Expr::Attribute(ExprAttribute { attr, value, .. }) = call.func.as_ref() else {
return; return;
}; };
@ -78,7 +78,7 @@ pub(crate) fn ssh_no_host_key_verification(checker: &mut Checker, call: &ExprCal
["paramiko", "client", "SSHClient"] | ["paramiko", "SSHClient"] ["paramiko", "client", "SSHClient"] | ["paramiko", "SSHClient"]
) )
}) { }) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
SSHNoHostKeyVerification, SSHNoHostKeyVerification,
policy_argument.range(), policy_argument.range(),
)); ));

View file

@ -48,7 +48,7 @@ impl Violation for SslInsecureVersion {
} }
/// S502 /// S502
pub(crate) fn ssl_insecure_version(checker: &mut Checker, call: &ExprCall) { pub(crate) fn ssl_insecure_version(checker: &Checker, call: &ExprCall) {
let Some(keyword) = checker let Some(keyword) = checker
.semantic() .semantic()
.resolve_qualified_name(call.func.as_ref()) .resolve_qualified_name(call.func.as_ref())
@ -68,7 +68,7 @@ pub(crate) fn ssl_insecure_version(checker: &mut Checker, call: &ExprCall) {
match &keyword.value { match &keyword.value {
Expr::Name(ast::ExprName { id, .. }) => { Expr::Name(ast::ExprName { id, .. }) => {
if is_insecure_protocol(id) { if is_insecure_protocol(id) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
SslInsecureVersion { SslInsecureVersion {
protocol: id.to_string(), protocol: id.to_string(),
}, },
@ -78,7 +78,7 @@ pub(crate) fn ssl_insecure_version(checker: &mut Checker, call: &ExprCall) {
} }
Expr::Attribute(ast::ExprAttribute { attr, .. }) => { Expr::Attribute(ast::ExprAttribute { attr, .. }) => {
if is_insecure_protocol(attr) { if is_insecure_protocol(attr) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
SslInsecureVersion { SslInsecureVersion {
protocol: attr.to_string(), protocol: attr.to_string(),
}, },

View file

@ -48,7 +48,7 @@ impl Violation for SslWithBadDefaults {
} }
/// S503 /// S503
pub(crate) fn ssl_with_bad_defaults(checker: &mut Checker, function_def: &StmtFunctionDef) { pub(crate) fn ssl_with_bad_defaults(checker: &Checker, function_def: &StmtFunctionDef) {
for default in function_def for default in function_def
.parameters .parameters
.iter_non_variadic_params() .iter_non_variadic_params()
@ -57,7 +57,7 @@ pub(crate) fn ssl_with_bad_defaults(checker: &mut Checker, function_def: &StmtFu
match default { match default {
Expr::Name(ast::ExprName { id, range, .. }) => { Expr::Name(ast::ExprName { id, range, .. }) => {
if is_insecure_protocol(id.as_str()) { if is_insecure_protocol(id.as_str()) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
SslWithBadDefaults { SslWithBadDefaults {
protocol: id.to_string(), protocol: id.to_string(),
}, },
@ -67,7 +67,7 @@ pub(crate) fn ssl_with_bad_defaults(checker: &mut Checker, function_def: &StmtFu
} }
Expr::Attribute(ast::ExprAttribute { attr, range, .. }) => { Expr::Attribute(ast::ExprAttribute { attr, range, .. }) => {
if is_insecure_protocol(attr.as_str()) { if is_insecure_protocol(attr.as_str()) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
SslWithBadDefaults { SslWithBadDefaults {
protocol: attr.to_string(), protocol: attr.to_string(),
}, },

View file

@ -36,16 +36,14 @@ impl Violation for SslWithNoVersion {
} }
/// S504 /// S504
pub(crate) fn ssl_with_no_version(checker: &mut Checker, call: &ExprCall) { pub(crate) fn ssl_with_no_version(checker: &Checker, call: &ExprCall) {
if checker if checker
.semantic() .semantic()
.resolve_qualified_name(call.func.as_ref()) .resolve_qualified_name(call.func.as_ref())
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["ssl", "wrap_socket"])) .is_some_and(|qualified_name| matches!(qualified_name.segments(), ["ssl", "wrap_socket"]))
{ {
if call.arguments.find_keyword("ssl_version").is_none() { if call.arguments.find_keyword("ssl_version").is_none() {
checker checker.report_diagnostic(Diagnostic::new(SslWithNoVersion, call.range()));
.diagnostics
.push(Diagnostic::new(SslWithNoVersion, call.range()));
} }
} }
} }

View file

@ -908,7 +908,7 @@ impl Violation for SuspiciousFTPLibUsage {
} }
} }
pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) { pub(crate) fn suspicious_function_call(checker: &Checker, call: &ExprCall) {
suspicious_function( suspicious_function(
checker, checker,
call.func.as_ref(), call.func.as_ref(),
@ -917,7 +917,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
); );
} }
pub(crate) fn suspicious_function_reference(checker: &mut Checker, func: &Expr) { pub(crate) fn suspicious_function_reference(checker: &Checker, func: &Expr) {
if checker.settings.preview.is_disabled() { if checker.settings.preview.is_disabled() {
return; return;
} }
@ -953,7 +953,7 @@ pub(crate) fn suspicious_function_reference(checker: &mut Checker, func: &Expr)
/// S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323 /// S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323
fn suspicious_function( fn suspicious_function(
checker: &mut Checker, checker: &Checker,
func: &Expr, func: &Expr,
arguments: Option<&Arguments>, arguments: Option<&Arguments>,
range: TextRange, range: TextRange,
@ -1176,12 +1176,12 @@ fn suspicious_function(
let diagnostic = Diagnostic::new(diagnostic_kind, range); let diagnostic = Diagnostic::new(diagnostic_kind, range);
if checker.enabled(diagnostic.kind.rule()) { if checker.enabled(diagnostic.kind.rule()) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
/// S308 /// S308
pub(crate) fn suspicious_function_decorator(checker: &mut Checker, decorator: &Decorator) { pub(crate) fn suspicious_function_decorator(checker: &Checker, decorator: &Decorator) {
// In preview mode, references are handled collectively by `suspicious_function_reference` // In preview mode, references are handled collectively by `suspicious_function_reference`
if checker.settings.preview.is_disabled() { if checker.settings.preview.is_disabled() {
suspicious_function(checker, &decorator.expression, None, decorator.range); suspicious_function(checker, &decorator.expression, None, decorator.range);

View file

@ -351,7 +351,7 @@ impl Violation for SuspiciousPyghmiImport {
} }
/// S401, S402, S403, S404, S405, S406, S407, S408, S409, S410, S411, S412, S413, S415 /// S401, S402, S403, S404, S405, S406, S407, S408, S409, S410, S411, S412, S413, S415
pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { pub(crate) fn suspicious_imports(checker: &Checker, stmt: &Stmt) {
// Skip stub files. // Skip stub files.
if checker.source_type.is_stub() { if checker.source_type.is_stub() {
return; return;
@ -602,13 +602,9 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) {
}; };
} }
fn check_and_push_diagnostic( fn check_and_push_diagnostic(checker: &Checker, diagnostic_kind: DiagnosticKind, range: TextRange) {
checker: &mut Checker,
diagnostic_kind: DiagnosticKind,
range: TextRange,
) {
let diagnostic = Diagnostic::new::<DiagnosticKind>(diagnostic_kind, range); let diagnostic = Diagnostic::new::<DiagnosticKind>(diagnostic_kind, range);
if checker.enabled(diagnostic.kind.rule()) { if checker.enabled(diagnostic.kind.rule()) {
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }

View file

@ -48,7 +48,7 @@ impl Violation for TarfileUnsafeMembers {
} }
/// S202 /// S202
pub(crate) fn tarfile_unsafe_members(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn tarfile_unsafe_members(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::TARFILE) { if !checker.semantic().seen_module(Modules::TARFILE) {
return; return;
} }
@ -70,7 +70,5 @@ pub(crate) fn tarfile_unsafe_members(checker: &mut Checker, call: &ast::ExprCall
return; return;
} }
checker checker.report_diagnostic(Diagnostic::new(TarfileUnsafeMembers, call.func.range()));
.diagnostics
.push(Diagnostic::new(TarfileUnsafeMembers, call.func.range()));
} }

View file

@ -53,7 +53,7 @@ impl Violation for TryExceptContinue {
/// S112 /// S112
pub(crate) fn try_except_continue( pub(crate) fn try_except_continue(
checker: &mut Checker, checker: &Checker,
except_handler: &ExceptHandler, except_handler: &ExceptHandler,
type_: Option<&Expr>, type_: Option<&Expr>,
body: &[Stmt], body: &[Stmt],
@ -61,9 +61,7 @@ pub(crate) fn try_except_continue(
) { ) {
if matches!(body, [Stmt::Continue(_)]) { if matches!(body, [Stmt::Continue(_)]) {
if check_typed_exception || is_untyped_exception(type_, checker.semantic()) { if check_typed_exception || is_untyped_exception(type_, checker.semantic()) {
checker checker.report_diagnostic(Diagnostic::new(TryExceptContinue, except_handler.range()));
.diagnostics
.push(Diagnostic::new(TryExceptContinue, except_handler.range()));
} }
} }
} }

View file

@ -49,7 +49,7 @@ impl Violation for TryExceptPass {
/// S110 /// S110
pub(crate) fn try_except_pass( pub(crate) fn try_except_pass(
checker: &mut Checker, checker: &Checker,
except_handler: &ExceptHandler, except_handler: &ExceptHandler,
type_: Option<&Expr>, type_: Option<&Expr>,
body: &[Stmt], body: &[Stmt],
@ -57,9 +57,7 @@ pub(crate) fn try_except_pass(
) { ) {
if matches!(body, [Stmt::Pass(_)]) { if matches!(body, [Stmt::Pass(_)]) {
if check_typed_exception || is_untyped_exception(type_, checker.semantic()) { if check_typed_exception || is_untyped_exception(type_, checker.semantic()) {
checker checker.report_diagnostic(Diagnostic::new(TryExceptPass, except_handler.range()));
.diagnostics
.push(Diagnostic::new(TryExceptPass, except_handler.range()));
} }
} }
} }

View file

@ -59,7 +59,7 @@ impl Violation for UnsafeYAMLLoad {
} }
/// S506 /// S506
pub(crate) fn unsafe_yaml_load(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn unsafe_yaml_load(checker: &Checker, call: &ast::ExprCall) {
if checker if checker
.semantic() .semantic()
.resolve_qualified_name(&call.func) .resolve_qualified_name(&call.func)
@ -82,13 +82,13 @@ pub(crate) fn unsafe_yaml_load(checker: &mut Checker, call: &ast::ExprCall) {
Expr::Name(ast::ExprName { id, .. }) => Some(id.to_string()), Expr::Name(ast::ExprName { id, .. }) => Some(id.to_string()),
_ => None, _ => None,
}; };
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
UnsafeYAMLLoad { loader }, UnsafeYAMLLoad { loader },
loader_arg.range(), loader_arg.range(),
)); ));
} }
} else { } else {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
UnsafeYAMLLoad { loader: None }, UnsafeYAMLLoad { loader: None },
call.func.range(), call.func.range(),
)); ));

View file

@ -49,13 +49,13 @@ impl Violation for WeakCryptographicKey {
} }
/// S505 /// S505
pub(crate) fn weak_cryptographic_key(checker: &mut Checker, call: &ExprCall) { pub(crate) fn weak_cryptographic_key(checker: &Checker, call: &ExprCall) {
let Some((cryptographic_key, range)) = extract_cryptographic_key(checker, call) else { let Some((cryptographic_key, range)) = extract_cryptographic_key(checker, call) else {
return; return;
}; };
if cryptographic_key.is_vulnerable() { if cryptographic_key.is_vulnerable() {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
WeakCryptographicKey { cryptographic_key }, WeakCryptographicKey { cryptographic_key },
range, range,
)); ));
@ -98,7 +98,7 @@ impl Display for CryptographicKey {
} }
fn extract_cryptographic_key( fn extract_cryptographic_key(
checker: &mut Checker, checker: &Checker,
call: &ExprCall, call: &ExprCall,
) -> Option<(CryptographicKey, TextRange)> { ) -> Option<(CryptographicKey, TextRange)> {
let qualified_name = checker.semantic().resolve_qualified_name(&call.func)?; let qualified_name = checker.semantic().resolve_qualified_name(&call.func)?;

View file

@ -76,7 +76,7 @@ impl Violation for BlindExcept {
/// BLE001 /// BLE001
pub(crate) fn blind_except( pub(crate) fn blind_except(
checker: &mut Checker, checker: &Checker,
type_: Option<&Expr>, type_: Option<&Expr>,
name: Option<&str>, name: Option<&str>,
body: &[Stmt], body: &[Stmt],
@ -107,7 +107,7 @@ pub(crate) fn blind_except(
return; return;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
BlindExcept { BlindExcept {
name: builtin_exception_type.to_string(), name: builtin_exception_type.to_string(),
}, },

View file

@ -101,7 +101,7 @@ impl Violation for BooleanDefaultValuePositionalArgument {
/// FBT002 /// FBT002
pub(crate) fn boolean_default_value_positional_argument( pub(crate) fn boolean_default_value_positional_argument(
checker: &mut Checker, checker: &Checker,
name: &str, name: &str,
decorator_list: &[Decorator], decorator_list: &[Decorator],
parameters: &Parameters, parameters: &Parameters,
@ -131,7 +131,7 @@ pub(crate) fn boolean_default_value_positional_argument(
return; return;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
BooleanDefaultValuePositionalArgument, BooleanDefaultValuePositionalArgument,
param.identifier(), param.identifier(),
)); ));

View file

@ -51,7 +51,7 @@ impl Violation for BooleanPositionalValueInCall {
} }
} }
pub(crate) fn boolean_positional_value_in_call(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn boolean_positional_value_in_call(checker: &Checker, call: &ast::ExprCall) {
if allow_boolean_trap(call, checker) { if allow_boolean_trap(call, checker) {
return; return;
} }
@ -61,8 +61,6 @@ pub(crate) fn boolean_positional_value_in_call(checker: &mut Checker, call: &ast
.iter() .iter()
.filter(|arg| arg.is_boolean_literal_expr()) .filter(|arg| arg.is_boolean_literal_expr())
{ {
checker checker.report_diagnostic(Diagnostic::new(BooleanPositionalValueInCall, arg.range()));
.diagnostics
.push(Diagnostic::new(BooleanPositionalValueInCall, arg.range()));
} }
} }

View file

@ -110,7 +110,7 @@ impl Violation for BooleanTypeHintPositionalArgument {
/// FBT001 /// FBT001
pub(crate) fn boolean_type_hint_positional_argument( pub(crate) fn boolean_type_hint_positional_argument(
checker: &mut Checker, checker: &Checker,
name: &str, name: &str,
decorator_list: &[Decorator], decorator_list: &[Decorator],
parameters: &Parameters, parameters: &Parameters,
@ -157,7 +157,7 @@ pub(crate) fn boolean_type_hint_positional_argument(
return; return;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
BooleanTypeHintPositionalArgument, BooleanTypeHintPositionalArgument,
parameter.identifier(), parameter.identifier(),
)); ));

View file

@ -144,7 +144,7 @@ fn is_empty_body(body: &[Stmt]) -> bool {
/// B024 /// B024
/// B027 /// B027
pub(crate) fn abstract_base_class( pub(crate) fn abstract_base_class(
checker: &mut Checker, checker: &Checker,
stmt: &Stmt, stmt: &Stmt,
name: &str, name: &str,
arguments: Option<&Arguments>, arguments: Option<&Arguments>,
@ -196,7 +196,7 @@ pub(crate) fn abstract_base_class(
&& is_empty_body(body) && is_empty_body(body)
&& !is_overload(decorator_list, checker.semantic()) && !is_overload(decorator_list, checker.semantic())
{ {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
EmptyMethodWithoutAbstractDecorator { EmptyMethodWithoutAbstractDecorator {
name: format!("{name}.{method_name}"), name: format!("{name}.{method_name}"),
}, },
@ -206,7 +206,7 @@ pub(crate) fn abstract_base_class(
} }
if checker.enabled(Rule::AbstractBaseClassWithoutAbstractMethod) { if checker.enabled(Rule::AbstractBaseClassWithoutAbstractMethod) {
if !has_abstract_method { if !has_abstract_method {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
AbstractBaseClassWithoutAbstractMethod { AbstractBaseClassWithoutAbstractMethod {
name: name.to_string(), name: name.to_string(),
}, },

View file

@ -74,7 +74,7 @@ fn assertion_error(msg: Option<&Expr>) -> Stmt {
} }
/// B011 /// B011
pub(crate) fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) { pub(crate) fn assert_false(checker: &Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) {
if !is_const_false(test) { if !is_const_false(test) {
return; return;
} }
@ -84,5 +84,5 @@ pub(crate) fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg:
checker.generator().stmt(&assertion_error(msg)), checker.generator().stmt(&assertion_error(msg)),
stmt.range(), stmt.range(),
))); )));
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }

View file

@ -57,7 +57,7 @@ impl fmt::Display for ExceptionKind {
} }
/// B017 /// B017
pub(crate) fn assert_raises_exception(checker: &mut Checker, items: &[WithItem]) { pub(crate) fn assert_raises_exception(checker: &Checker, items: &[WithItem]) {
for item in items { for item in items {
let Expr::Call(ast::ExprCall { let Expr::Call(ast::ExprCall {
func, func,
@ -99,7 +99,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, items: &[WithItem])
continue; continue;
}; };
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
AssertRaisesException { exception }, AssertRaisesException { exception },
item.range(), item.range(),
)); ));

View file

@ -50,7 +50,7 @@ impl Violation for AssignmentToOsEnviron {
} }
/// B003 /// B003
pub(crate) fn assignment_to_os_environ(checker: &mut Checker, targets: &[Expr]) { pub(crate) fn assignment_to_os_environ(checker: &Checker, targets: &[Expr]) {
let [target] = targets else { let [target] = targets else {
return; return;
}; };
@ -66,7 +66,5 @@ pub(crate) fn assignment_to_os_environ(checker: &mut Checker, targets: &[Expr])
if id != "os" { if id != "os" {
return; return;
} }
checker checker.report_diagnostic(Diagnostic::new(AssignmentToOsEnviron, target.range()));
.diagnostics
.push(Diagnostic::new(AssignmentToOsEnviron, target.range()));
} }

View file

@ -58,7 +58,7 @@ impl Violation for BatchedWithoutExplicitStrict {
} }
/// B911 /// B911
pub(crate) fn batched_without_explicit_strict(checker: &mut Checker, call: &ExprCall) { pub(crate) fn batched_without_explicit_strict(checker: &Checker, call: &ExprCall) {
if checker.settings.target_version < PythonVersion::Py313 { if checker.settings.target_version < PythonVersion::Py313 {
return; return;
} }
@ -87,5 +87,5 @@ pub(crate) fn batched_without_explicit_strict(checker: &mut Checker, call: &Expr
} }
let diagnostic = Diagnostic::new(BatchedWithoutExplicitStrict, call.range); let diagnostic = Diagnostic::new(BatchedWithoutExplicitStrict, call.range);
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }

View file

@ -74,7 +74,7 @@ impl Violation for CachedInstanceMethod {
} }
/// B019 /// B019
pub(crate) fn cached_instance_method(checker: &mut Checker, function_def: &ast::StmtFunctionDef) { pub(crate) fn cached_instance_method(checker: &Checker, function_def: &ast::StmtFunctionDef) {
let scope = checker.semantic().current_scope(); let scope = checker.semantic().current_scope();
// Parent scope _must_ be a class. // Parent scope _must_ be a class.
@ -102,9 +102,7 @@ pub(crate) fn cached_instance_method(checker: &mut Checker, function_def: &ast::
return; return;
} }
checker checker.report_diagnostic(Diagnostic::new(CachedInstanceMethod, decorator.range()));
.diagnostics
.push(Diagnostic::new(CachedInstanceMethod, decorator.range()));
} }
} }
} }

View file

@ -44,7 +44,7 @@ impl Violation for ClassAsDataStructure {
} }
/// B903 /// B903
pub(crate) fn class_as_data_structure(checker: &mut Checker, class_def: &ast::StmtClassDef) { pub(crate) fn class_as_data_structure(checker: &Checker, class_def: &ast::StmtClassDef) {
// skip stub files // skip stub files
if checker.source_type.is_stub() { if checker.source_type.is_stub() {
return; return;
@ -105,9 +105,7 @@ pub(crate) fn class_as_data_structure(checker: &mut Checker, class_def: &ast::St
} }
if has_dunder_init && public_methods == 1 { if has_dunder_init && public_methods == 1 {
checker checker.report_diagnostic(Diagnostic::new(ClassAsDataStructure, class_def.range()));
.diagnostics
.push(Diagnostic::new(ClassAsDataStructure, class_def.range()));
} }
} }

View file

@ -120,7 +120,7 @@ fn type_pattern(elts: Vec<&Expr>) -> Expr {
/// B014 /// B014
fn duplicate_handler_exceptions<'a>( fn duplicate_handler_exceptions<'a>(
checker: &mut Checker, checker: &Checker,
expr: &'a Expr, expr: &'a Expr,
elts: &'a [Expr], elts: &'a [Expr],
) -> FxHashMap<UnqualifiedName<'a>, &'a Expr> { ) -> FxHashMap<UnqualifiedName<'a>, &'a Expr> {
@ -167,7 +167,7 @@ fn duplicate_handler_exceptions<'a>(
}, },
expr.range(), expr.range(),
))); )));
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
@ -175,7 +175,7 @@ fn duplicate_handler_exceptions<'a>(
} }
/// B025 /// B025
pub(crate) fn duplicate_exceptions(checker: &mut Checker, handlers: &[ExceptHandler]) { pub(crate) fn duplicate_exceptions(checker: &Checker, handlers: &[ExceptHandler]) {
let mut seen: FxHashSet<UnqualifiedName> = FxHashSet::default(); let mut seen: FxHashSet<UnqualifiedName> = FxHashSet::default();
let mut duplicates: FxHashMap<UnqualifiedName, Vec<&Expr>> = FxHashMap::default(); let mut duplicates: FxHashMap<UnqualifiedName, Vec<&Expr>> = FxHashMap::default();
for handler in handlers { for handler in handlers {
@ -217,7 +217,7 @@ pub(crate) fn duplicate_exceptions(checker: &mut Checker, handlers: &[ExceptHand
.current_statement() .current_statement()
.as_try_stmt() .as_try_stmt()
.is_some_and(|try_stmt| try_stmt.is_star); .is_some_and(|try_stmt| try_stmt.is_star);
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
DuplicateTryBlockException { DuplicateTryBlockException {
name: name.segments().join("."), name: name.segments().join("."),
is_star, is_star,

View file

@ -55,7 +55,7 @@ impl Violation for DuplicateValue {
} }
/// B033 /// B033
pub(crate) fn duplicate_value(checker: &mut Checker, set: &ast::ExprSet) { pub(crate) fn duplicate_value(checker: &Checker, set: &ast::ExprSet) {
let mut seen_values: FxHashMap<HashableExpr, &Expr> = FxHashMap::default(); let mut seen_values: FxHashMap<HashableExpr, &Expr> = FxHashMap::default();
for (index, value) in set.iter().enumerate() { for (index, value) in set.iter().enumerate() {
if value.is_literal_expr() { if value.is_literal_expr() {
@ -72,7 +72,7 @@ pub(crate) fn duplicate_value(checker: &mut Checker, set: &ast::ExprSet) {
remove_member(set, index, checker.locator().contents()).map(Fix::safe_edit) remove_member(set, index, checker.locator().contents()).map(Fix::safe_edit)
}); });
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
}; };
} }

View file

@ -50,7 +50,7 @@ impl Violation for ExceptWithEmptyTuple {
} }
/// B029 /// B029
pub(crate) fn except_with_empty_tuple(checker: &mut Checker, except_handler: &ExceptHandler) { pub(crate) fn except_with_empty_tuple(checker: &Checker, except_handler: &ExceptHandler) {
let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { type_, .. }) = let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { type_, .. }) =
except_handler; except_handler;
let Some(type_) = type_ else { let Some(type_) = type_ else {
@ -66,7 +66,7 @@ pub(crate) fn except_with_empty_tuple(checker: &mut Checker, except_handler: &Ex
.current_statement() .current_statement()
.as_try_stmt() .as_try_stmt()
.is_some_and(|try_stmt| try_stmt.is_star); .is_some_and(|try_stmt| try_stmt.is_star);
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
ExceptWithEmptyTuple { is_star }, ExceptWithEmptyTuple { is_star },
except_handler.range(), except_handler.range(),
)); ));

View file

@ -53,10 +53,7 @@ impl Violation for ExceptWithNonExceptionClasses {
} }
/// B030 /// B030
pub(crate) fn except_with_non_exception_classes( pub(crate) fn except_with_non_exception_classes(checker: &Checker, except_handler: &ExceptHandler) {
checker: &mut Checker,
except_handler: &ExceptHandler,
) {
let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { type_, .. }) = let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { type_, .. }) =
except_handler; except_handler;
let Some(type_) = type_ else { let Some(type_) = type_ else {
@ -72,7 +69,7 @@ pub(crate) fn except_with_non_exception_classes(
.current_statement() .current_statement()
.as_try_stmt() .as_try_stmt()
.is_some_and(|try_stmt| try_stmt.is_star); .is_some_and(|try_stmt| try_stmt.is_star);
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
ExceptWithNonExceptionClasses { is_star }, ExceptWithNonExceptionClasses { is_star },
expr.range(), expr.range(),
)); ));

View file

@ -41,7 +41,7 @@ impl Violation for FStringDocstring {
} }
/// B021 /// B021
pub(crate) fn f_string_docstring(checker: &mut Checker, body: &[Stmt]) { pub(crate) fn f_string_docstring(checker: &Checker, body: &[Stmt]) {
let Some(stmt) = body.first() else { let Some(stmt) = body.first() else {
return; return;
}; };
@ -51,7 +51,5 @@ pub(crate) fn f_string_docstring(checker: &mut Checker, body: &[Stmt]) {
if !value.is_f_string_expr() { if !value.is_f_string_expr() {
return; return;
} }
checker checker.report_diagnostic(Diagnostic::new(FStringDocstring, stmt.identifier()));
.diagnostics
.push(Diagnostic::new(FStringDocstring, stmt.identifier()));
} }

View file

@ -128,7 +128,7 @@ impl Visitor<'_> for ArgumentDefaultVisitor<'_, '_> {
} }
/// B008 /// B008
pub(crate) fn function_call_in_argument_default(checker: &mut Checker, parameters: &Parameters) { pub(crate) fn function_call_in_argument_default(checker: &Checker, parameters: &Parameters) {
// Map immutable calls to (module, member) format. // Map immutable calls to (module, member) format.
let extend_immutable_calls: Vec<QualifiedName> = checker let extend_immutable_calls: Vec<QualifiedName> = checker
.settings .settings
@ -150,6 +150,6 @@ pub(crate) fn function_call_in_argument_default(checker: &mut Checker, parameter
} }
for (check, range) in visitor.diagnostics { for (check, range) in visitor.diagnostics {
checker.diagnostics.push(Diagnostic::new(check, range)); checker.report_diagnostic(Diagnostic::new(check, range));
} }
} }

View file

@ -277,7 +277,7 @@ impl<'a> Visitor<'a> for AssignedNamesVisitor<'a> {
} }
/// B023 /// B023
pub(crate) fn function_uses_loop_variable(checker: &mut Checker, node: &Node) { pub(crate) fn function_uses_loop_variable(checker: &Checker, node: &Node) {
// Identify any "suspicious" variables. These are defined as variables that are // Identify any "suspicious" variables. These are defined as variables that are
// referenced in a function or lambda body, but aren't bound as arguments. // referenced in a function or lambda body, but aren't bound as arguments.
let suspicious_variables = { let suspicious_variables = {
@ -304,9 +304,8 @@ pub(crate) fn function_uses_loop_variable(checker: &mut Checker, node: &Node) {
// loop, flag it. // loop, flag it.
for name in suspicious_variables { for name in suspicious_variables {
if reassigned_in_loop.contains(&name.id.as_str()) { if reassigned_in_loop.contains(&name.id.as_str()) {
if !checker.flake8_bugbear_seen.contains(&name.range()) { if checker.insert_flake8_bugbear_range(name.range()) {
checker.flake8_bugbear_seen.push(name.range()); checker.report_diagnostic(Diagnostic::new(
checker.diagnostics.push(Diagnostic::new(
FunctionUsesLoopVariable { FunctionUsesLoopVariable {
name: name.id.to_string(), name: name.id.to_string(),
}, },

View file

@ -48,12 +48,7 @@ impl AlwaysFixableViolation for GetAttrWithConstant {
} }
/// B009 /// B009
pub(crate) fn getattr_with_constant( pub(crate) fn getattr_with_constant(checker: &Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
checker: &mut Checker,
expr: &Expr,
func: &Expr,
args: &[Expr],
) {
let [obj, arg] = args else { let [obj, arg] = args else {
return; return;
}; };
@ -93,5 +88,5 @@ pub(crate) fn getattr_with_constant(
), ),
expr.range(), expr.range(),
))); )));
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }

View file

@ -53,10 +53,10 @@ impl Violation for JumpStatementInFinally {
} }
} }
fn walk_stmt(checker: &mut Checker, body: &[Stmt], f: fn(&Stmt) -> bool) { fn walk_stmt(checker: &Checker, body: &[Stmt], f: fn(&Stmt) -> bool) {
for stmt in body { for stmt in body {
if f(stmt) { if f(stmt) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
JumpStatementInFinally { JumpStatementInFinally {
name: match stmt { name: match stmt {
Stmt::Break(_) => "break", Stmt::Break(_) => "break",
@ -89,7 +89,7 @@ fn walk_stmt(checker: &mut Checker, body: &[Stmt], f: fn(&Stmt) -> bool) {
} }
/// B012 /// B012
pub(crate) fn jump_statement_in_finally(checker: &mut Checker, finalbody: &[Stmt]) { pub(crate) fn jump_statement_in_finally(checker: &Checker, finalbody: &[Stmt]) {
walk_stmt(checker, finalbody, |stmt| { walk_stmt(checker, finalbody, |stmt| {
matches!(stmt, Stmt::Break(_) | Stmt::Continue(_) | Stmt::Return(_)) matches!(stmt, Stmt::Break(_) | Stmt::Continue(_) | Stmt::Return(_))
}); });

View file

@ -53,7 +53,7 @@ impl Violation for LoopIteratorMutation {
} }
/// B909 /// B909
pub(crate) fn loop_iterator_mutation(checker: &mut Checker, stmt_for: &StmtFor) { pub(crate) fn loop_iterator_mutation(checker: &Checker, stmt_for: &StmtFor) {
let StmtFor { let StmtFor {
target, target,
iter, iter,
@ -110,9 +110,7 @@ pub(crate) fn loop_iterator_mutation(checker: &mut Checker, stmt_for: &StmtFor)
let name = UnqualifiedName::from_expr(iter) let name = UnqualifiedName::from_expr(iter)
.map(|name| name.to_string()) .map(|name| name.to_string())
.map(SourceCodeSnippet::new); .map(SourceCodeSnippet::new);
checker checker.report_diagnostic(Diagnostic::new(LoopIteratorMutation { name }, *mutation));
.diagnostics
.push(Diagnostic::new(LoopIteratorMutation { name }, *mutation));
} }
} }

View file

@ -50,7 +50,7 @@ impl Violation for LoopVariableOverridesIterator {
} }
/// B020 /// B020
pub(crate) fn loop_variable_overrides_iterator(checker: &mut Checker, target: &Expr, iter: &Expr) { pub(crate) fn loop_variable_overrides_iterator(checker: &Checker, target: &Expr, iter: &Expr) {
let target_names = { let target_names = {
let mut target_finder = NameFinder::default(); let mut target_finder = NameFinder::default();
target_finder.visit_expr(target); target_finder.visit_expr(target);
@ -64,7 +64,7 @@ pub(crate) fn loop_variable_overrides_iterator(checker: &mut Checker, target: &E
for (name, expr) in target_names { for (name, expr) in target_names {
if iter_names.contains_key(name) { if iter_names.contains_key(name) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
LoopVariableOverridesIterator { LoopVariableOverridesIterator {
name: name.to_string(), name: name.to_string(),
}, },

View file

@ -85,7 +85,7 @@ impl Violation for MutableArgumentDefault {
} }
/// B006 /// B006
pub(crate) fn mutable_argument_default(checker: &mut Checker, function_def: &ast::StmtFunctionDef) { pub(crate) fn mutable_argument_default(checker: &Checker, function_def: &ast::StmtFunctionDef) {
// Skip stub files // Skip stub files
if checker.source_type.is_stub() { if checker.source_type.is_stub() {
return; return;
@ -124,7 +124,7 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, function_def: &ast
) { ) {
diagnostic.set_fix(fix); diagnostic.set_fix(fix);
} }
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }

View file

@ -68,7 +68,7 @@ impl Violation for MutableContextvarDefault {
} }
/// B039 /// B039
pub(crate) fn mutable_contextvar_default(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn mutable_contextvar_default(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::CONTEXTVARS) { if !checker.semantic().seen_module(Modules::CONTEXTVARS) {
return; return;
} }
@ -102,8 +102,6 @@ pub(crate) fn mutable_contextvar_default(checker: &mut Checker, call: &ast::Expr
matches!(qualified_name.segments(), ["contextvars", "ContextVar"]) matches!(qualified_name.segments(), ["contextvars", "ContextVar"])
}) })
{ {
checker checker.report_diagnostic(Diagnostic::new(MutableContextvarDefault, default.range()));
.diagnostics
.push(Diagnostic::new(MutableContextvarDefault, default.range()));
} }
} }

View file

@ -51,7 +51,7 @@ impl AlwaysFixableViolation for NoExplicitStacklevel {
} }
/// B028 /// B028
pub(crate) fn no_explicit_stacklevel(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn no_explicit_stacklevel(checker: &Checker, call: &ast::ExprCall) {
if !checker if !checker
.semantic() .semantic()
.resolve_qualified_name(&call.func) .resolve_qualified_name(&call.func)
@ -88,5 +88,5 @@ pub(crate) fn no_explicit_stacklevel(checker: &mut Checker, call: &ast::ExprCall
diagnostic.set_fix(Fix::unsafe_edit(edit)); diagnostic.set_fix(Fix::unsafe_edit(edit));
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }

View file

@ -37,10 +37,8 @@ impl Violation for RaiseLiteral {
} }
/// B016 /// B016
pub(crate) fn raise_literal(checker: &mut Checker, expr: &Expr) { pub(crate) fn raise_literal(checker: &Checker, expr: &Expr) {
if expr.is_literal_expr() { if expr.is_literal_expr() {
checker checker.report_diagnostic(Diagnostic::new(RaiseLiteral, expr.range()));
.diagnostics
.push(Diagnostic::new(RaiseLiteral, expr.range()));
} }
} }

View file

@ -68,7 +68,7 @@ impl Violation for RaiseWithoutFromInsideExcept {
/// B904 /// B904
pub(crate) fn raise_without_from_inside_except( pub(crate) fn raise_without_from_inside_except(
checker: &mut Checker, checker: &Checker,
name: Option<&str>, name: Option<&str>,
body: &[Stmt], body: &[Stmt],
) { ) {
@ -106,7 +106,7 @@ pub(crate) fn raise_without_from_inside_except(
.as_try_stmt() .as_try_stmt()
.is_some_and(|try_stmt| try_stmt.is_star); .is_some_and(|try_stmt| try_stmt.is_star);
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
RaiseWithoutFromInsideExcept { is_star }, RaiseWithoutFromInsideExcept { is_star },
range, range,
)); ));

View file

@ -56,7 +56,7 @@ impl Violation for ReSubPositionalArgs {
} }
/// B034 /// B034
pub(crate) fn re_sub_positional_args(checker: &mut Checker, call: &ast::ExprCall) { pub(crate) fn re_sub_positional_args(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::RE) { if !checker.semantic().seen_module(Modules::RE) {
return; return;
} }
@ -75,7 +75,7 @@ pub(crate) fn re_sub_positional_args(checker: &mut Checker, call: &ast::ExprCall
}; };
if call.arguments.args.len() > method.num_args() { if call.arguments.args.len() > method.num_args() {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
ReSubPositionalArgs { method }, ReSubPositionalArgs { method },
call.range(), call.range(),
)); ));

View file

@ -53,10 +53,7 @@ impl AlwaysFixableViolation for RedundantTupleInExceptionHandler {
} }
/// B013 /// B013
pub(crate) fn redundant_tuple_in_exception_handler( pub(crate) fn redundant_tuple_in_exception_handler(checker: &Checker, handlers: &[ExceptHandler]) {
checker: &mut Checker,
handlers: &[ExceptHandler],
) {
for handler in handlers { for handler in handlers {
let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
type_: Some(type_), type_: Some(type_),
@ -103,6 +100,6 @@ pub(crate) fn redundant_tuple_in_exception_handler(
), ),
type_.range(), type_.range(),
))); )));
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }

View file

@ -91,7 +91,7 @@ impl Violation for ReturnInGenerator {
} }
/// B901 /// B901
pub(crate) fn return_in_generator(checker: &mut Checker, function_def: &StmtFunctionDef) { pub(crate) fn return_in_generator(checker: &Checker, function_def: &StmtFunctionDef) {
if function_def.name.id == "__await__" { if function_def.name.id == "__await__" {
return; return;
} }
@ -101,9 +101,7 @@ pub(crate) fn return_in_generator(checker: &mut Checker, function_def: &StmtFunc
if visitor.has_yield { if visitor.has_yield {
if let Some(return_) = visitor.return_ { if let Some(return_) = visitor.return_ {
checker checker.report_diagnostic(Diagnostic::new(ReturnInGenerator, return_));
.diagnostics
.push(Diagnostic::new(ReturnInGenerator, return_));
} }
} }
} }

View file

@ -307,7 +307,7 @@ impl<'a> Visitor<'a> for GroupNameFinder<'a> {
/// B031 /// B031
pub(crate) fn reuse_of_groupby_generator( pub(crate) fn reuse_of_groupby_generator(
checker: &mut Checker, checker: &Checker,
target: &Expr, target: &Expr,
body: &[Stmt], body: &[Stmt],
iter: &Expr, iter: &Expr,
@ -339,8 +339,6 @@ pub(crate) fn reuse_of_groupby_generator(
finder.visit_stmt(stmt); finder.visit_stmt(stmt);
} }
for expr in finder.exprs { for expr in finder.exprs {
checker checker.report_diagnostic(Diagnostic::new(ReuseOfGroupbyGenerator, expr.range()));
.diagnostics
.push(Diagnostic::new(ReuseOfGroupbyGenerator, expr.range()));
} }
} }

View file

@ -61,12 +61,7 @@ fn assignment(obj: &Expr, name: &str, value: &Expr, generator: Generator) -> Str
} }
/// B010 /// B010
pub(crate) fn setattr_with_constant( pub(crate) fn setattr_with_constant(checker: &Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
checker: &mut Checker,
expr: &Expr,
func: &Expr,
args: &[Expr],
) {
let [obj, name, value] = args else { let [obj, name, value] = args else {
return; return;
}; };
@ -100,7 +95,7 @@ pub(crate) fn setattr_with_constant(
assignment(obj, name.to_str(), value, checker.generator()), assignment(obj, name.to_str(), value, checker.generator()),
expr.range(), expr.range(),
))); )));
checker.diagnostics.push(diagnostic); checker.report_diagnostic(diagnostic);
} }
} }
} }

View file

@ -57,7 +57,7 @@ impl Violation for StarArgUnpackingAfterKeywordArg {
/// B026 /// B026
pub(crate) fn star_arg_unpacking_after_keyword_arg( pub(crate) fn star_arg_unpacking_after_keyword_arg(
checker: &mut Checker, checker: &Checker,
args: &[Expr], args: &[Expr],
keywords: &[Keyword], keywords: &[Keyword],
) { ) {
@ -71,7 +71,7 @@ pub(crate) fn star_arg_unpacking_after_keyword_arg(
if arg.start() <= keyword.start() { if arg.start() <= keyword.start() {
continue; continue;
} }
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
StarArgUnpackingAfterKeywordArg, StarArgUnpackingAfterKeywordArg,
arg.range(), arg.range(),
)); ));

View file

@ -47,7 +47,7 @@ impl Violation for StaticKeyDictComprehension {
} }
/// RUF011 /// RUF011
pub(crate) fn static_key_dict_comprehension(checker: &mut Checker, dict_comp: &ast::ExprDictComp) { pub(crate) fn static_key_dict_comprehension(checker: &Checker, dict_comp: &ast::ExprDictComp) {
// Collect the bound names in the comprehension's generators. // Collect the bound names in the comprehension's generators.
let names = { let names = {
let mut visitor = StoredNameFinder::default(); let mut visitor = StoredNameFinder::default();
@ -58,7 +58,7 @@ pub(crate) fn static_key_dict_comprehension(checker: &mut Checker, dict_comp: &a
}; };
if is_constant(&dict_comp.key, &names) { if is_constant(&dict_comp.key, &names) {
checker.diagnostics.push(Diagnostic::new( checker.report_diagnostic(Diagnostic::new(
StaticKeyDictComprehension { StaticKeyDictComprehension {
key: SourceCodeSnippet::from_str(checker.locator().slice(dict_comp.key.as_ref())), key: SourceCodeSnippet::from_str(checker.locator().slice(dict_comp.key.as_ref())),
}, },

Some files were not shown because too many files have changed in this diff Show more