Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SONARPY-2366 Propagate binary expressions of the same type #2216

Merged
merged 2 commits into from
Dec 6, 2024

Conversation

maksim-grebeniuk-sonarsource
Copy link
Contributor

@maksim-grebeniuk-sonarsource maksim-grebeniuk-sonarsource commented Dec 5, 2024

@maksim-grebeniuk-sonarsource maksim-grebeniuk-sonarsource force-pushed the SONARPY-2366 branch 6 times, most recently from 175bd8b to e6767e0 Compare December 5, 2024 12:41
Copy link
Contributor

@Seppli11 Seppli11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overall implementation looks good. However, I've left some comments and thoughts.

&& rightOperand.typeV2() instanceof ObjectType rightObjectType
&& rightObjectType.unwrappedType() instanceof ClassType rightClassType
&& leftClassType == rightClassType) {
return new ObjectType(leftClassType, TypeSource.min(leftObjectType.typeSource(), rightObjectType.typeSource()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't the ObjectType have attributes or members which would get lost here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed - there is no generic way of transfer the rest of type attributes for the binary expression result calculation

import org.sonar.plugins.python.api.tree.Tree;
import org.sonar.python.types.HasTypeDependencies;

public class TypeDependenciesCalculator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of a TypeDependenciesCalculator as it helps splitting type inference and the types from the AST and reduces the complexity of inheritance. I wonder though, if it makes sense to keep the HasTypeDependencies interface around. It leaves AST nodes which have their logic implemented in this class in a weird place.

Case in point, BinaryExpressionImpl implements HasTypeDependencies and has an implementation of HasTypeDependencies#typeDependencies(), but that method will never be called.
Alternatively, the BinaryExpressionImpl#typeDependencies() could throw an exception, but that goes against all OOP wisdom. Finally, the BinaryExpressionImpl could simply not implement HasTypeDependencies, but conceptially, that would be strange. As a reader, I would expect a binary expression to have type dependencies.

To summaries, I feel that, either, we should get rid of HasTypeDependencies entirely and move everything here, or move the implementation of getTypeDependencies() for BinaryExpression to BinaryExpressionImpl (along with the SAME_TYPE_PRODUCING_BINARY_EXPRESSION_KINDS)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, having thought about this a bit more, maybe TypeDependenciesCalculator could be a TreeVisistor, which calculates the dependencies of a given Tree

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tree visitor is not needed here (discussed)

} else if (e instanceof HasTypeDependencies hasTypeDependencies) {
workList.addAll(hasTypeDependencies.typeDependencies());
} else if (typeDependenciesCalculator.hasTypeDependencies(e)) {
workList.addAll(typeDependenciesCalculator.getTypeDependencies(e));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TypeInference.Propagation#computeDependencies(...) also calls HasTypeDependencies#typeDependencies(). It probably should also use the TypeDependenciesCalculator

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to affect the v1 type inference

@ParameterizedTest
@MethodSource("binaryExpressionsSource")
void binaryExpressionTest(String code, PythonType expectedType) {
assertThat(lastExpression(code).typeV2()).isInstanceOf(ObjectType.class).extracting(PythonType::unwrappedType).isEqualTo(expectedType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have negative tests. For example to check if 1 + 2.0 is UNKNOWN.

Copy link
Contributor

@Seppli11 Seppli11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the effort. LGTM!

@maksim-grebeniuk-sonarsource maksim-grebeniuk-sonarsource merged commit 5a9201b into master Dec 6, 2024
12 checks passed
@maksim-grebeniuk-sonarsource maksim-grebeniuk-sonarsource deleted the SONARPY-2366 branch December 6, 2024 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants