Skip to content

Commit 849b430

Browse files
committed
SONARJAVA-1372 only consider ternary operators if java version >= 8
1 parent 118c49c commit 849b430

4 files changed

Lines changed: 85 additions & 7 deletions

File tree

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.sonar.java.checks;
2121

2222
import com.google.common.collect.ImmutableList;
23+
import org.apache.commons.lang.ArrayUtils;
2324
import org.sonar.api.server.rule.RulesDefinition;
2425
import org.sonar.check.Priority;
2526
import org.sonar.check.Rule;
@@ -39,6 +40,7 @@
3940
import org.sonar.plugins.java.api.tree.ParameterizedTypeTree;
4041
import org.sonar.plugins.java.api.tree.ReturnStatementTree;
4142
import org.sonar.plugins.java.api.tree.Tree;
43+
import org.sonar.plugins.java.api.tree.Tree.Kind;
4244
import org.sonar.plugins.java.api.tree.TypeCastTree;
4345
import org.sonar.plugins.java.api.tree.TypeTree;
4446
import org.sonar.plugins.java.api.tree.VariableTree;
@@ -61,8 +63,20 @@
6163
@SqaleConstantRemediation("1min")
6264
public class DiamondOperatorCheck extends SubscriptionBaseVisitor implements JavaVersionAwareVisitor {
6365

66+
private static final Tree.Kind[] JAVA_7_KINDS = new Tree.Kind[] {
67+
Tree.Kind.VARIABLE,
68+
Tree.Kind.TYPE_CAST,
69+
Tree.Kind.RETURN_STATEMENT,
70+
Tree.Kind.ASSIGNMENT};
71+
private static final Tree.Kind[] JAVA_8_KINDS = (Tree.Kind[]) ArrayUtils.addAll(JAVA_7_KINDS, new Tree.Kind[] {
72+
Tree.Kind.CONDITIONAL_EXPRESSION});
73+
private Tree.Kind[] expressionKindsToCheck = JAVA_7_KINDS;
74+
6475
@Override
6576
public boolean isCompatibleWithJavaVersion(@Nullable Integer version) {
77+
if (JavaVersionHelper.java8Compatible(version)) {
78+
expressionKindsToCheck = JAVA_8_KINDS;
79+
}
6680
return JavaVersionHelper.java7Compatible(version);
6781
}
6882

@@ -76,7 +90,7 @@ public void visitNode(Tree tree) {
7690
NewClassTree newClassTree = (NewClassTree) tree;
7791
TypeTree newTypeTree = newClassTree.identifier();
7892
if (newClassTree.classBody() == null && isParameterizedType(newTypeTree)) {
79-
TypeTree type = getTypeFromExpression(tree.parent());
93+
TypeTree type = getTypeFromExpression(tree.parent(), expressionKindsToCheck);
8094
if (type != null && isParameterizedType(type)) {
8195
reportIssue(
8296
((ParameterizedTypeTree) newTypeTree).typeArguments(),
@@ -87,9 +101,9 @@ public void visitNode(Tree tree) {
87101
}
88102

89103
@CheckForNull
90-
private static TypeTree getTypeFromExpression(Tree expression) {
91-
if (expression.is(Tree.Kind.VARIABLE, Tree.Kind.TYPE_CAST, Tree.Kind.RETURN_STATEMENT, Tree.Kind.ASSIGNMENT, Tree.Kind.CONDITIONAL_EXPRESSION)) {
92-
TypeTreeLocator visitor = new TypeTreeLocator();
104+
private static TypeTree getTypeFromExpression(Tree expression, Tree.Kind[] kinds) {
105+
if (expression.is(kinds)) {
106+
TypeTreeLocator visitor = new TypeTreeLocator(kinds);
93107
expression.accept(visitor);
94108
return visitor.type;
95109
}
@@ -105,8 +119,15 @@ private static boolean isParameterizedType(TypeTree type) {
105119

106120
private static class TypeTreeLocator extends BaseTreeVisitor {
107121

122+
private final Tree.Kind[] kinds;
123+
124+
@Nullable
108125
private TypeTree type = null;
109126

127+
public TypeTreeLocator(Kind[] kinds) {
128+
this.kinds = kinds;
129+
}
130+
110131
@Override
111132
public void visitReturnStatement(ReturnStatementTree tree) {
112133
type = getMethodReturnType(tree);
@@ -121,7 +142,7 @@ public void visitTypeCast(TypeCastTree tree) {
121142
public void visitAssignmentExpression(AssignmentExpressionTree tree) {
122143
Tree assignedVariable = getAssignedVariable(tree.variable());
123144
if (assignedVariable != null) {
124-
type = getTypeFromExpression(assignedVariable);
145+
type = getTypeFromExpression(assignedVariable, kinds);
125146
}
126147
}
127148

@@ -132,7 +153,7 @@ public void visitVariable(VariableTree tree) {
132153

133154
@Override
134155
public void visitConditionalExpression(ConditionalExpressionTree tree) {
135-
type = getTypeFromExpression(tree.parent());
156+
type = getTypeFromExpression(tree.parent(), kinds);
136157
}
137158

138159
private static TypeTree getMethodReturnType(ReturnStatementTree returnStatementTree) {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import java.util.ArrayList;
2+
import java.util.HashMap;
3+
import java.util.Iterator;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
class A {
8+
List<Object> myList1 = new ArrayList<>(); // Compliant
9+
List<Object> myList2 = new ArrayList<Object>(); // Noncompliant [[sc=39;ec=47]] {{Replace the type specification in this constructor call with the diamond operator ("<>").}}
10+
11+
void foo() {
12+
List<Object> myList;
13+
myList = new ArrayList<>(); // Compliant
14+
myList = new ArrayList<Object>(); // Noncompliant [[sc=27;ec=35]]
15+
16+
List<String> strings1 = new ArrayList<>(); // Compliant
17+
List<String> strings2 = new ArrayList<String>(); // Noncompliant [[sc=42;ec=50]]
18+
Map<String,List<Integer>> map1 = new HashMap<>(); // Compliant
19+
Map<String,List<Integer>> map2 = new HashMap<String,List<Integer>>(); // Noncompliant [[sc=49;ec=71]]
20+
21+
List myOtherList = new ArrayList<Object>(); // Compliant
22+
new A().myList1 = new ArrayList<>(); // Compliant
23+
new A().myList1 = new ArrayList<Object>(); // Noncompliant [[sc=36;ec=44]]
24+
25+
List<Object>[] myArrayOfList = new List[10];
26+
myArrayOfList[0] = new ArrayList<>(); // Compliant
27+
myArrayOfList[1] = new ArrayList<Object>(); // Noncompliant [[sc=37;ec=45]]
28+
29+
new ArrayList<Object>().add(new Object()); // Compliant
30+
31+
((List<Object>) new ArrayList<Object>()).isEmpty(); // Noncompliant [[sc=34;ec=42]]
32+
((List<Object>) new ArrayList<>()).isEmpty(); // Compliant
33+
34+
Iterator<Object> iterator = new Iterator<Object>() { // Compliant - anonymous classes requires to be typed
35+
};
36+
37+
MyUnknownVariable = new ArrayList<Object>(); // Compliant
38+
}
39+
40+
List<Object> qix(boolean test) {
41+
List<Object> myList = test ?
42+
new ArrayList<>() : // Compliant
43+
new ArrayList<Object>(); // Compliant - using diamond operator only works with java 8
44+
45+
myList = new ArrayList<>(test ? new ArrayList<>() : new ArrayList<Object>(5)); // Compliant
46+
if (test) {
47+
return new ArrayList<>(); // Compliant
48+
}
49+
return new ArrayList<Object>(); // Noncompliant [[sc=25;ec=33]]
50+
}
51+
}

java-checks/src/test/files/checks/DiamondOperatorCheck.java renamed to java-checks/src/test/files/checks/DiamondOperatorCheck_java_8.java

File renamed without changes.

java-checks/src/test/java/org/sonar/java/checks/DiamondOperatorCheckTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@ public void test_no_version() {
3131

3232
@Test
3333
public void test_with_java_7() {
34-
JavaCheckVerifier.verify("src/test/files/checks/DiamondOperatorCheck.java", new DiamondOperatorCheck(), 7);
34+
JavaCheckVerifier.verify("src/test/files/checks/DiamondOperatorCheck_java_7.java", new DiamondOperatorCheck(), 7);
35+
}
36+
37+
@Test
38+
public void test_with_java_8() {
39+
// take into account ternary operators
40+
JavaCheckVerifier.verify("src/test/files/checks/DiamondOperatorCheck_java_8.java", new DiamondOperatorCheck(), 8);
3541
}
3642

3743
}

0 commit comments

Comments
 (0)