Skip to content

Commit 513de18

Browse files
committed
Improve other areas of the semantic model also
1 parent c70e3e6 commit 513de18

File tree

5 files changed

+63
-15
lines changed

5 files changed

+63
-15
lines changed

crates/ruff_linter/resources/test/fixtures/refurb/FURB129.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ def func():
4141
pass
4242

4343

44+
import builtins
45+
46+
47+
with builtins.open("FURB129.py") as f:
48+
for line in f.readlines():
49+
pass
50+
51+
52+
from builtins import open as o
53+
54+
55+
with o("FURB129.py") as f:
56+
for line in f.readlines():
57+
pass
58+
59+
4460
# False positives
4561
def func(f):
4662
for _line in f.readlines():

crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB129_FURB129.py.snap

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,40 @@ FURB129.py:38:22: FURB129 [*] Instead of calling `readlines()`, iterate over fil
204204
40 40 | for _line in bar.readlines():
205205
41 41 | pass
206206

207+
FURB129.py:48:17: FURB129 [*] Instead of calling `readlines()`, iterate over file object directly
208+
|
209+
47 | with builtins.open("FURB129.py") as f:
210+
48 | for line in f.readlines():
211+
| ^^^^^^^^^^^^^ FURB129
212+
49 | pass
213+
|
214+
= help: Remove `readlines()`
215+
216+
Unsafe fix
217+
45 45 |
218+
46 46 |
219+
47 47 | with builtins.open("FURB129.py") as f:
220+
48 |- for line in f.readlines():
221+
48 |+ for line in f:
222+
49 49 | pass
223+
50 50 |
224+
51 51 |
225+
226+
FURB129.py:56:17: FURB129 [*] Instead of calling `readlines()`, iterate over file object directly
227+
|
228+
55 | with o("FURB129.py") as f:
229+
56 | for line in f.readlines():
230+
| ^^^^^^^^^^^^^ FURB129
231+
57 | pass
232+
|
233+
= help: Remove `readlines()`
207234

235+
Unsafe fix
236+
53 53 |
237+
54 54 |
238+
55 55 | with o("FURB129.py") as f:
239+
56 |- for line in f.readlines():
240+
56 |+ for line in f:
241+
57 57 | pass
242+
58 58 |
243+
59 59 |

crates/ruff_python_semantic/src/analyze/function_type.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub fn classify(
3737
semantic
3838
.resolve_qualified_name(map_callable(expr))
3939
.is_some_and( |qualified_name| {
40-
matches!(qualified_name.segments(), ["", "type"] | ["abc", "ABCMeta"])
40+
matches!(qualified_name.segments(), ["" | "builtins", "type"] | ["abc", "ABCMeta"])
4141
})
4242
})
4343
|| decorator_list.iter().any(|decorator| is_class_method(decorator, semantic, classmethod_decorators))
@@ -63,7 +63,7 @@ fn is_static_method(
6363
.is_some_and(|qualified_name| {
6464
matches!(
6565
qualified_name.segments(),
66-
["", "staticmethod"] | ["abc", "abstractstaticmethod"]
66+
["" | "builtins", "staticmethod"] | ["abc", "abstractstaticmethod"]
6767
) || staticmethod_decorators
6868
.iter()
6969
.any(|decorator| qualified_name == QualifiedName::from_dotted_name(decorator))
@@ -103,7 +103,7 @@ fn is_class_method(
103103
.is_some_and(|qualified_name| {
104104
matches!(
105105
qualified_name.segments(),
106-
["", "classmethod"] | ["abc", "abstractclassmethod"]
106+
["" | "builtins", "classmethod"] | ["abc", "abstractclassmethod"]
107107
) || classmethod_decorators
108108
.iter()
109109
.any(|decorator| qualified_name == QualifiedName::from_dotted_name(decorator))

crates/ruff_python_semantic/src/analyze/typing.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ impl TypeChecker for IoBaseChecker {
686686
.is_some_and(|qualified_name| {
687687
matches!(
688688
qualified_name.segments(),
689-
["io", "open" | "open_code"] | ["os" | "", "open"]
689+
["io", "open" | "open_code"] | ["os" | "" | "builtins", "open"]
690690
)
691691
})
692692
}

crates/ruff_python_semantic/src/analyze/visibility.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,16 @@ pub enum Visibility {
1515

1616
/// Returns `true` if a function is a "static method".
1717
pub fn is_staticmethod(decorator_list: &[Decorator], semantic: &SemanticModel) -> bool {
18-
decorator_list.iter().any(|decorator| {
19-
semantic
20-
.resolve_qualified_name(map_callable(&decorator.expression))
21-
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["", "staticmethod"]))
22-
})
18+
decorator_list
19+
.iter()
20+
.any(|decorator| semantic.match_builtin_expr(&decorator.expression, "staticmethod"))
2321
}
2422

2523
/// Returns `true` if a function is a "class method".
2624
pub fn is_classmethod(decorator_list: &[Decorator], semantic: &SemanticModel) -> bool {
27-
decorator_list.iter().any(|decorator| {
28-
semantic
29-
.resolve_qualified_name(map_callable(&decorator.expression))
30-
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["", "classmethod"]))
31-
})
25+
decorator_list
26+
.iter()
27+
.any(|decorator| semantic.match_builtin_expr(&decorator.expression, "classmethod"))
3228
}
3329

3430
/// Returns `true` if a function definition is an `@overload`.
@@ -79,7 +75,7 @@ pub fn is_property(
7975
.is_some_and(|qualified_name| {
8076
matches!(
8177
qualified_name.segments(),
82-
["", "property"] | ["functools", "cached_property"]
78+
["" | "builtins", "property"] | ["functools", "cached_property"]
8379
) || extra_properties
8480
.iter()
8581
.any(|extra_property| extra_property.segments() == qualified_name.segments())

0 commit comments

Comments
 (0)