Add missing rule code comments (#18906)

<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

While making some of my other changes, I noticed some of the lints were
missing comments with their lint code/had the wrong numbered lint code.
These comments are super useful since they allow for very easily and
quickly finding the source code of a lint, so I decided to try and
normalize them.

Most of them were fairly straightforward, just adding a doc
comment/comment in the appropriate place.

I decided to make all of the `Pylint` rules have the `PL` prefix.
Previously it was split between no prefix and having prefix, but I
decided to normalize to with prefix since that's what's in the docs, and
the with prefix will show up on no prefix searches, while the reverse is
not true.

I also ran into a lot of rules with implementations in "non-standard"
places (where "standard" means inside a file matching the glob
`crates/ruff_linter/rules/*/rules/**/*.rs` and/or the same rule file
where the rule `struct`/`ViolationMetadata` is defined).

I decided to move all the implementations out of
`crates/ruff_linter/src/checkers/ast/analyze/deferred_scopes.rs` and
into their own files, since that is what the rest of the rules in
`deferred_scopes.rs` did, and those were just the outliers.

There were several rules which I did not end up moving, which you can
see as the extra paths I had to add to my python code besides the
"standard" glob. These rules are generally the error-type rules that
just wrap an error from the parser, and have very small
implementations/are very tightly linked to the module they are in, and
generally every rule of that type was implemented in module instead of
in the "standard" place.

Resolving that requires answering a question I don't think I'm equipped
to handle: Is the point of these comments to give quick access to the
rule definition/docs, or the rule implementation? For all the rules with
implementations in the "standard" location this isn't a problem, as they
are the same, but it is an issue for all of these error type rules. In
the end I chose to leave the implementations where they were, but I'm
not sure if that was the right choice.

<details>
<summary>Python script I wrote to find missing comments</summary>

This script assumes it is placed in the top level `ruff` directory (ie
next to `.git`/`crates`/`README.md`)

```py
import re
from copy import copy
from pathlib import Path

linter_to_code_prefix = {
    "Airflow": "AIR",
    "Eradicate": "ERA",
    "FastApi": "FAST",
    "Flake82020": "YTT",
    "Flake8Annotations": "ANN",
    "Flake8Async": "ASYNC",
    "Flake8Bandit": "S",
    "Flake8BlindExcept": "BLE",
    "Flake8BooleanTrap": "FBT",
    "Flake8Bugbear": "B",
    "Flake8Builtins": "A",
    "Flake8Commas": "COM",
    "Flake8Comprehensions": "C4",
    "Flake8Copyright": "CPY",
    "Flake8Datetimez": "DTZ",
    "Flake8Debugger": "T10",
    "Flake8Django": "DJ",
    "Flake8ErrMsg": "EM",
    "Flake8Executable": "EXE",
    "Flake8Fixme": "FIX",
    "Flake8FutureAnnotations": "FA",
    "Flake8GetText": "INT",
    "Flake8ImplicitStrConcat": "ISC",
    "Flake8ImportConventions": "ICN",
    "Flake8Logging": "LOG",
    "Flake8LoggingFormat": "G",
    "Flake8NoPep420": "INP",
    "Flake8Pie": "PIE",
    "Flake8Print": "T20",
    "Flake8Pyi": "PYI",
    "Flake8PytestStyle": "PT",
    "Flake8Quotes": "Q",
    "Flake8Raise": "RSE",
    "Flake8Return": "RET",
    "Flake8Self": "SLF",
    "Flake8Simplify": "SIM",
    "Flake8Slots": "SLOT",
    "Flake8TidyImports": "TID",
    "Flake8Todos": "TD",
    "Flake8TypeChecking": "TC",
    "Flake8UnusedArguments": "ARG",
    "Flake8UsePathlib": "PTH",
    "Flynt": "FLY",
    "Isort": "I",
    "McCabe": "C90",
    "Numpy": "NPY",
    "PandasVet": "PD",
    "PEP8Naming": "N",
    "Perflint": "PERF",
    "Pycodestyle": "",
    "Pydoclint": "DOC",
    "Pydocstyle": "D",
    "Pyflakes": "F",
    "PygrepHooks": "PGH",
    "Pylint": "PL",
    "Pyupgrade": "UP",
    "Refurb": "FURB",
    "Ruff": "RUF",
    "Tryceratops": "TRY",
}

ruff = Path(__file__).parent / "crates"

ruff_linter = ruff / "ruff_linter" / "src"

code_to_rule_name = {}

with open(ruff_linter / "codes.rs") as codes_file:
    for linter, code, rule_name in re.findall(
        # The (?<! skips ruff test rules
        # Only Preview|Stable rules are checked
        r"(?<!#\[cfg\(any\(feature = \"test-rules\", test\)\)\]\n)        \((\w+), \"(\w+)\"\) => \(RuleGroup::(?:Preview|Stable), [\w:]+::(\w+)\)",
        codes_file.read(),
    ):
        code_to_rule_name[linter_to_code_prefix[linter] + code] = (rule_name, [])

ruff_linter_rules = ruff_linter / "rules"
for rule_file_path in [
    *ruff_linter_rules.rglob("*/rules/**/*.rs"),
    ruff / "ruff_python_parser" / "src" / "semantic_errors.rs",
    ruff_linter / "pyproject_toml.rs",
    ruff_linter / "checkers" / "noqa.rs",
    ruff_linter / "checkers" / "ast" / "mod.rs",
    ruff_linter / "checkers" / "ast" / "analyze" / "unresolved_references.rs",
    ruff_linter / "checkers" / "ast" / "analyze" / "expression.rs",
    ruff_linter / "checkers" / "ast" / "analyze" / "statement.rs",
]:
    with open(rule_file_path, encoding="utf-8") as f:
        rule_file_content = f.read()
    for code, (rule, _) in copy(code_to_rule_name).items():
        if rule in rule_file_content:
            if f"// {code}" in rule_file_content or f", {code}" in rule_file_content:
                del code_to_rule_name[code]
            else:
                code_to_rule_name[code][1].append(rule_file_path)

for code, rule in code_to_rule_name.items():
    print(code, rule[0])
    for path in rule[1]:
        print(path)
```

</details>

## Test Plan

<!-- How was it tested? -->

N/A, no tests/functionality affected.
This commit is contained in:
GiGaGon 2025-06-24 18:18:57 -07:00 committed by GitHub
parent 62975b3ab2
commit 90f47e9b7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 66 additions and 15 deletions

View file

@ -93,6 +93,7 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
pyflakes::rules::undefined_local(checker, scope_id, scope);
}
// PLW0602
if checker.is_rule_enabled(Rule::GlobalVariableNotAssigned) {
for (name, binding_id) in scope.bindings() {
let binding = checker.semantic.binding(binding_id);
@ -123,6 +124,7 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
}
}
// PLR1704
if checker.is_rule_enabled(Rule::RedefinedArgumentFromLocal) {
for (name, binding_id) in scope.bindings() {
for shadow in checker.semantic.shadowed_bindings(scope_id, binding_id) {
@ -156,6 +158,7 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
}
}
// F402
if checker.is_rule_enabled(Rule::ImportShadowedByLoopVar) {
for (name, binding_id) in scope.bindings() {
for shadow in checker.semantic.shadowed_bindings(scope_id, binding_id) {
@ -197,6 +200,7 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
}
}
// F811
if checker.is_rule_enabled(Rule::RedefinedWhileUnused) {
// Index the redefined bindings by statement.
let mut redefinitions = FxHashMap::default();

View file

@ -539,6 +539,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
let location = expr.range();
match pyflakes::format::FormatSummary::try_from(string_value.to_str()) {
Err(e) => {
// F521
if checker.is_rule_enabled(Rule::StringDotFormatInvalidFormat) {
checker.report_diagnostic(
pyflakes::rules::StringDotFormatInvalidFormat {
@ -1315,6 +1316,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
typ: CFormatErrorType::UnsupportedFormatChar(c),
..
}) => {
// F509
if checker
.is_rule_enabled(Rule::PercentFormatUnsupportedFormatCharacter)
{
@ -1327,6 +1329,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
}
}
Err(e) => {
// F501
if checker.is_rule_enabled(Rule::PercentFormatInvalidFormat) {
checker.report_diagnostic(
pyflakes::rules::PercentFormatInvalidFormat {

View file

@ -828,6 +828,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
pyflakes::rules::future_feature_not_defined(checker, alias);
}
} else if &alias.name == "*" {
// F406
if checker.is_rule_enabled(Rule::UndefinedLocalWithNestedImportStarUsage) {
if !matches!(checker.semantic.current_scope().kind, ScopeKind::Module) {
checker.report_diagnostic(
@ -838,6 +839,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
);
}
}
// F403
if checker.is_rule_enabled(Rule::UndefinedLocalWithImportStar) {
checker.report_diagnostic(
pyflakes::rules::UndefinedLocalWithImportStar {

View file

@ -13,6 +13,7 @@ pub(crate) fn unresolved_references(checker: &Checker) {
for reference in checker.semantic.unresolved_references() {
if reference.is_wildcard_import() {
// F406
if checker.is_rule_enabled(Rule::UndefinedLocalWithImportStarUsage) {
checker.report_diagnostic(
pyflakes::rules::UndefinedLocalWithImportStarUsage {
@ -22,6 +23,7 @@ pub(crate) fn unresolved_references(checker: &Checker) {
);
}
} else {
// F821
if checker.is_rule_enabled(Rule::UndefinedName) {
if checker.semantic.in_no_type_check() {
continue;

View file

@ -625,6 +625,7 @@ impl SemanticSyntaxContext for Checker<'_> {
fn report_semantic_error(&self, error: SemanticSyntaxError) {
match error.kind {
SemanticSyntaxErrorKind::LateFutureImport => {
// F404
if self.is_rule_enabled(Rule::LateFutureImport) {
self.report_diagnostic(LateFutureImport, error.range);
}
@ -646,6 +647,7 @@ impl SemanticSyntaxContext for Checker<'_> {
}
}
SemanticSyntaxErrorKind::ReturnOutsideFunction => {
// F706
if self.is_rule_enabled(Rule::ReturnOutsideFunction) {
self.report_diagnostic(ReturnOutsideFunction, error.range);
}
@ -2808,6 +2810,7 @@ impl<'a> Checker<'a> {
Err(parse_error) => {
self.semantic.restore(snapshot);
// F722
if self.is_rule_enabled(Rule::ForwardAnnotationSyntaxError) {
self.report_type_diagnostic(
pyflakes::rules::ForwardAnnotationSyntaxError {
@ -2955,6 +2958,7 @@ impl<'a> Checker<'a> {
self.semantic.flags -= SemanticModelFlags::DUNDER_ALL_DEFINITION;
} else {
if self.semantic.global_scope().uses_star_imports() {
// F405
if self.is_rule_enabled(Rule::UndefinedLocalWithImportStarUsage) {
self.report_diagnostic(
pyflakes::rules::UndefinedLocalWithImportStarUsage {
@ -2965,6 +2969,7 @@ impl<'a> Checker<'a> {
.set_parent(definition.start());
}
} else {
// F822
if self.is_rule_enabled(Rule::UndefinedExport) {
if is_undefined_export_in_dunder_init_enabled(self.settings())
|| !self.path.ends_with("__init__.py")

View file

@ -22,6 +22,7 @@ use crate::{Edit, Fix, Locator};
use super::ast::LintContext;
/// RUF100
pub(crate) fn check_noqa(
context: &mut LintContext,
path: &Path,

View file

@ -11,6 +11,7 @@ use crate::registry::Rule;
use crate::rules::ruff::rules::InvalidPyprojectToml;
use crate::settings::LinterSettings;
/// RUF200
pub fn lint_pyproject_toml(
source_file: &SourceFile,
settings: &LinterSettings,

View file

@ -738,6 +738,7 @@ pub(crate) fn definition(
.suppress_none_returning
&& is_none_returning(body)
) {
// ANN206
if is_method && visibility::is_classmethod(decorator_list, checker.semantic()) {
if checker.is_rule_enabled(Rule::MissingReturnTypeClassMethod) {
let return_type = if is_stub_function(function, checker) {
@ -765,6 +766,7 @@ pub(crate) fn definition(
diagnostics.push(diagnostic);
}
} else if is_method && visibility::is_staticmethod(decorator_list, checker.semantic()) {
// ANN205
if checker.is_rule_enabled(Rule::MissingReturnTypeStaticMethod) {
let return_type = if is_stub_function(function, checker) {
None
@ -791,6 +793,7 @@ pub(crate) fn definition(
diagnostics.push(diagnostic);
}
} else if is_method && visibility::is_init(name) {
// ANN204
// Allow omission of return annotation in `__init__` functions, as long as at
// least one argument is typed.
if checker.is_rule_enabled(Rule::MissingReturnTypeSpecialMethod) {

View file

@ -51,6 +51,7 @@ impl Violation for BooleanPositionalValueInCall {
}
}
/// FBT003
pub(crate) fn boolean_positional_value_in_call(checker: &Checker, call: &ast::ExprCall) {
if allow_boolean_trap(call, checker) {
return;

View file

@ -46,7 +46,7 @@ impl Violation for StaticKeyDictComprehension {
}
}
/// RUF011
/// B035, RUF011
pub(crate) fn static_key_dict_comprehension(checker: &Checker, dict_comp: &ast::ExprDictComp) {
// Collect the bound names in the comprehension's generators.
let names = {

View file

@ -58,6 +58,7 @@ impl Violation for CallDateFromtimestamp {
}
}
/// DTZ012
pub(crate) fn call_date_fromtimestamp(checker: &Checker, func: &Expr, location: TextRange) {
if !checker.semantic().seen_module(Modules::DATETIME) {
return;

View file

@ -57,6 +57,7 @@ impl Violation for CallDateToday {
}
}
/// DTZ011
pub(crate) fn call_date_today(checker: &Checker, func: &Expr, location: TextRange) {
if !checker.semantic().seen_module(Modules::DATETIME) {
return;

View file

@ -69,6 +69,7 @@ impl Violation for CallDatetimeFromtimestamp {
}
}
/// DTZ006
pub(crate) fn call_datetime_fromtimestamp(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::DATETIME) {
return;

View file

@ -67,6 +67,7 @@ impl Violation for CallDatetimeNowWithoutTzinfo {
}
}
/// DTZ005
pub(crate) fn call_datetime_now_without_tzinfo(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::DATETIME) {
return;

View file

@ -56,6 +56,7 @@ impl Violation for CallDatetimeToday {
}
}
/// DTZ002
pub(crate) fn call_datetime_today(checker: &Checker, func: &Expr, location: TextRange) {
if !checker.semantic().seen_module(Modules::DATETIME) {
return;

View file

@ -60,6 +60,7 @@ impl Violation for CallDatetimeUtcfromtimestamp {
}
}
/// DTZ004
pub(crate) fn call_datetime_utcfromtimestamp(checker: &Checker, func: &Expr, location: TextRange) {
if !checker.semantic().seen_module(Modules::DATETIME) {
return;

View file

@ -63,6 +63,7 @@ impl Violation for CallDatetimeWithoutTzinfo {
}
}
/// DTZ001
pub(crate) fn call_datetime_without_tzinfo(checker: &Checker, call: &ast::ExprCall) {
if !checker.semantic().seen_module(Modules::DATETIME) {
return;

View file

@ -46,6 +46,7 @@ impl Violation for Debugger {
}
}
/// T100
/// Checks for the presence of a debugger call.
pub(crate) fn debugger_call(checker: &Checker, expr: &Expr, func: &Expr) {
if let Some(using_type) =
@ -64,6 +65,7 @@ pub(crate) fn debugger_call(checker: &Checker, expr: &Expr, func: &Expr) {
}
}
/// T100
/// Checks for the presence of a debugger import.
pub(crate) fn debugger_import(checker: &Checker, stmt: &Stmt, module: Option<&str>, name: &str) {
if let Some(module) = module {

View file

@ -59,6 +59,7 @@ impl Violation for ExcInfoOutsideExceptHandler {
}
}
/// LOG014
pub(crate) fn exc_info_outside_except_handler(checker: &Checker, call: &ExprCall) {
let semantic = checker.semantic();

View file

@ -171,7 +171,7 @@ pub(crate) fn logging_call(checker: &Checker, call: &ast::ExprCall) {
_ => return,
};
// G001 - G004
// G001, G002, G003, G004
let msg_pos = usize::from(matches!(logging_call_type, LoggingCallType::LogCall));
if let Some(format_arg) = call.arguments.find_argument_value("msg", msg_pos) {
check_msg(checker, format_arg);

View file

@ -55,6 +55,7 @@ impl Violation for PytestFailWithoutMessage {
}
}
/// PT016
pub(crate) fn fail_call(checker: &Checker, call: &ast::ExprCall) {
if is_pytest_fail(&call.func, checker.semantic()) {
// Allow either `pytest.fail(reason="...")` (introduced in pytest 7.0) or

View file

@ -225,6 +225,7 @@ fn check_useless_usefixtures(checker: &Checker, decorator: &Decorator, marker: &
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_deletion(decorator.range())));
}
/// PT023, PT026
pub(crate) fn marks(checker: &Checker, decorators: &[Decorator]) {
let enforce_parentheses = checker.is_rule_enabled(Rule::PytestIncorrectMarkParenthesesStyle);
let enforce_useless_usefixtures =

View file

@ -170,6 +170,7 @@ const fn is_non_trivial_with_body(body: &[Stmt]) -> bool {
}
}
/// PT010
pub(crate) fn raises_call(checker: &Checker, call: &ast::ExprCall) {
if is_pytest_raises(&call.func, checker.semantic()) {
if checker.is_rule_enabled(Rule::PytestRaisesWithoutException) {
@ -205,6 +206,7 @@ pub(crate) fn raises_call(checker: &Checker, call: &ast::ExprCall) {
}
}
/// PT012
pub(crate) fn complex_raises(checker: &Checker, stmt: &Stmt, items: &[WithItem], body: &[Stmt]) {
let raises_called = items.iter().any(|item| match &item.context_expr {
Expr::Call(ast::ExprCall { func, .. }) => is_pytest_raises(func, checker.semantic()),

View file

@ -154,6 +154,7 @@ fn get_complexity_number(stmts: &[Stmt]) -> usize {
complexity
}
/// C901
pub(crate) fn function_is_too_complex(
checker: &Checker,
stmt: &Stmt,

View file

@ -181,15 +181,19 @@ pub(crate) fn call(checker: &Checker, func: &Expr) {
let range = func.range();
match attr.as_str() {
// PD003
"isnull" if checker.is_rule_enabled(Rule::PandasUseOfDotIsNull) => {
checker.report_diagnostic(PandasUseOfDotIsNull, range);
}
// PD004
"notnull" if checker.is_rule_enabled(Rule::PandasUseOfDotNotNull) => {
checker.report_diagnostic(PandasUseOfDotNotNull, range);
}
// PD010
"pivot" | "unstack" if checker.is_rule_enabled(Rule::PandasUseOfDotPivotOrUnstack) => {
checker.report_diagnostic(PandasUseOfDotPivotOrUnstack, range);
}
// PD013
"stack" if checker.is_rule_enabled(Rule::PandasUseOfDotStack) => {
checker.report_diagnostic(PandasUseOfDotStack, range);
}

View file

@ -163,12 +163,15 @@ pub(crate) fn subscript(checker: &Checker, value: &Expr, expr: &Expr) {
let range = expr.range();
match attr.as_str() {
// PD007
"ix" if checker.is_rule_enabled(Rule::PandasUseOfDotIx) => {
checker.report_diagnostic(PandasUseOfDotIx, range)
}
// PD008
"at" if checker.is_rule_enabled(Rule::PandasUseOfDotAt) => {
checker.report_diagnostic(PandasUseOfDotAt, range)
}
// PD009
"iat" if checker.is_rule_enabled(Rule::PandasUseOfDotIat) => {
checker.report_diagnostic(PandasUseOfDotIat, range)
}

View file

@ -30,6 +30,7 @@ impl Violation for FutureFeatureNotDefined {
}
}
/// F407
pub(crate) fn future_feature_not_defined(checker: &Checker, alias: &Alias) {
if is_feature_name(&alias.name) {
return;

View file

@ -276,6 +276,7 @@ fn find_dunder_all_exprs<'a>(semantic: &'a SemanticModel) -> Vec<&'a ast::Expr>
.collect()
}
/// F401
/// For some unused binding in an import statement...
///
/// __init__.py ∧ 1stpty → safe, if one __all__, add to __all__

View file

@ -73,7 +73,7 @@ impl Violation for EqWithoutHash {
}
}
/// W1641
/// PLW1641
pub(crate) fn object_without_hash_method(checker: &Checker, class: &StmtClassDef) {
if checker.source_type.is_stub() {
return;

View file

@ -80,7 +80,7 @@ impl Violation for IfStmtMinMax {
}
}
/// R1730, R1731
/// PLR1730, PLR1731
pub(crate) fn if_stmt_min_max(checker: &Checker, stmt_if: &ast::StmtIf) {
let ast::StmtIf {
test,

View file

@ -55,7 +55,7 @@ impl Violation for ImportOutsideTopLevel {
}
}
/// C0415
/// PLC0415
pub(crate) fn import_outside_top_level(checker: &Checker, stmt: &Stmt) {
if checker.semantic().current_scope().kind.is_module() {
// "Top-level" imports are allowed

View file

@ -48,7 +48,7 @@ impl Violation for InvalidHashReturnType {
}
}
/// E0309
/// PLE0309
pub(crate) fn invalid_hash_return(checker: &Checker, function_def: &ast::StmtFunctionDef) {
if function_def.name.as_str() != "__hash__" {
return;

View file

@ -50,7 +50,7 @@ impl Violation for InvalidIndexReturnType {
}
}
/// E0305
/// PLE0305
pub(crate) fn invalid_index_return(checker: &Checker, function_def: &ast::StmtFunctionDef) {
if function_def.name.as_str() != "__index__" {
return;

View file

@ -49,7 +49,7 @@ impl Violation for InvalidLengthReturnType {
}
}
/// E0303
/// PLE0303
pub(crate) fn invalid_length_return(checker: &Checker, function_def: &ast::StmtFunctionDef) {
if function_def.name.as_str() != "__len__" {
return;

View file

@ -44,7 +44,7 @@ impl Violation for InvalidStrReturnType {
}
}
/// E0307
/// PLE0307
pub(crate) fn invalid_str_return(checker: &Checker, function_def: &ast::StmtFunctionDef) {
if function_def.name.as_str() != "__str__" {
return;

View file

@ -53,7 +53,7 @@ impl Violation for NonlocalAndGlobal {
}
}
/// E115
/// PLE0115
pub(crate) fn nonlocal_and_global(checker: &Checker, nonlocal: &ast::StmtNonlocal) {
// Determine whether any of the newly declared `nonlocal` variables are already declared as
// `global`.

View file

@ -35,6 +35,7 @@ impl Violation for RepeatedKeywordArgument {
}
}
/// PLE1132
pub(crate) fn repeated_keyword_argument(checker: &Checker, call: &ExprCall) {
let ExprCall { arguments, .. } = call;

View file

@ -66,7 +66,7 @@ impl Violation for SelfOrClsAssignment {
}
}
/// PLW0127
/// PLW0642
pub(crate) fn self_or_cls_assignment(checker: &Checker, target: &Expr) {
let ScopeKind::Function(ast::StmtFunctionDef {
name,

View file

@ -58,7 +58,7 @@ impl Violation for SingledispatchMethod {
}
}
/// E1519
/// PLE1519
pub(crate) fn singledispatch_method(checker: &Checker, scope: &Scope) {
let Some(func) = scope.kind.as_function() else {
return;

View file

@ -56,7 +56,7 @@ impl Violation for SingledispatchmethodFunction {
}
}
/// E1520
/// PLE1520
pub(crate) fn singledispatchmethod_function(checker: &Checker, scope: &Scope) {
let Some(func) = scope.kind.as_function() else {
return;

View file

@ -99,7 +99,7 @@ impl Violation for TooManyPublicMethods {
}
}
/// R0904
/// PLR0904
pub(crate) fn too_many_public_methods(
checker: &Checker,
class_def: &ast::StmtClassDef,

View file

@ -64,6 +64,7 @@ impl AlwaysFixableViolation for IntOnSlicedStr {
}
}
/// FURB166
pub(crate) fn int_on_sliced_str(checker: &Checker, call: &ExprCall) {
// Verify that the function is `int`.
if !checker.semantic().match_builtin_expr(&call.func, "int") {

View file

@ -114,6 +114,7 @@ impl PytestContextType {
}
}
/// RUF061
pub(crate) fn legacy_raises_warns_deprecated_call(checker: &Checker, call: &ast::ExprCall) {
let semantic = checker.semantic();
let Some(context_type) = PytestContextType::from_expr_name(&call.func, semantic) else {

View file

@ -158,6 +158,7 @@ pub(crate) fn sort_dunder_all_ann_assign(checker: &Checker, node: &ast::StmtAnnA
}
}
/// RUF022
/// Sort a tuple or list that defines or mutates the global variable `__all__`.
///
/// This routine checks whether the tuple or list is sorted, and emits a

View file

@ -105,6 +105,7 @@ impl Violation for UnsortedDunderSlots {
const SORTING_STYLE: SortingStyle = SortingStyle::Natural;
/// RUF023
/// Sort a tuple, list, dict or set that defines `__slots__` in a class scope.
///
/// This routine checks whether the display is sorted, and emits a

View file

@ -74,7 +74,7 @@ impl Violation for UnnecessaryNestedLiteral {
}
}
/// RUF039
/// RUF041
pub(crate) fn unnecessary_nested_literal<'a>(checker: &Checker, literal_expr: &'a Expr) {
let mut is_nested = false;