|
16 | 16 | */ |
17 | 17 | package org.sonar.plugins.python.api.types.v2; |
18 | 18 |
|
| 19 | +import java.util.HashMap; |
19 | 20 | import java.util.List; |
| 21 | +import java.util.Map; |
20 | 22 | import org.junit.jupiter.api.Disabled; |
21 | 23 | import org.junit.jupiter.api.Test; |
22 | 24 | import org.sonar.plugins.python.api.LocationInFile; |
|
30 | 32 | import org.sonar.python.PythonTestUtils; |
31 | 33 | import org.sonar.python.semantic.SymbolUtils; |
32 | 34 | import org.sonar.python.semantic.v2.ClassTypeBuilder; |
| 35 | +import org.sonar.python.semantic.v2.ProjectLevelTypeTable; |
33 | 36 | import org.sonar.python.semantic.v2.SymbolTableBuilderV2; |
34 | 37 | import org.sonar.python.semantic.v2.SymbolV2; |
35 | 38 | import org.sonar.python.semantic.v2.TypeInferenceV2; |
|
38 | 41 | import static org.assertj.core.api.Assertions.assertThat; |
39 | 42 | import static org.sonar.python.PythonTestUtils.parse; |
40 | 43 | import static org.sonar.python.PythonTestUtils.parseWithoutSymbols; |
| 44 | +import static org.sonar.python.PythonTestUtils.pythonFile; |
| 45 | +import static org.sonar.python.semantic.ProjectLevelSymbolTable.empty; |
41 | 46 | import static org.sonar.python.types.v2.TypesTestUtils.PROJECT_LEVEL_TYPE_TABLE; |
42 | 47 |
|
43 | 48 | public class ClassTypeTest { |
@@ -109,6 +114,45 @@ void multiple_local_parents() { |
109 | 114 | assertThat(classB.superClasses()).extracting(TypeWrapper::type).containsExactlyInAnyOrder(classC, classA); |
110 | 115 | } |
111 | 116 |
|
| 117 | + @Test |
| 118 | + void recursive_inheritance_resolve_member() { |
| 119 | + var classTypes = multiFilesClassTypes(Map.ofEntries( |
| 120 | + Map.entry( |
| 121 | + "a.py", |
| 122 | + """ |
| 123 | + from b import B |
| 124 | + class A(B): ... |
| 125 | + """ |
| 126 | + ), |
| 127 | + Map.entry( |
| 128 | + "b.py", |
| 129 | + """ |
| 130 | + from a import A |
| 131 | + class B(A): ... |
| 132 | + """ |
| 133 | + ) |
| 134 | + ) |
| 135 | + ); |
| 136 | + ClassType classA = classTypes.get("a.A"); |
| 137 | + assertThat(classA.resolveMember("foo")).isEmpty(); |
| 138 | + } |
| 139 | + |
| 140 | + @Test |
| 141 | + void unresolved_inheritance_resolve_member() { |
| 142 | + var classTypes = multiFilesClassTypes(Map.ofEntries( |
| 143 | + Map.entry( |
| 144 | + "a.py", |
| 145 | + """ |
| 146 | + from b import B |
| 147 | + class A(B): ... |
| 148 | + """ |
| 149 | + ) |
| 150 | + ) |
| 151 | + ); |
| 152 | + ClassType classA = classTypes.get("a.A"); |
| 153 | + assertThat(classA.resolveMember("foo")).containsInstanceOf(UnknownType.UnresolvedImportType.class); |
| 154 | + } |
| 155 | + |
112 | 156 | @Test |
113 | 157 | void unknown_parent() { |
114 | 158 | List<ClassType> classTypes = classTypes( |
@@ -611,4 +655,31 @@ public static List<ClassType> classTypes(String... code) { |
611 | 655 | .map(ClassType.class::cast) |
612 | 656 | .toList(); |
613 | 657 | } |
| 658 | + |
| 659 | + public static Map<String, ClassType> multiFilesClassTypes(Map<String, String> filesCodes) { |
| 660 | + var projectSymbolTable = empty(); |
| 661 | + var result = new HashMap<String, ClassType>(); |
| 662 | + |
| 663 | + filesCodes.forEach((fileName, code) -> { |
| 664 | + var fileInput = parseWithoutSymbols(code); |
| 665 | + projectSymbolTable.addModule(fileInput, "", pythonFile(fileName)); |
| 666 | + }); |
| 667 | + |
| 668 | + filesCodes.forEach((fileName, code) -> { |
| 669 | + FileInput fileInput = parseWithoutSymbols(code); |
| 670 | + var symbolTable = new SymbolTableBuilderV2(fileInput) |
| 671 | + .build(); |
| 672 | + |
| 673 | + new TypeInferenceV2(new ProjectLevelTypeTable(projectSymbolTable), pythonFile(fileName), symbolTable, "").inferTypes(fileInput); |
| 674 | + PythonTestUtils.getAllDescendant(fileInput, t -> t.is(Tree.Kind.CLASSDEF)) |
| 675 | + .stream() |
| 676 | + .map(ClassDef.class::cast) |
| 677 | + .map(ClassDef::name) |
| 678 | + .map(Name::typeV2) |
| 679 | + .map(ClassType.class::cast) |
| 680 | + .forEach(ct -> result.put(ct.fullyQualifiedName(), ct)); |
| 681 | + }); |
| 682 | + |
| 683 | + return result; |
| 684 | + } |
614 | 685 | } |
0 commit comments