Skip to content

Commit 9b3cd26

Browse files
SONARPY-1794 Avoid inferring types for global variables (#1771)
* SONARPY-1794 Avoid inferring types for global variables * Update ruling expectations
1 parent f8c6c2a commit 9b3cd26

File tree

4 files changed

+31
-32
lines changed

4 files changed

+31
-32
lines changed

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

Lines changed: 0 additions & 14 deletions
This file was deleted.

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,5 +203,11 @@ def assigning_global(my_func):
203203
some_global_func = my_func
204204

205205
def calling_global_func():
206-
# FP
207-
some_global_func() # Noncompliant
206+
some_global_func() # OK
207+
208+
209+
some_nonlocal_var = 42
210+
211+
def using_nonlocal_var():
212+
nonlocal some_nonlocal_var
213+
some_nonlocal_var() # Noncompliant

python-frontend/src/main/java/org/sonar/python/semantic/v2/SymbolTableBuilderV2.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ public void visitAssignmentExpression(AssignmentExpression assignmentExpression)
347347

348348
@Override
349349
public void visitGlobalStatement(GlobalStatement globalStatement) {
350-
// FIXME: handle global statements
351-
350+
// Global statements are not binding usages, but we consider them as such for symbol creation
351+
globalStatement.variables().forEach(name -> moduleScope.addBindingUsage(name, UsageV2.Kind.GLOBAL_DECLARATION, null));
352352
super.visitGlobalStatement(globalStatement);
353353
}
354354

python-frontend/src/main/java/org/sonar/python/semantic/v2/TypeInferenceV2.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.sonar.python.semantic.v2;
2121

2222
import java.util.ArrayDeque;
23+
import java.util.ArrayList;
2324
import java.util.Collection;
2425
import java.util.Deque;
2526
import java.util.List;
@@ -278,20 +279,26 @@ public void visitQualifiedExpression(QualifiedExpression qualifiedExpression) {
278279

279280
@Override
280281
public void visitName(Name name) {
281-
var type = Optional.of(name)
282-
.map(Name::symbolV2)
283-
.map(SymbolV2::usages)
284-
.stream()
285-
.flatMap(Collection::stream)
286-
.filter(UsageV2::isBindingUsage)
287-
.map(UsageV2::tree)
288-
.filter(Expression.class::isInstance)
289-
.map(Expression.class::cast)
290-
.map(Expression::typeV2)
291-
.toList();
292-
293-
if (type.size() == 1) {
294-
setTypeToName(name, type.get(0));
282+
SymbolV2 symbolV2 = name.symbolV2();
283+
if (symbolV2 == null) {
284+
return;
285+
}
286+
List<PythonType> types = new ArrayList<>();
287+
for (UsageV2 usage : symbolV2.usages()) {
288+
if (usage.kind().equals(UsageV2.Kind.GLOBAL_DECLARATION)) {
289+
// Don't infer type for global variables
290+
return;
291+
}
292+
Optional.of(usage)
293+
.filter(UsageV2::isBindingUsage)
294+
.map(UsageV2::tree)
295+
.filter(Expression.class::isInstance)
296+
.map(Expression.class::cast)
297+
.map(Expression::typeV2)
298+
.ifPresent(types::add);
299+
}
300+
if (types.size() == 1) {
301+
setTypeToName(name, types.get(0));
295302
}
296303
}
297304

0 commit comments

Comments
 (0)