Skip to content

Commit

Permalink
SONARPY-2537 Reproduce changes
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaume-dequenne-sonarsource committed Jan 27, 2025
1 parent 2cb6b04 commit 7c65f17
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,13 @@ private void addSymbolUsage(Name name) {
var scope = currentScope();
var symbol = scope.resolve(name.name());
if (symbol != null && symbol.usages().stream().noneMatch(usage -> usage.tree().equals(name))) {
symbol.addUsage(name, UsageV2.Kind.OTHER);
if (name.parent().is(Tree.Kind.GLOBAL_STMT)) {
symbol.addUsage(name, UsageV2.Kind.GLOBAL_DECLARATION);
} else if (name.parent().is(Tree.Kind.NONLOCAL_STMT)) {
symbol.addUsage(name, UsageV2.Kind.NONLOCAL_DECLARATION);
} else {
symbol.addUsage(name, UsageV2.Kind.OTHER);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ private static Set<SymbolV2> getTrackedVars(Set<SymbolV2> localVariables, Set<Na
boolean hasMissingBindingUsage = variable.usages().stream()
.filter(UsageV2::isBindingUsage)
.anyMatch(u -> !assignedNames.contains(u.tree()));
boolean isGlobal = variable.usages().stream().anyMatch(v -> v.kind().equals(UsageV2.Kind.GLOBAL_DECLARATION));
if (!hasMissingBindingUsage && !isGlobal) {
boolean isGlobalOrNonLocal = variable.usages().stream().anyMatch(v -> v.kind().equals(UsageV2.Kind.GLOBAL_DECLARATION) || v.kind().equals(UsageV2.Kind.NONLOCAL_DECLARATION));
if (!hasMissingBindingUsage && !isGlobalOrNonLocal) {
trackedVars.add(variable);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public enum Kind {
EXCEPTION_INSTANCE,
WITH_INSTANCE,
GLOBAL_DECLARATION,
NONLOCAL_DECLARATION,
PATTERN_DECLARATION,
TYPE_PARAM_DECLARATION,
TYPE_ALIAS_DECLARATION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,58 @@ void global_variable_builtin() {
""").typeV2().unwrappedType()).isEqualTo(PythonType.UNKNOWN);
}

@Test
void global_variable_in_nested_function() {
FileInput fileInput = inferTypes("""
def outer():
a = 24
def nested():
global a
a
""");
var outerFunctionDef = (FunctionDef) fileInput.statements().statements().get(0);
SymbolV2 symbolV2 = ((Name) ((ExpressionStatement) outerFunctionDef.body().statements().get(2)).expressions().get(0)).symbolV2();
assertThat(symbolV2.usages()).extracting(UsageV2::kind).containsExactlyInAnyOrder(UsageV2.Kind.ASSIGNMENT_LHS, UsageV2.Kind.GLOBAL_DECLARATION, UsageV2.Kind.OTHER);
}

@Test
void nonlocal_variable_in_nested_function() {
FileInput fileInput = inferTypes("""
def outer():
a = 24
def nested():
nonlocal a
a
""");
var outerFunctionDef = (FunctionDef) fileInput.statements().statements().get(0);
SymbolV2 symbolV2 = ((Name) ((ExpressionStatement) outerFunctionDef.body().statements().get(2)).expressions().get(0)).symbolV2();
assertThat(symbolV2.usages()).extracting(UsageV2::kind).containsExactlyInAnyOrder(UsageV2.Kind.ASSIGNMENT_LHS, UsageV2.Kind.NONLOCAL_DECLARATION, UsageV2.Kind.OTHER);
}

@Test
void nonlocal_variable_try_except() {
FileInput fileInput = inferTypes("""
def outer():
contains_target = True
def nested(item):
nonlocal contains_target
if cond():
contains_target = contains_target and foo()
try:
return contains_target
except Exception as e:
...
contains_target
""");
var outerFunctionDef = (FunctionDef) fileInput.statements().statements().get(0);
SymbolV2 symbolV2 = ((Name) ((ExpressionStatement) outerFunctionDef.body().statements().get(3)).expressions().get(0)).symbolV2();
assertThat(symbolV2.usages()).extracting(UsageV2::kind).containsExactlyInAnyOrder(
UsageV2.Kind.ASSIGNMENT_LHS, UsageV2.Kind.NONLOCAL_DECLARATION, UsageV2.Kind.ASSIGNMENT_LHS, UsageV2.Kind.OTHER, UsageV2.Kind.OTHER, UsageV2.Kind.OTHER
);
}

@Test
void conditional_assignment() {
PythonType type = lastExpression("""
Expand Down

0 comments on commit 7c65f17

Please sign in to comment.