Skip to content

Commit 27ef3aa

Browse files
committed
SONARJAVA-1437 Precise issue location for a bunch of rules
1 parent efd3065 commit 27ef3aa

40 files changed

Lines changed: 100 additions & 96 deletions

java-checks/src/main/java/org/sonar/java/checks/AbstractClassWithoutAbstractMethodCheck.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ public void visitNode(Tree tree) {
6464
}
6565
if (isExtendingObject(classTree) && nbAbstractMethod == nbOfMembers) {
6666
// emtpy abstract class or only abstract method
67-
context.addIssue(tree, this, "Convert this \"" + typeSymbol + "\" class to an interface");
67+
context.reportIssue(this, classTree.simpleName(), "Convert this \"" + typeSymbol + "\" class to an interface");
6868
}
6969
if (nbOfMembers > 0 && nbAbstractMethod == 0 && !isPartialImplementation(classTree)) {
7070
// Not empty abstract class with no abstract method
71-
context.addIssue(tree, this, "Convert this \"" + typeSymbol + "\" class to a concrete class with a private constructor");
71+
context.reportIssue(this, classTree.simpleName(), "Convert this \"" + typeSymbol + "\" class to a concrete class with a private constructor");
7272
}
7373
}
7474
}

java-checks/src/main/java/org/sonar/java/checks/ArrayEqualsCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void visitMethodInvocation(MethodInvocationTree tree) {
5454
if (tree.methodSelect().is(Tree.Kind.MEMBER_SELECT)) {
5555
MemberSelectExpressionTree mset = (MemberSelectExpressionTree) tree.methodSelect();
5656
if ("equals".equals(mset.identifier().name()) && mset.expression().symbolType().isArray()) {
57-
context.addIssue(tree, this, "Use the '==' operator instead of calling the equals() method to prevent any misunderstandings");
57+
context.reportIssue(this, mset.identifier(), "Use the '==' operator instead of calling the equals() method to prevent any misunderstandings");
5858
}
5959
}
6060
super.visitMethodInvocation(tree);

java-checks/src/main/java/org/sonar/java/checks/BooleanInversionCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public void visitNode(Tree tree) {
6666
Tree.Kind.EQUAL_TO, Tree.Kind.NOT_EQUAL_TO,
6767
Tree.Kind.LESS_THAN, Tree.Kind.GREATER_THAN,
6868
Tree.Kind.LESS_THAN_OR_EQUAL_TO, Tree.Kind.GREATER_THAN_OR_EQUAL_TO)) {
69-
context.addIssue(tree, this, "Use the opposite operator (\"" + OPERATORS.get(((BinaryExpressionTree) expression).operatorToken().text()) + "\") instead.");
69+
context.reportIssue(this, tree, "Use the opposite operator (\"" + OPERATORS.get(((BinaryExpressionTree) expression).operatorToken().text()) + "\") instead.");
7070
}
7171
}
7272

java-checks/src/main/java/org/sonar/java/checks/CatchUsesExceptionWithContextCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public void visitCatch(CatchTree tree) {
101101
super.visitCatch(tree);
102102
Collection<IdentifierTree> usages = validUsagesStack.pop();
103103
if (usages.isEmpty()) {
104-
context.addIssue(tree, this, "Either log or rethrow this exception.");
104+
context.reportIssue(this, tree.parameter(), "Either log or rethrow this exception.");
105105
}
106106
}
107107
}

java-checks/src/main/java/org/sonar/java/checks/CollapsibleIfCandidateCheck.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package org.sonar.java.checks;
2121

22+
import com.google.common.collect.Lists;
2223
import org.sonar.api.server.rule.RulesDefinition;
2324
import org.sonar.check.Priority;
2425
import org.sonar.check.Rule;
@@ -48,24 +49,26 @@
4849
public class CollapsibleIfCandidateCheck extends BaseTreeVisitor implements JavaFileScanner {
4950

5051
private JavaFileScannerContext context;
51-
private Deque<Boolean> outerIf = new ArrayDeque<>();
52+
private Deque<IfStatementTree> outerIf = new ArrayDeque<>();
5253

5354
@Override
5455
public void scanFile(JavaFileScannerContext context) {
5556
this.context = context;
5657
scan(context.getTree());
58+
outerIf.clear();
5759
}
5860

5961
@Override
6062
public void visitIfStatement(IfStatementTree tree) {
6163

6264
if (!outerIf.isEmpty() && !hasElseClause(tree)) {
63-
context.addIssue(tree, this, "Merge this if statement with the enclosing one.");
65+
context.reportIssue(this, tree.ifKeyword(), "Merge this if statement with the enclosing one.",
66+
Lists.newArrayList(new JavaFileScannerContext.Location("", outerIf.peek().ifKeyword())), null);
6467
}
6568

6669
if (!hasElseClause(tree) && hasBodySingleIfStatement(tree.thenStatement())) {
6770
// children of this if statement are eligible for issues
68-
outerIf.push(Boolean.TRUE);
71+
outerIf.push(tree);
6972
// recurse into sub-tree
7073
super.visitIfStatement(tree);
7174
if (!outerIf.isEmpty()) {

java-checks/src/main/java/org/sonar/java/checks/CollectionImplementationReferencedCheck.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,7 @@ private void checkIfAllowed(@Nullable TypeTree tree, String messagePrefix) {
134134
String collectionInterface = MAPPING.get(collectionImplementation);
135135

136136
if (collectionInterface != null) {
137-
context.addIssue(
138-
tree,
139-
this,
140-
messagePrefix + messageRemainder(collectionImplementation, collectionInterface));
137+
context.reportIssue(this, tree, messagePrefix + messageRemainder(collectionImplementation, collectionInterface));
141138
}
142139
}
143140

java-checks/src/main/java/org/sonar/java/checks/CollectionIsEmptyCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public void visitBinaryExpression(BinaryExpressionTree tree) {
7474
super.visitBinaryExpression(tree);
7575

7676
if (hasCallToSizeMethod(tree) && isEmptyComparison(tree)) {
77-
context.addIssue(tree, this, "Use isEmpty() to check whether the collection is empty or not.");
77+
context.reportIssue(this, tree, "Use isEmpty() to check whether the collection is empty or not.");
7878
}
7979
}
8080

java-checks/src/main/java/org/sonar/java/checks/CollectionsEmptyConstantsCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public void visitMemberSelectExpression(MemberSelectExpressionTree tree) {
6767
boolean isCollectionsCall = tree.expression().is(Kind.IDENTIFIER) && "Collections".equals(((IdentifierTree) tree.expression()).name());
6868
boolean callEmptyConstant = identifier.startsWith("EMPTY_");
6969
if (isCollectionsCall && callEmptyConstant) {
70-
context.addIssue(tree, this, "Replace \"Collections."+identifier+"\" by \"Collections."+ IDENTIFIER_REPLACEMENT.get(identifier)+"\".");
70+
context.reportIssue(this, tree, "Replace \"Collections." + identifier + "\" by \"Collections." + IDENTIFIER_REPLACEMENT.get(identifier) + "\".");
7171
}
7272
}
7373

java-checks/src/main/java/org/sonar/java/checks/EnumMapCheck.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public void visitVariable(VariableTree tree) {
6363
if (tree.type().symbolType().isSubtypeOf("java.util.Map")) {
6464
ExpressionTree initializer = tree.initializer();
6565
if (initializer != null) {
66-
checkNewMap(tree, initializer, hasEnumKey(tree.type().symbolType()));
66+
checkNewMap(initializer, hasEnumKey(tree.type().symbolType()));
6767
}
6868
} else {
6969
super.visitVariable(tree);
@@ -73,7 +73,7 @@ public void visitVariable(VariableTree tree) {
7373
@Override
7474
public void visitAssignmentExpression(AssignmentExpressionTree tree) {
7575
if (tree.variable().symbolType().isSubtypeOf("java.util.Map")) {
76-
checkNewMap(tree, tree.expression(), hasEnumKey(tree.variable().symbolType()));
76+
checkNewMap(tree.expression(), hasEnumKey(tree.variable().symbolType()));
7777
} else {
7878
super.visitAssignmentExpression(tree);
7979
}
@@ -88,12 +88,12 @@ public void visitNewClass(NewClassTree tree) {
8888
}
8989
}
9090

91-
private void checkNewMap(Tree tree, ExpressionTree given, boolean useEnumKey) {
91+
private void checkNewMap(ExpressionTree given, boolean useEnumKey) {
9292
ExpressionTree expression = ExpressionsHelper.skipParentheses(given);
9393
if (expression.is(Tree.Kind.NEW_CLASS)) {
9494
NewClassTree newClassTree = (NewClassTree) expression;
9595
if (newClassTree.symbolType().isSubtypeOf("java.util.HashMap") && (useEnumKey || hasEnumKey(newClassTree.identifier().symbolType()))) {
96-
addIssue(tree);
96+
addIssue(newClassTree);
9797
}
9898
}
9999
}
@@ -110,7 +110,7 @@ private static boolean hasEnumKey(Type type) {
110110
}
111111

112112
private void addIssue(Tree typeTree) {
113-
context.addIssue(typeTree, this, "Convert this Map to an EnumMap.");
113+
context.reportIssue(this, typeTree, "Convert this Map to an EnumMap.");
114114
}
115115

116116
}

java-checks/src/main/java/org/sonar/java/checks/ErrorClassExtendedCheck.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.sonar.plugins.java.api.tree.IdentifierTree;
3232
import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree;
3333
import org.sonar.plugins.java.api.tree.Tree;
34+
import org.sonar.plugins.java.api.tree.TypeTree;
3435
import org.sonar.squidbridge.annotations.ActivatedByDefault;
3536
import org.sonar.squidbridge.annotations.SqaleConstantRemediation;
3637
import org.sonar.squidbridge.annotations.SqaleSubCharacteristic;
@@ -55,16 +56,17 @@ public void scanFile(JavaFileScannerContext context) {
5556

5657
@Override
5758
public void visitClass(ClassTree tree) {
58-
if (tree.is(Tree.Kind.CLASS) && tree.superClass() != null) {
59-
if (tree.superClass().is(Tree.Kind.IDENTIFIER)) {
60-
IdentifierTree idt = (IdentifierTree) tree.superClass();
59+
TypeTree superClass = tree.superClass();
60+
if (tree.is(Tree.Kind.CLASS) && superClass != null) {
61+
if (superClass.is(Tree.Kind.IDENTIFIER)) {
62+
IdentifierTree idt = (IdentifierTree) superClass;
6163
if ("Error".equals(idt.name())) {
62-
context.addIssue(tree, this, "Extend \"java.lang.Exception\" or one of its subclasses.");
64+
context.reportIssue(this, superClass, "Extend \"java.lang.Exception\" or one of its subclasses.");
6365
}
64-
} else if (tree.superClass().is(Tree.Kind.MEMBER_SELECT)) {
65-
MemberSelectExpressionTree mse = (MemberSelectExpressionTree) tree.superClass();
66+
} else if (superClass.is(Tree.Kind.MEMBER_SELECT)) {
67+
MemberSelectExpressionTree mse = (MemberSelectExpressionTree) superClass;
6668
if ("Error".equals(mse.identifier().name()) && isJavaLang(mse.expression())) {
67-
context.addIssue(tree, this, "Extend \"java.lang.Exception\" or one of its subclasses.");
69+
context.reportIssue(this, superClass, "Extend \"java.lang.Exception\" or one of its subclasses.");
6870
}
6971
}
7072
}

0 commit comments

Comments
 (0)