Skip to content

Commit 6b0ca3d

Browse files
Seppli11sonartech
authored andcommitted
SONARPY-3535 Make typing.Any resolve to unknown (#692)
GitOrigin-RevId: 3654d801b7adbe525d24064a4cdfa063aea20d66
1 parent 8bf1fe5 commit 6b0ca3d

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@
2020
import java.util.Map;
2121
import java.util.Optional;
2222
import java.util.stream.Collectors;
23-
import org.sonar.python.index.Descriptor;
24-
import org.sonar.python.semantic.ProjectLevelSymbolTable;
25-
import org.sonar.python.semantic.v2.converter.AnyDescriptorToPythonTypeConverter;
2623
import org.sonar.plugins.python.api.types.v2.ModuleType;
2724
import org.sonar.plugins.python.api.types.v2.PythonType;
2825
import org.sonar.plugins.python.api.types.v2.TypeOrigin;
2926
import org.sonar.plugins.python.api.types.v2.TypeWrapper;
27+
import org.sonar.python.index.Descriptor;
28+
import org.sonar.python.semantic.ProjectLevelSymbolTable;
29+
import org.sonar.python.semantic.v2.converter.AnyDescriptorToPythonTypeConverter;
30+
import org.sonar.python.semantic.v2.dynamicstubs.DynamicStubsProvider;
3031

3132
public class SymbolsModuleTypeProvider {
3233
private final ProjectLevelSymbolTable projectLevelSymbolTable;
@@ -94,6 +95,7 @@ private Optional<ModuleType> createModuleTypeFromTypeShed(String moduleName, Str
9495
}
9596

9697
private ModuleType createModuleType(String moduleName, String moduleFqn, ModuleType parent, Map<String, TypeWrapper> members) {
98+
members.putAll(DynamicStubsProvider.createDynamicStubs(moduleFqn));
9799
addTypingAliases(moduleFqn, members);
98100
return new ModuleType(moduleName, moduleFqn, parent, members);
99101
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* SonarQube Python Plugin
3+
* Copyright (C) 2011-2025 SonarSource Sàrl
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the Sonar Source-Available License for more details.
13+
*
14+
* You should have received a copy of the Sonar Source-Available License
15+
* along with this program; if not, see https://sonarsource.com/license/ssal/
16+
*/
17+
package org.sonar.python.semantic.v2.dynamicstubs;
18+
19+
import java.util.Map;
20+
import org.sonar.plugins.python.api.types.v2.PythonType;
21+
import org.sonar.plugins.python.api.types.v2.TypeWrapper;
22+
23+
public class DynamicStubsProvider {
24+
25+
private DynamicStubsProvider() {
26+
}
27+
28+
public static Map<String, TypeWrapper> createDynamicStubs(String moduleFqn) {
29+
return switch (moduleFqn) {
30+
case "typing" -> typingDynamicStubs();
31+
default -> Map.of();
32+
};
33+
}
34+
35+
/**
36+
* A lot of the types exported by the typing module need a special representation in the internal type system.
37+
* Furthermore, mypy isn't able to analyze moduels called "typing", as it clashes internally with the standard
38+
* library's typing module (see https://github.com/python/mypy/issues/1876). As a result, this function allows us
39+
* to create the proper special types for the typing module.
40+
*
41+
* @return a map of the stubs for the typing module
42+
*/
43+
private static Map<String, TypeWrapper> typingDynamicStubs() {
44+
return Map.of(
45+
// Every type is compatible with Any, and Any is compatible with every type. This is represented as UNKNOWN in PythonType
46+
"Any", TypeWrapper.of(PythonType.UNKNOWN));
47+
}
48+
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4069,4 +4069,22 @@ def foo((a, b)):
40694069
var fooMethodDef = (FunctionDef) classDef.body().statements().get(0);
40704070
assertThat(fooMethodDef.name().typeV2()).isInstanceOf(FunctionType.class);
40714071
}
4072+
4073+
@Test
4074+
void anyResolvesToUnknown() {
4075+
Expression anyExpression = lastExpression("""
4076+
from typing import Any
4077+
Any
4078+
""");
4079+
assertThat(anyExpression.typeV2()).isEqualTo(PythonType.UNKNOWN);
4080+
}
4081+
4082+
@Test
4083+
void typingExtensionsAnyResolvesToUnknown() {
4084+
Expression anyExpression = lastExpression("""
4085+
from typing_extensions import Any
4086+
Any
4087+
""");
4088+
assertThat(anyExpression.typeV2()).isEqualTo(PythonType.UNKNOWN);
4089+
}
40724090
}

0 commit comments

Comments
 (0)