diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM118.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM118.py index 945d6968a3fd2..79afeb5d843e7 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM118.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM118.py @@ -58,3 +58,8 @@ def __contains__(self, key: object) -> bool: .keys() ): continue + +from builtins import dict as SneakyDict + +d = SneakyDict() +key in d.keys() # SIM118 diff --git a/crates/ruff_linter/resources/test/fixtures/perflint/PERF403.py b/crates/ruff_linter/resources/test/fixtures/perflint/PERF403.py index e28723673a0ff..8ef430c8fc9f3 100644 --- a/crates/ruff_linter/resources/test/fixtures/perflint/PERF403.py +++ b/crates/ruff_linter/resources/test/fixtures/perflint/PERF403.py @@ -81,3 +81,11 @@ def foo(): result = {} for idx, name in enumerate(fruit): result[name] = idx # PERF403 + + +def foo(): + from builtins import dict as SneakyDict + fruit = ["apple", "pear", "orange"] + result = SneakyDict() + for idx, name in enumerate(fruit): + result[name] = idx # PERF403 diff --git a/crates/ruff_linter/resources/test/fixtures/refurb/FURB131.py b/crates/ruff_linter/resources/test/fixtures/refurb/FURB131.py index 02280e876c67a..d867cabff75eb 100644 --- a/crates/ruff_linter/resources/test/fixtures/refurb/FURB131.py +++ b/crates/ruff_linter/resources/test/fixtures/refurb/FURB131.py @@ -49,6 +49,14 @@ def yes_five(x: Dict[int, str]): x = 1 + +from builtins import list as SneakyList + + +sneaky = SneakyList() +# FURB131 +del sneaky[:] + # these should not del names["key"] diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM118_SIM118.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM118_SIM118.py.snap index f5ee64bb00f81..8acd4d438bc9e 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM118_SIM118.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM118_SIM118.py.snap @@ -397,5 +397,19 @@ SIM118.py:55:5: SIM118 [*] Use `key in dict` instead of `key in dict.keys()` 58 |+ 59 59 | ): 60 60 | continue +61 61 | +SIM118.py:65:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()` + | +64 | d = SneakyDict() +65 | key in d.keys() # SIM118 + | ^^^^^^^^^^^^^^^ SIM118 + | + = help: Remove `.keys()` +ℹ Safe fix +62 62 | from builtins import dict as SneakyDict +63 63 | +64 64 | d = SneakyDict() +65 |-key in d.keys() # SIM118 + 65 |+key in d # SIM118 diff --git a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF403_PERF403.py.snap b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF403_PERF403.py.snap index 38e98d9faf7af..f0418ee5542ed 100644 --- a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF403_PERF403.py.snap +++ b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF403_PERF403.py.snap @@ -49,4 +49,10 @@ PERF403.py:83:9: PERF403 Use a dictionary comprehension instead of a for-loop | ^^^^^^^^^^^^^^^^^^ PERF403 | - +PERF403.py:91:9: PERF403 Use a dictionary comprehension instead of a for-loop + | +89 | result = SneakyDict() +90 | for idx, name in enumerate(fruit): +91 | result[name] = idx # PERF403 + | ^^^^^^^^^^^^^^^^^^ PERF403 + | diff --git a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB131_FURB131.py.snap b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB131_FURB131.py.snap index aa5eb46521e4c..fcd3ecd84eb12 100644 --- a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB131_FURB131.py.snap +++ b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB131_FURB131.py.snap @@ -150,4 +150,23 @@ FURB131.py:48:5: FURB131 [*] Prefer `clear` over deleting a full slice 50 50 | x = 1 51 51 | +FURB131.py:58:1: FURB131 [*] Prefer `clear` over deleting a full slice + | +56 | sneaky = SneakyList() +57 | # FURB131 +58 | del sneaky[:] + | ^^^^^^^^^^^^^ FURB131 +59 | +60 | # these should not + | + = help: Replace with `clear()` +ℹ Unsafe fix +55 55 | +56 56 | sneaky = SneakyList() +57 57 | # FURB131 +58 |-del sneaky[:] + 58 |+sneaky.clear() +59 59 | +60 60 | # these should not +61 61 | diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index ce82294fbe900..4d239017ddfe7 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -539,7 +539,7 @@ trait BuiltinTypeChecker { /// Check annotation expression to match the intended type. fn match_annotation(annotation: &Expr, semantic: &SemanticModel) -> bool { let value = map_subscript(annotation); - Self::match_builtin_type(value, semantic) + semantic.match_builtin_expr(value, Self::BUILTIN_TYPE_NAME) || semantic.match_typing_expr(value, Self::TYPING_NAME) } @@ -562,15 +562,7 @@ trait BuiltinTypeChecker { let Expr::Call(ast::ExprCall { func, .. }) = initializer else { return false; }; - Self::match_builtin_type(func.as_ref(), semantic) - } - - /// Check if the given expression names the builtin type. - fn match_builtin_type(type_expr: &Expr, semantic: &SemanticModel) -> bool { - let Expr::Name(ast::ExprName { id, .. }) = type_expr else { - return false; - }; - id == Self::BUILTIN_TYPE_NAME && semantic.is_builtin(Self::BUILTIN_TYPE_NAME) + semantic.match_builtin_expr(func, Self::BUILTIN_TYPE_NAME) } }