Skip to content

Commit 1dfb87d

Browse files
SONARPY-786 RSPEC-3827: Extract detection of never defined variable i… (SonarSource#853)
1 parent 2fd368e commit 1dfb87d

18 files changed

Lines changed: 417 additions & 264 deletions

File tree

Lines changed: 0 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,5 @@
11
{
2-
'project:S1716.py':[
3-
4,
4-
],
5-
'project:buildbot-0.8.6p1/buildbot/test/unit/test_db_sourcestamps.py':[
6-
120,
7-
],
8-
'project:mypy-0.782/test-data/stdlib-samples/3.2/test/test_tempfile.py':[
9-
262,
10-
568,
11-
],
12-
'project:numpy-1.16.4/numpy/distutils/ccompiler.py':[
13-
214,
14-
696,
15-
],
16-
'project:numpy-1.16.4/numpy/distutils/npy_pkg_config.py':[
17-
249,
18-
249,
19-
],
20-
'project:numpy-1.16.4/numpy/distutils/unixccompiler.py':[
21-
15,
22-
133,
23-
],
24-
'project:numpy-1.16.4/numpy/linalg/lapack_lite/clapack_scrub.py':[
25-
306,
26-
],
27-
'project:numpy-1.16.4/numpy/matlib.py':[
28-
49,
29-
171,
30-
352,
31-
],
32-
'project:tensorflow/__init__.py':[
33-
39,
34-
40,
35-
],
36-
'project:tensorflow/python/autograph/converters/control_flow_test.py':[
37-
680,
38-
],
39-
'project:tensorflow/python/autograph/pyct/cfg_test.py':[
40-
1224,
41-
1279,
42-
],
43-
'project:tensorflow/python/autograph/pyct/static_analysis/activity_test.py':[
44-
199,
45-
],
462
'project:tensorflow/python/autograph/pyct/static_analysis/liveness_test.py':[
473
270,
48-
510,
49-
],
50-
'project:tensorflow/python/autograph/pyct/static_analysis/reaching_definitions_test.py':[
51-
133,
52-
373,
53-
],
54-
'project:twisted-12.1.0/doc/core/howto/listings/pb/trap_client.py':[
55-
21,
56-
21,
57-
],
58-
'project:twisted-12.1.0/doc/core/howto/tutorial/listings/finger/finger19a_changes.py':[
59-
2,
60-
9,
61-
11,
62-
11,
63-
17,
64-
27,
65-
28,
66-
28,
67-
],
68-
'project:twisted-12.1.0/doc/core/howto/tutorial/listings/finger/finger19b_changes.py':[
69-
7,
70-
9,
71-
9,
72-
],
73-
'project:twisted-12.1.0/doc/core/howto/tutorial/listings/finger/finger19c_changes.py':[
74-
8,
75-
10,
76-
10,
77-
],
78-
'project:twisted-12.1.0/doc/core/howto/tutorial/listings/finger/finger_config.py':[
79-
6,
80-
7,
81-
8,
82-
8,
83-
12,
84-
14,
85-
20,
86-
25,
87-
35,
88-
35,
89-
],
90-
'project:twisted-12.1.0/doc/historic/2003/pycon/deferex/deferex-bad-adding.py':[
91-
8,
92-
],
93-
'project:twisted-12.1.0/doc/historic/2003/pycon/deferex/deferex-forwarding.py':[
94-
3,
95-
],
96-
'project:twisted-12.1.0/doc/historic/2003/pycon/deferex/deferex-listing0.py':[
97-
4,
98-
13,
99-
],
100-
'project:twisted-12.1.0/doc/historic/2003/pycon/deferex/deferex-listing2.py':[
101-
8,
102-
],
103-
'project:twisted-12.1.0/doc/web/examples/users.rpy.py':[
104-
24,
105-
],
106-
'project:twisted-12.1.0/twisted/conch/scripts/cftp.py':[
107-
431,
108-
],
109-
'project:twisted-12.1.0/twisted/conch/scripts/ckeygen.py':[
110-
75,
111-
],
112-
'project:twisted-12.1.0/twisted/conch/scripts/tkconch.py':[
113-
376,
114-
],
115-
'project:twisted-12.1.0/twisted/python/compat.py':[
116-
22,
117-
],
118-
'project:twisted-12.1.0/twisted/runner/inetdtap.py':[
119-
58,
120-
59,
121-
62,
122-
152,
123-
],
124-
'project:twisted-12.1.0/twisted/test/proto_helpers.py':[
125-
412,
126-
414,
127-
],
128-
'project:twisted-12.1.0/twisted/test/test_amp.py':[
129-
2985,
130-
2989,
131-
],
132-
'project:twisted-12.1.0/twisted/test/test_paths.py':[
133-
527,
1344
],
1355
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
{
2+
'project:S1716.py':[
3+
4,
4+
],
5+
'project:buildbot-0.8.6p1/buildbot/test/unit/test_db_sourcestamps.py':[
6+
120,
7+
],
8+
'project:mypy-0.782/test-data/stdlib-samples/3.2/test/test_tempfile.py':[
9+
262,
10+
568,
11+
],
12+
'project:numpy-1.16.4/numpy/distutils/ccompiler.py':[
13+
214,
14+
696,
15+
],
16+
'project:numpy-1.16.4/numpy/distutils/npy_pkg_config.py':[
17+
249,
18+
249,
19+
],
20+
'project:numpy-1.16.4/numpy/distutils/unixccompiler.py':[
21+
15,
22+
133,
23+
],
24+
'project:numpy-1.16.4/numpy/linalg/lapack_lite/clapack_scrub.py':[
25+
306,
26+
],
27+
'project:numpy-1.16.4/numpy/matlib.py':[
28+
49,
29+
171,
30+
352,
31+
],
32+
'project:tensorflow/__init__.py':[
33+
39,
34+
40,
35+
],
36+
'project:tensorflow/python/autograph/converters/control_flow_test.py':[
37+
680,
38+
],
39+
'project:tensorflow/python/autograph/pyct/cfg_test.py':[
40+
1224,
41+
1279,
42+
],
43+
'project:tensorflow/python/autograph/pyct/static_analysis/activity_test.py':[
44+
199,
45+
],
46+
'project:tensorflow/python/autograph/pyct/static_analysis/liveness_test.py':[
47+
510,
48+
],
49+
'project:tensorflow/python/autograph/pyct/static_analysis/reaching_definitions_test.py':[
50+
133,
51+
373,
52+
],
53+
'project:twisted-12.1.0/doc/core/howto/listings/pb/trap_client.py':[
54+
21,
55+
21,
56+
],
57+
'project:twisted-12.1.0/doc/core/howto/tutorial/listings/finger/finger19a_changes.py':[
58+
2,
59+
9,
60+
11,
61+
11,
62+
17,
63+
27,
64+
28,
65+
28,
66+
],
67+
'project:twisted-12.1.0/doc/core/howto/tutorial/listings/finger/finger19b_changes.py':[
68+
7,
69+
9,
70+
9,
71+
],
72+
'project:twisted-12.1.0/doc/core/howto/tutorial/listings/finger/finger19c_changes.py':[
73+
8,
74+
10,
75+
10,
76+
],
77+
'project:twisted-12.1.0/doc/core/howto/tutorial/listings/finger/finger_config.py':[
78+
6,
79+
7,
80+
8,
81+
8,
82+
12,
83+
14,
84+
20,
85+
25,
86+
35,
87+
35,
88+
],
89+
'project:twisted-12.1.0/doc/historic/2003/pycon/deferex/deferex-bad-adding.py':[
90+
8,
91+
],
92+
'project:twisted-12.1.0/doc/historic/2003/pycon/deferex/deferex-forwarding.py':[
93+
3,
94+
],
95+
'project:twisted-12.1.0/doc/historic/2003/pycon/deferex/deferex-listing0.py':[
96+
4,
97+
13,
98+
],
99+
'project:twisted-12.1.0/doc/historic/2003/pycon/deferex/deferex-listing2.py':[
100+
8,
101+
],
102+
'project:twisted-12.1.0/doc/web/examples/users.rpy.py':[
103+
24,
104+
],
105+
'project:twisted-12.1.0/twisted/conch/scripts/cftp.py':[
106+
431,
107+
],
108+
'project:twisted-12.1.0/twisted/conch/scripts/ckeygen.py':[
109+
75,
110+
],
111+
'project:twisted-12.1.0/twisted/conch/scripts/tkconch.py':[
112+
376,
113+
],
114+
'project:twisted-12.1.0/twisted/python/compat.py':[
115+
22,
116+
],
117+
'project:twisted-12.1.0/twisted/runner/inetdtap.py':[
118+
58,
119+
59,
120+
62,
121+
152,
122+
],
123+
'project:twisted-12.1.0/twisted/test/proto_helpers.py':[
124+
412,
125+
414,
126+
],
127+
'project:twisted-12.1.0/twisted/test/test_amp.py':[
128+
2985,
129+
2989,
130+
],
131+
'project:twisted-12.1.0/twisted/test/test_paths.py':[
132+
527,
133+
],
134+
}

python-checks/src/main/java/org/sonar/python/checks/CheckList.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,13 @@ public static Iterable<Class> getChecks() {
200200
TooManyReturnsCheck.class,
201201
TrailingCommentCheck.class,
202202
TrailingWhitespaceCheck.class,
203-
UndeclaredNameUsageCheck.class,
203+
ReferencedBeforeAssignmentCheck.class,
204204
UndefinedNameAllPropertyCheck.class,
205205
UnreachableExceptCheck.class,
206206
UnreadPrivateAttributesCheck.class,
207207
UnreadPrivateInnerClassesCheck.class,
208208
UnreadPrivateMethodsCheck.class,
209+
UndefinedSymbolsCheck.class,
209210
UnusedLocalVariableCheck.class,
210211
UnusedNestedDefinitionCheck.class,
211212
UnverifiedHostnameCheck.class,

python-checks/src/main/java/org/sonar/python/checks/UndeclaredNameUsageCheck.java renamed to python-checks/src/main/java/org/sonar/python/checks/ReferencedBeforeAssignmentCheck.java

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -29,36 +29,20 @@
2929
import org.sonar.plugins.python.api.SubscriptionContext;
3030
import org.sonar.plugins.python.api.cfg.CfgBlock;
3131
import org.sonar.plugins.python.api.cfg.ControlFlowGraph;
32+
import org.sonar.plugins.python.api.symbols.Symbol;
3233
import org.sonar.plugins.python.api.symbols.Usage;
33-
import org.sonar.plugins.python.api.tree.BaseTreeVisitor;
34-
import org.sonar.plugins.python.api.tree.CallExpression;
35-
import org.sonar.plugins.python.api.tree.FileInput;
3634
import org.sonar.plugins.python.api.tree.FunctionDef;
37-
import org.sonar.plugins.python.api.tree.ImportFrom;
38-
import org.sonar.plugins.python.api.tree.Name;
3935
import org.sonar.plugins.python.api.tree.Tree;
4036
import org.sonar.python.cfg.CfgUtils;
4137
import org.sonar.python.cfg.fixpoint.DefinedVariablesAnalysis;
4238
import org.sonar.python.cfg.fixpoint.DefinedVariablesAnalysis.DefinedVariables;
43-
import org.sonar.plugins.python.api.symbols.Symbol;
4439
import org.sonar.python.tree.TreeUtils;
4540

4641
@Rule(key = "S3827")
47-
public class UndeclaredNameUsageCheck extends PythonSubscriptionCheck {
42+
public class ReferencedBeforeAssignmentCheck extends PythonSubscriptionCheck {
4843

4944
@Override
5045
public void initialize(Context context) {
51-
context.registerSyntaxNodeConsumer(Tree.Kind.FILE_INPUT, ctx -> {
52-
FileInput fileInput = (FileInput) ctx.syntaxNode();
53-
if (importsManipulatedAllProperty(fileInput)) {
54-
return;
55-
}
56-
UnresolvedSymbolsVisitor unresolvedSymbolsVisitor = new UnresolvedSymbolsVisitor();
57-
fileInput.accept(unresolvedSymbolsVisitor);
58-
if (!unresolvedSymbolsVisitor.callGlobalsOrLocals && !unresolvedSymbolsVisitor.hasUnresolvedWildcardImport) {
59-
addNameIssues(unresolvedSymbolsVisitor.nameIssues, ctx);
60-
}
61-
});
6246

6347
context.registerSyntaxNodeConsumer(Tree.Kind.FUNCDEF, ctx -> {
6448
List<Symbol> ignoredSymbols = new ArrayList<>();
@@ -76,10 +60,6 @@ public void initialize(Context context) {
7660
});
7761
}
7862

79-
private static boolean importsManipulatedAllProperty(FileInput fileInput) {
80-
return fileInput.globalVariables().stream().anyMatch(s -> s.name().equals("__all__") && s.fullyQualifiedName() != null);
81-
}
82-
8363
private static void checkCfgBlock(CfgBlock cfgBlock, SubscriptionContext ctx, DefinedVariables definedVariables,
8464
Set<CfgBlock> unreachableBlocks, DefinedVariablesAnalysis analysis, List<Symbol> ignoredSymbols) {
8565
Map<Symbol, DefinedVariablesAnalysis.VariableDefinition> currentState = new HashMap<>(definedVariables.getIn());
@@ -111,41 +91,4 @@ private static boolean isSymbolUsedInUnreachableBlocks(DefinedVariablesAnalysis
11191
private static boolean isUndefined(DefinedVariablesAnalysis.VariableDefinition varDef) {
11292
return varDef == DefinedVariablesAnalysis.VariableDefinition.UNDEFINED;
11393
}
114-
115-
private static void addNameIssues(Map<String, List<Name>> nameIssues, SubscriptionContext subscriptionContext) {
116-
nameIssues.forEach((name, list) -> {
117-
Name first = list.get(0);
118-
PreciseIssue issue = subscriptionContext.addIssue(first, first.name() + " is not defined. Change its name or define it before using it");
119-
list.stream().skip(1).forEach(n -> issue.secondary(n, null));
120-
});
121-
}
122-
123-
private static class UnresolvedSymbolsVisitor extends BaseTreeVisitor {
124-
125-
private boolean hasUnresolvedWildcardImport = false;
126-
private boolean callGlobalsOrLocals = false;
127-
private Map<String, List<Name>> nameIssues = new HashMap<>();
128-
129-
@Override
130-
public void visitName(Name name) {
131-
if (name.isVariable() && name.symbol() == null) {
132-
nameIssues.computeIfAbsent(name.name(), k -> new ArrayList<>()).add(name);
133-
}
134-
}
135-
136-
@Override
137-
public void visitImportFrom(ImportFrom importFrom) {
138-
hasUnresolvedWildcardImport |= importFrom.hasUnresolvedWildcardImport();
139-
super.visitImportFrom(importFrom);
140-
}
141-
142-
@Override
143-
public void visitCallExpression(CallExpression callExpression) {
144-
if (callExpression.callee().is(Tree.Kind.NAME)) {
145-
String name = ((Name) callExpression.callee()).name();
146-
callGlobalsOrLocals |= name.equals("globals") || name.equals("locals");
147-
}
148-
super.visitCallExpression(callExpression);
149-
}
150-
}
15194
}

0 commit comments

Comments
 (0)