|
31 | 31 | import org.sonar.plugins.python.api.tree.ArgList;
|
32 | 32 | import org.sonar.plugins.python.api.tree.AssignmentStatement;
|
33 | 33 | import org.sonar.plugins.python.api.tree.BaseTreeVisitor;
|
| 34 | +import org.sonar.plugins.python.api.tree.BinaryExpression; |
34 | 35 | import org.sonar.plugins.python.api.tree.ClassDef;
|
35 | 36 | import org.sonar.plugins.python.api.tree.DictionaryLiteral;
|
36 | 37 | import org.sonar.plugins.python.api.tree.DottedName;
|
|
44 | 45 | import org.sonar.plugins.python.api.tree.Name;
|
45 | 46 | import org.sonar.plugins.python.api.tree.NoneExpression;
|
46 | 47 | import org.sonar.plugins.python.api.tree.NumericLiteral;
|
| 48 | +import org.sonar.plugins.python.api.tree.Parameter; |
47 | 49 | import org.sonar.plugins.python.api.tree.QualifiedExpression;
|
48 | 50 | import org.sonar.plugins.python.api.tree.RegularArgument;
|
49 | 51 | import org.sonar.plugins.python.api.tree.SetLiteral;
|
50 | 52 | import org.sonar.plugins.python.api.tree.StringLiteral;
|
| 53 | +import org.sonar.plugins.python.api.tree.SubscriptionExpression; |
51 | 54 | import org.sonar.plugins.python.api.tree.Tree;
|
52 | 55 | import org.sonar.plugins.python.api.tree.Tuple;
|
| 56 | +import org.sonar.plugins.python.api.tree.TypeAnnotation; |
53 | 57 | import org.sonar.plugins.python.api.types.InferredType;
|
54 | 58 | import org.sonar.python.semantic.v2.ClassTypeBuilder;
|
55 | 59 | import org.sonar.python.semantic.v2.FunctionTypeBuilder;
|
|
71 | 75 | import org.sonar.python.types.v2.ModuleType;
|
72 | 76 | import org.sonar.python.types.v2.ObjectType;
|
73 | 77 | import org.sonar.python.types.v2.PythonType;
|
| 78 | +import org.sonar.python.types.v2.TypeSource; |
74 | 79 | import org.sonar.python.types.v2.UnionType;
|
75 | 80 |
|
76 | 81 | import static org.sonar.python.semantic.SymbolUtils.pathOf;
|
@@ -114,23 +119,23 @@ public void visitTuple(Tuple tuple) {
|
114 | 119 | }
|
115 | 120 | ModuleType builtins = this.projectLevelTypeTable.getModule();
|
116 | 121 | PythonType tupleType = builtins.resolveMember("tuple").orElse(PythonType.UNKNOWN);
|
117 |
| - ((TupleImpl) tuple).typeV2(new ObjectType(tupleType, attributes, new ArrayList<>())); |
| 122 | + ((TupleImpl) tuple).typeV2(new ObjectType(tupleType, attributes, new ArrayList<>())); |
118 | 123 | }
|
119 | 124 |
|
120 | 125 | @Override
|
121 | 126 | public void visitDictionaryLiteral(DictionaryLiteral dictionaryLiteral) {
|
122 | 127 | super.visitDictionaryLiteral(dictionaryLiteral);
|
123 | 128 | ModuleType builtins = this.projectLevelTypeTable.getModule();
|
124 | 129 | PythonType dictType = builtins.resolveMember("dict").orElse(PythonType.UNKNOWN);
|
125 |
| - ((DictionaryLiteralImpl) dictionaryLiteral).typeV2(new ObjectType(dictType, new ArrayList<>(), new ArrayList<>())); |
| 130 | + ((DictionaryLiteralImpl) dictionaryLiteral).typeV2(new ObjectType(dictType, new ArrayList<>(), new ArrayList<>())); |
126 | 131 | }
|
127 | 132 |
|
128 | 133 | @Override
|
129 | 134 | public void visitSetLiteral(SetLiteral setLiteral) {
|
130 | 135 | super.visitSetLiteral(setLiteral);
|
131 | 136 | ModuleType builtins = this.projectLevelTypeTable.getModule();
|
132 | 137 | PythonType setType = builtins.resolveMember("set").orElse(PythonType.UNKNOWN);
|
133 |
| - ((SetLiteralImpl) setLiteral).typeV2(new ObjectType(setType, new ArrayList<>(), new ArrayList<>())); |
| 138 | + ((SetLiteralImpl) setLiteral).typeV2(new ObjectType(setType, new ArrayList<>(), new ArrayList<>())); |
134 | 139 | }
|
135 | 140 |
|
136 | 141 | @Override
|
@@ -329,6 +334,43 @@ public void visitAssignmentStatement(AssignmentStatement assignmentStatement) {
|
329 | 334 | });
|
330 | 335 | }
|
331 | 336 |
|
| 337 | + @Override |
| 338 | + public void visitParameter(Parameter parameter) { |
| 339 | + scan(parameter.typeAnnotation()); |
| 340 | + scan(parameter.defaultValue()); |
| 341 | + Optional.ofNullable(parameter.typeAnnotation()) |
| 342 | + .map(TypeAnnotation::expression) |
| 343 | + .map(TrivialTypeInferenceVisitor::resolveTypeAnnotationExpressionType) |
| 344 | + .ifPresent(type -> setTypeToName(parameter.name(), type)); |
| 345 | + scan(parameter.name()); |
| 346 | + } |
| 347 | + |
| 348 | + private static PythonType resolveTypeAnnotationExpressionType(Expression expression) { |
| 349 | + if (expression instanceof Name name && name.typeV2() != PythonType.UNKNOWN) { |
| 350 | + return new ObjectType(name.typeV2(), TypeSource.TYPE_HINT); |
| 351 | + } else if (expression instanceof SubscriptionExpression subscriptionExpression && subscriptionExpression.object().typeV2() != PythonType.UNKNOWN) { |
| 352 | + var candidateTypes = subscriptionExpression.subscripts() |
| 353 | + .expressions() |
| 354 | + .stream() |
| 355 | + .map(Expression::typeV2) |
| 356 | + .distinct() |
| 357 | + .toList(); |
| 358 | + |
| 359 | + var elementsType = UnionType.or(candidateTypes); |
| 360 | + |
| 361 | + var attributes = new ArrayList<PythonType>(); |
| 362 | + attributes.add(new ObjectType(elementsType, TypeSource.TYPE_HINT)); |
| 363 | + return new ObjectType(subscriptionExpression.object().typeV2(), attributes, new ArrayList<>(), TypeSource.TYPE_HINT); |
| 364 | + } else if (expression instanceof BinaryExpression binaryExpression) { |
| 365 | + var left = resolveTypeAnnotationExpressionType(binaryExpression.leftOperand()); |
| 366 | + var right = resolveTypeAnnotationExpressionType(binaryExpression.rightOperand()); |
| 367 | + // TODO: we need to make a decision on should here be a union type of object types or an object type of a union type. |
| 368 | + // ATM it is blocked by the generic types resolution redesign |
| 369 | + return UnionType.or(left, right); |
| 370 | + } |
| 371 | + return PythonType.UNKNOWN; |
| 372 | + } |
| 373 | + |
332 | 374 | @Override
|
333 | 375 | public void visitQualifiedExpression(QualifiedExpression qualifiedExpression) {
|
334 | 376 | scan(qualifiedExpression.qualifier());
|
|
0 commit comments