diff --git a/python-checks/src/main/java/org/sonar/python/checks/IdentityComparisonWithCachedTypesCheck.java b/python-checks/src/main/java/org/sonar/python/checks/IdentityComparisonWithCachedTypesCheck.java
index 26fe377c67..1a026521cc 100644
--- a/python-checks/src/main/java/org/sonar/python/checks/IdentityComparisonWithCachedTypesCheck.java
+++ b/python-checks/src/main/java/org/sonar/python/checks/IdentityComparisonWithCachedTypesCheck.java
@@ -19,9 +19,7 @@
*/
package org.sonar.python.checks;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import org.sonar.check.Rule;
import org.sonar.plugins.python.api.PythonSubscriptionCheck;
import org.sonar.plugins.python.api.SubscriptionContext;
@@ -56,21 +54,21 @@ public class IdentityComparisonWithCachedTypesCheck extends PythonSubscriptionCh
* Fully qualified names of constructors and functions that would are guaranteed to create fresh objects with
* references not shared anywhere else.
*
- * If a reference arises from an call to one of these functions, and it does not escape anywhere else, then an
+ * If a reference arises from a call to one of these functions, and it does not escape anywhere else, then an
* is
-comparison with such a reference will always return False
.
*
* Note that these are fully qualified names of (value-level) expressions, not types.
*/
- private static final Set FQNS_CONSTRUCTORS_RETURNING_UNIQUE_REF = new HashSet<>(
- asList("frozenset", "bytes", "int", "float", "str", "tuple", "hash"));
+ private static final List FQNS_CONSTRUCTORS_RETURNING_UNIQUE_REF =
+ asList("frozenset", "bytes", "int", "float", "str", "tuple", "hash");
/**
* Names of types that usually should not be compared with is
.
*
* Note that these are names of types, not `fqn`s of expressions.
*/
- private static final Set NAMES_OF_TYPES_UNSUITABLE_FOR_COMPARISON = new HashSet<>(
- asList("frozenset", "bytes", "int", "float", "tuple"));
+ private static final List NAMES_OF_TYPES_UNSUITABLE_FOR_COMPARISON =
+ asList("frozenset", "bytes", "int", "float", "tuple");
private TypeChecker typeChecker;
private TypeCheckBuilder isNoneTypeChecker;
@@ -158,9 +156,9 @@ private boolean isUnsuitableType(PythonType type) {
}
private boolean isConstructorReturningUniqueRef(PythonType type) {
- for(String constructorName : FQNS_CONSTRUCTORS_RETURNING_UNIQUE_REF) {
+ for (String constructorName : FQNS_CONSTRUCTORS_RETURNING_UNIQUE_REF) {
TypeCheckBuilder constructorChecker = typeChecker.typeCheckBuilder().isTypeWithName(constructorName);
- if(constructorChecker.check(type) == TriBool.TRUE) {
+ if (constructorChecker.check(type) == TriBool.TRUE) {
return true;
}
}
diff --git a/python-checks/src/test/resources/checks/identityComparisonWithCachedTypes.py b/python-checks/src/test/resources/checks/identityComparisonWithCachedTypes.py
index 58823bea7f..621215fc09 100644
--- a/python-checks/src/test/resources/checks/identityComparisonWithCachedTypes.py
+++ b/python-checks/src/test/resources/checks/identityComparisonWithCachedTypes.py
@@ -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
+
def literal_comparison_compliant(param):
param is param # ok from the point of this rule
param is someUnknownFunction(42) # ok
diff --git a/python-frontend/src/main/java/org/sonar/python/semantic/v2/types/TrivialTypeInferenceVisitor.java b/python-frontend/src/main/java/org/sonar/python/semantic/v2/types/TrivialTypeInferenceVisitor.java
index 8a4027928f..a9f0012f32 100644
--- a/python-frontend/src/main/java/org/sonar/python/semantic/v2/types/TrivialTypeInferenceVisitor.java
+++ b/python-frontend/src/main/java/org/sonar/python/semantic/v2/types/TrivialTypeInferenceVisitor.java
@@ -57,6 +57,7 @@
import org.sonar.plugins.python.api.tree.Tree;
import org.sonar.plugins.python.api.tree.Tuple;
import org.sonar.plugins.python.api.tree.TypeAnnotation;
+import org.sonar.plugins.python.api.tree.UnaryExpression;
import org.sonar.python.semantic.v2.ClassTypeBuilder;
import org.sonar.python.semantic.v2.FunctionTypeBuilder;
import org.sonar.python.semantic.v2.ProjectLevelTypeTable;
@@ -72,6 +73,7 @@
import org.sonar.python.tree.SetLiteralImpl;
import org.sonar.python.tree.StringLiteralImpl;
import org.sonar.python.tree.TupleImpl;
+import org.sonar.python.tree.UnaryExpressionImpl;
import org.sonar.python.types.v2.ClassType;
import org.sonar.python.types.v2.FunctionType;
import org.sonar.python.types.v2.Member;
@@ -152,6 +154,15 @@ public void visitNumericLiteral(NumericLiteral numericLiteral) {
numericLiteralImpl.typeV2(new ObjectType(pythonType, new ArrayList<>(), new ArrayList<>()));
}
+ @Override
+ public void visitUnaryExpression(UnaryExpression unaryExpr) {
+ super.visitUnaryExpression(unaryExpr);
+
+ if(unaryExpr instanceof UnaryExpressionImpl unaryExprImpl) {
+ unaryExprImpl.typeV2(unaryExpr.expression().typeV2());
+ }
+ }
+
@Override
public void visitNone(NoneExpression noneExpression) {
ModuleType builtins = this.projectLevelTypeTable.getBuiltinsModule();
diff --git a/python-frontend/src/main/java/org/sonar/python/tree/UnaryExpressionImpl.java b/python-frontend/src/main/java/org/sonar/python/tree/UnaryExpressionImpl.java
index db001fbed0..dcb67968be 100644
--- a/python-frontend/src/main/java/org/sonar/python/tree/UnaryExpressionImpl.java
+++ b/python-frontend/src/main/java/org/sonar/python/tree/UnaryExpressionImpl.java
@@ -31,6 +31,7 @@
import org.sonar.plugins.python.api.tree.UnaryExpression;
import org.sonar.plugins.python.api.types.InferredType;
import org.sonar.python.types.InferredTypes;
+import org.sonar.python.types.v2.PythonType;
public class UnaryExpressionImpl extends PyTree implements UnaryExpression {
@@ -39,6 +40,7 @@ public class UnaryExpressionImpl extends PyTree implements UnaryExpression {
private final Kind kind;
private final Token operator;
private final Expression expression;
+ private PythonType type = PythonType.UNKNOWN;
private static Map kindsByOperator() {
Map map = new HashMap<>();
@@ -90,4 +92,14 @@ public InferredType type() {
}
return InferredTypes.anyType();
}
+
+ public UnaryExpression typeV2(PythonType type) {
+ this.type = type;
+ return this;
+ }
+
+ @Override
+ public PythonType typeV2() {
+ return type;
+ }
}