Skip to content

Commit 551b34f

Browse files
sonar-nigel[bot]Vibe Bot
authored andcommitted
SONARPY-1806 Fix false positive in S6730 when using np.bool (SONARPY-1806) (#983)
Co-authored-by: Vibe Bot <vibe-bot@sonarsource.com> GitOrigin-RevId: 051c750045a94da4a13324b89eba55d9d2ea1c3a
1 parent 68ecb38 commit 551b34f

File tree

3 files changed

+32
-22
lines changed

3 files changed

+32
-22
lines changed

python-checks/src/main/java/org/sonar/python/checks/DeprecatedNumpyTypesCheck.java

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,33 @@
1616
*/
1717
package org.sonar.python.checks;
1818

19-
import java.util.Map;
20-
import java.util.Optional;
19+
import java.util.List;
2120
import org.sonar.check.Rule;
2221
import org.sonar.plugins.python.api.PythonSubscriptionCheck;
2322
import org.sonar.plugins.python.api.SubscriptionContext;
2423
import org.sonar.plugins.python.api.quickfix.PythonQuickFix;
25-
import org.sonar.plugins.python.api.symbols.Symbol;
2624
import org.sonar.plugins.python.api.tree.QualifiedExpression;
2725
import org.sonar.plugins.python.api.tree.Tree;
26+
import org.sonar.plugins.python.api.types.v2.matchers.TypeMatcher;
27+
import org.sonar.plugins.python.api.types.v2.matchers.TypeMatchers;
2828
import org.sonar.python.quickfix.TextEditUtils;
2929

3030
@Rule(key = "S6730")
3131
public class DeprecatedNumpyTypesCheck extends PythonSubscriptionCheck {
3232

3333
private static final String MESSAGE = "Replace this deprecated \"numpy\" type alias with the builtin type \"%s\".";
3434
private static final String QUICK_FIX_MESSAGE = "Replace with %s.";
35-
private static final Map<String, String> TYPE_TO_CHECK = Map.of(
36-
"numpy.bool", "bool",
37-
"numpy.int", "int",
38-
"numpy.float", "float",
39-
"numpy.complex", "complex",
40-
"numpy.object", "object",
41-
"numpy.str", "str",
42-
"numpy.long", "int",
43-
"numpy.unicode", "str");
35+
36+
private record DeprecatedType(TypeMatcher matcher, String replacement) {}
37+
38+
private static final List<DeprecatedType> DEPRECATED_TYPES = List.of(
39+
new DeprecatedType(TypeMatchers.withFQN("numpy.int"), "int"),
40+
new DeprecatedType(TypeMatchers.withFQN("numpy.float"), "float"),
41+
new DeprecatedType(TypeMatchers.withFQN("numpy.complex"), "complex"),
42+
new DeprecatedType(TypeMatchers.withFQN("numpy.object"), "object"),
43+
new DeprecatedType(TypeMatchers.withFQN("numpy.str"), "str"),
44+
new DeprecatedType(TypeMatchers.withFQN("numpy.long"), "int"),
45+
new DeprecatedType(TypeMatchers.withFQN("numpy.unicode"), "str"));
4446

4547
@Override
4648
public void initialize(Context context) {
@@ -50,13 +52,15 @@ public void initialize(Context context) {
5052

5153
private static void checkForDeprecatedTypesNames(SubscriptionContext ctx) {
5254
QualifiedExpression expression = (QualifiedExpression) ctx.syntaxNode();
53-
Optional.ofNullable(expression.symbol())
54-
.map(Symbol::fullyQualifiedName)
55-
.map(TYPE_TO_CHECK::get)
56-
.ifPresent(type -> raiseIssue(expression, type, ctx));
55+
for (DeprecatedType deprecatedType : DEPRECATED_TYPES) {
56+
if (deprecatedType.matcher().isTrueFor(expression, ctx)) {
57+
raiseIssue(expression, deprecatedType.replacement(), ctx);
58+
return;
59+
}
60+
}
5761
}
5862

59-
private static void raiseIssue(Tree expression, String replacementType, SubscriptionContext ctx) {
63+
private static void raiseIssue(QualifiedExpression expression, String replacementType, SubscriptionContext ctx) {
6064
PreciseIssue issue = ctx.addIssue(expression, String.format(MESSAGE, replacementType));
6165
PythonQuickFix quickFix = PythonQuickFix.newQuickFix(
6266
String.format(QUICK_FIX_MESSAGE, replacementType),

python-checks/src/test/java/org/sonar/python/checks/DeprecatedNumpyTypesCheckTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ def foo():
5555

5656
private static Stream<Arguments> numpyTypeProvider(){
5757
return Stream.of(
58-
Arguments.of("np.bool", "(True)", "bool"),
5958
Arguments.of("np.int", "(42)", "int"),
6059
Arguments.of("np.float", "(4.2)", "float"),
6160
Arguments.of("np.complex", "(-2.0, -1.2)", "complex"),

python-checks/src/test/resources/checks/deprecatedNumpyTypesCheck.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33

44
def failure():
5-
b = np.bool(True) # Noncompliant {{Replace this deprecated "numpy" type alias with the builtin type "bool".}}
6-
# ^^^^^^^
75
i = np.int(42) # Noncompliant {{Replace this deprecated "numpy" type alias with the builtin type "int".}}
86
# ^^^^^^
97
f = np.float(4.2) # Noncompliant {{Replace this deprecated "numpy" type alias with the builtin type "float".}}
@@ -21,8 +19,6 @@ def failure():
2119

2220
def failure_import_as_z():
2321
import numpy as z
24-
b = z.bool(True) # Noncompliant
25-
# ^^^^^^
2622
i = z.int(42) # Noncompliant
2723
# ^^^^^
2824
f = z.float(4.2) # Noncompliant
@@ -39,6 +35,8 @@ def failure_import_as_z():
3935
# ^^^^^^^^^
4036

4137
def success():
38+
b = np.bool(True)
39+
b = np.bool(False)
4240
b = True # Compliant
4341
b = bool(True) # Compliant
4442
i = 42 # Compliant
@@ -54,3 +52,12 @@ def success():
5452
u = "bar" # Compliant
5553
u = str("bar") # Compliant
5654

55+
def success_np_bool_usages():
56+
# np.bool is no longer deprecated (reintroduced in NumPy 2.x)
57+
arr = np.zeros(2).astype(np.bool)
58+
mask = np.ones((3, 4), dtype=np.bool)
59+
empty = np.zeros_like(arr, dtype=np.bool)
60+
if arr.dtype == np.bool:
61+
pass
62+
dtype = np.bool
63+

0 commit comments

Comments
 (0)