|
16 | 16 | */ |
17 | 17 | package org.sonar.python.checks; |
18 | 18 |
|
| 19 | +import java.util.ArrayList; |
| 20 | +import java.util.List; |
19 | 21 | import org.sonar.check.Rule; |
20 | 22 | import org.sonar.plugins.python.api.PythonSubscriptionCheck; |
21 | 23 | import org.sonar.plugins.python.api.SubscriptionContext; |
|
40 | 42 | public class EnumerateUnpackingCheck extends PythonSubscriptionCheck { |
41 | 43 |
|
42 | 44 | private static final String MESSAGE = "Unpack the value from 'enumerate()' directly instead of using an index lookup."; |
| 45 | + private static final String SECONDARY_MESSAGE = "Replace this index lookup with the unpacked value."; |
43 | 46 | private static final TypeMatcher ENUMERATE_MATCHER = TypeMatchers.isType("enumerate"); |
44 | 47 |
|
45 | 48 | @Override |
@@ -84,26 +87,30 @@ private static void check(SubscriptionContext ctx) { |
84 | 87 | return; |
85 | 88 | } |
86 | 89 |
|
87 | | - boolean hasSubscriptWriteTarget = TreeUtils.hasDescendant(forStatement.body(), |
88 | | - node -> isMatchingSubscript(node, indexSymbol, iterableSymbol) |
89 | | - && isSubscriptWriteTarget((SubscriptionExpression) node)); |
| 90 | + List<SubscriptionExpression> matchingSubscripts = new ArrayList<>(); |
| 91 | + collectMatchingSubscripts(forStatement.body(), indexSymbol, iterableSymbol, matchingSubscripts); |
90 | 92 |
|
91 | | - if (hasSubscriptWriteTarget) { |
| 93 | + if (matchingSubscripts.isEmpty()) { |
| 94 | + return; |
| 95 | + } |
| 96 | + if (matchingSubscripts.stream().anyMatch(EnumerateUnpackingCheck::isSubscriptWriteTarget)) { |
92 | 97 | return; |
93 | 98 | } |
94 | 99 |
|
95 | | - boolean hasRedundantSubscript = TreeUtils.hasDescendant(forStatement.body(), |
96 | | - node -> isMatchingSubscript(node, indexSymbol, iterableSymbol)); |
| 100 | + PreciseIssue issue = ctx.addIssue(call, MESSAGE); |
| 101 | + matchingSubscripts.forEach(subscript -> issue.secondary(subscript, SECONDARY_MESSAGE)); |
| 102 | + } |
97 | 103 |
|
98 | | - if (hasRedundantSubscript) { |
99 | | - ctx.addIssue(call, MESSAGE); |
| 104 | + private static void collectMatchingSubscripts(Tree tree, SymbolV2 indexSymbol, SymbolV2 iterableSymbol, List<SubscriptionExpression> result) { |
| 105 | + for (Tree child : tree.children()) { |
| 106 | + if (child instanceof SubscriptionExpression subscription && isMatchingSubscript(subscription, indexSymbol, iterableSymbol)) { |
| 107 | + result.add(subscription); |
| 108 | + } |
| 109 | + collectMatchingSubscripts(child, indexSymbol, iterableSymbol, result); |
100 | 110 | } |
101 | 111 | } |
102 | 112 |
|
103 | | - private static boolean isMatchingSubscript(Tree node, SymbolV2 indexSymbol, SymbolV2 iterableSymbol) { |
104 | | - if (!(node instanceof SubscriptionExpression subscription)) { |
105 | | - return false; |
106 | | - } |
| 113 | + private static boolean isMatchingSubscript(SubscriptionExpression subscription, SymbolV2 indexSymbol, SymbolV2 iterableSymbol) { |
107 | 114 | if (subscription.subscripts().expressions().size() != 1) { |
108 | 115 | return false; |
109 | 116 | } |
|
0 commit comments