1919import org .sonar .check .Rule ;
2020import org .sonar .plugins .python .api .PythonSubscriptionCheck ;
2121import org .sonar .plugins .python .api .SubscriptionContext ;
22+ import org .sonar .plugins .python .api .symbols .Symbol ;
23+ import org .sonar .plugins .python .api .symbols .Usage ;
2224import org .sonar .plugins .python .api .tree .BinaryExpression ;
25+ import org .sonar .plugins .python .api .tree .Expression ;
2326import org .sonar .plugins .python .api .tree .IsExpression ;
27+ import org .sonar .plugins .python .api .tree .Parameter ;
2428import org .sonar .plugins .python .api .tree .Tree ;
2529import org .sonar .plugins .python .api .tree .Tree .Kind ;
2630import org .sonar .plugins .python .api .types .BuiltinTypes ;
2731import org .sonar .plugins .python .api .types .InferredType ;
32+ import org .sonar .python .tree .TreeUtils ;
2833
2934import static org .sonar .python .checks .utils .CheckUtils .isNone ;
3035
@@ -54,8 +59,12 @@ private static void checkEqualityComparison(SubscriptionContext ctx, BinaryExpre
5459 private static void checkIdentityComparison (SubscriptionContext ctx , IsExpression comparison ) {
5560 InferredType left = comparison .leftOperand ().type ();
5661 InferredType right = comparison .rightOperand ().type ();
62+
5763 // `isObject` Removes FP when the return type of a function is an object
58- if (!left .isIdentityComparableWith (right ) && (isNone (left ) || isNone (right )) && !(isObject (left ) || isObject (right ))) {
64+ // `isArgsOrKwargs` Removes FP when *args or **kwargs are used as their type are tuple and dict when type hinted with `Any`.
65+ var isIdentityComparableWith = left .isIdentityComparableWith (right );
66+ var isOperandArgsOrKwargs = isArgsOrKwargs (comparison .leftOperand ()) || isArgsOrKwargs (comparison .rightOperand ());
67+ if (!isIdentityComparableWith && (isNone (left ) || isNone (right )) && !(isObject (left ) || isObject (right )) && !isOperandArgsOrKwargs ) {
5968 addIssue (ctx , comparison , "identity check" , comparison .notToken () != null );
6069 } else if (isNone (left ) && isNone (right )) {
6170 addIssue (ctx , comparison , "identity check" , comparison .notToken () == null );
@@ -75,4 +84,12 @@ private static boolean isObject(InferredType type) {
7584 return type .canOnlyBe (BuiltinTypes .OBJECT_TYPE );
7685 }
7786
87+ private static boolean isArgsOrKwargs (Expression expr ) {
88+ return TreeUtils .getSymbolFromTree (expr ).map (Symbol ::usages )
89+ .map (usages -> usages .stream ().anyMatch (ComparisonToNoneCheck ::isUsedAsArgsOrKwargs )).orElse (false );
90+ }
91+
92+ private static boolean isUsedAsArgsOrKwargs (Usage usage ) {
93+ return usage .tree ().parent () instanceof Parameter parameter && parameter .starToken () != null ;
94+ }
7895}
0 commit comments