Skip to content

Commit b1177cf

Browse files
ivandalboscovilchik-elena
authored andcommitted
SONARPY-154 False Positive on rules considering nested class properties (SonarSource#37)
1 parent 68cf0f0 commit b1177cf

5 files changed

Lines changed: 66 additions & 12 deletions

File tree

its/ruling/src/test/resources/expected/python-S116.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@
120120
],
121121
'project:buildbot-0.8.6p1/buildbot/test/unit/test_process_users_manual.py':[
122122
36,
123-
36,
124123
],
125124
'project:buildbot-0.8.6p1/buildbot/test/unit/test_schedulers_basic.py':[
126125
46,
@@ -508,8 +507,8 @@
508507
479,
509508
480,
510509
482,
511-
933,
512-
935,
510+
907,
511+
909,
513512
1114,
514513
],
515514
'project:twisted-12.1.0/twisted/internet/defer.py':[
@@ -1395,7 +1394,6 @@
13951394
'project:twisted-12.1.0/twisted/web/test/test_webclient.py':[
13961395
1084,
13971396
1349,
1398-
1349,
13991397
],
14001398
'project:twisted-12.1.0/twisted/web/test/test_wsgi.py':[
14011399
112,

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.sonar.python.api.PythonGrammar;
2828

2929
public class NewSymbolsAnalyzer {
30+
3031
private List<Token> symbols;
3132

3233
public List<Token> getClassFields(AstNode classDef) {
@@ -36,11 +37,18 @@ public List<Token> getClassFields(AstNode classDef) {
3637
List<AstNode> methods = classDef.getFirstChild(PythonGrammar.SUITE).getDescendants(PythonGrammar.FUNCDEF);
3738

3839
for (AstNode method : methods) {
39-
addFieldsInMethod(method);
40+
// ignore any nested class
41+
if (belongToClass(classDef, method)) {
42+
addFieldsInMethod(method);
43+
}
4044
}
4145
return symbols;
4246
}
4347

48+
private static boolean belongToClass(AstNode classDef, AstNode methodOrStmt) {
49+
return classDef.equals(methodOrStmt.getFirstAncestor(PythonGrammar.CLASSDEF, PythonGrammar.FUNCDEF));
50+
}
51+
4452
private void addFieldsInMethod(AstNode method) {
4553
AstNode suite = method.getFirstChild(PythonGrammar.SUITE);
4654
List<AstNode> expressions = suite.getDescendants(PythonGrammar.EXPRESSION_STMT);
@@ -100,12 +108,10 @@ private List<Token> findFieldsInClassBody(AstNode classDef) {
100108
List<AstNode> statements = classDef.getFirstChild(PythonGrammar.SUITE).getChildren(PythonGrammar.STATEMENT);
101109
List<AstNode> expressions = new LinkedList<>();
102110
for (AstNode statement : statements) {
103-
if (!statement.hasDescendant(PythonGrammar.FUNCDEF)) {
104-
expressions.addAll(statement.getDescendants(PythonGrammar.EXPRESSION_STMT));
105-
}
111+
expressions.addAll(statement.getDescendants(PythonGrammar.EXPRESSION_STMT));
106112
}
107113
for (AstNode expression : expressions) {
108-
if (CheckUtils.isAssignmentExpression(expression)) {
114+
if (CheckUtils.isAssignmentExpression(expression) && belongToClass(classDef, expression)) {
109115
addSimpleIdentifiersFromLongAssignmentExpression(expression);
110116
}
111117
}
@@ -117,4 +123,5 @@ public List<Token> getVariablesFromLongAssignmentExpression(List<Token> varNames
117123
addSimpleIdentifiersFromLongAssignmentExpression(expression);
118124
return symbols;
119125
}
126+
120127
}

python-checks/src/test/resources/checks/duplicatedMethodFieldNames.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,34 @@ def GO_DOWN(self): # Noncompliant [[secondary=-2]]
1212
def NAME(self):
1313
pass
1414

15-
NAME = foo(NAME)
15+
NAME = func(NAME)
1616

1717
def NAME(self):
1818
pass
19+
20+
def hello(self):
21+
pass
22+
23+
foo = 1
24+
25+
fOo = 1 # Noncompliant {{Rename field "fOo" to prevent any misunderstanding/clash with field "foo" defined on line 23}}
26+
# ^^^
27+
28+
baz = 100
29+
30+
bat = 1000
31+
32+
class B:
33+
34+
Foo = 1
35+
36+
bar = 10
37+
38+
def __init__(self):
39+
self.baR = 10 # Noncompliant {{Rename field "baR" to prevent any misunderstanding/clash with field "bar" defined on line 36}}
40+
# ^^^
41+
self.baz = 100
42+
self.baT = 1000
43+
44+
def HEllo(self):
45+
pass

python-checks/src/test/resources/checks/fieldDuplicatesClassName.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,16 @@ def fun(self):
1717

1818
class MyClass1(MyClass):
1919
myClass1 = 1
20+
21+
class MyClass:
22+
class B:
23+
myClass = 1
24+
def foo(self):
25+
self.myClass = 1
26+
27+
class MyClass:
28+
if True:
29+
MYCLASS = 1 # Noncompliant
30+
def foo(self):
31+
self.myCLASS = 1 # Noncompliant
32+
myClass = 1 # compliant, local var

python-checks/src/test/resources/checks/fieldName.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,16 @@ def fun(self):
3737
self.Field4 = self.Field5 = 6
3838

3939
class MyClass3(object):
40-
myField = 4 # Noncompliant
40+
myField = 4 # Noncompliant
4141

4242
class MyClass4(MyClass3):
43-
myField = 4
43+
myField = 4
44+
45+
class MyClass5:
46+
class MyClass6:
47+
myField1 = 1 # Noncompliant
48+
49+
class MyClass7:
50+
class MyClass8:
51+
def foo(self):
52+
self.myField2 = 2 # Noncompliant

0 commit comments

Comments
 (0)