-
Notifications
You must be signed in to change notification settings - Fork 94
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-2204 Migrate S5795 IdentityComparisonWithCachedTypesCheck to the new type model #2097
Conversation
774a2e6
to
d4837f0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes on the rule look good.
I'm not fully certain on the changes for the propagation of unary expression as I believe it should probably be done in FlowSensitiveTypeInference
. I also think it would have deserved an explicitly separate ticket.
Small nitpick on the commit history that is not as clean as it could be.
@@ -49,12 +52,40 @@ public class IdentityComparisonWithCachedTypesCheck extends PythonSubscriptionCh | |||
public static final String IS_QUICK_FIX_MESSAGE = "Replace with \"==\""; | |||
public static final String IS_NOT_QUICK_FIX_MESSAGE = "Replace with \"!=\""; | |||
|
|||
/** | |||
* Fully qualified names of constructors and functions that would are guaranteed to create fresh objects with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you didn't add this, but there's a typo here (that would are guaranteed
-> that are guaranteed
). Can you take the opportunity to fix it?
* <code>is</code>-comparison with such a reference will always return <code>False</code>. | ||
* <p> | ||
* Note that these are fully qualified names of (value-level) expressions, not types. | ||
*/ | ||
private static final Set<String> FQNS_CONSTRUCTORS_RETURNING_UNIQUE_REF = new HashSet<>( | ||
asList("frozenset", "bytes", "int", "float", "str", "tuple", "hash")); | ||
private static final List<String> FQNS_CONSTRUCTORS_RETURNING_UNIQUE_REF = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I'm confused to see this being further changed in this propagate unary expressions
commit. I feel it would have been cleaner to squash this with the first commit.
@@ -18,6 +18,9 @@ def literal_comparison(param): | |||
(4, 5) is param # Noncompliant {{Replace this "is" operator with "=="; identity operator is not reliable here.}} | |||
# ^^ | |||
|
|||
param is -1 #Noncompliant |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: We usually add a space # Noncompliant
.
Also, just out of curiosity did you add these cases because of regressions on ruling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it was from a ruling
@@ -152,6 +156,23 @@ public void visitNumericLiteral(NumericLiteral numericLiteral) { | |||
numericLiteralImpl.typeV2(new ObjectType(pythonType, new ArrayList<>(), new ArrayList<>())); | |||
} | |||
|
|||
@Override | |||
public void visitUnaryExpression(UnaryExpression unaryExpr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think by having this in the trivial type inference visitor rather than the flow-sensitive one, you are actually not covering cases such as:
x = 42
y = -x
The trivial type inference visitor is really meant to evaluate the type of trivial expressions that do not depend on control flow, such as builtins or the names of class and function definitions. It is only used for propagation in some cases where "normal" propagation would not lead to the desired result (see SONARPY-2244 and SONARPY-2245 for an example).
Here, the expression -42
has a trivial type only because the expression 42
has a trivial type (INT
), but you don't have a guarantee that the expression for a unary operation will be trivial.
PythonType type = expr.typeV2(); | ||
if (isUnsuitableType(type)) { | ||
if (expr instanceof Name name) { | ||
SymbolV2 symb = name.symbolV2(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the comment and condition below still make sense? I don't think Name#symbolV2
can return null.
5f92243
to
596343c
Compare
As discussed, the way this PR implements the propagation of unary expressions means that only the type of unary literal expressions are properly propagated (e.g. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overall changes look good.
However, I think it would make sense to make intentions a bit clearer.
I'd like you to split this in 3 commits:
- Infer types of unary expressions for literals
- Implement the changes of the rule (keeping the null check for symbols & the test that covers it, but not the ticket references to SONARPY-2259 and SONARPY-2260)
- Document missing symbols for builtins and unassigned variables. (add unit tests in
SymbolTableBuilderV2Test
highlighting SONARPY-2259 and SONARPY-2260).
(Normally, I'd split the 3rd commit if implementing the migration from scratch, but I think the cost of adding it at this point of the PR is rather low)
type(arr) is tuple # see SONARPY-2259 | ||
some_thing is other_thing # see SONARPY-2260 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it makes sense to reference these other tickets here.
I think there is a distinction to be made between:
- A test case added to highlight an unwanted behavior of the rule (e.g FP/FN).
- A test case added to ensure proper test coverage, because of an unrelated limitation.
In the first case, it is normal to reference the ticket that would fix the unwanted behavior. In the second, fixing the ticket will not change the test result anyway, and the reference to the ticket is likely to stay in the code because of that (c.f Michael's comments on our weekly about stale ticket references in our code). Simply having the case for coverage is enough.
That being said, I think it would make sense to have actual frontend tests for our symbol tables (most likely in SymbolTableBuilderV2Test
) that highlight these behaviors and link to a ticket.
@@ -18,6 +18,9 @@ def literal_comparison(param): | |||
(4, 5) is param # Noncompliant {{Replace this "is" operator with "=="; identity operator is not reliable here.}} | |||
# ^^ | |||
|
|||
param is -1 # Noncompliant | |||
param is 1 + 1 #Noncompliant |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Missing space.
PythonType type = expr.typeV2(); | ||
if (isUnsuitableType(type)) { | ||
if (expr instanceof Name name) { | ||
SymbolV2 symbol = name.symbolV2(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name#symbolV2
should probably be annotated @CheckForNull
since it can return null
96fde07
to
2795cfd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. When SONARPY-2275 is merged, I believe this can be rebased, which will make ruling green then this can be merged.
2795cfd
to
cd6581f
Compare
cd6581f
to
08dde75
Compare
|
SONARPY-2204
Part of