Skip to content

Commit c613e9b

Browse files
Seppli11sonartech
authored andcommitted
SONARPY-3600 Prevent Types from TrivialTypeInferenceVisistor leaking into the ProjectLevelTypeTable (#749)
GitOrigin-RevId: caf3181d7d653489069d875def0d67b77ce488e0
1 parent 43f74d4 commit c613e9b

File tree

4 files changed

+17
-16
lines changed

4 files changed

+17
-16
lines changed

python-frontend/src/main/java/org/sonar/plugins/python/api/types/v2/ModuleType.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,6 @@ public ModuleType(@Nullable String name,
4242
this.parent = parent;
4343
this.members = members;
4444
this.subModules = new ConcurrentHashMap<>();
45-
registerAsSubmoduleOfParent(parent);
46-
}
47-
48-
private void registerAsSubmoduleOfParent(@Nullable ModuleType parent) {
49-
if (parent == null) {
50-
return;
51-
}
52-
parent.subModules.putIfAbsent(this.name, TypeWrapper.of(this));
5345
}
5446

5547
public ModuleType(@Nullable String name) {
@@ -66,6 +58,10 @@ public ModuleType(@Nullable String name,
6658
this(name, null, parent, members);
6759
}
6860

61+
public void registerSubmodule(ModuleType submodule) {
62+
subModules.putIfAbsent(submodule.name(), TypeWrapper.of(submodule));
63+
}
64+
6965
@Override
7066
public Optional<PythonType> resolveMember(String memberName) {
7167
return Optional.ofNullable(members.get(memberName)).map(TypeWrapper::type).or(() -> resolveSubmodule(memberName));

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ public PythonType convertModuleType(List<String> moduleFqn, ModuleType parent) {
6666
var moduleFqnString = getModuleFqnString(moduleFqn);
6767
Optional<ModuleType> result = createModuleTypeFromProjectLevelSymbolTable(moduleName, moduleFqnString, parent)
6868
.or(() -> createModuleTypeFromTypeShed(moduleName, moduleFqnString, parent));
69+
6970
if (result.isEmpty()) {
7071
return PythonType.UNKNOWN;
7172
}
72-
return result.get();
73+
var moduleType = result.get();
74+
parent.registerSubmodule(moduleType);
75+
return moduleType;
7376
}
7477

7578
private static String getModuleFqnString(List<String> moduleFqn) {

python-frontend/src/test/java/org/sonar/plugins/python/api/types/v2/ModuleTypeTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void constructorTest() {
2929
var b = new ModuleType("b", "a.b", a, new HashMap<>());
3030

3131
Assertions.assertThat(b.fullyQualifiedName()).isEqualTo("a.b");
32-
Assertions.assertThat(a.resolveMember("b")).containsSame(b);
32+
Assertions.assertThat(a.resolveMember("b")).isEmpty();
3333
}
3434

3535
@Test
@@ -49,6 +49,7 @@ void replaceMemberIfUnknown() {
4949
a.members().put("b", TypeWrapper.UNKNOWN_TYPE_WRAPPER);
5050
Assertions.assertThat(a.resolveMember("b")).containsSame(PythonType.UNKNOWN);
5151
var b = new ModuleType("b", a);
52+
a.registerSubmodule(b);
5253
Assertions.assertThat(a.resolveMember("b")).containsSame(PythonType.UNKNOWN);
5354
Assertions.assertThat(a.resolveSubmodule("b")).containsSame(b);
5455
}
@@ -69,6 +70,7 @@ void registerAsSubmoduleTest() {
6970
a.members().put("b", TypeWrapper.UNKNOWN_TYPE_WRAPPER);
7071
Assertions.assertThat(a.resolveSubmodule("b")).isEmpty();
7172
var b = new ModuleType("b", a, Map.of());
73+
a.registerSubmodule(b);
7274
Assertions.assertThat(a.resolveMember("b")).containsSame(PythonType.UNKNOWN);
7375
Assertions.assertThat(a.resolveSubmodule("b")).containsSame(b);
7476
// no parent: no effect
@@ -79,8 +81,10 @@ void registerAsSubmoduleTest() {
7981
void doNotReplaceKnownSubmodule() {
8082
var a = new ModuleType("a");
8183
ModuleType existingSubmodule = new ModuleType("b", a, Map.of());
84+
a.registerSubmodule(existingSubmodule);
8285
Assertions.assertThat(a.resolveSubmodule("b")).containsSame(existingSubmodule);
83-
new ModuleType("b", a, Map.of());
86+
var b = new ModuleType("b", a, Map.of());
87+
a.registerSubmodule(b);
8488
Assertions.assertThat(a.resolveSubmodule("b")).containsSame(existingSubmodule);
8589
}
8690

python-frontend/src/test/java/org/sonar/python/semantic/v2/TypeInferenceV2Test.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
import org.sonar.python.tree.TreeUtils;
8787
import org.sonar.python.tree.TupleImpl;
8888
import org.sonar.python.types.v2.LazyType;
89-
import org.sonar.python.types.v2.SimpleTypeWrapper;
89+
import org.sonar.python.types.v2.LazyTypeWrapper;
9090

9191
import static org.assertj.core.api.Assertions.assertThat;
9292
import static org.sonar.python.PythonTestUtils.getFirstDescendant;
@@ -4891,6 +4891,7 @@ class SuperClass: ...
48914891
class AClass(SuperClass):
48924892
...
48934893
""";
4894+
project.addModule("package/finalModule.py", finalModuleCode);
48944895
PythonFile finalModulePythonFile = pythonFile("finalModule.py");
48954896
new PythonVisitorContext.Builder(project.inferTypes(finalModuleCode), finalModulePythonFile)
48964897
.typeTable(project.projectLevelTypeTable())
@@ -4902,10 +4903,7 @@ class AClass(SuperClass):
49024903
assertThat(bType).isInstanceOfSatisfying(ClassType.class, classType -> {
49034904
assertThat(classType.superClasses())
49044905
.satisfies(typeWrapper -> assertThat(typeWrapper)
4905-
// This should be a LazyTypeWrapper because the ClassDescriptorToPythonTypeConverter
4906-
// will create a LazyTypeWrapper for the super class.
4907-
// See SONARPY-3600
4908-
.isInstanceOf(SimpleTypeWrapper.class), Index.atIndex(0));
4906+
.isInstanceOf(LazyTypeWrapper.class), Index.atIndex(0));
49094907
});
49104908
}
49114909
}

0 commit comments

Comments
 (0)