Skip to content

Commit ac3982b

Browse files
authored
SONARPY-2266 TypeAnnotationToPythonTypeConverter creates nested LazyUnionType (#2222)
1 parent fceee63 commit ac3982b

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

python-frontend/src/main/java/org/sonar/python/types/v2/LazyUnionType.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@
1616
*/
1717
package org.sonar.python.types.v2;
1818

19+
import com.google.common.annotations.VisibleForTesting;
20+
import java.util.Collections;
1921
import java.util.HashSet;
2022
import java.util.Set;
23+
import java.util.stream.Collectors;
24+
import java.util.stream.Stream;
2125

2226
public class LazyUnionType implements PythonType, ResolvableType {
2327

24-
private final Set<PythonType> candidates = new HashSet<>();
28+
private final Set<PythonType> candidates;
2529

2630
public LazyUnionType(Set<PythonType> candidates) {
27-
this.candidates.addAll(candidates);
31+
this.candidates = candidates.stream().flatMap(LazyUnionType::flattenLazyUnionTypes).collect(Collectors.toCollection(HashSet::new));
2832
}
2933

3034
public PythonType resolve() {
@@ -37,4 +41,16 @@ public PythonType resolve() {
3741
}
3842
return UnionType.or(resolvedCandidates);
3943
}
44+
45+
private static Stream<PythonType> flattenLazyUnionTypes(PythonType type) {
46+
if (type instanceof LazyUnionType lazyUnionType) {
47+
return lazyUnionType.candidates.stream();
48+
}
49+
return Stream.of(type);
50+
}
51+
52+
@VisibleForTesting
53+
protected Set<PythonType> candidates() {
54+
return Collections.unmodifiableSet(candidates);
55+
}
4056
}

python-frontend/src/test/java/org/sonar/python/types/v2/LazyUnionTypeTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import java.util.Set;
2020
import org.junit.jupiter.api.Test;
2121
import org.mockito.Mockito;
22+
import org.sonar.python.semantic.ProjectLevelSymbolTable;
2223
import org.sonar.python.semantic.v2.LazyTypesContext;
24+
import org.sonar.python.semantic.v2.ProjectLevelTypeTable;
2325

2426
import static org.assertj.core.api.Assertions.assertThat;
2527
import static org.mockito.Mockito.when;
@@ -37,4 +39,23 @@ void lazyUnionTypeResolvesNestedLazyTypesWhenAccessed() {
3739
UnionType unionType = (UnionType) lazyUnionType.resolve();
3840
assertThat(unionType.candidates()).containsExactlyInAnyOrder(INT_TYPE, FLOAT_TYPE);
3941
}
42+
43+
@Test
44+
void flattened() {
45+
LazyTypesContext lazyTypesContext = Mockito.spy(new LazyTypesContext(new ProjectLevelTypeTable(ProjectLevelSymbolTable.empty())));
46+
47+
var lazyType1 = lazyTypeUnresolved("lazy1", lazyTypesContext);
48+
var lazyType2 = lazyTypeUnresolved("lazy2", lazyTypesContext);
49+
var lazyType3 = lazyTypeUnresolved("lazy3", lazyTypesContext);
50+
51+
var lazyUnionType1 = new LazyUnionType(Set.of(lazyType1, lazyType2, lazyType3));
52+
var lazyUnionType2 = new LazyUnionType(Set.of(lazyType1, lazyType2, lazyType3, lazyUnionType1));
53+
assertThat(lazyUnionType2.candidates()).containsExactlyInAnyOrder(lazyType1, lazyType2, lazyType3);
54+
}
55+
56+
LazyType lazyTypeUnresolved(String name, LazyTypesContext lazyTypesContext) {
57+
var lazyType = lazyTypesContext.getOrCreateLazyType(name);
58+
when(lazyTypesContext.resolveLazyType(lazyType)).thenReturn(new UnknownType.UnresolvedImportType(name));
59+
return lazyType;
60+
}
4061
}

0 commit comments

Comments
 (0)