Skip to content

Commit bd98741

Browse files
UnionType#resolveMember: handle typeclasses with unresolved hierarchies (#677)
1 parent ef4f3bd commit bd98741

File tree

5 files changed

+23
-1
lines changed

5 files changed

+23
-1
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ def builtin_functions():
101101

102102
str.ljust(str(1), 3)
103103

104+
x = {}
105+
x = []
106+
x.pop(())
107+
104108
def type_aliases():
105109
def with_set(a : Set[int]): ...
106110
def with_dict(a : Dict[int, int]): ...

python-frontend/src/main/java/org/sonar/python/semantic/ClassSymbolImpl.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ public void addSuperClass(Symbol symbol) {
8686

8787
@Override
8888
public boolean hasUnresolvedTypeHierarchy() {
89-
for (Symbol superClassSymbol : allSuperClasses(true)) {
89+
return hasUnresolvedTypeHierarchy(true);
90+
}
91+
92+
public boolean hasUnresolvedTypeHierarchy(boolean includeAmbiguousSymbols) {
93+
for (Symbol superClassSymbol : allSuperClasses(includeAmbiguousSymbols)) {
9094
if (superClassSymbol.kind() != Kind.CLASS) {
9195
return true;
9296
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.sonar.plugins.python.api.symbols.ClassSymbol;
2727
import org.sonar.plugins.python.api.symbols.Symbol;
2828
import org.sonar.plugins.python.api.types.InferredType;
29+
import org.sonar.python.semantic.ClassSymbolImpl;
2930

3031
class RuntimeType implements InferredType {
3132

@@ -116,6 +117,10 @@ private Set<String> typeClassMembersFQN() {
116117
return typeClassMembersFQN;
117118
}
118119

120+
boolean hasUnresolvedHierarchy() {
121+
return ((ClassSymbolImpl) typeClass).hasUnresolvedTypeHierarchy(false);
122+
}
123+
119124
@Override
120125
public int hashCode() {
121126
return Objects.hash(typeClass.fullyQualifiedName(), typeClassSuperClassesFQN(), typeClassMembersFQN());

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ public boolean canHaveMember(String memberName) {
7171

7272
@Override
7373
public Optional<Symbol> resolveMember(String memberName) {
74+
if (types.stream().anyMatch(type -> type instanceof RuntimeType && ((RuntimeType) type).hasUnresolvedHierarchy())) {
75+
return Optional.empty();
76+
}
7477
Set<Optional<Symbol>> resolved = types.stream()
7578
.map(t -> t.resolveMember(memberName))
7679
.filter(Optional::isPresent)

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121

2222
import java.util.Arrays;
2323
import java.util.Collections;
24+
import java.util.HashSet;
2425
import org.junit.Test;
2526
import org.sonar.plugins.python.api.types.InferredType;
27+
import org.sonar.python.semantic.AmbiguousSymbolImpl;
2628
import org.sonar.python.semantic.ClassSymbolImpl;
2729
import org.sonar.python.semantic.SymbolImpl;
2830

@@ -80,6 +82,10 @@ public void resolveMember() {
8082
assertThat(or(runtimeType(x), runtimeType(y)).resolveMember("foo")).contains(foo);
8183
assertThat(or(runtimeType(x), runtimeType(z)).resolveMember("bar")).isEmpty();
8284
assertThat(or(runtimeType(x), runtimeType(z)).resolveMember("xxx")).isEmpty();
85+
86+
ClassSymbolImpl classWithUnresolvedHierarchy = new ClassSymbolImpl("u", "u");
87+
classWithUnresolvedHierarchy.addSuperClass(AmbiguousSymbolImpl.create(new HashSet<>(Arrays.asList(x, new ClassSymbolImpl("x", "x")))));
88+
assertThat(or(runtimeType(x), runtimeType(classWithUnresolvedHierarchy)).resolveMember("foo")).isEmpty();
8389
}
8490

8591
@Test

0 commit comments

Comments
 (0)