Skip to content

Commit 6bf4651

Browse files
committed
[F823] Warn when variable name is referenced before assignment
ghstack-source-id: 0f31d5c Pull Request resolved: #277
1 parent 40ed43b commit 6bf4651

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
import libcst as cst
7+
8+
from fixit import CstLintRule, InvalidTestCase as Invalid, ValidTestCase as Valid
9+
10+
11+
class NoReferenceBeforeAssignmentRule(CstLintRule):
12+
"""
13+
Local variables should be defined before the are referenced.
14+
15+
Autofix: N/A
16+
"""
17+
18+
CUSTOM_MESSAGE = ("Local variable {name} was referenced without "
19+
"being defined in the current scope. Either define"
20+
" it locally or use the `global` keyword to access"
21+
" a global variable.")
22+
23+
METADATA_DEPENDENCIES = (cst.metadata.ScopeProvider,)
24+
25+
def __init__(self) -> None:
26+
super().__init__()
27+
28+
def visit_Name(self, node: cst.Name) -> None:
29+
try:
30+
metadata = self.get_metadata(cst.metadata.ScopeProvider, node)
31+
assert metadata is not None
32+
accesses = metadata.accesses
33+
except KeyError:
34+
# Not all Names have ExpressionContext
35+
return
36+
for access in accesses:
37+
if access.node is node and len(access.referents) == 0:
38+
assert isinstance(access.node, cst.Name)
39+
name = access.node.value
40+
self.report(node, self.CUSTOM_MESSAGE.format(name=name))
41+
42+
VALID = [
43+
Valid(
44+
"""
45+
y = 2 + 3
46+
"""
47+
),
48+
Valid(
49+
"""
50+
a = 2
51+
y = a + 3
52+
"""
53+
),
54+
Valid(
55+
"""
56+
a = 2
57+
58+
def fn():
59+
return a + 3
60+
"""
61+
),
62+
Valid(
63+
"""
64+
a = abs(1.333)
65+
"""
66+
),
67+
Valid(
68+
"""
69+
a = [2**i for i in (1, 2, 3)]
70+
"""
71+
),
72+
]
73+
74+
INVALID = [
75+
Invalid(
76+
"""
77+
y = a + 3
78+
a = 2
79+
"""
80+
),
81+
Invalid(
82+
"""
83+
def fn():
84+
return a + 3
85+
"""
86+
),
87+
Invalid(
88+
"""
89+
a = foo(1.333)
90+
"""
91+
),
92+
Invalid(
93+
"""
94+
a = [2**j for i in (1, 2, 3)]
95+
"""
96+
),
97+
]

0 commit comments

Comments
 (0)