diff --git a/its/autoscan/src/test/resources/autoscan/diffs/diff_S1172.json b/its/autoscan/src/test/resources/autoscan/diffs/diff_S1172.json index 322daa80d40..72a00406d35 100644 --- a/its/autoscan/src/test/resources/autoscan/diffs/diff_S1172.json +++ b/its/autoscan/src/test/resources/autoscan/diffs/diff_S1172.json @@ -1,6 +1,6 @@ { "ruleKey": "S1172", "hasTruePositives": true, - "falseNegatives": 32, + "falseNegatives": 33, "falsePositives": 0 } diff --git a/java-checks-test-sources/default/src/main/java/checks/StaticFieldUpateCheckSample.java b/java-checks-test-sources/default/src/main/java/checks/StaticFieldUpateCheckSample.java index 31f4f052bf6..846c9076ecf 100644 --- a/java-checks-test-sources/default/src/main/java/checks/StaticFieldUpateCheckSample.java +++ b/java-checks-test-sources/default/src/main/java/checks/StaticFieldUpateCheckSample.java @@ -13,6 +13,7 @@ public void nonCompliantAssignments() { staticValue = value + 1; // Noncompliant {{Make the enclosing method "static" or remove this set.}} // ^^^^^^^^^^^ staticValue += value; // Noncompliant {{Make the enclosing method "static" or remove this set.}} + staticValue >>= value; // Noncompliant {{Make the enclosing method "static" or remove this set.}} staticValue++; // Noncompliant {{Make the enclosing method "static" or remove this set.}} ++staticValue; // Noncompliant {{Make the enclosing method "static" or remove this set.}} StaticFieldUpateCheckSample.staticValue++; // Noncompliant {{Make the enclosing method "static" or remove this set.}} diff --git a/java-checks-test-sources/default/src/main/java/checks/jspecify/nullmarked/RedundantNullabilityAnnotationsCheckSample.java b/java-checks-test-sources/default/src/main/java/checks/jspecify/nullmarked/RedundantNullabilityAnnotationsCheckSample.java index 82e1f9b9d57..a072326f4e0 100644 --- a/java-checks-test-sources/default/src/main/java/checks/jspecify/nullmarked/RedundantNullabilityAnnotationsCheckSample.java +++ b/java-checks-test-sources/default/src/main/java/checks/jspecify/nullmarked/RedundantNullabilityAnnotationsCheckSample.java @@ -205,6 +205,20 @@ static interface InnerRecord { } + @NullMarked // Noncompliant {{Remove redundant annotation @NullMarked at class level as inside scope annotation @NullMarked at package level.}} + static @interface Annotation { + } + + @NullMarked // Noncompliant {{Remove redundant annotation @NullMarked at class level as inside scope annotation @NullMarked at package level.}} + enum InnerEnum { + A, + B; + + public void f(@NonNull String s) { // Noncompliant {{Remove redundant annotation @NonNull as inside scope annotation @NullMarked at class level.}} + // Do something + } + } + } enum TEST_COVERAGE { diff --git a/java-checks/src/main/java/org/sonar/java/checks/AbstractCallToDeprecatedCodeChecker.java b/java-checks/src/main/java/org/sonar/java/checks/AbstractCallToDeprecatedCodeChecker.java index 06a2aaf45d2..c90f7d717be 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/AbstractCallToDeprecatedCodeChecker.java +++ b/java-checks/src/main/java/org/sonar/java/checks/AbstractCallToDeprecatedCodeChecker.java @@ -16,7 +16,6 @@ */ package org.sonar.java.checks; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -29,6 +28,7 @@ import org.sonar.plugins.java.api.tree.MethodTree; import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; +import org.sonarsource.analyzer.commons.collections.ListUtils; public abstract class AbstractCallToDeprecatedCodeChecker extends IssuableSubscriptionVisitor { @@ -41,7 +41,7 @@ public final void leaveFile(JavaFileScannerContext context) { @Override public final List nodesToVisit() { - return Arrays.asList(Tree.Kind.IDENTIFIER, Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE, Tree.Kind.METHOD, Tree.Kind.CONSTRUCTOR); + return ListUtils.concat(Tree.Kind.CLASS_KINDS, List.of(Tree.Kind.IDENTIFIER, Tree.Kind.METHOD, Tree.Kind.CONSTRUCTOR)); } @Override @@ -120,7 +120,7 @@ private static boolean isDeprecatedMethod(Tree tree) { } private static boolean isDeprecatedClassTree(Tree tree) { - return tree.is(Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE) && ((ClassTree) tree).symbol().isDeprecated(); + return Tree.Kind.CLASS_KINDS.contains(tree.kind()) && ((ClassTree) tree).symbol().isDeprecated(); } boolean isFlaggedForRemoval(Symbol deprecatedSymbol) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/AssignmentInSubExpressionCheck.java b/java-checks/src/main/java/org/sonar/java/checks/AssignmentInSubExpressionCheck.java index df3790d9e4e..94049d79864 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/AssignmentInSubExpressionCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/AssignmentInSubExpressionCheck.java @@ -39,20 +39,6 @@ @Rule(key = "S1121") public class AssignmentInSubExpressionCheck extends BaseTreeVisitor implements JavaFileScanner { - private static final Kind[] ASSIGNMENT_EXPRESSIONS = new Kind[]{ - Kind.AND_ASSIGNMENT, - Kind.ASSIGNMENT, - Kind.DIVIDE_ASSIGNMENT, - Kind.LEFT_SHIFT_ASSIGNMENT, - Kind.RIGHT_SHIFT_ASSIGNMENT, - Kind.MINUS_ASSIGNMENT, - Kind.MULTIPLY_ASSIGNMENT, - Kind.OR_ASSIGNMENT, - Kind.PLUS_ASSIGNMENT, - Kind.REMAINDER_ASSIGNMENT, - Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, - Kind.XOR_ASSIGNMENT}; - private JavaFileScannerContext context; @Override @@ -71,7 +57,7 @@ public void visitAnnotation(AnnotationTree annotationTree) { @Override public void visitLambdaExpression(LambdaExpressionTree lambdaExpressionTree) { //skip lambda if body is an assignment - if(!lambdaExpressionTree.body().is(ASSIGNMENT_EXPRESSIONS)) { + if(!(lambdaExpressionTree.body() instanceof AssignmentExpressionTree)) { super.visitLambdaExpression(lambdaExpressionTree); } } diff --git a/java-checks/src/main/java/org/sonar/java/checks/CallOuterPrivateMethodCheck.java b/java-checks/src/main/java/org/sonar/java/checks/CallOuterPrivateMethodCheck.java index 6b309ade91c..4ea36391004 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/CallOuterPrivateMethodCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/CallOuterPrivateMethodCheck.java @@ -16,7 +16,6 @@ */ package org.sonar.java.checks; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -44,7 +43,7 @@ public class CallOuterPrivateMethodCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.CLASS, Tree.Kind.INTERFACE); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/CallSuperMethodFromInnerClassCheck.java b/java-checks/src/main/java/org/sonar/java/checks/CallSuperMethodFromInnerClassCheck.java index a99c01f3b17..959167cb13a 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/CallSuperMethodFromInnerClassCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/CallSuperMethodFromInnerClassCheck.java @@ -16,7 +16,6 @@ */ package org.sonar.java.checks; -import java.util.Arrays; import java.util.List; import org.sonar.check.Rule; import org.sonar.java.model.ExpressionUtils; @@ -34,7 +33,7 @@ public class CallSuperMethodFromInnerClassCheck extends IssuableSubscriptionVisi @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.CLASS, Tree.Kind.INTERFACE); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/ClassFieldCountCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ClassFieldCountCheck.java index 45587a250f0..5c73c50b857 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ClassFieldCountCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ClassFieldCountCheck.java @@ -16,6 +16,7 @@ */ package org.sonar.java.checks; +import java.util.List; import org.sonar.check.Rule; import org.sonar.check.RuleProperty; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; @@ -24,9 +25,6 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; -import java.util.Arrays; -import java.util.List; - import static org.sonar.java.checks.helpers.ExpressionsHelper.reportOnClassTree; @Rule(key = "S1820") @@ -43,7 +41,7 @@ public class ClassFieldCountCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.CLASS, Tree.Kind.INTERFACE, Tree.Kind.ENUM); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/CollectionIsEmptyCheck.java b/java-checks/src/main/java/org/sonar/java/checks/CollectionIsEmptyCheck.java index 98f8146397f..e7c63619592 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/CollectionIsEmptyCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/CollectionIsEmptyCheck.java @@ -63,13 +63,7 @@ private enum EmptyComparisonType { Tree.Kind.GREATER_THAN, Tree.Kind.GREATER_THAN_OR_EQUAL_TO }; - private static final Tree.Kind[] CLASS_TREES = { - Tree.Kind.CLASS, - Tree.Kind.ENUM, - Tree.Kind.INTERFACE, - Tree.Kind.RECORD, - Tree.Kind.ANNOTATION_TYPE - }; + private static final Tree.Kind[] CLASS_TREES = Tree.Kind.CLASS_KINDS.toArray(new Tree.Kind[0]); private static final Deque IS_COLLECTION_ENCLOSING_TYPES_STACK = new LinkedList<>(); @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/ExpressionComplexityCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ExpressionComplexityCheck.java index 02ba9aedd5c..4826a51b587 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ExpressionComplexityCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ExpressionComplexityCheck.java @@ -16,6 +16,10 @@ */ package org.sonar.java.checks; +import java.util.Collections; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; import org.sonar.check.Rule; import org.sonar.check.RuleProperty; import org.sonar.java.checks.helpers.MethodTreeUtils; @@ -24,12 +28,7 @@ import org.sonar.plugins.java.api.tree.LambdaExpressionTree; import org.sonar.plugins.java.api.tree.MethodTree; import org.sonar.plugins.java.api.tree.Tree; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; +import org.sonarsource.analyzer.commons.collections.ListUtils; @Rule(key = "S1067") public class ExpressionComplexityCheck extends IssuableSubscriptionVisitor { @@ -56,9 +55,7 @@ public void setContext(JavaFileScannerContext context) { @Override public List nodesToVisit() { - return Arrays.asList( - Tree.Kind.CLASS, - Tree.Kind.RECORD, + return ListUtils.concat(Tree.Kind.CLASS_KINDS, Tree.Kind.ASSIGNMENT_KINDS, List.of( Tree.Kind.POSTFIX_INCREMENT, Tree.Kind.POSTFIX_DECREMENT, Tree.Kind.PREFIX_INCREMENT, @@ -95,18 +92,6 @@ public List nodesToVisit() { Tree.Kind.TYPE_CAST, Tree.Kind.INSTANCE_OF, Tree.Kind.PARENTHESIZED_EXPRESSION, - Tree.Kind.ASSIGNMENT, - Tree.Kind.MULTIPLY_ASSIGNMENT, - Tree.Kind.DIVIDE_ASSIGNMENT, - Tree.Kind.REMAINDER_ASSIGNMENT, - Tree.Kind.PLUS_ASSIGNMENT, - Tree.Kind.MINUS_ASSIGNMENT, - Tree.Kind.LEFT_SHIFT_ASSIGNMENT, - Tree.Kind.RIGHT_SHIFT_ASSIGNMENT, - Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, - Tree.Kind.AND_ASSIGNMENT, - Tree.Kind.XOR_ASSIGNMENT, - Tree.Kind.OR_ASSIGNMENT, Tree.Kind.INT_LITERAL, Tree.Kind.LONG_LITERAL, Tree.Kind.FLOAT_LITERAL, @@ -118,12 +103,12 @@ public List nodesToVisit() { Tree.Kind.IDENTIFIER, Tree.Kind.ARRAY_TYPE, Tree.Kind.LAMBDA_EXPRESSION, - Tree.Kind.PRIMITIVE_TYPE); + Tree.Kind.PRIMITIVE_TYPE)); } @Override public void visitNode(Tree tree) { - if (tree.is(Tree.Kind.CLASS, Tree.Kind.RECORD, Tree.Kind.NEW_ARRAY) || isLambdaWithBlock(tree)) { + if (Tree.Kind.CLASS_KINDS.contains(tree.kind()) || tree.is(Tree.Kind.NEW_ARRAY) || isLambdaWithBlock(tree)) { count.push(0); level.push(0); } else { @@ -136,7 +121,7 @@ public void visitNode(Tree tree) { @Override public void leaveNode(Tree tree) { - if (tree.is(Tree.Kind.CLASS, Tree.Kind.RECORD, Tree.Kind.NEW_ARRAY) || isLambdaWithBlock(tree)) { + if (Tree.Kind.CLASS_KINDS.contains(tree.kind()) || tree.is(Tree.Kind.NEW_ARRAY) || isLambdaWithBlock(tree)) { count.pop(); level.pop(); } else { @@ -155,7 +140,7 @@ public void leaveNode(Tree tree) { private static boolean isInsideEquals(Tree tree) { Tree parent = tree.parent(); - while (parent != null && !parent.is(Tree.Kind.CLASS, Tree.Kind.RECORD)) { + while (parent != null && !Tree.Kind.CLASS_KINDS.contains(parent.kind())) { if (parent.is(Tree.Kind.METHOD) && MethodTreeUtils.isEqualsMethod((MethodTree) parent)) { return true; } diff --git a/java-checks/src/main/java/org/sonar/java/checks/HiddenFieldCheck.java b/java-checks/src/main/java/org/sonar/java/checks/HiddenFieldCheck.java index 8bd9a261ac5..5edaaad8be3 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/HiddenFieldCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/HiddenFieldCheck.java @@ -17,7 +17,6 @@ package org.sonar.java.checks; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Deque; import java.util.HashSet; @@ -27,8 +26,6 @@ import java.util.Set; import javax.annotation.Nullable; import org.sonar.check.Rule; -import org.sonarsource.analyzer.commons.collections.MapBuilder; -import org.sonarsource.analyzer.commons.collections.SetUtils; import org.sonar.java.model.JavaTree; import org.sonar.java.model.LineUtils; import org.sonar.java.model.ModifiersUtils; @@ -42,6 +39,9 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey; +import org.sonarsource.analyzer.commons.collections.ListUtils; +import org.sonarsource.analyzer.commons.collections.MapBuilder; +import org.sonarsource.analyzer.commons.collections.SetUtils; @DeprecatedRuleKey(ruleKey = "HiddenFieldCheck", repositoryKey = "squid") @Rule(key = "S1117") @@ -53,18 +53,12 @@ public class HiddenFieldCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList( - Tree.Kind.CLASS, - Tree.Kind.ENUM, - Tree.Kind.INTERFACE, - Tree.Kind.ANNOTATION_TYPE, - Tree.Kind.RECORD, - Tree.Kind.IMPLICIT_CLASS, - Tree.Kind.VARIABLE, - Tree.Kind.METHOD, - Tree.Kind.CONSTRUCTOR, - Tree.Kind.STATIC_INITIALIZER - ); + return ListUtils.concat(Tree.Kind.CLASS_KINDS, List.of( + Tree.Kind.VARIABLE, + Tree.Kind.METHOD, + Tree.Kind.CONSTRUCTOR, + Tree.Kind.STATIC_INITIALIZER + )); } @Override @@ -131,14 +125,7 @@ private static boolean isInStaticInnerClass(VariableTree hiddenVariable, Variabl } private static boolean isClassTree(Tree tree) { - return tree.is( - Tree.Kind.CLASS, - Tree.Kind.ENUM, - Tree.Kind.INTERFACE, - Tree.Kind.ANNOTATION_TYPE, - Tree.Kind.RECORD, - Tree.Kind.IMPLICIT_CLASS - ); + return Tree.Kind.CLASS_KINDS.contains(tree.kind()); } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/InnerClassTooManyLinesCheck.java b/java-checks/src/main/java/org/sonar/java/checks/InnerClassTooManyLinesCheck.java index 52c09481997..56be2bc910c 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/InnerClassTooManyLinesCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/InnerClassTooManyLinesCheck.java @@ -16,6 +16,7 @@ */ package org.sonar.java.checks; +import java.util.List; import org.sonar.check.Rule; import org.sonar.check.RuleProperty; import org.sonar.java.checks.helpers.ExpressionsHelper; @@ -27,9 +28,6 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.Tree.Kind; -import java.util.Arrays; -import java.util.List; - @Rule(key = "S2972") public class InnerClassTooManyLinesCheck extends IssuableSubscriptionVisitor { @@ -42,7 +40,7 @@ public class InnerClassTooManyLinesCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Kind.CLASS, Kind.ENUM, Kind.INTERFACE, Kind.ANNOTATION_TYPE); + return Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/InterfaceOrSuperclassShadowingCheck.java b/java-checks/src/main/java/org/sonar/java/checks/InterfaceOrSuperclassShadowingCheck.java index 6f4032afaad..8831a4d9d75 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/InterfaceOrSuperclassShadowingCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/InterfaceOrSuperclassShadowingCheck.java @@ -16,24 +16,22 @@ */ package org.sonar.java.checks; +import java.util.List; +import java.util.Locale; +import javax.annotation.Nullable; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; import org.sonar.plugins.java.api.tree.ClassTree; import org.sonar.plugins.java.api.tree.Tree; -import javax.annotation.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.Locale; @Rule(key = "S2176") public class InterfaceOrSuperclassShadowingCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.CLASS, Tree.Kind.INTERFACE, Tree.Kind.RECORD); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/MembersDifferOnlyByCapitalizationCheck.java b/java-checks/src/main/java/org/sonar/java/checks/MembersDifferOnlyByCapitalizationCheck.java index d1881013ba7..61452d896e7 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/MembersDifferOnlyByCapitalizationCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/MembersDifferOnlyByCapitalizationCheck.java @@ -16,7 +16,6 @@ */ package org.sonar.java.checks; -import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -47,7 +46,7 @@ public class MembersDifferOnlyByCapitalizationCheck extends IssuableSubscription @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.CLASS, Tree.Kind.INTERFACE, Tree.Kind.ENUM, Tree.Kind.RECORD); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/MultipleMainInstancesCheck.java b/java-checks/src/main/java/org/sonar/java/checks/MultipleMainInstancesCheck.java index 88b1a10d9ae..989a1ee8cf6 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/MultipleMainInstancesCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/MultipleMainInstancesCheck.java @@ -32,7 +32,7 @@ public class MultipleMainInstancesCheck extends IssuableSubscriptionVisitor implements JavaVersionAwareVisitor { @Override public List nodesToVisit() { - return List.of(Tree.Kind.CLASS, Tree.Kind.INTERFACE, Tree.Kind.ENUM, Tree.Kind.RECORD, Tree.Kind.IMPLICIT_CLASS); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/OneDeclarationPerLineCheck.java b/java-checks/src/main/java/org/sonar/java/checks/OneDeclarationPerLineCheck.java index e164fc53938..183f30cc6a9 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/OneDeclarationPerLineCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/OneDeclarationPerLineCheck.java @@ -17,7 +17,6 @@ package org.sonar.java.checks; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -36,6 +35,7 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.Tree.Kind; import org.sonar.plugins.java.api.tree.VariableTree; +import org.sonarsource.analyzer.commons.collections.ListUtils; import static org.sonar.java.reporting.AnalyzerMessage.textSpanBetween; @@ -46,12 +46,12 @@ public class OneDeclarationPerLineCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Kind.INTERFACE, Kind.CLASS, Kind.ENUM, Kind.ANNOTATION_TYPE, Kind.BLOCK, Kind.STATIC_INITIALIZER, Kind.CASE_GROUP); + return ListUtils.concat(Kind.CLASS_KINDS, List.of(Kind.BLOCK, Kind.STATIC_INITIALIZER, Kind.CASE_GROUP)); } @Override public void visitNode(Tree tree) { - if (tree.is(Kind.INTERFACE, Kind.CLASS, Kind.ENUM, Kind.ANNOTATION_TYPE)) { + if (Kind.CLASS_KINDS.contains(tree.kind())) { // Field class declaration checkVariables(((ClassTree) tree).members()); } else if (tree.is(Kind.BLOCK, Kind.STATIC_INITIALIZER)) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/PublicStaticMutableMembersCheck.java b/java-checks/src/main/java/org/sonar/java/checks/PublicStaticMutableMembersCheck.java index db8186849b8..995de6f60b3 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/PublicStaticMutableMembersCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/PublicStaticMutableMembersCheck.java @@ -44,6 +44,7 @@ import org.sonar.plugins.java.api.tree.NewArrayTree; import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; +import org.sonarsource.analyzer.commons.collections.ListUtils; @Rule(key = "S2386") public class PublicStaticMutableMembersCheck extends IssuableSubscriptionVisitor { @@ -115,7 +116,7 @@ public class PublicStaticMutableMembersCheck extends IssuableSubscriptionVisitor @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.INTERFACE, Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.ASSIGNMENT); + return ListUtils.concat(Tree.Kind.CLASS_KINDS, List.of(Tree.Kind.ASSIGNMENT)); } @Override @@ -170,8 +171,8 @@ private void checkAssignment(AssignmentExpressionTree node) { @Override public void leaveNode(Tree tree) { - // cleanup - if (tree.is(Tree.Kind.CLASS, Tree.Kind.ENUM)) { + // cleanup for every class-like declaration visited (i.e. all subscribed nodes except ASSIGNMENT) + if (!tree.is(Tree.Kind.ASSIGNMENT)) { IMMUTABLE_CANDIDATES.removeAll(CLASS_IMMUTABLE_CANDIDATES.getOrDefault(tree, Collections.emptyList())); } } diff --git a/java-checks/src/main/java/org/sonar/java/checks/RedundantModifierCheck.java b/java-checks/src/main/java/org/sonar/java/checks/RedundantModifierCheck.java index 97bbce5461c..762c280afc4 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/RedundantModifierCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/RedundantModifierCheck.java @@ -16,7 +16,6 @@ */ package org.sonar.java.checks; -import java.util.Arrays; import java.util.List; import org.sonar.check.Rule; import org.sonar.java.model.ModifiersUtils; @@ -34,7 +33,7 @@ public class RedundantModifierCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE, Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.RECORD); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/RedundantNullabilityAnnotationsCheck.java b/java-checks/src/main/java/org/sonar/java/checks/RedundantNullabilityAnnotationsCheck.java index fbe1163870d..a77374001d9 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/RedundantNullabilityAnnotationsCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/RedundantNullabilityAnnotationsCheck.java @@ -16,7 +16,6 @@ */ package org.sonar.java.checks; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -41,7 +40,7 @@ public class RedundantNullabilityAnnotationsCheck extends IssuableSubscriptionVi @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.INTERFACE, Tree.Kind.CLASS, Tree.Kind.RECORD); + return Tree.Kind.CLASS_KINDS; } @Override @@ -79,7 +78,7 @@ private void checkMembers(SymbolMetadata.NullabilityData classNullabilityData, } else if (member.is(Tree.Kind.METHOD)) { // check method checkMethod(classNullabilityData, (MethodTree) member, scope); - } else if (member.is(Tree.Kind.CLASS, Tree.Kind.INTERFACE, Tree.Kind.RECORD)) { + } else if (member.is(Tree.Kind.CLASS, Tree.Kind.INTERFACE, Tree.Kind.RECORD, Tree.Kind.ENUM, Tree.Kind.ANNOTATION_TYPE)) { // check inner class checkInnerClass(classNullabilityData, (ClassTree) member, scope); } diff --git a/java-checks/src/main/java/org/sonar/java/checks/StaticFieldUpateCheck.java b/java-checks/src/main/java/org/sonar/java/checks/StaticFieldUpateCheck.java index 9981f9b9725..c11a1733b8d 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/StaticFieldUpateCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/StaticFieldUpateCheck.java @@ -39,19 +39,6 @@ @Rule(key = "S2696") public class StaticFieldUpateCheck extends AbstractInSynchronizeChecker { - private static final Kind[] ASSIGNMENT_EXPRESSIONS = new Kind[]{ - Kind.AND_ASSIGNMENT, - Kind.ASSIGNMENT, - Kind.DIVIDE_ASSIGNMENT, - Kind.LEFT_SHIFT_ASSIGNMENT, - Kind.MINUS_ASSIGNMENT, - Kind.MULTIPLY_ASSIGNMENT, - Kind.OR_ASSIGNMENT, - Kind.PLUS_ASSIGNMENT, - Kind.REMAINDER_ASSIGNMENT, - Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, - Kind.XOR_ASSIGNMENT}; - private static final Kind[] UNARY_EXPRESSIONS = new Kind[]{ Kind.POSTFIX_DECREMENT, Kind.POSTFIX_INCREMENT, @@ -64,7 +51,7 @@ public class StaticFieldUpateCheck extends AbstractInSynchronizeChecker { public List nodesToVisit() { ArrayList nodesToVisit = new ArrayList<>(super.nodesToVisit()); nodesToVisit.add(Kind.STATIC_INITIALIZER); - nodesToVisit.addAll(Arrays.asList(ASSIGNMENT_EXPRESSIONS)); + nodesToVisit.addAll(Kind.ASSIGNMENT_KINDS); nodesToVisit.addAll(Arrays.asList(UNARY_EXPRESSIONS)); return nodesToVisit; } @@ -79,8 +66,8 @@ public void visitNode(Tree tree) { } else if (tree.is(Kind.STATIC_INITIALIZER)) { withinStaticMethod.push(true); } else if (isInInstanceMethod() && !hasAnyParentStatic() && !hasAnyParentSync()) { - if (tree.is(ASSIGNMENT_EXPRESSIONS)) { - checkVariableModification(((AssignmentExpressionTree) tree).variable()); + if (tree instanceof AssignmentExpressionTree assignment) { + checkVariableModification(assignment.variable()); } else if (tree.is(UNARY_EXPRESSIONS)) { checkVariableModification(((UnaryExpressionTree) tree).expression()); } diff --git a/java-checks/src/main/java/org/sonar/java/checks/SynchronizedClassUsageCheck.java b/java-checks/src/main/java/org/sonar/java/checks/SynchronizedClassUsageCheck.java index c2feeab25e3..7e88b5b51f9 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/SynchronizedClassUsageCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/SynchronizedClassUsageCheck.java @@ -18,7 +18,6 @@ import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Deque; import java.util.HashSet; @@ -40,6 +39,7 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.TypeTree; import org.sonar.plugins.java.api.tree.VariableTree; +import org.sonarsource.analyzer.commons.collections.ListUtils; import org.sonarsource.analyzer.commons.collections.MapBuilder; @Rule(key = "S1149") @@ -59,7 +59,7 @@ public class SynchronizedClassUsageCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { // We register on compilation units to clear the visited set when scanning a new file - return Arrays.asList(Tree.Kind.CLASS, Tree.Kind.COMPILATION_UNIT, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE); + return ListUtils.concat(Tree.Kind.CLASS_KINDS, List.of(Tree.Kind.COMPILATION_UNIT)); } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/TooManyMethodsCheck.java b/java-checks/src/main/java/org/sonar/java/checks/TooManyMethodsCheck.java index 716675e5323..ddfa3d5b702 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/TooManyMethodsCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/TooManyMethodsCheck.java @@ -16,7 +16,6 @@ */ package org.sonar.java.checks; -import java.util.Arrays; import java.util.List; import org.sonar.check.Rule; import org.sonar.check.RuleProperty; @@ -49,7 +48,7 @@ public class TooManyMethodsCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE, Tree.Kind.RECORD); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/VolatileVariablesOperationsCheck.java b/java-checks/src/main/java/org/sonar/java/checks/VolatileVariablesOperationsCheck.java index 76dd5e722ac..2693852b653 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/VolatileVariablesOperationsCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/VolatileVariablesOperationsCheck.java @@ -37,6 +37,7 @@ import org.sonar.plugins.java.api.tree.Modifier; import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.UnaryExpressionTree; +import org.sonarsource.analyzer.commons.collections.ListUtils; @Rule(key = "S3078") public class VolatileVariablesOperationsCheck extends IssuableSubscriptionVisitor { @@ -45,24 +46,12 @@ public class VolatileVariablesOperationsCheck extends IssuableSubscriptionVisito @Override public List nodesToVisit() { - return List.of( + return ListUtils.concat(Tree.Kind.ASSIGNMENT_KINDS, List.of( Tree.Kind.PREFIX_DECREMENT, Tree.Kind.PREFIX_INCREMENT, Tree.Kind.POSTFIX_DECREMENT, - Tree.Kind.POSTFIX_INCREMENT, - Tree.Kind.ASSIGNMENT, - Tree.Kind.PLUS_ASSIGNMENT, - Tree.Kind.MINUS_ASSIGNMENT, - Tree.Kind.MULTIPLY_ASSIGNMENT, - Tree.Kind.DIVIDE_ASSIGNMENT, - Tree.Kind.REMAINDER_ASSIGNMENT, - Tree.Kind.LEFT_SHIFT_ASSIGNMENT, - Tree.Kind.RIGHT_SHIFT_ASSIGNMENT, - Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, - Tree.Kind.AND_ASSIGNMENT, - Tree.Kind.XOR_ASSIGNMENT, - Tree.Kind.OR_ASSIGNMENT - ); + Tree.Kind.POSTFIX_INCREMENT + )); } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/helpers/ClassPatternsUtils.java b/java-checks/src/main/java/org/sonar/java/checks/helpers/ClassPatternsUtils.java index dc85c801744..4524cab7bac 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/helpers/ClassPatternsUtils.java +++ b/java-checks/src/main/java/org/sonar/java/checks/helpers/ClassPatternsUtils.java @@ -102,7 +102,7 @@ private static boolean isStatic(Tree member) { } private static boolean isClassTree(Tree member) { - return member.is(Tree.Kind.CLASS) || member.is(Tree.Kind.ANNOTATION_TYPE) || member.is(Tree.Kind.INTERFACE) || member.is(Tree.Kind.ENUM); + return Tree.Kind.CLASS_KINDS.contains(member.kind()); } private static boolean hasStaticModifier(ModifiersTree modifiers) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/naming/BadConstantNameCheck.java b/java-checks/src/main/java/org/sonar/java/checks/naming/BadConstantNameCheck.java index 0ba6e29cf6c..8f581f5c058 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/naming/BadConstantNameCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/naming/BadConstantNameCheck.java @@ -16,6 +16,8 @@ */ package org.sonar.java.checks.naming; +import java.util.List; +import java.util.regex.Pattern; import org.sonar.check.Rule; import org.sonar.check.RuleProperty; import org.sonar.java.checks.serialization.SerializableContract; @@ -27,10 +29,6 @@ import org.sonar.plugins.java.api.tree.ModifierKeywordTree; import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey; @DeprecatedRuleKey(ruleKey = "S00115", repositoryKey = "squid") @@ -48,7 +46,7 @@ public class BadConstantNameCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/spring/SpelExpressionCheck.java b/java-checks/src/main/java/org/sonar/java/checks/spring/SpelExpressionCheck.java index 7146561d920..3a677ba3f22 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/spring/SpelExpressionCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/spring/SpelExpressionCheck.java @@ -70,7 +70,7 @@ public class SpelExpressionCheck extends IssuableSubscriptionVisitor { "[a-zA-Z0-9/_-]++(\\[\\d++])*+(\\.[a-zA-Z0-9/_-]++(\\[\\d++])*+)*+"); public List nodesToVisit() { - return List.of(Tree.Kind.CLASS, Tree.Kind.INTERFACE); + return Tree.Kind.CLASS_KINDS; } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/tests/MockitoStaticImportCheck.java b/java-checks/src/main/java/org/sonar/java/checks/tests/MockitoStaticImportCheck.java index 8ed2578983e..7696fa67649 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/tests/MockitoStaticImportCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/tests/MockitoStaticImportCheck.java @@ -35,6 +35,7 @@ import org.sonar.plugins.java.api.tree.MethodTree; import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; +import org.sonarsource.analyzer.commons.collections.ListUtils; @Rule(key = "S8924") public class MockitoStaticImportCheck extends IssuableSubscriptionVisitor { @@ -53,14 +54,14 @@ public class MockitoStaticImportCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return List.of(Tree.Kind.COMPILATION_UNIT, Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.RECORD, Tree.Kind.METHOD_INVOCATION); + return ListUtils.concat(Tree.Kind.CLASS_KINDS, List.of(Tree.Kind.COMPILATION_UNIT, Tree.Kind.METHOD_INVOCATION)); } @Override public void visitNode(Tree tree) { switch (tree.kind()) { case COMPILATION_UNIT -> collectConflictingImports((CompilationUnitTree) tree); - case CLASS, ENUM, INTERFACE, RECORD -> pushClassMethods((ClassTree) tree); + case CLASS, ENUM, INTERFACE, RECORD, ANNOTATION_TYPE, IMPLICIT_CLASS -> pushClassMethods((ClassTree) tree); case METHOD_INVOCATION -> checkMethodInvocation((MethodInvocationTree) tree); default -> { /* not visited */ } } @@ -69,7 +70,7 @@ public void visitNode(Tree tree) { @Override public void leaveNode(Tree tree) { switch (tree.kind()) { - case CLASS, ENUM, INTERFACE, RECORD -> classMethodsStack.pop(); + case CLASS, ENUM, INTERFACE, RECORD, ANNOTATION_TYPE, IMPLICIT_CLASS -> classMethodsStack.pop(); default -> { /* nothing */ } } } diff --git a/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedPrivateClassCheck.java b/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedPrivateClassCheck.java index f51749b0e35..19f6de71966 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedPrivateClassCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedPrivateClassCheck.java @@ -16,7 +16,6 @@ */ package org.sonar.java.checks.unused; -import java.util.Arrays; import java.util.List; import org.sonar.check.Rule; import org.sonar.java.checks.helpers.UnresolvedIdentifiersVisitor; @@ -25,6 +24,7 @@ import org.sonar.plugins.java.api.tree.ClassTree; import org.sonar.plugins.java.api.tree.IdentifierTree; import org.sonar.plugins.java.api.tree.Tree; +import org.sonarsource.analyzer.commons.collections.ListUtils; @Rule(key = "S3985") public class UnusedPrivateClassCheck extends IssuableSubscriptionVisitor { @@ -33,7 +33,7 @@ public class UnusedPrivateClassCheck extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.COMPILATION_UNIT, Tree.Kind.CLASS, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE, Tree.Kind.ENUM); + return ListUtils.concat(Tree.Kind.CLASS_KINDS, List.of(Tree.Kind.COMPILATION_UNIT)); } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedPrivateFieldCheck.java b/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedPrivateFieldCheck.java index 6b65de2a075..ef38a5bfb7f 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedPrivateFieldCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedPrivateFieldCheck.java @@ -72,20 +72,6 @@ public class UnusedPrivateFieldCheck extends IssuableSubscriptionVisitor { "lombok.AllArgsConstructor" ); - private static final Tree.Kind[] ASSIGNMENT_KINDS = { - Tree.Kind.ASSIGNMENT, - Tree.Kind.MULTIPLY_ASSIGNMENT, - Tree.Kind.DIVIDE_ASSIGNMENT, - Tree.Kind.REMAINDER_ASSIGNMENT, - Tree.Kind.PLUS_ASSIGNMENT, - Tree.Kind.MINUS_ASSIGNMENT, - Tree.Kind.LEFT_SHIFT_ASSIGNMENT, - Tree.Kind.RIGHT_SHIFT_ASSIGNMENT, - Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, - Tree.Kind.AND_ASSIGNMENT, - Tree.Kind.XOR_ASSIGNMENT, - Tree.Kind.OR_ASSIGNMENT}; - private final List classes = new ArrayList<>(); private final Map> assignments = new HashMap<>(); private final Set unknownIdentifiers = new HashSet<>(); @@ -248,9 +234,8 @@ private Set getIgnoredAnnotations() { } private void collectAssignment(ExpressionTree expressionTree) { - if (expressionTree.is(ASSIGNMENT_KINDS)) { - AssignmentExpressionTree assignmentExpressionTree = (AssignmentExpressionTree) expressionTree; - ExpressionTree variable = (assignmentExpressionTree).variable(); + if (expressionTree instanceof AssignmentExpressionTree assignmentExpressionTree) { + ExpressionTree variable = assignmentExpressionTree.variable(); IdentifierTree identifier = null; if (variable.is(Tree.Kind.IDENTIFIER)) { identifier = (IdentifierTree) variable; diff --git a/java-frontend/src/main/java/org/sonar/java/Measurer.java b/java-frontend/src/main/java/org/sonar/java/Measurer.java index 977455037fc..ff8dc8e9ba4 100644 --- a/java-frontend/src/main/java/org/sonar/java/Measurer.java +++ b/java-frontend/src/main/java/org/sonar/java/Measurer.java @@ -39,14 +39,7 @@ public class Measurer extends SubscriptionVisitor { - private static final Tree.Kind[] CLASS_KINDS = new Tree.Kind[]{ - Tree.Kind.CLASS, - Tree.Kind.INTERFACE, - Tree.Kind.ENUM, - Tree.Kind.ANNOTATION_TYPE, - Tree.Kind.RECORD, - Tree.Kind.IMPLICIT_CLASS - }; + private static final Tree.Kind[] CLASS_KINDS = Tree.Kind.CLASS_KINDS.toArray(new Tree.Kind[0]); private final SensorContext sensorContext; private final NoSonarFilter noSonarFilter; diff --git a/java-frontend/src/main/java/org/sonar/java/ast/visitors/ComplexityVisitor.java b/java-frontend/src/main/java/org/sonar/java/ast/visitors/ComplexityVisitor.java index 874c128c523..938fe358915 100644 --- a/java-frontend/src/main/java/org/sonar/java/ast/visitors/ComplexityVisitor.java +++ b/java-frontend/src/main/java/org/sonar/java/ast/visitors/ComplexityVisitor.java @@ -57,14 +57,14 @@ public void visitMethod(MethodTree tree) { @Override public void visitClass(ClassTree tree) { - if(root.is(Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE, Tree.Kind.COMPILATION_UNIT)) { + if (Tree.Kind.CLASS_KINDS.contains(root.kind()) || root.is(Tree.Kind.COMPILATION_UNIT)) { super.visitClass(tree); } } @Override public void visitLambdaExpression(LambdaExpressionTree lambdaExpressionTree) { - if(root.is(Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE, Tree.Kind.COMPILATION_UNIT) || lambdaExpressionTree.equals(root)) { + if (Tree.Kind.CLASS_KINDS.contains(root.kind()) || root.is(Tree.Kind.COMPILATION_UNIT) || lambdaExpressionTree.equals(root)) { blame.add(lambdaExpressionTree.arrowToken()); super.visitLambdaExpression(lambdaExpressionTree); } diff --git a/java-frontend/src/main/java/org/sonar/java/ast/visitors/PublicApiChecker.java b/java-frontend/src/main/java/org/sonar/java/ast/visitors/PublicApiChecker.java index 29c45664087..ff8e68234d1 100644 --- a/java-frontend/src/main/java/org/sonar/java/ast/visitors/PublicApiChecker.java +++ b/java-frontend/src/main/java/org/sonar/java/ast/visitors/PublicApiChecker.java @@ -21,16 +21,16 @@ import java.util.Objects; import java.util.Optional; import javax.annotation.Nullable; -import org.sonar.plugins.java.api.tree.SyntaxTrivia.CommentKind; -import org.sonarsource.analyzer.commons.collections.ListUtils; import org.sonar.java.model.ModifiersUtils; import org.sonar.plugins.java.api.tree.ClassTree; import org.sonar.plugins.java.api.tree.MethodTree; import org.sonar.plugins.java.api.tree.Modifier; import org.sonar.plugins.java.api.tree.ModifiersTree; import org.sonar.plugins.java.api.tree.SyntaxTrivia; +import org.sonar.plugins.java.api.tree.SyntaxTrivia.CommentKind; import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; +import org.sonarsource.analyzer.commons.collections.ListUtils; public class PublicApiChecker { @@ -38,14 +38,7 @@ private PublicApiChecker() { // Utility class } - private static final Tree.Kind[] CLASS_KINDS = { - Tree.Kind.CLASS, - Tree.Kind.INTERFACE, - Tree.Kind.ENUM, - Tree.Kind.ANNOTATION_TYPE, - Tree.Kind.RECORD, - Tree.Kind.IMPLICIT_CLASS - }; + private static final Tree.Kind[] CLASS_KINDS = Tree.Kind.CLASS_KINDS.toArray(new Tree.Kind[0]); private static final Tree.Kind[] METHOD_KINDS = { Tree.Kind.METHOD, diff --git a/java-frontend/src/main/java/org/sonar/java/model/JUtils.java b/java-frontend/src/main/java/org/sonar/java/model/JUtils.java index 903f0048ef7..98f62dd9207 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/JUtils.java +++ b/java-frontend/src/main/java/org/sonar/java/model/JUtils.java @@ -115,7 +115,7 @@ public static Symbol enclosingClass(Tree t) { if (t == null) { return null; } - if (t.is(Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE)) { + if (Tree.Kind.CLASS_KINDS.contains(t.kind())) { return ((ClassTree) t).symbol(); } t = t.parent(); diff --git a/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/Tree.java b/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/Tree.java index 244b4c2959f..a82959ba821 100644 --- a/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/Tree.java +++ b/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/Tree.java @@ -16,8 +16,9 @@ */ package org.sonar.plugins.java.api.tree; -import org.sonar.java.annotations.Beta; +import java.util.List; import javax.annotation.Nullable; +import org.sonar.java.annotations.Beta; import org.sonar.sslr.grammar.GrammarRuleKey; /** @@ -151,6 +152,7 @@ enum Kind implements GrammarRuleKey { /** * {@link SwitchExpressionTree} + * * @since SonarJava 5.12: Support of Java 12 */ SWITCH_EXPRESSION(SwitchExpressionTree.class), @@ -776,6 +778,46 @@ enum Kind implements GrammarRuleKey { */ LIST(ListTree.class); + /** + * The {@link Kind}s of all class-like type declarations: {@link Kind#CLASS}, {@link Kind#ENUM}, {@link Kind#INTERFACE}, + * {@link Kind#ANNOTATION_TYPE}, {@link Kind#RECORD} and {@link Kind#IMPLICIT_CLASS}. All of these are backed by {@link ClassTree}. + * + *

Use this as the single source of truth when a visitor or predicate must handle every class-like structure, instead of + * hand-listing the kinds. In particular, it can be returned directly from {@code nodesToVisit()} of a subscription visitor that + * needs to visit all class declarations.

+ */ + public static final List CLASS_KINDS = List.of( + CLASS, + ENUM, + INTERFACE, + ANNOTATION_TYPE, + RECORD, + IMPLICIT_CLASS + ); + + /** + * The {@link Kind}s of all assignment expressions: the simple {@link Kind#ASSIGNMENT} and the eleven compound assignment + * operators. All of these are backed by {@link AssignmentExpressionTree}. + * + *

Use this as the single source of truth when a visitor or predicate must handle every assignment structure, instead of + * hand-listing the kinds. In particular, it can be returned directly from {@code nodesToVisit()} of a subscription visitor that + * needs to visit all assignments.

+ */ + public static final List ASSIGNMENT_KINDS = List.of( + ASSIGNMENT, + MULTIPLY_ASSIGNMENT, + DIVIDE_ASSIGNMENT, + REMAINDER_ASSIGNMENT, + PLUS_ASSIGNMENT, + MINUS_ASSIGNMENT, + LEFT_SHIFT_ASSIGNMENT, + RIGHT_SHIFT_ASSIGNMENT, + UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, + AND_ASSIGNMENT, + XOR_ASSIGNMENT, + OR_ASSIGNMENT + ); + final Class associatedInterface; Kind(Class associatedInterface) { diff --git a/java-frontend/src/test/java/org/sonar/plugins/java/api/tree/TreeTest.java b/java-frontend/src/test/java/org/sonar/plugins/java/api/tree/TreeTest.java index 6670957227b..ed0808a7837 100644 --- a/java-frontend/src/test/java/org/sonar/plugins/java/api/tree/TreeTest.java +++ b/java-frontend/src/test/java/org/sonar/plugins/java/api/tree/TreeTest.java @@ -16,6 +16,7 @@ */ package org.sonar.plugins.java.api.tree; +import java.util.Arrays; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -27,4 +28,20 @@ void test() { assertThat(Tree.Kind.values()).hasSize(129); } + @Test + void class_kinds_contains_exactly_all_kinds_backed_by_class_tree() { + Tree.Kind[] expected = Arrays.stream(Tree.Kind.values()) + .filter(kind -> kind.getAssociatedInterface() == ClassTree.class) + .toArray(Tree.Kind[]::new); + assertThat(Tree.Kind.CLASS_KINDS).containsExactlyInAnyOrder(expected); + } + + @Test + void assignment_kinds_contains_exactly_all_kinds_backed_by_assignment_expression_tree() { + Tree.Kind[] expected = Arrays.stream(Tree.Kind.values()) + .filter(kind -> kind.getAssociatedInterface() == AssignmentExpressionTree.class) + .toArray(Tree.Kind[]::new); + assertThat(Tree.Kind.ASSIGNMENT_KINDS).containsExactlyInAnyOrder(expected); + } + }