diff --git a/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsBuilderMethodFinder.java b/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsBuilderMethodFinder.java index bb2f1bc014a..6df1003cfb1 100644 --- a/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsBuilderMethodFinder.java +++ b/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsBuilderMethodFinder.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; import org.sonar.plugins.java.api.semantic.Symbol; @@ -67,7 +66,7 @@ public void visitNode(Tree tree) { // If the call to build is made on a builder variable, we look into initialization and usages for a call to the method getIdentifier(invocation).ifPresentOrElse(identifier -> { Symbol symbol = identifier.symbol(); - if (!JUtils.isLocalVariable(symbol) || JUtils.isParameter(symbol)) { + if (!symbol.isLocalVariable() || symbol.isParameter()) { return; } VariableTree declaration = (VariableTree) symbol.declaration(); diff --git a/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsConsumerBuilderUsageCheck.java b/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsConsumerBuilderUsageCheck.java index 79b6819e319..dc769276776 100644 --- a/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsConsumerBuilderUsageCheck.java +++ b/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsConsumerBuilderUsageCheck.java @@ -26,7 +26,6 @@ import org.sonar.java.checks.helpers.ExpressionsHelper; import org.sonar.java.checks.methods.AbstractMethodDetection; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.model.Symbols; import org.sonar.plugins.java.api.semantic.MethodMatchers; import org.sonar.plugins.java.api.semantic.Symbol; @@ -118,7 +117,7 @@ private static boolean isVariableContainingABuilderResult(ExpressionTree express return false; } Symbol variable = ((IdentifierTree) expression).symbol(); - return JUtils.isLocalVariable(variable) && + return variable.isLocalVariable() && ExpressionsHelper.initializedAndAssignedExpressionStream(variable) .anyMatch(AwsConsumerBuilderUsageCheck::isBuilder); } diff --git a/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsLambdaSyncCallCheck.java b/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsLambdaSyncCallCheck.java index 3ade46b51d4..e8f51d13a1b 100644 --- a/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsLambdaSyncCallCheck.java +++ b/java-checks-aws/src/main/java/org/sonar/java/checks/aws/AwsLambdaSyncCallCheck.java @@ -25,7 +25,6 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - import org.sonar.check.Rule; import org.sonar.java.checks.helpers.ExpressionsHelper; import org.sonar.java.model.ExpressionUtils; @@ -39,9 +38,6 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; -import static org.sonar.java.model.JUtils.isLocalVariable; -import static org.sonar.java.model.JUtils.isParameter; - @Rule(key = "S6246") public class AwsLambdaSyncCallCheck extends AbstractAwsMethodVisitor { @@ -89,10 +85,10 @@ private static Optional getSyncCalls(MethodInvocationTree tree) { // We know there is at least one usage, i.e. the one we just got above. List localUsages = invokeRequest.symbol().usages().stream() - .filter(u -> isLocalVariable(u.symbol()) && !u.equals(invokeRequest)) + .filter(u -> u.symbol().isLocalVariable() && !u.equals(invokeRequest)) .collect(Collectors.toList()); - if (isParameter(invokeRequest.symbol()) + if (invokeRequest.symbol().isParameter() || localUsages.stream().anyMatch(lu -> isArgumentToACall(lu) || statementSetsAsyncCall(lu)) || declarationSetsAsyncCall(invokeRequest)) { return Optional.empty(); @@ -113,7 +109,7 @@ private static boolean isArgumentToACall(IdentifierTree invokeRequest) { private static boolean hasLocalVarDeclaration(IdentifierTree invokeRequest) { Tree declaration = invokeRequest.symbol().declaration(); - return (declaration != null && declaration.is(Tree.Kind.VARIABLE) && isLocalVariable(((VariableTree) declaration).symbol())); + return (declaration != null && declaration.is(Tree.Kind.VARIABLE) && ((VariableTree) declaration).symbol().isLocalVariable()); } /** diff --git a/java-checks-common/src/main/java/org/sonar/java/checks/helpers/ExpressionsHelper.java b/java-checks-common/src/main/java/org/sonar/java/checks/helpers/ExpressionsHelper.java index 67d4153ab96..b335d531382 100644 --- a/java-checks-common/src/main/java/org/sonar/java/checks/helpers/ExpressionsHelper.java +++ b/java-checks-common/src/main/java/org/sonar/java/checks/helpers/ExpressionsHelper.java @@ -32,7 +32,6 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.JavaFileScannerContext; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; @@ -255,7 +254,7 @@ public static Optional getInvokedSymbol(MethodInvocationTree mit) { } public static boolean isNotReassigned(Symbol symbol) { - return symbol.isFinal() || (symbol.isVariableSymbol() && JUtils.isEffectivelyFinal(((Symbol.VariableSymbol) symbol))); + return symbol.isFinal() || (symbol.isVariableSymbol() && ((Symbol.VariableSymbol) symbol).isEffectivelyFinal()); } public static List getIdentifierAssignments(IdentifierTree identifier) { diff --git a/java-checks-common/src/main/java/org/sonar/java/checks/helpers/HardcodedStringExpressionChecker.java b/java-checks-common/src/main/java/org/sonar/java/checks/helpers/HardcodedStringExpressionChecker.java index 630ea526616..30a99a8bea9 100644 --- a/java-checks-common/src/main/java/org/sonar/java/checks/helpers/HardcodedStringExpressionChecker.java +++ b/java-checks-common/src/main/java/org/sonar/java/checks/helpers/HardcodedStringExpressionChecker.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Set; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.model.LiteralUtils; import org.sonar.plugins.java.api.JavaFileScannerContext; import org.sonar.plugins.java.api.semantic.MethodMatchers; @@ -158,12 +157,12 @@ private static boolean isDerivedFromPlainText(IdentifierTree identifier, List visited) { Symbol symbol = identifier.symbol(); boolean firstVisit = visited.add(symbol); - if (!firstVisit || !symbol.isVariableSymbol() || JUtils.isParameter(symbol) || isNonFinalField(symbol)) { + if (!firstVisit || !symbol.isVariableSymbol() || symbol.isParameter() || isNonFinalField(symbol)) { return false; } VariableTree variable = (VariableTree) symbol.declaration(); if (variable == null) { - return JUtils.constantValue((Symbol.VariableSymbol) symbol).isPresent(); + return ((Symbol.VariableSymbol) symbol).constantValue().isPresent(); } List assignments = getIdentifierAssignments(identifier); diff --git a/java-checks-common/src/test/java/org/sonar/java/checks/helpers/ExpressionsHelperTest.java b/java-checks-common/src/test/java/org/sonar/java/checks/helpers/ExpressionsHelperTest.java index 9478ec4a73c..4283d8f08f1 100644 --- a/java-checks-common/src/test/java/org/sonar/java/checks/helpers/ExpressionsHelperTest.java +++ b/java-checks-common/src/test/java/org/sonar/java/checks/helpers/ExpressionsHelperTest.java @@ -21,12 +21,14 @@ import java.lang.reflect.Constructor; import javax.annotation.Nullable; - import org.junit.jupiter.api.Test; +import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.tree.IdentifierTree; import org.sonar.plugins.java.api.tree.MethodTree; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; class ExpressionsHelperTest extends JParserTestUtils { @@ -127,6 +129,23 @@ void variableSwapSOE() { assertValueResolution(code, null); } + @Test + void isNotReassignedTest(){ + Symbol.VariableSymbol symbol = mock(Symbol.VariableSymbol.class); + + when(symbol.isFinal()).thenReturn(true); + assertThat(ExpressionsHelper.isNotReassigned(symbol)).isTrue(); + + when(symbol.isFinal()).thenReturn(false); + assertThat(ExpressionsHelper.isNotReassigned(symbol)).isFalse(); + + when(symbol.isVariableSymbol()).thenReturn(true); + assertThat(ExpressionsHelper.isNotReassigned(symbol)).isFalse(); + + when(symbol.isEffectivelyFinal()).thenReturn(true); + assertThat(ExpressionsHelper.isNotReassigned(symbol)).isTrue(); + } + private void assertValueResolution(String code, @Nullable T target) { MethodTree method = methodTree(code); IdentifierTree a = variableFromLastReturnStatement(method.block().body()); diff --git a/java-checks-common/src/test/java/org/sonar/java/checks/helpers/HardcodedStringExpressionCheckerTest.java b/java-checks-common/src/test/java/org/sonar/java/checks/helpers/HardcodedStringExpressionCheckerTest.java new file mode 100644 index 00000000000..c9afab6bc05 --- /dev/null +++ b/java-checks-common/src/test/java/org/sonar/java/checks/helpers/HardcodedStringExpressionCheckerTest.java @@ -0,0 +1,78 @@ +/* + * SonarQube Java + * Copyright (C) 2012-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.java.checks.helpers; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.java.api.semantic.Symbol; +import org.sonar.plugins.java.api.tree.IdentifierTree; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.VariableTree; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.java.checks.helpers.HardcodedStringExpressionChecker.isExpressionDerivedFromPlainText; + +class HardcodedStringExpressionCheckerTest { + + @Test + void isExpressionDerivedFromPlainTextTest() { + IdentifierTree expression = mock(IdentifierTree.class); + when(expression.kind()).thenReturn(Tree.Kind.IDENTIFIER); + Symbol.VariableSymbol symbol = mockSymbol(true, false, true); + Symbol owner = mockOwner(true); + when(symbol.owner()).thenReturn(owner); + VariableTree declaration = mock(VariableTree.class); + when(symbol.declaration()).thenReturn(declaration); + when(expression.symbol()).thenReturn(symbol); + + assertThat(isExpressionDerivedFromPlainText(expression, new ArrayList<>(), new HashSet<>())).isFalse(); + + when(symbol.declaration()).thenReturn(null); + when(symbol.constantValue()).thenReturn(Optional.of("SOME VALUE")); + assertThat(isExpressionDerivedFromPlainText(expression, new ArrayList<>(), new HashSet<>())).isTrue(); + + when(symbol.isVariableSymbol()).thenReturn(false); + assertThat(isExpressionDerivedFromPlainText(expression, new ArrayList<>(), new HashSet<>())).isFalse(); + + when(symbol.isVariableSymbol()).thenReturn(true); + when(symbol.isParameter()).thenReturn(true); + assertThat(isExpressionDerivedFromPlainText(expression, new ArrayList<>(), new HashSet<>())).isFalse(); + + } + + private Symbol mockOwner(boolean isTypeSymbol){ + Symbol owner = mock(Symbol.class); + when(owner.isTypeSymbol()).thenReturn(isTypeSymbol); + return owner; + } + + private Symbol.VariableSymbol mockSymbol(boolean isVariableSymbol, boolean isParameter, boolean isFinal){ + Symbol.VariableSymbol symbol = mock(Symbol.VariableSymbol.class); + when(symbol.isVariableSymbol()).thenReturn(isVariableSymbol); + when(symbol.isParameter()).thenReturn(isParameter); + when(symbol.isFinal()).thenReturn(isFinal); + return symbol; + } + +} diff --git a/java-checks/src/main/java/org/sonar/java/checks/AbstractMissingDeprecatedChecker.java b/java-checks/src/main/java/org/sonar/java/checks/AbstractMissingDeprecatedChecker.java index 0b1153f0e2f..ad82c533f27 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/AbstractMissingDeprecatedChecker.java +++ b/java-checks/src/main/java/org/sonar/java/checks/AbstractMissingDeprecatedChecker.java @@ -33,7 +33,6 @@ import static org.sonar.java.checks.helpers.DeprecatedCheckerHelper.deprecatedAnnotation; import static org.sonar.java.checks.helpers.DeprecatedCheckerHelper.hasJavadocDeprecatedTag; -import static org.sonar.java.model.JUtils.isLocalVariable; public abstract class AbstractMissingDeprecatedChecker extends IssuableSubscriptionVisitor { @@ -48,7 +47,7 @@ public List nodesToVisit() { @Override public void visitNode(Tree tree) { - boolean isLocalVar = tree.is(Tree.Kind.VARIABLE) && isLocalVariable(((VariableTree) tree).symbol()); + boolean isLocalVar = tree.is(Tree.Kind.VARIABLE) && ((VariableTree) tree).symbol().isLocalVariable(); AnnotationTree deprecatedAnnotation = deprecatedAnnotation(tree); boolean hasDeprecatedAnnotation = deprecatedAnnotation != null; boolean hasJavadocDeprecatedTag = hasJavadocDeprecatedTag(tree); diff --git a/java-checks/src/main/java/org/sonar/java/checks/AbstractSerializableInnerClassRule.java b/java-checks/src/main/java/org/sonar/java/checks/AbstractSerializableInnerClassRule.java index 5aff823dc70..7ceba144418 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/AbstractSerializableInnerClassRule.java +++ b/java-checks/src/main/java/org/sonar/java/checks/AbstractSerializableInnerClassRule.java @@ -20,7 +20,6 @@ package org.sonar.java.checks; import org.sonar.java.checks.helpers.ExpressionsHelper; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; @@ -62,7 +61,7 @@ private void visitClassTree(ClassTree classTree) { } private static boolean isInnerClass(Symbol.TypeSymbol typeSymbol) { - return !typeSymbol.equals(JUtils.outermostClass(typeSymbol)); + return !typeSymbol.equals(typeSymbol.outermostClass()); } protected boolean isSerializable(Type type) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/AnonymousClassShouldBeLambdaCheck.java b/java-checks/src/main/java/org/sonar/java/checks/AnonymousClassShouldBeLambdaCheck.java index dd2a5d143e1..b75c48081d6 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/AnonymousClassShouldBeLambdaCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/AnonymousClassShouldBeLambdaCheck.java @@ -24,11 +24,10 @@ import java.util.Set; import java.util.stream.Collectors; import org.sonar.check.Rule; -import org.sonar.plugins.java.api.JavaVersionAwareVisitor; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.JavaFileScanner; import org.sonar.plugins.java.api.JavaFileScannerContext; import org.sonar.plugins.java.api.JavaVersion; +import org.sonar.plugins.java.api.JavaVersionAwareVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Symbol.MethodSymbol; import org.sonar.plugins.java.api.semantic.Type; @@ -89,7 +88,7 @@ private static boolean isSAM(ClassTree classBody) { // should be anonymous class of interface and not abstract class return symbol.interfaces().size() == 1 && symbol.superClass().is(JAVA_LANG_OBJECT) - && hasSingleAbstractMethodInHierarchy(JUtils.superTypes(symbol)); + && hasSingleAbstractMethodInHierarchy(symbol.superTypes()); } return false; } diff --git a/java-checks/src/main/java/org/sonar/java/checks/CollectionInappropriateCallsCheck.java b/java-checks/src/main/java/org/sonar/java/checks/CollectionInappropriateCallsCheck.java index f86d19f21e9..107ca8f76c9 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/CollectionInappropriateCallsCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/CollectionInappropriateCallsCheck.java @@ -26,7 +26,6 @@ import java.util.stream.Collectors; import org.sonar.check.Rule; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.model.Symbols; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; @@ -155,7 +154,7 @@ private static Type findSuperTypeMatching(Type type, String genericTypeName) { if (type.is(genericTypeName)) { return type; } - return JUtils.superTypes(type.symbol()) + return type.symbol().superTypes() .stream() .filter(superType -> superType.is(genericTypeName)) .findFirst() diff --git a/java-checks/src/main/java/org/sonar/java/checks/CompareToNotOverloadedCheck.java b/java-checks/src/main/java/org/sonar/java/checks/CompareToNotOverloadedCheck.java index 9867b594108..5254ca2f329 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/CompareToNotOverloadedCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/CompareToNotOverloadedCheck.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.List; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.tree.MethodTree; @@ -41,7 +40,7 @@ public void visitNode(Tree tree) { MethodTree methodTree = (MethodTree) tree; if (isCompareToMethod(methodTree) && Boolean.FALSE.equals(methodTree.isOverriding())) { Symbol.TypeSymbol ownerType = (Symbol.TypeSymbol) methodTree.symbol().owner(); - JUtils.superTypes(ownerType).stream().filter(supertype -> supertype.is("java.lang.Comparable")).findFirst().ifPresent( + ownerType.superTypes().stream().filter(supertype -> supertype.is("java.lang.Comparable")).findFirst().ifPresent( comparableType -> { String name = "Object"; if (comparableType.isParameterized()) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/ConstructorCallingOverridableCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ConstructorCallingOverridableCheck.java index 5bc38f7623a..797fa6f2e3d 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ConstructorCallingOverridableCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ConstructorCallingOverridableCheck.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.List; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; @@ -112,7 +111,7 @@ private boolean isThisOrSuper(ExpressionTree expression) { private boolean isMethodDefinedOnConstructedType(Symbol symbol) { Type typeDefiningMethod = symbol.enclosingClass().type().erasure(); - for (Type superType : JUtils.superTypes(constructorType)) { + for (Type superType : constructorType.superTypes()) { if (superType.erasure().equals(typeDefiningMethod)) { return true; } diff --git a/java-checks/src/main/java/org/sonar/java/checks/DeadStoreCheck.java b/java-checks/src/main/java/org/sonar/java/checks/DeadStoreCheck.java index 81b25c8645a..49c877e5c76 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/DeadStoreCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/DeadStoreCheck.java @@ -51,8 +51,6 @@ import org.sonar.plugins.java.api.tree.UnaryExpressionTree; import org.sonar.plugins.java.api.tree.VariableTree; -import static org.sonar.java.model.JUtils.isLocalVariable; - @Rule(key = "S1854") public class DeadStoreCheck extends IssuableSubscriptionVisitor { @@ -156,7 +154,7 @@ private void handleAssignment(Set out, Set assignmentLHS, Assignme ExpressionTree lhs = ExpressionUtils.skipParentheses(element.variable()); if (lhs.is(Tree.Kind.IDENTIFIER)) { Symbol symbol = ((IdentifierTree) lhs).symbol(); - if (isLocalVariable(symbol) + if (symbol.isLocalVariable() && !out.contains(symbol) && (element.is(Tree.Kind.ASSIGNMENT) || isParentExpressionStatement(element)) && !UNRESOLVED_IDENTIFIERS_VISITOR.isUnresolved(symbol.name())) { @@ -177,7 +175,7 @@ private static boolean isParentExpressionStatement(Tree element) { private static void handleIdentifier(Set out, Set assignmentLHS, IdentifierTree element) { Symbol symbol = element.symbol(); - if (!assignmentLHS.contains(element) && isLocalVariable(symbol)) { + if (!assignmentLHS.contains(element) && symbol.isLocalVariable()) { out.add(symbol); } } @@ -234,7 +232,7 @@ private void handlePrefixExpression(Set out, UnaryExpressionTree element ExpressionTree expression = element.expression(); if (isParentExpressionStatement(element) && expression.is(Tree.Kind.IDENTIFIER)) { Symbol symbol = ((IdentifierTree) expression).symbol(); - if (isLocalVariable(symbol) && !out.contains(symbol)) { + if (symbol.isLocalVariable() && !out.contains(symbol)) { createIssue(element, symbol); } } @@ -244,7 +242,7 @@ private void handlePostfixExpression(Set out, UnaryExpressionTree elemen ExpressionTree expression = ExpressionUtils.skipParentheses(element.expression()); if (expression.is(Tree.Kind.IDENTIFIER)) { Symbol symbol = ((IdentifierTree) expression).symbol(); - if (isLocalVariable(symbol) && !out.contains(symbol)) { + if (symbol.isLocalVariable() && !out.contains(symbol)) { createIssue(element, symbol); } } @@ -306,7 +304,7 @@ public void visitAssignmentExpression(AssignmentExpressionTree tree) { ExpressionTree lhs = ExpressionUtils.skipParentheses(tree.variable()); if (lhs.is(Tree.Kind.IDENTIFIER)) { Symbol symbol = ((IdentifierTree) lhs).symbol(); - if (isLocalVariable(symbol)) { + if (symbol.isLocalVariable()) { assignedLocalVars.add(symbol); } super.visitAssignmentExpression(tree); diff --git a/java-checks/src/main/java/org/sonar/java/checks/ForLoopVariableTypeCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ForLoopVariableTypeCheck.java index cf2a8e2bc5d..fcb472836b6 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ForLoopVariableTypeCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ForLoopVariableTypeCheck.java @@ -23,7 +23,6 @@ import java.util.List; import javax.annotation.CheckForNull; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.JavaFileScannerContext; import org.sonar.plugins.java.api.semantic.Symbol; @@ -81,7 +80,7 @@ private static Type getCollectionItemType(ExpressionTree expression) { return ((Type.ArrayType) expressionType).elementType(); } if(expressionType.isClass()) { - return JUtils.superTypes(expressionType.symbol()).stream() + return expressionType.symbol().superTypes().stream() .filter(t -> t.is("java.lang.Iterable") && t.isParameterized()) .findFirst() .map(iter -> iter.typeArguments().get(0)) diff --git a/java-checks/src/main/java/org/sonar/java/checks/LazyArgEvaluationCheck.java b/java-checks/src/main/java/org/sonar/java/checks/LazyArgEvaluationCheck.java index 3363be8de44..80cbabe174b 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/LazyArgEvaluationCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/LazyArgEvaluationCheck.java @@ -27,7 +27,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.JavaFileScanner; import org.sonar.plugins.java.api.JavaFileScannerContext; import org.sonar.plugins.java.api.semantic.MethodMatchers; @@ -315,7 +314,7 @@ private static boolean isGetterMatchingFieldNameAndType(Symbol.MethodSymbol meth private static boolean isAnnotationMethod(MethodInvocationTree tree) { Symbol owner = tree.methodSymbol().owner(); - return owner.isTypeSymbol() && JUtils.isAnnotation((Symbol.TypeSymbol) owner); + return owner.isTypeSymbol() && ((Symbol.TypeSymbol) owner).isAnnotation(); } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/LeastSpecificTypeCheck.java b/java-checks/src/main/java/org/sonar/java/checks/LeastSpecificTypeCheck.java index 3bc1ee6c83c..862faef990b 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/LeastSpecificTypeCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/LeastSpecificTypeCheck.java @@ -27,7 +27,6 @@ import java.util.Optional; import java.util.Set; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.SymbolMetadata; @@ -182,7 +181,7 @@ private void computeChainsForSuperType(List> result, Symbol m, Type t private static boolean definesOrInheritsSymbol(Symbol symbol, Symbol.TypeSymbol typeSymbol) { return definesSymbol(symbol, typeSymbol) - || JUtils.superTypes(typeSymbol).stream().anyMatch(superType -> definesSymbol(symbol, superType.symbol())); + || typeSymbol.superTypes().stream().anyMatch(superType -> definesSymbol(symbol, superType.symbol())); } private static boolean definesSymbol(Symbol m, Symbol.TypeSymbol typeSymbol) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/ReuseRandomCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ReuseRandomCheck.java index b2a1a6d91be..98beb3c33be 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ReuseRandomCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ReuseRandomCheck.java @@ -24,7 +24,6 @@ import org.sonar.check.Rule; import org.sonar.java.checks.methods.AbstractMethodDetection; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.semantic.MethodMatchers; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.tree.AssignmentExpressionTree; @@ -83,7 +82,7 @@ private static boolean isUsedOnlyLocally(Tree tree) { private static boolean isLocalVariable(ExpressionTree expression) { if (expression.is(Kind.IDENTIFIER)) { - return JUtils.isLocalVariable(((IdentifierTree) expression).symbol()); + return ((IdentifierTree) expression).symbol().isLocalVariable(); } return false; } diff --git a/java-checks/src/main/java/org/sonar/java/checks/SynchronizedFieldAssignmentCheck.java b/java-checks/src/main/java/org/sonar/java/checks/SynchronizedFieldAssignmentCheck.java index ac6429c9b31..11a8a6aec2a 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/SynchronizedFieldAssignmentCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/SynchronizedFieldAssignmentCheck.java @@ -24,7 +24,6 @@ import javax.annotation.CheckForNull; import org.sonar.check.Rule; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.tree.AssignmentExpressionTree; @@ -65,7 +64,7 @@ public void visitNode(Tree tree) { private static Symbol getParam(ExpressionTree tree) { if (tree.is(Tree.Kind.IDENTIFIER)) { Symbol reference = ((IdentifierTree) tree).symbol(); - if (JUtils.isParameter(reference)) { + if (reference.isParameter()) { return reference; } } diff --git a/java-checks/src/main/java/org/sonar/java/checks/TransientFieldInNonSerializableCheck.java b/java-checks/src/main/java/org/sonar/java/checks/TransientFieldInNonSerializableCheck.java index a85bb269379..1994141729e 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/TransientFieldInNonSerializableCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/TransientFieldInNonSerializableCheck.java @@ -20,7 +20,6 @@ package org.sonar.java.checks; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.java.model.ModifiersUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol; @@ -56,7 +55,7 @@ public void visitNode(Tree tree) { } private static boolean isNotSerializable(Symbol.TypeSymbol symbol) { - for (Type superType : JUtils.superTypes(symbol)) { + for (Type superType : symbol.superTypes()) { if (superType.isUnknown()) { return false; } diff --git a/java-checks/src/main/java/org/sonar/java/checks/UselessExtendsCheck.java b/java-checks/src/main/java/org/sonar/java/checks/UselessExtendsCheck.java index 49d4ebf6d71..2f9863062c7 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/UselessExtendsCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/UselessExtendsCheck.java @@ -20,7 +20,6 @@ package org.sonar.java.checks; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.java.model.SyntacticEquivalence; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol.TypeSymbol; @@ -59,7 +58,7 @@ public void visitNode(Tree tree) { } List superInterfacesTypes = getTypes(superInterfaces); - List superTypes = new ArrayList<>(JUtils.superTypes(classTree.symbol())); + List superTypes = new ArrayList<>(classTree.symbol().superTypes()); superTypes.sort(new SuperTypeComparator(superInterfacesTypes)); Set reportedNames = new HashSet<>(); diff --git a/java-checks/src/main/java/org/sonar/java/checks/VarCanBeUsedCheck.java b/java-checks/src/main/java/org/sonar/java/checks/VarCanBeUsedCheck.java index d7c5b536743..c1a8282c446 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/VarCanBeUsedCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/VarCanBeUsedCheck.java @@ -22,15 +22,13 @@ import java.util.Collections; import java.util.List; import java.util.Locale; - import org.sonar.check.Rule; -import org.sonar.plugins.java.api.JavaVersionAwareVisitor; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.model.LineUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.JavaFileScannerContext; import org.sonar.plugins.java.api.JavaVersion; +import org.sonar.plugins.java.api.JavaVersionAwareVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; import org.sonar.plugins.java.api.tree.ExpressionTree; @@ -80,7 +78,7 @@ public void visitNode(Tree tree) { type.is(Tree.Kind.VAR_TYPE) || isArrayInitializerWithoutType(initializer) || symbolType.isUnknown() || - !JUtils.isLocalVariable(variableTree.symbol()) || + !variableTree.symbol().isLocalVariable() || symbolType.isParameterized()) { return; } diff --git a/java-checks/src/main/java/org/sonar/java/checks/regex/AbstractRegexCheck.java b/java-checks/src/main/java/org/sonar/java/checks/regex/AbstractRegexCheck.java index b2a2326c75e..b5b9790a5bf 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/regex/AbstractRegexCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/regex/AbstractRegexCheck.java @@ -33,7 +33,6 @@ import javax.annotation.Nullable; import org.sonar.java.annotations.VisibleForTesting; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.regex.RegexCheck; import org.sonar.java.regex.RegexScannerContext; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; @@ -273,7 +272,7 @@ protected static Optional getFinalVariableInitializer(Identifier } Symbol.VariableSymbol variableSymbol = (Symbol.VariableSymbol) symbol; - if (!(variableSymbol.isFinal() || JUtils.isEffectivelyFinal(variableSymbol))) { + if (!(variableSymbol.isFinal() || variableSymbol.isEffectivelyFinal())) { return Optional.empty(); } VariableTree declaration = variableSymbol.declaration(); diff --git a/java-checks/src/main/java/org/sonar/java/checks/regex/AbstractRegexCheckTrackingMatchers.java b/java-checks/src/main/java/org/sonar/java/checks/regex/AbstractRegexCheckTrackingMatchers.java index b3df08055fc..9d5a71975c1 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/regex/AbstractRegexCheckTrackingMatchers.java +++ b/java-checks/src/main/java/org/sonar/java/checks/regex/AbstractRegexCheckTrackingMatchers.java @@ -30,7 +30,6 @@ import java.util.Set; import javax.annotation.Nullable; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.semantic.MethodMatchers; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; @@ -247,7 +246,7 @@ private void handleAssignment(MethodInvocationTree mit, RegexParseResult regex) private static boolean isPrivateEffectivelyFinalVariable(Symbol symbol) { return (symbol.isPrivate() || symbol.owner().isMethodSymbol()) && symbol.isVariableSymbol() - && (symbol.isFinal() || JUtils.isEffectivelyFinal((Symbol.VariableSymbol) symbol)); + && (symbol.isFinal() || ((Symbol.VariableSymbol) symbol).isEffectivelyFinal()); } private static Optional getAssignedPrivateEffectivelyFinalVariable(MethodInvocationTree mit) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/security/AndroidNonAuthenticatedUsersCheck.java b/java-checks/src/main/java/org/sonar/java/checks/security/AndroidNonAuthenticatedUsersCheck.java index 188cb06f122..104ef6bdfeb 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/security/AndroidNonAuthenticatedUsersCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/security/AndroidNonAuthenticatedUsersCheck.java @@ -36,7 +36,6 @@ import org.sonar.plugins.java.api.tree.VariableTree; import static org.sonar.java.checks.helpers.MethodTreeUtils.subsequentMethodInvocation; -import static org.sonar.java.model.JUtils.isLocalVariable; @Rule(key = "S6288") public class AndroidNonAuthenticatedUsersCheck extends AbstractMethodDetection { @@ -105,7 +104,7 @@ private static Optional getNotAuthenticatedConstructor(ExpressionT } private static Optional getNotAuthenticatedConstructorInDeclaration(Symbol symbol) { - if (isLocalVariable(symbol)) { + if (symbol.isLocalVariable()) { Tree declaration = symbol.declaration(); if (declaration instanceof VariableTree) { ExpressionTree initializer = ((VariableTree) declaration).initializer(); diff --git a/java-checks/src/main/java/org/sonar/java/checks/security/AndroidUnencryptedDatabaseCheck.java b/java-checks/src/main/java/org/sonar/java/checks/security/AndroidUnencryptedDatabaseCheck.java index 8348c2db4de..2980110dc35 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/security/AndroidUnencryptedDatabaseCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/security/AndroidUnencryptedDatabaseCheck.java @@ -35,8 +35,6 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; -import static org.sonar.java.model.JUtils.isLocalVariable; - @Rule(key = "S6291") public class AndroidUnencryptedDatabaseCheck extends IssuableSubscriptionVisitor { @@ -133,7 +131,7 @@ private static boolean canEncryptToken(IdentifierTree tokenIdentifier) { } private static boolean declarationIsEncrypted(Symbol symbol) { - if (isLocalVariable(symbol)) { + if (symbol.isLocalVariable()) { Tree declaration = symbol.declaration(); if (declaration instanceof VariableTree) { ExpressionTree initializer = ((VariableTree) declaration).initializer(); diff --git a/java-checks/src/main/java/org/sonar/java/checks/security/CipherBlockChainingCheck.java b/java-checks/src/main/java/org/sonar/java/checks/security/CipherBlockChainingCheck.java index 49827dc9698..8a71bd83833 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/security/CipherBlockChainingCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/security/CipherBlockChainingCheck.java @@ -23,7 +23,6 @@ import org.sonar.check.Rule; import org.sonar.java.checks.methods.AbstractMethodDetection; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.model.Symbols; import org.sonar.plugins.java.api.semantic.MethodMatchers; import org.sonar.plugins.java.api.semantic.Symbol; @@ -74,7 +73,7 @@ protected void onConstructorFound(NewClassTree newClassTree) { private static boolean isDynamicallyGenerated(ExpressionTree tree) { if (tree.is(Tree.Kind.IDENTIFIER)) { Symbol symbol = ((IdentifierTree) tree).symbol(); - if (JUtils.isParameter(symbol)) { + if (symbol.isParameter()) { return true; } VariableTree declaration = symbol.isVariableSymbol() ? ((Symbol.VariableSymbol) symbol).declaration() : null; diff --git a/java-checks/src/main/java/org/sonar/java/checks/security/JWTWithStrongCipherCheck.java b/java-checks/src/main/java/org/sonar/java/checks/security/JWTWithStrongCipherCheck.java index 503224d2e94..88b1098b68a 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/security/JWTWithStrongCipherCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/security/JWTWithStrongCipherCheck.java @@ -34,8 +34,6 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; -import static org.sonar.java.model.JUtils.isLocalVariable; - @Rule(key = "S5659") public class JWTWithStrongCipherCheck extends IssuableSubscriptionVisitor { @@ -150,7 +148,7 @@ private static boolean canSignToken(IdentifierTree tokenIdentifier) { } private static boolean declarationIsSigned(Symbol symbol) { - if (isLocalVariable(symbol)) { + if (symbol.isLocalVariable()) { Tree declaration = symbol.declaration(); if (declaration instanceof VariableTree) { ExpressionTree initializer = ((VariableTree) declaration).initializer(); diff --git a/java-checks/src/main/java/org/sonar/java/checks/serialization/SerialVersionUidCheck.java b/java-checks/src/main/java/org/sonar/java/checks/serialization/SerialVersionUidCheck.java index 94730f587ba..79fbbc5ec93 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/serialization/SerialVersionUidCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/serialization/SerialVersionUidCheck.java @@ -23,7 +23,6 @@ import java.util.Collections; import java.util.List; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; @@ -97,13 +96,13 @@ private static boolean isExclusion(Symbol.TypeSymbol symbol) { } private static boolean isGuiClass(Symbol.TypeSymbol symbol) { - for (Type superType : JUtils.superTypes(symbol)) { + for (Type superType : symbol.superTypes()) { Symbol.TypeSymbol superTypeSymbol = superType.symbol(); if (hasGuiPackage(superTypeSymbol)) { return true; } } - return hasGuiPackage(symbol) || (!symbol.equals(JUtils.outermostClass(symbol)) && isGuiClass(JUtils.outermostClass(symbol))); + return hasGuiPackage(symbol) || (!symbol.equals(symbol.outermostClass()) && isGuiClass(symbol.outermostClass())); } private static boolean hasGuiPackage(Symbol.TypeSymbol superTypeSymbol) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedLocalVariableCheck.java b/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedLocalVariableCheck.java index 31f3696edf9..d544acd490c 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedLocalVariableCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedLocalVariableCheck.java @@ -38,9 +38,6 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.VariableTree; -import static org.sonar.java.model.JUtils.isLocalVariable; -import static org.sonar.java.model.JUtils.isParameter; - @Rule(key = "S1481") public class UnusedLocalVariableCheck extends IssuableSubscriptionVisitor { @@ -112,8 +109,8 @@ private static Tree skipParenthesesUpwards(Tree tree) { private static boolean isProperLocalVariable(VariableTree variable) { Symbol symbol = variable.symbol(); - return isLocalVariable(symbol) - && !isParameter(symbol) + return symbol.isLocalVariable() + && !symbol.isParameter() && !isDefinedInCatchClause(variable) && !isTryResource(variable); } diff --git a/java-checks/src/test/java/org/sonar/java/checks/helpers/ExpressionsHelperTest.java b/java-checks/src/test/java/org/sonar/java/checks/helpers/ExpressionsHelperTest.java index edb5e9762db..c5a4b3473ff 100644 --- a/java-checks/src/test/java/org/sonar/java/checks/helpers/ExpressionsHelperTest.java +++ b/java-checks/src/test/java/org/sonar/java/checks/helpers/ExpressionsHelperTest.java @@ -19,10 +19,9 @@ */ package org.sonar.java.checks.helpers; +import java.lang.reflect.Constructor; import javax.annotation.Nullable; import org.junit.jupiter.api.Test; - -import java.lang.reflect.Constructor; import org.sonar.plugins.java.api.tree.IdentifierTree; import org.sonar.plugins.java.api.tree.MethodTree; diff --git a/java-frontend/src/main/java/org/sonar/java/cfg/LiveVariables.java b/java-frontend/src/main/java/org/sonar/java/cfg/LiveVariables.java index 7c3bf5e5076..8168afde14e 100644 --- a/java-frontend/src/main/java/org/sonar/java/cfg/LiveVariables.java +++ b/java-frontend/src/main/java/org/sonar/java/cfg/LiveVariables.java @@ -19,8 +19,16 @@ */ package org.sonar.java.cfg; -import org.sonarsource.analyzer.commons.collections.ListUtils; -import org.sonarsource.analyzer.commons.collections.SetUtils; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.tree.AssignmentExpressionTree; import org.sonar.plugins.java.api.tree.ExpressionTree; @@ -32,19 +40,8 @@ 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 javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import java.util.Collections; -import java.util.Deque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import static org.sonar.java.model.JUtils.isLocalVariable; +import org.sonarsource.analyzer.commons.collections.ListUtils; +import org.sonarsource.analyzer.commons.collections.SetUtils; public class LiveVariables { @@ -195,7 +192,7 @@ private void processAssignment(AssignmentExpressionTree element, Set blo } private boolean includeSymbol(Symbol symbol) { - return isLocalVariable(symbol) || (includeFields && isField(symbol)); + return symbol.isLocalVariable() || (includeFields && isField(symbol)); } private static boolean isField(Symbol symbol) { diff --git a/java-frontend/src/main/java/org/sonar/java/model/ExpressionUtils.java b/java-frontend/src/main/java/org/sonar/java/model/ExpressionUtils.java index ef5be660252..6f2c1a60247 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/ExpressionUtils.java +++ b/java-frontend/src/main/java/org/sonar/java/model/ExpressionUtils.java @@ -300,7 +300,7 @@ private static Object resolveIdentifier(IdentifierTree tree) { return Boolean.FALSE; } } - return JUtils.constantValue((Symbol.VariableSymbol) symbol).orElse(null); + return ((Symbol.VariableSymbol) symbol).constantValue().orElse(null); } @CheckForNull diff --git a/java-frontend/src/main/java/org/sonar/java/model/JTypeSymbol.java b/java-frontend/src/main/java/org/sonar/java/model/JTypeSymbol.java index 97c627bfd31..bcf06486a8f 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/JTypeSymbol.java +++ b/java-frontend/src/main/java/org/sonar/java/model/JTypeSymbol.java @@ -19,6 +19,9 @@ */ package org.sonar.java.model; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; @@ -54,6 +57,11 @@ final class JTypeSymbol extends JSymbol implements Symbol.TypeSymbol { */ private Collection memberSymbols; + /** + * Cache for {@link #superTypes()}. + */ + private Set superTypes; + final SpecialField superSymbol = new SpecialField() { @Override public String name() { @@ -156,6 +164,36 @@ public ClassTree declaration() { return (ClassTree) super.declaration(); } + @Override + public Set superTypes() { + if (superTypes == null) { + if (isUnknown()) { + superTypes = Collections.emptySet(); + } else { + superTypes = new HashSet<>(); + JUtils.collectSuperTypes(superTypes, sema, typeBinding()); + } + } + return superTypes; + } + + @Override + @Nullable + public TypeSymbol outermostClass() { + Symbol symbol = this; + Symbol result = null; + while (symbol != null && !symbol.isPackageSymbol()) { + result = symbol; + symbol = symbol.owner(); + } + return (Symbol.TypeSymbol) result; + } + + @Override + public boolean isAnnotation() { + return !isUnknown() && typeBinding().isAnnotation(); + } + abstract class SpecialField extends Symbols.DefaultSymbol implements Symbol.VariableSymbol { @Override public final Symbol owner() { @@ -192,6 +230,25 @@ public final List usages() { public final VariableTree declaration() { return null; } + + @Override + public final boolean isEffectivelyFinal(){ + return false; + } + @Override + public final Optional constantValue() { + return Optional.empty(); + } + + @Override + public final boolean isLocalVariable() { + return false; + } + + @Override + public final boolean isParameter() { + return false; + } } } 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 34b14ea2c45..673f54fe993 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 @@ -72,52 +72,7 @@ public static boolean isIntersectionType(Type type) { return !type.isUnknown() && ((JType) type).typeBinding.isIntersectionType(); } - public static boolean isAnnotation(Symbol.TypeSymbol typeSymbol) { - return !typeSymbol.isUnknown() && ((JTypeSymbol) typeSymbol).typeBinding().isAnnotation(); - } - - public static boolean isEffectivelyFinal(Symbol.VariableSymbol variableSymbol) { - return (variableSymbol instanceof JVariableSymbol) && ((IVariableBinding) ((JVariableSymbol) variableSymbol).binding).isEffectivelyFinal(); - } - - public static boolean isLocalVariable(Symbol symbol) { - return symbol.isVariableSymbol() && symbol.owner().isMethodSymbol(); - } - - public static boolean isParameter(Symbol symbol) { - if (symbol instanceof JTypeSymbol.SpecialField) { - return false; - } - return symbol.isVariableSymbol() && - ((symbol instanceof JVariableSymbol.ParameterPlaceholderSymbol) - || ((IVariableBinding) ((JVariableSymbol) symbol).binding).isParameter()); - } - - public static Optional constantValue(Symbol.VariableSymbol symbol) { - if (!symbol.isFinal() || !symbol.isStatic() || !(symbol instanceof JVariableSymbol)) { - return Optional.empty(); - } - Object c = ((IVariableBinding) ((JVariableSymbol) symbol).binding).getConstantValue(); - if (c instanceof Short) { - c = Integer.valueOf((Short) c); - } else if (c instanceof Byte) { - c = Integer.valueOf((Byte) c); - } else if (c instanceof Character) { - c = Integer.valueOf((Character) c); - } - return Optional.ofNullable(c); - } - - public static Set superTypes(Symbol.TypeSymbol typeSymbol) { - if (typeSymbol.isUnknown()) { - return Collections.emptySet(); - } - Set result = new HashSet<>(); - collectSuperTypes(result, ((JTypeSymbol) typeSymbol).sema, ((JTypeSymbol) typeSymbol).typeBinding()); - return result; - } - - private static void collectSuperTypes(Set result, JSema sema, ITypeBinding typeBinding) { + public static void collectSuperTypes(Set result, JSema sema, ITypeBinding typeBinding) { ITypeBinding s = typeBinding.getSuperclass(); if (s != null) { result.add(sema.type(s)); @@ -129,16 +84,6 @@ private static void collectSuperTypes(Set result, JSema sema, ITypeBinding } } - public static Symbol.TypeSymbol outermostClass(Symbol.TypeSymbol typeSymbol) { - Symbol symbol = typeSymbol; - Symbol result = null; - while (!symbol.isPackageSymbol()) { - result = symbol; - symbol = symbol.owner(); - } - return (Symbol.TypeSymbol) result; - } - public static Symbol getPackage(Symbol symbol) { while (!symbol.isPackageSymbol()) { symbol = symbol.owner(); diff --git a/java-frontend/src/main/java/org/sonar/java/model/JVariableSymbol.java b/java-frontend/src/main/java/org/sonar/java/model/JVariableSymbol.java index cf3b03b23c3..95aeefe1928 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/JVariableSymbol.java +++ b/java-frontend/src/main/java/org/sonar/java/model/JVariableSymbol.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.List; +import java.util.Optional; import javax.annotation.Nullable; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; @@ -33,6 +34,10 @@ final class JVariableSymbol extends JSymbol implements Symbol.VariableSymbol { + // cache for this.constantValue() + private boolean constantValueComputed = false; + private Optional constantValue; + JVariableSymbol(JSema sema, IVariableBinding variableBinding) { super(sema, variableBinding); } @@ -43,6 +48,43 @@ public VariableTree declaration() { return (VariableTree) super.declaration(); } + @Override + public boolean isEffectivelyFinal() { + return ((IVariableBinding)binding).isEffectivelyFinal(); + } + + @Override + public Optional constantValue() { + if (!constantValueComputed) { + constantValueComputed = true; + if (!isFinal() || !isStatic()) { + constantValue = Optional.empty(); + } else { + Object c = ((IVariableBinding) binding).getConstantValue(); + if (c instanceof Short) { + c = Integer.valueOf((Short) c); + } else if (c instanceof Byte) { + c = Integer.valueOf((Byte) c); + } else if (c instanceof Character) { + c = Integer.valueOf((Character) c); + } + constantValue = Optional.ofNullable(c); + } + } + return constantValue; + } + + @Override + public boolean isLocalVariable() { + Symbol owner = owner(); + return owner != null && owner.isMethodSymbol(); + } + + @Override + public boolean isParameter() { + return ((IVariableBinding) binding).isParameter(); + } + static class ParameterPlaceholderSymbol extends Symbols.DefaultSymbol implements Symbol.VariableSymbol { private final String name; @@ -99,6 +141,26 @@ public VariableTree declaration() { return null; } + @Override + public boolean isEffectivelyFinal() { + return false; + } + + @Override + public Optional constantValue() { + return Optional.empty(); + } + + @Override + public boolean isLocalVariable() { + return false; + } + + @Override + public boolean isParameter() { + return true; + } + @Override public SymbolMetadata metadata() { return metadata; diff --git a/java-frontend/src/main/java/org/sonar/java/model/Symbols.java b/java-frontend/src/main/java/org/sonar/java/model/Symbols.java index 2e998f81254..4ff235e9517 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/Symbols.java +++ b/java-frontend/src/main/java/org/sonar/java/model/Symbols.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -211,6 +212,21 @@ public ClassTree declaration() { return null; } + @Override + public Set superTypes() { + return Collections.emptySet(); + } + + @Override + public TypeSymbol outermostClass() { + return Symbols.unknownTypeSymbol; + } + + @Override + public boolean isAnnotation() { + return false; + } + @Override public Type superClass() { return null; diff --git a/java-frontend/src/main/java/org/sonar/plugins/java/api/JavaVersionAwareVisitor.java b/java-frontend/src/main/java/org/sonar/plugins/java/api/JavaVersionAwareVisitor.java index 001117d0b4e..9b60072e69d 100644 --- a/java-frontend/src/main/java/org/sonar/plugins/java/api/JavaVersionAwareVisitor.java +++ b/java-frontend/src/main/java/org/sonar/plugins/java/api/JavaVersionAwareVisitor.java @@ -20,7 +20,6 @@ package org.sonar.plugins.java.api; import org.sonar.java.annotations.Beta; -import org.sonar.plugins.java.api.JavaVersion; /** * Implementing this interface allows a check to be executed - or not - during analysis, depending diff --git a/java-frontend/src/main/java/org/sonar/plugins/java/api/semantic/Symbol.java b/java-frontend/src/main/java/org/sonar/plugins/java/api/semantic/Symbol.java index 7744aa27b03..285b98f2865 100644 --- a/java-frontend/src/main/java/org/sonar/plugins/java/api/semantic/Symbol.java +++ b/java-frontend/src/main/java/org/sonar/plugins/java/api/semantic/Symbol.java @@ -21,6 +21,8 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; +import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.plugins.java.api.tree.ClassTree; @@ -114,6 +116,20 @@ public interface Symbol { @Nullable Tree declaration(); + /** + * @return true if this symbol represents a variable which is a local variable of a method. + */ + default boolean isLocalVariable() { + return false; + } + + /** + * @return true if this symbol represents a variable which is a parameter of a method. + */ + default boolean isParameter() { + return false; + } + /** * Symbol for a type : class, enum, interface or annotation. */ @@ -150,6 +166,21 @@ interface TypeSymbol extends Symbol { @Override ClassTree declaration(); + /** + * @return the set of types that are super types of this type (extended classes and implemented interfaces). + */ + Set superTypes(); + + /** + * @return the most outer class containing this symbol. + */ + Symbol.TypeSymbol outermostClass(); + + /** + * @return true if this type is an annotation. + */ + boolean isAnnotation(); + } /** @@ -161,6 +192,17 @@ interface VariableSymbol extends Symbol { @Override VariableTree declaration(); + /** + * @return true if this variable is effectively final. + * A variable is effectively final if it is not explicitly declared final but never reassigned after initialization. + */ + boolean isEffectivelyFinal(); + + /** + * @return the constant value of this variable if it has one. + */ + Optional constantValue(); + } /** diff --git a/java-frontend/src/test/java/org/sonar/java/model/ClassesLayoutTest.java b/java-frontend/src/test/java/org/sonar/java/model/ClassesLayoutTest.java index 21dff8cc452..2697fa9317e 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/ClassesLayoutTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/ClassesLayoutTest.java @@ -100,7 +100,7 @@ void type() { @Test void symbol_type() { assertAll( - () -> assertThat(instanceSize(JTypeSymbol.class, X86_64)).isEqualTo(96), + () -> assertThat(instanceSize(JTypeSymbol.class, X86_64)).isEqualTo(104), () -> assertThat(instanceSize(JTypeSymbol.class, X86_64_COOPS)).isEqualTo(56) ); } @@ -116,8 +116,8 @@ void symbol_method() { @Test void symbol_variable() { assertAll( - () -> assertThat(instanceSize(JVariableSymbol.class, X86_64)).isEqualTo(56), - () -> assertThat(instanceSize(JVariableSymbol.class, X86_64_COOPS)).isEqualTo(32) + () -> assertThat(instanceSize(JVariableSymbol.class, X86_64)).isEqualTo(72), + () -> assertThat(instanceSize(JVariableSymbol.class, X86_64_COOPS)).isEqualTo(40) ); } diff --git a/java-frontend/src/test/java/org/sonar/java/model/JMethodSymbolTest.java b/java-frontend/src/test/java/org/sonar/java/model/JMethodSymbolTest.java index 62ee13bca0c..0d8ae7c48c2 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/JMethodSymbolTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/JMethodSymbolTest.java @@ -139,6 +139,7 @@ void test_declaration_not_in_code() { assertThat(parameterSymbol1.declaration()).isNull(); assertThat(parameterSymbol1.metadata()).isSameAs(parameterSymbol2.metadata()); assertThat(parameterSymbol1.isVariableSymbol()).isTrue(); + assertThat(parameterSymbol1.isLocalVariable()).isFalse(); assertThat(parameterSymbol1.isFinal()).isFalse(); } @@ -443,7 +444,6 @@ void testParameterDeclarationsOfCompactConstructor() { assertThat(symbol.declarationParameters()).hasSize(6); } - private static JMethodSymbol getJMethodSymbolFromClassText(String classText){ return getJMethodSymbolFromClassText(classText, false); } diff --git a/java-frontend/src/test/java/org/sonar/java/model/JTypeSymbolTest.java b/java-frontend/src/test/java/org/sonar/java/model/JTypeSymbolTest.java index 307b4c33c99..56fe8817592 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/JTypeSymbolTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/JTypeSymbolTest.java @@ -19,16 +19,17 @@ */ package org.sonar.java.model; +import java.util.Objects; import org.eclipse.jdt.core.dom.ITypeBinding; import org.junit.jupiter.api.Test; import org.sonar.java.model.declaration.ClassTreeImpl; import org.sonar.java.model.declaration.MethodTreeImpl; import org.sonar.java.model.declaration.VariableTreeImpl; -import java.util.Objects; - import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; class JTypeSymbolTest { @@ -88,6 +89,70 @@ void memberSymbols() { ); } + @Test + void superTypesTest(){ + JavaTree.CompilationUnitTreeImpl cu = test("interface I { } class C implements I { } class C2 extends C { }"); + ITypeBinding javaLangObject = Objects.requireNonNull(cu.sema.resolveType("java.lang.Object")); + assertThat(cu.sema.typeSymbol(javaLangObject).superTypes()).isEmpty(); + + ClassTreeImpl interfaceI = (ClassTreeImpl) cu.types().get(0); + JTypeSymbol interfaceITypeSymbol = cu.sema.typeSymbol(interfaceI.typeBinding); + assertThat(interfaceITypeSymbol.superTypes()).isEmpty(); + assertThat(interfaceITypeSymbol.superTypes()).isEmpty(); // repeat call to cover cache + + ClassTreeImpl classC = (ClassTreeImpl) cu.types().get(1); + JTypeSymbol classCTypeSymbol = cu.sema.typeSymbol(classC.typeBinding); + assertThat(classCTypeSymbol.superTypes()).containsExactly(interfaceITypeSymbol.type(), cu.sema.type(javaLangObject)); + + + ClassTreeImpl classC2 = (ClassTreeImpl) cu.types().get(2); + JTypeSymbol classC2TypeSymbol = cu.sema.typeSymbol(classC2.typeBinding); + assertThat(classC2TypeSymbol.superTypes()).containsExactly(classCTypeSymbol.type() ,interfaceITypeSymbol.type(), cu.sema.type(javaLangObject)); + + ITypeBinding brokenTypeBinding = spy(classC2.typeBinding); + when(brokenTypeBinding.isRecovered()).thenReturn(true); + JTypeSymbol brokenTypeSymbol = new JTypeSymbol(cu.sema, brokenTypeBinding); + assertThat(brokenTypeSymbol.superTypes()).isEmpty(); + } + + @Test + void outermostClassTest() { + JavaTree.CompilationUnitTreeImpl cu = test("class C { class N {} }"); + ClassTreeImpl outerClass = (ClassTreeImpl) cu.types().get(0); + ClassTreeImpl innerClass = (ClassTreeImpl) outerClass.members().get(0); + JTypeSymbol innerClassSymbol = cu.sema.typeSymbol(innerClass.typeBinding); + JTypeSymbol outerClassSymbol = cu.sema.typeSymbol(outerClass.typeBinding); + assertThat(innerClassSymbol.outermostClass()).isSameAs(outerClassSymbol); + assertThat(innerClassSymbol.outermostClass()).isSameAs(outerClassSymbol); + } + + @Test + void isAnnotationTest(){ + JTypeSymbol annotationSymbol = getJTypeSymbolFromClassText("@interface A { }", true); + assertThat(annotationSymbol.isAnnotation()).isFalse(); + annotationSymbol = getJTypeSymbolFromClassText("@interface A { }", false); + assertThat(annotationSymbol.isAnnotation()).isTrue(); + JTypeSymbol classSymbol = getJTypeSymbolFromClassText("class C { }", false); + assertThat(classSymbol.isAnnotation()).isFalse(); + } + + @Test + void isEffectivelyFinalTest(){ + JTypeSymbol classSymbol = getJTypeSymbolFromClassText("class C { }", false); + assertThat(classSymbol.superSymbol.isEffectivelyFinal()).isFalse(); + } + + private static JTypeSymbol getJTypeSymbolFromClassText(String classText, boolean isUnknown){ + JavaTree.CompilationUnitTreeImpl cu = test(classText); + ClassTreeImpl c = (ClassTreeImpl) cu.types().get(0); + if(isUnknown){ + ITypeBinding brokenTypeBinding = spy(c.typeBinding); + when(brokenTypeBinding.isRecovered()).thenReturn(true); + return new JTypeSymbol(cu.sema, brokenTypeBinding); + } + return new JTypeSymbol(cu.sema, c.typeBinding); + } + private static JavaTree.CompilationUnitTreeImpl test(String source) { return (JavaTree.CompilationUnitTreeImpl) JParserTestUtils.parse(source); } diff --git a/java-frontend/src/test/java/org/sonar/java/model/JUtilsTest.java b/java-frontend/src/test/java/org/sonar/java/model/JUtilsTest.java index d355a35cb6c..1a9e04549f3 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/JUtilsTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/JUtilsTest.java @@ -228,28 +228,6 @@ void unresolved_type_is_not_a_type_var() { } } - @Nested - class IsAnnotation { - private final JavaTree.CompilationUnitTreeImpl cu = test("@interface Anno { Unknown u; }"); - private final ClassTreeImpl anno = firstClass(cu); - - @Test - void annotation() { - assertThat(JUtils.isAnnotation(anno.symbol())).isTrue(); - } - - @Test - void simple_type_is_not_an_annotation() { - assertThat(JUtils.isAnnotation(OBJECT_TYPE.symbol())).isFalse(); - } - - @Test - void unresolved_type_is_not_an_annotation() { - VariableTreeImpl u = firstField(anno); - assertThat(JUtils.isAnnotation(u.type().symbolType().symbol())).isFalse(); - } - } - @Test void effectivelyFinal() { JavaTree.CompilationUnitTreeImpl cu = test("class A { void foo(Object o) { int i = 42; int j = 43; j++; foo(i); } }"); @@ -260,10 +238,10 @@ void effectivelyFinal() { VariableTreeImpl j = (VariableTreeImpl) body.get(1); assertThat(i.symbol().isVariableSymbol()).isTrue(); - assertThat(JUtils.isEffectivelyFinal((Symbol.VariableSymbol) i.symbol())).isTrue(); + assertThat(((Symbol.VariableSymbol) i.symbol()).isEffectivelyFinal()).isTrue(); assertThat(j.symbol().isVariableSymbol()).isTrue(); - assertThat(JUtils.isEffectivelyFinal((Symbol.VariableSymbol) j.symbol())).isFalse(); + assertThat(((Symbol.VariableSymbol) j.symbol()).isEffectivelyFinal()).isFalse(); } @Test @@ -276,7 +254,7 @@ void placeholder_are_never_effectivelyFinal() { Symbol.MethodSymbol methodSymbol = mit.methodSymbol(); Symbol symbol = methodSymbol.declarationParameters().get(0); assertThat(symbol.isVariableSymbol()).isTrue(); - assertThat(JUtils.isEffectivelyFinal((Symbol.VariableSymbol) symbol)).isFalse(); + assertThat(((Symbol.VariableSymbol) symbol).isEffectivelyFinal()).isFalse(); } @Nested @@ -292,25 +270,25 @@ class IsLocalVariable { void local_variable() { MethodTreeImpl m = nthMethod(c, 2); VariableTreeImpl localVariable = (VariableTreeImpl) m.block().body().get(0); - assertThat(JUtils.isLocalVariable(localVariable.symbol())).isTrue(); + assertThat(localVariable.symbol().isLocalVariable()).isTrue(); } @Test void variable_from_initializer_is_local_variable() { BlockTree staticInitializer = (BlockTree) c.members().get(0); VariableTreeImpl v = (VariableTreeImpl) staticInitializer.body().get(0); - assertThat(JUtils.isLocalVariable(v.symbol())).isTrue(); + assertThat(v.symbol().isLocalVariable()).isTrue(); } @Test void field_is_not_a_local_variable() { VariableTreeImpl field = nthField(c, 1); - assertThat(JUtils.isLocalVariable(field.symbol())).isFalse(); + assertThat(field.symbol().isLocalVariable()).isFalse(); } @Test void type_symbol_is_not_a_local_variable() { - assertThat(JUtils.isLocalVariable(c.symbol())).isFalse(); + assertThat(c.symbol().isLocalVariable()).isFalse(); } } @@ -330,24 +308,24 @@ class IsParameter { @Test void field_is_not_parameter() { VariableTreeImpl field = firstField(c); - assertThat(JUtils.isParameter(field.symbol())).isFalse(); + assertThat(field.symbol().isParameter()).isFalse(); } @Test void local_variable_is_not_parameter() { VariableTreeImpl localVariable = (VariableTreeImpl) m.block().body().get(0); - assertThat(JUtils.isParameter(localVariable.symbol())).isFalse(); + assertThat(localVariable.symbol().isParameter()).isFalse(); } @Test void parameter() { VariableTreeImpl p = (VariableTreeImpl) m.parameters().get(0); - assertThat(JUtils.isParameter(p.symbol())).isTrue(); + assertThat(p.symbol().isParameter()).isTrue(); } @Test void not_a_variable_is_not_a_parameter() { - assertThat(JUtils.isParameter(OBJECT_TYPE.symbol())).isFalse(); + assertThat(OBJECT_TYPE.symbol().isParameter()).isFalse(); } @Test @@ -355,7 +333,7 @@ void this_is_not_a_parameter() { ExpressionStatementTreeImpl es = (ExpressionStatementTreeImpl) m.block().body().get(1); MethodInvocationTreeImpl mit = (MethodInvocationTreeImpl) es.expression(); IdentifierTreeImpl arg0 = (IdentifierTreeImpl) mit.arguments().get(0); - assertThat(JUtils.isParameter(arg0.symbol())).isFalse(); + assertThat(arg0.symbol().isParameter()).isFalse(); } @Test @@ -363,7 +341,7 @@ void placeholder_symbols_are_parameters() { ExpressionStatementTreeImpl es = (ExpressionStatementTreeImpl) m.block().body().get(2); MethodInvocationTreeImpl mit = (MethodInvocationTreeImpl) es.expression(); Symbol.MethodSymbol symbol = mit.methodSymbol(); - assertThat(JUtils.isParameter(symbol.declarationParameters().get(0))).isTrue(); + assertThat(symbol.declarationParameters().get(0).isParameter()).isTrue(); } } @@ -379,14 +357,14 @@ void this_can_not_be_evaluated() { MethodInvocationTreeImpl mit = (MethodInvocationTreeImpl) es.expression(); IdentifierTreeImpl thisArg = (IdentifierTreeImpl) mit.arguments().get(0); assertThat(thisArg.symbol().isVariableSymbol()).isTrue(); - assertThat(JUtils.constantValue((Symbol.VariableSymbol) thisArg.symbol())).isEmpty(); + assertThat(((Symbol.VariableSymbol) thisArg.symbol()).constantValue()).isEmpty(); } @Test void static_non_final_field_can_not_be_evaluated() { VariableTreeImpl field = firstField(c); assertThat(field.symbol().isVariableSymbol()).isTrue(); - assertThat(JUtils.constantValue((Symbol.VariableSymbol) field.symbol())).isEmpty(); + assertThat(((Symbol.VariableSymbol) field.symbol()).constantValue()).isEmpty(); } @Test @@ -396,7 +374,7 @@ void placeholders_can_not_be_evaluated() { Symbol.MethodSymbol methodSymbol = mit.methodSymbol(); Symbol symbol = methodSymbol.declarationParameters().get(0); assertThat(symbol.isVariableSymbol()).isTrue(); - assertThat(JUtils.constantValue((Symbol.VariableSymbol) symbol)).isEmpty(); + assertThat(((Symbol.VariableSymbol) symbol).constantValue()).isEmpty(); } @Test @@ -405,22 +383,22 @@ void constantValue() { ClassTreeImpl c = firstClass(cu); Symbol.VariableSymbol shortConstant = cu.sema.variableSymbol(firstField(c).variableBinding); - assertThat(JUtils.constantValue(shortConstant).orElseThrow(AssertionError::new)) + assertThat(shortConstant.constantValue().orElseThrow(AssertionError::new)) .isInstanceOf(Integer.class) .isEqualTo(42); Symbol.VariableSymbol charConstant = cu.sema.variableSymbol(nthField(c, 1).variableBinding); - assertThat(JUtils.constantValue(charConstant).orElseThrow(AssertionError::new)) + assertThat(charConstant.constantValue().orElseThrow(AssertionError::new)) .isInstanceOf(Integer.class) .isEqualTo(42); Symbol.VariableSymbol byteConstant = cu.sema.variableSymbol(nthField(c, 2).variableBinding); - assertThat(JUtils.constantValue(byteConstant).orElseThrow(AssertionError::new)) + assertThat(byteConstant.constantValue().orElseThrow(AssertionError::new)) .isInstanceOf(Integer.class) .isEqualTo(42); Symbol.VariableSymbol booleanConstant = cu.sema.variableSymbol(nthField(c, 3).variableBinding); - assertThat(JUtils.constantValue(booleanConstant).orElseThrow(AssertionError::new)) + assertThat(booleanConstant.constantValue().orElseThrow(AssertionError::new)) .isInstanceOf(Boolean.class) .isEqualTo(Boolean.FALSE); } @@ -435,18 +413,18 @@ class SuperTypes { @Test void Objects_has_no_supertypes() { - assertThat(JUtils.superTypes(OBJECT_TYPE.symbol())).isEmpty(); + assertThat(OBJECT_TYPE.symbol().superTypes()).isEmpty(); } @Test void unresolved_type_has_no_supertypes() { VariableTreeImpl u = firstField(c); - assertThat(JUtils.superTypes(u.type().symbolType().symbol())).isEmpty(); + assertThat(u.type().symbolType().symbol().superTypes()).isEmpty(); } @Test void unresolved_types_are_also_part_of_supertypes() { - Set superTypes = JUtils.superTypes(c.symbol()); + Set superTypes = c.symbol().superTypes(); assertThat(superTypes).hasSize(3); assertThat(superTypes.stream().map(Type::name)).containsOnly("Object", "Serializable", "Unknown"); } @@ -454,7 +432,7 @@ void unresolved_types_are_also_part_of_supertypes() { @Test void supertypes_are_called_in_all_hierarchy() { ClassTreeImpl b = nthClass(cu, 1); - Set superTypes = JUtils.superTypes(b.symbol()); + Set superTypes = b.symbol().superTypes(); assertThat(superTypes).hasSize(7); assertThat(superTypes.stream().map(Type::name)).containsOnly("C", "Object", "Serializable", "Unknown", "List", "Collection", "Iterable"); } @@ -468,9 +446,9 @@ void outermostClass() { ClassTreeImpl b = firstClass(a); ClassTreeImpl c = firstClass(b); - assertThat(JUtils.outermostClass(aTypeSymbol)).isSameAs(aTypeSymbol); - assertThat(JUtils.outermostClass(b.symbol())).isSameAs(aTypeSymbol); - assertThat(JUtils.outermostClass(c.symbol())).isSameAs(aTypeSymbol); + assertThat(aTypeSymbol.outermostClass()).isSameAs(aTypeSymbol); + assertThat(b.symbol().outermostClass()).isSameAs(aTypeSymbol); + assertThat(c.symbol().outermostClass()).isSameAs(aTypeSymbol); } @Nested @@ -808,7 +786,7 @@ void object_type_has_no_direct_supertypes() { void direct_supertypes_might_be_equal_to_all_supertypes() { ClassTreeImpl c = firstClass(cu); Set directSuperTypes = JUtils.directSuperTypes(c.symbol().type()); - Set allSuperTypes = JUtils.superTypes(c.symbol()); + Set allSuperTypes = c.symbol().superTypes(); assertThat(directSuperTypes) .hasSize(3) .isEqualTo(allSuperTypes); @@ -819,7 +797,7 @@ void direct_supertypes_might_be_equal_to_all_supertypes() { void direct_supertypes_is_generaly_a_subset_of_all_supertypes() { ClassTreeImpl b = nthClass(cu, 1); Set directSuperTypes = JUtils.directSuperTypes(b.symbol().type()); - Set allSuperTypes = JUtils.superTypes(b.symbol()); + Set allSuperTypes = b.symbol().superTypes(); assertThat(directSuperTypes).hasSize(2); assertThat(directSuperTypes.stream().map(Type::name)).containsOnly("C", "List"); assertThat(allSuperTypes) diff --git a/java-frontend/src/test/java/org/sonar/java/model/JVariableSymbolTest.java b/java-frontend/src/test/java/org/sonar/java/model/JVariableSymbolTest.java new file mode 100644 index 00000000000..45a73febae2 --- /dev/null +++ b/java-frontend/src/test/java/org/sonar/java/model/JVariableSymbolTest.java @@ -0,0 +1,61 @@ +/* + * SonarQube Java + * Copyright (C) 2012-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.java.model; + +import org.junit.jupiter.api.Test; +import org.sonar.java.model.declaration.ClassTreeImpl; +import org.sonar.java.model.declaration.MethodTreeImpl; +import org.sonar.java.model.declaration.VariableTreeImpl; +import static org.assertj.core.api.Assertions.assertThat; + +class JVariableSymbolTest { + + @Test + void isLocalVariable() { + JavaTree.CompilationUnitTreeImpl cu = test("class C { void m() { String a; } String field; }"); + ClassTreeImpl c = (ClassTreeImpl) cu.types().get(0); + MethodTreeImpl method = (MethodTreeImpl) c.members().get(0); + VariableTreeImpl localVariable = (VariableTreeImpl) method.block().body().get(0); + JVariableSymbol variableSymbol = cu.sema.variableSymbol(localVariable.variableBinding); + assertThat(variableSymbol.isLocalVariable()).isTrue(); + VariableTreeImpl classVariable = (VariableTreeImpl) c.members().get(1); + variableSymbol = cu.sema.variableSymbol(classVariable.variableBinding); + assertThat(variableSymbol.isLocalVariable()).isFalse(); + } + + @Test + void isParameter() { + JavaTree.CompilationUnitTreeImpl cu = test("class C { void m(int p) { String a; } }"); + ClassTreeImpl c = (ClassTreeImpl) cu.types().get(0); + MethodTreeImpl method = (MethodTreeImpl) c.members().get(0); + VariableTreeImpl localVariable = (VariableTreeImpl) method.block().body().get(0); + + JVariableSymbol variableSymbol = cu.sema.variableSymbol(localVariable.variableBinding); + assertThat(variableSymbol.isParameter()).isFalse(); + + VariableTreeImpl parameter = (VariableTreeImpl) method.parameters().get(0); + variableSymbol = cu.sema.variableSymbol(parameter.variableBinding); + assertThat(variableSymbol.isParameter()).isTrue(); + } + + private static JavaTree.CompilationUnitTreeImpl test(String source) { + return (JavaTree.CompilationUnitTreeImpl) JParserTestUtils.parse(source); + } +} diff --git a/java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java b/java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java index 722957e486e..fe6c6a29fc3 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java @@ -20,9 +20,10 @@ package org.sonar.java.model; import java.io.File; -import javax.annotation.Nullable; import org.eclipse.jdt.core.dom.IAnnotationBinding; import org.junit.jupiter.api.Test; +import org.sonar.java.model.declaration.ClassTreeImpl; +import org.sonar.java.model.declaration.VariableTreeImpl; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.SymbolMetadata; import org.sonar.plugins.java.api.semantic.SymbolMetadata.AnnotationInstance; @@ -146,6 +147,9 @@ void unknown_type_symbol() { assertThat(unknownTypeSymbol.interfaces()).isEmpty(); assertThat(unknownTypeSymbol.memberSymbols()).isEmpty(); assertThat(unknownTypeSymbol.lookupSymbols("whatever")).isEmpty(); + assertThat(unknownTypeSymbol.isAnnotation()).isFalse(); + assertThat(unknownTypeSymbol.outermostClass()).isEqualTo(Symbols.unknownTypeSymbol); + assertThat(unknownTypeSymbol.superTypes()).isEmpty(); } @Test @@ -193,4 +197,20 @@ private static void assertCommonProperties(Symbol unknownSymbol) { assertThat(unknownSymbol.type()).isEqualTo(Symbols.unknownType); assertThat(unknownSymbol.enclosingClass()).isEqualTo(Symbols.unknownTypeSymbol); } + + @Test + void testIsAnnotation() { + JSema sema = ((JavaTree.CompilationUnitTreeImpl) JParserTestUtils.parse("")).sema; + Type objectType = sema.type(sema.resolveType("java.lang.Object")); + JavaTree.CompilationUnitTreeImpl cu = (JavaTree.CompilationUnitTreeImpl) JParserTestUtils.parse("@interface Anno { Unknown u; }"); + ClassTreeImpl anno = (ClassTreeImpl) cu.types().get(0); + + assertThat(anno.symbol().isAnnotation()).isTrue(); + + assertThat(objectType.symbol().isAnnotation()).isFalse(); + + VariableTreeImpl u = (VariableTreeImpl) anno.members().get(0); + assertThat(u.type().symbolType().symbol().isAnnotation()).isFalse(); + } + } diff --git a/java-frontend/src/test/java/org/sonar/java/resolve/ConstantTest.java b/java-frontend/src/test/java/org/sonar/java/resolve/ConstantTest.java index 7fa7a47fec4..e5e8aef35bb 100644 --- a/java-frontend/src/test/java/org/sonar/java/resolve/ConstantTest.java +++ b/java-frontend/src/test/java/org/sonar/java/resolve/ConstantTest.java @@ -28,7 +28,6 @@ import org.sonar.java.TestUtils; import org.sonar.java.ast.JavaAstScanner; import org.sonar.java.ast.visitors.SubscriptionVisitor; -import org.sonar.java.model.JUtils; import org.sonar.java.model.VisitorsBridge; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.tree.Tree; @@ -56,7 +55,7 @@ public void visitNode(Tree tree) { Object value = null; Symbol symbol = variableTree.symbol(); if (symbol.isVariableSymbol()) { - value = JUtils.constantValue((Symbol.VariableSymbol) symbol).orElse(null); + value = ((Symbol.VariableSymbol) symbol).constantValue().orElse(null); } valuesByFieldName.put(variableTree.simpleName().name(), value); } diff --git a/java-symbolic-execution/src/main/java/org/sonar/java/se/ProgramState.java b/java-symbolic-execution/src/main/java/org/sonar/java/se/ProgramState.java index 2d0c758053d..b9978a00619 100644 --- a/java-symbolic-execution/src/main/java/org/sonar/java/se/ProgramState.java +++ b/java-symbolic-execution/src/main/java/org/sonar/java/se/ProgramState.java @@ -19,12 +19,10 @@ */ package org.sonar.java.se; -import java.util.HashSet; -import org.sonar.java.annotations.VisibleForTesting; -import org.sonar.java.Preconditions; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; @@ -32,10 +30,8 @@ import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import org.sonarsource.analyzer.commons.collections.PCollections; -import org.sonarsource.analyzer.commons.collections.PMap; -import org.sonarsource.analyzer.commons.collections.PStack; -import org.sonarsource.analyzer.commons.collections.SetUtils; +import org.sonar.java.Preconditions; +import org.sonar.java.annotations.VisibleForTesting; import org.sonar.java.se.checks.CustomUnclosedResourcesCheck; import org.sonar.java.se.checks.LocksNotUnlockedCheck; import org.sonar.java.se.checks.StreamConsumedCheck; @@ -50,8 +46,10 @@ import org.sonar.java.se.symbolicvalues.SymbolicValue; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; - -import static org.sonar.java.model.JUtils.isLocalVariable; +import org.sonarsource.analyzer.commons.collections.PCollections; +import org.sonarsource.analyzer.commons.collections.PMap; +import org.sonarsource.analyzer.commons.collections.PStack; +import org.sonarsource.analyzer.commons.collections.SetUtils; public class ProgramState { @@ -413,7 +411,7 @@ class CleanAction implements BiConsumer { @Override public void accept(Symbol symbol, SymbolicValue symbolicValue) { - if (isLocalVariable(symbol) && !liveVariables.contains(symbol) && !protectedSymbolicValues.contains(symbolicValue)) { + if (symbol.isLocalVariable() && !liveVariables.contains(symbol) && !protectedSymbolicValues.contains(symbolicValue)) { newProgramState = true; newValues = newValues.remove(symbol); newReferences = decreaseReference(newReferences, symbolicValue); diff --git a/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/DivisionByZeroCheck.java b/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/DivisionByZeroCheck.java index ab1ebffb2a5..57b4c533970 100644 --- a/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/DivisionByZeroCheck.java +++ b/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/DivisionByZeroCheck.java @@ -29,7 +29,6 @@ import org.sonar.check.Rule; import org.sonar.java.cfg.CFG; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.se.CheckerContext; import org.sonar.java.se.Flow; import org.sonar.java.se.FlowComputation; @@ -399,7 +398,7 @@ public void visitIdentifier(IdentifierTree identifier) { } Type type = identifier.symbolType(); if (type.isPrimitive() || type.isPrimitiveWrapper()) { - JUtils.constantValue((Symbol.VariableSymbol) symbol) + ((Symbol.VariableSymbol) symbol).constantValue() .filter(Number.class::isInstance) .map(Number.class::cast) .ifPresent(num -> { diff --git a/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/MinMaxRangeCheck.java b/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/MinMaxRangeCheck.java index 9e6409e6de7..b02ba755910 100644 --- a/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/MinMaxRangeCheck.java +++ b/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/MinMaxRangeCheck.java @@ -27,7 +27,6 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.check.Rule; -import org.sonar.java.model.JUtils; import org.sonar.java.model.LiteralUtils; import org.sonar.java.se.CheckerContext; import org.sonar.java.se.Flow; @@ -175,7 +174,7 @@ private static ProgramState handleNumericalConstant(CheckerContext context, Iden } NumericalConstraint numericalConstraint = programState.getConstraint(constant, NumericalConstraint.class); if (numericalConstraint == null) { - return JUtils.constantValue(((Symbol.VariableSymbol) identifier)) + return ((Symbol.VariableSymbol) identifier).constantValue() .filter(Number.class::isInstance) .map(Number.class::cast) .map(value -> programState.addConstraint(constant, new NumericalConstraint(value))) diff --git a/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/NonNullSetToNullCheck.java b/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/NonNullSetToNullCheck.java index 0b6749c815c..a2d22d05a3a 100644 --- a/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/NonNullSetToNullCheck.java +++ b/java-symbolic-execution/src/main/java/org/sonar/java/se/checks/NonNullSetToNullCheck.java @@ -29,7 +29,6 @@ import org.sonar.check.Rule; import org.sonar.java.cfg.CFG; import org.sonar.java.model.ExpressionUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.se.CheckerContext; import org.sonar.java.se.ProgramState; import org.sonar.java.se.constraint.ConstraintManager; @@ -55,7 +54,6 @@ import org.sonar.plugins.java.api.tree.VariableTree; import org.sonarsource.analyzer.commons.collections.ListUtils; -import static org.sonar.java.model.JUtils.isLocalVariable; import static org.sonar.java.se.NullabilityDataUtils.nullabilityAsString; import static org.sonar.plugins.java.api.semantic.SymbolMetadata.NullabilityLevel.PACKAGE; import static org.sonar.plugins.java.api.semantic.SymbolMetadata.NullabilityLevel.VARIABLE; @@ -204,7 +202,7 @@ public void visitAssignmentExpression(AssignmentExpressionTree tree) { if (ExpressionUtils.isSimpleAssignment(tree)) { IdentifierTree variable = ExpressionUtils.extractIdentifier(tree); Symbol symbol = variable.symbol(); - if (JUtils.isParameter(symbol)) { + if (symbol.isParameter()) { // It is fine to assign a parameter to null in the body of the method. return; } @@ -298,7 +296,7 @@ private boolean isLocalExpression(@Nullable ExpressionTree expression) { return false; } if (expression.is(Tree.Kind.IDENTIFIER)) { - return isLocalVariable(((IdentifierTree) expression).symbol()); + return ((IdentifierTree) expression).symbol().isLocalVariable(); } return true; } diff --git a/java-symbolic-execution/src/test/java/org/sonar/java/se/ExplodedGraphWalkerTest.java b/java-symbolic-execution/src/test/java/org/sonar/java/se/ExplodedGraphWalkerTest.java index 0939b8cd38e..3b2f4774b4a 100644 --- a/java-symbolic-execution/src/test/java/org/sonar/java/se/ExplodedGraphWalkerTest.java +++ b/java-symbolic-execution/src/test/java/org/sonar/java/se/ExplodedGraphWalkerTest.java @@ -31,7 +31,6 @@ import org.junit.jupiter.api.Test; import org.sonar.java.cfg.CFG; import org.sonar.java.checks.verifier.TestUtils; -import org.sonar.java.model.JUtils; import org.sonar.java.se.checks.AllowXMLInclusionCheck; import org.sonar.java.se.checks.BooleanGratuitousExpressionsCheck; import org.sonar.java.se.checks.ConditionalUnreachableCodeCheck; diff --git a/sonar-java-plugin/src/main/resources/static/documentation.md b/sonar-java-plugin/src/main/resources/static/documentation.md index b97fe79f7a1..5bcbc658b7c 100644 --- a/sonar-java-plugin/src/main/resources/static/documentation.md +++ b/sonar-java-plugin/src/main/resources/static/documentation.md @@ -147,20 +147,27 @@ The tutorial [Writing Custom Java Rules 101](https://redirect.sonarsource.com/do All the API changes are related to ECJ utility methods that were commonly used in the analyzer and could benefit the implementation of custom rules. -* New Method `Symbol.MethodSymbol.isOverridable()`. Returns whether this method is overridable. -* New Method `Symbol.MethodSymbol.isVarArgsMethod()`. Returns whether this method has a vararg parameter. -* New Method `Symbol.MethodSymbol.isDefaultMethod()`. Returns whether this method has a default implementation. -* New Method `Symbol.MethodSymbol.isParametrizedMethod()`. Returns whether this method has type parameters. -* New Method `Symbol.MethodSymbol.isSynchronizedMethod()`. Returns whether this method is synchronized. -* New method: `Type#isPrimitiveWrapper()`. Check if this type is a primitive wrapper. -* New method: `Type#primitiveWrapperType()`. Returns the type of the primitive wrapper. -* New method: `Type#primitiveType()`. Returns the type of the primitive. -* New method: `Type#isNullType()`. Returns whether this type is the null type. -* New method: `Type#isTypeVar()`. Returns whether this type represents a type variable. -* New method: `Type#isRawType()`. Check if this type is a raw type. -* New method: `Type#declaringType()`. Returns the declaring type of this type. -* New method: `ImportTree#symbol()`. Returns the symbol of this `ImportTree`. -* New method: `TypeParameterTree#symbol()`. Returns the symbol of this `TypeParameterTree`. +* New method: `Symbol.TypeSymbol.superTypes()`. Returns the list of super types of this type. +* New method: `Symbol.TypeSymbol.outermostClass()`. Returns the outermost class of this type. +* New method: `Symbol.TypeSymbol.isAnnotation()`. Returns whether this type is an annotation. +* New method: `Symbol.VariableSymbol.isEffectivelyFinal()`. Returns whether this variable is effectively final. +* New method: `Symbol.VariableSymbol.constantValue()`. Returns the constant value of this variable. +* New Method: `Symbol.MethodSymbol.isOverridable()`. Returns whether this method is overridable. +* New Method: `Symbol.MethodSymbol.isVarArgsMethod()`. Returns whether this method has a vararg parameter. +* New Method: `Symbol.MethodSymbol.isDefaultMethod()`. Returns whether this method has a default implementation. +* New Method: `Symbol.MethodSymbol.isParametrizedMethod()`. Returns whether this method has type parameters. +* New Method: `Symbol.MethodSymbol.isSynchronizedMethod()`. Returns whether this method is synchronized. +* New method: `Symbol.isLocalVariable()`. Returns whether this variable is a local variable. +* New method: `Symbol.isParameter()`. Returns whether this variable is a parameter. +* New method: `Type.isPrimitiveWrapper()`. Check if this type is a primitive wrapper. +* New method: `Type.primitiveWrapperType()`. Returns the type of the primitive wrapper. +* New method: `Type.primitiveType()`. Returns the type of the primitive. +* New method: `Type.isNullType()`. Returns whether this type is the null type. +* New method: `Type.isTypeVar()`. Returns whether this type represents a type variable. +* New method: `Type.isRawType()`. Check if this type is a raw type. +* New method: `Type.declaringType()`. Returns the declaring type of this type. +* New method: `ImportTree.symbol()`. Returns the symbol of this `ImportTree`. +* New method: `TypeParameterTree.symbol()`. Returns the symbol of this `TypeParameterTree`. #### **7.25**