Skip to content

Commit 02ead7a

Browse files
SONARPY-557: Fix FP on S3827 when modules manipulate __all__ property (#562)
1 parent d23b808 commit 02ead7a

6 files changed

Lines changed: 30 additions & 0 deletions

File tree

python-checks-testkit/src/main/java/org/sonar/python/checks/utils/PythonCheckVerifier.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ public static void verify(List<String> paths, PythonCheck check) {
7575
createVerifier(files, check, globalSymbolsPerModule, baseDirFile).assertOneOrMoreIssues();
7676
}
7777

78+
public static void verifyNoIssue(List<String> paths, PythonCheck check) {
79+
List<File> files = paths.stream().map(File::new).collect(Collectors.toList());
80+
File baseDirFile = new File(files.get(0).getParent());
81+
Map<String, Set<Symbol>> globalSymbolsPerModule = TestPythonVisitorRunner.globalSymbols(files, baseDirFile);
82+
createVerifier(files, check, globalSymbolsPerModule, baseDirFile).assertNoIssues();
83+
}
84+
7885
private static MultiFileVerifier createVerifier(List<File> files, PythonCheck check, Map<String, Set<Symbol>> globalSymbolsPerModule, @Nullable File baseDir) {
7986
MultiFileVerifier multiFileVerifier = MultiFileVerifier.create(files.get(0).toPath(), UTF_8);
8087
for (File file : files) {

python-checks-testkit/src/test/java/org/sonar/python/checks/utils/PythonCheckVerifierAdditionalTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package org.sonar.python.checks.utils;
2121

22+
import java.util.Collections;
2223
import org.assertj.core.api.Assertions;
2324
import org.junit.Test;
2425
import org.sonar.plugins.python.api.PythonSubscriptionCheck;
@@ -57,6 +58,7 @@ public void initialize(Context context) {
5758
}
5859
};
5960
PythonCheckVerifier.verifyNoIssue(BASE_DIR + "no_issue.py", check);
61+
PythonCheckVerifier.verifyNoIssue(Collections.singletonList(BASE_DIR + "no_issue.py"), check);
6062

6163
try {
6264
PythonCheckVerifier.verifyNoIssue(BASE_DIR + "file_issue.py", check);

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public class UndeclaredNameUsageCheck extends PythonSubscriptionCheck {
5050
public void initialize(Context context) {
5151
context.registerSyntaxNodeConsumer(Tree.Kind.FILE_INPUT, ctx -> {
5252
FileInput fileInput = (FileInput) ctx.syntaxNode();
53+
if (importsManipulatedAllProperty(fileInput)) {
54+
return;
55+
}
5356
UnresolvedSymbolsVisitor unresolvedSymbolsVisitor = new UnresolvedSymbolsVisitor();
5457
fileInput.accept(unresolvedSymbolsVisitor);
5558
if (!unresolvedSymbolsVisitor.callGlobalsOrLocals && !unresolvedSymbolsVisitor.hasUnresolvedWildcardImport) {
@@ -73,6 +76,10 @@ public void initialize(Context context) {
7376
});
7477
}
7578

79+
private static boolean importsManipulatedAllProperty(FileInput fileInput) {
80+
return fileInput.globalVariables().stream().anyMatch(s -> s.name().equals("__all__") && s.fullyQualifiedName() != null);
81+
}
82+
7683
private static void checkCfgBlock(CfgBlock cfgBlock, SubscriptionContext ctx, DefinedVariables definedVariables,
7784
Set<CfgBlock> unreachableBlocks, DefinedVariablesAnalysis analysis, List<Symbol> ignoredSymbols) {
7885
Map<Symbol, DefinedVariablesAnalysis.VariableDefinition> currentState = new HashMap<>(definedVariables.getIn());

python-checks/src/test/java/org/sonar/python/checks/UndeclaredNameUsageCheckTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ public void test_wildcard_import() {
3737
new UndeclaredNameUsageCheck());
3838
}
3939

40+
@Test
41+
public void test_wildcard_import_all_property() {
42+
PythonCheckVerifier.verifyNoIssue(
43+
Arrays.asList("src/test/resources/checks/undeclaredNameUsageImportWithAll.py", "src/test/resources/checks/undeclaredNameUsageAll/__init__.py"),
44+
new UndeclaredNameUsageCheck());
45+
}
46+
4047
@Test
4148
public void test_unresolved_wildcard_import() {
4249
PythonCheckVerifier.verifyNoIssue("src/test/resources/checks/undeclaredNameUsageWithUnresolvedWildcardImport.py", new UndeclaredNameUsageCheck());
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# mod.py
2+
def get_exported():
3+
def f(): pass
4+
return f
5+
__all__ = get_exported()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from undeclaredNameUsageAll import *
2+
f() # OK

0 commit comments

Comments
 (0)