Skip to content

Commit f662efa

Browse files
SONARPY-773 Add type names for Union types
1 parent 8c899a0 commit f662efa

5 files changed

Lines changed: 10 additions & 6 deletions

File tree

python-checks/src/test/resources/checks/incompatibleOperands/comparison.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def builtin_noncompliant(p):
1010
x = 42
1111
else:
1212
x = complex(1)
13-
x > "1" # Noncompliant {{Fix this invalid ">" operation between incompatible types.}}
13+
x > "1" # Noncompliant {{Fix this invalid ">" operation between incompatible types (Union[int, complex] and str).}}
1414
"1" < x # Noncompliant
1515

1616

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def call_noncallable(p):
3737
x = 42
3838
else:
3939
x = 'str'
40-
x() # Noncompliant {{Fix this call; "x" is not callable.}}
40+
x() # Noncompliant {{Fix this call; "x" has type Union[int, str] and it is not callable.}}
4141

4242
def flow_sensitivity():
4343
my_var = "hello"

python-frontend/src/main/java/org/sonar/python/types/InferredTypes.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
import java.util.Collections;
2424
import java.util.HashMap;
2525
import java.util.HashSet;
26+
import java.util.LinkedHashSet;
2627
import java.util.List;
2728
import java.util.Map;
2829
import java.util.Set;
30+
import java.util.stream.Collectors;
2931
import java.util.stream.Stream;
3032
import javax.annotation.CheckForNull;
3133
import javax.annotation.Nullable;
@@ -164,7 +166,7 @@ public static Collection<ClassSymbol> typeSymbols(InferredType inferredType) {
164166
return Collections.singleton(((RuntimeType) inferredType).getTypeClass());
165167
}
166168
if (inferredType instanceof UnionType) {
167-
Set<ClassSymbol> typeClasses = new HashSet<>();
169+
Set<ClassSymbol> typeClasses = new LinkedHashSet<>();
168170
((UnionType) inferredType).types().forEach(type -> typeClasses.addAll(typeSymbols(type)));
169171
return typeClasses;
170172
}
@@ -176,6 +178,8 @@ public static String typeName(InferredType inferredType) {
176178
Collection<ClassSymbol> typeClasses = typeSymbols(inferredType);
177179
if (typeClasses.size() == 1) {
178180
return typeClasses.iterator().next().name();
181+
} else if (typeClasses.size() > 1) {
182+
return "Union[" + typeClasses.stream().map(ClassSymbol::name).collect(Collectors.joining(", ")) + "]";
179183
}
180184
return null;
181185
}

python-frontend/src/main/java/org/sonar/python/types/UnionType.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
package org.sonar.python.types;
2121

2222
import java.util.Collections;
23-
import java.util.HashSet;
23+
import java.util.LinkedHashSet;
2424
import java.util.Objects;
2525
import java.util.Optional;
2626
import java.util.Set;
@@ -45,7 +45,7 @@ public static InferredType or(InferredType type1, InferredType type2) {
4545
if (type1.equals(type2)) {
4646
return type1;
4747
}
48-
Set<InferredType> types = new HashSet<>();
48+
Set<InferredType> types = new LinkedHashSet<>();
4949
addTypes(type1, types);
5050
addTypes(type2, types);
5151
return new UnionType(types);

python-frontend/src/test/java/org/sonar/python/types/InferredTypesTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public void test_typeName() {
145145
ClassSymbol a = new ClassSymbolImpl("A", "mod.A");
146146
assertThat(InferredTypes.typeName(new RuntimeType(a))).isEqualTo("A");
147147

148-
assertThat(InferredTypes.typeName(or(STR, INT))).isNull();
148+
assertThat(InferredTypes.typeName(or(STR, INT))).isEqualTo("Union[str, int]");
149149
assertThat(InferredTypes.typeName(InferredTypes.anyType())).isNull();
150150
}
151151

0 commit comments

Comments
 (0)