From 689342496815418b5d236e1d279f9df4d5674013 Mon Sep 17 00:00:00 2001 From: leonardo-pilastri-sonarsource <115481625+leonardo-pilastri-sonarsource@users.noreply.github.com> Date: Mon, 20 Nov 2023 15:31:51 +0100 Subject: [PATCH] SONARJAVA-4576 Update API with methods from JUtils (#4551) --- .../CollectionInappropriateCallsCheck.java | 2 +- .../java/checks/CompareWithEqualsVisitor.java | 5 +- .../java/checks/ConfusingVarargCheck.java | 2 +- .../sonar/java/checks/ConstantMathCheck.java | 3 +- .../java/checks/InnerStaticClassesCheck.java | 3 +- .../java/checks/MapKeyNotComparableCheck.java | 2 +- .../PrimitiveTypeBoxingWithToStringCheck.java | 3 +- ...imitiveWrappersInTernaryOperatorCheck.java | 3 +- .../org/sonar/java/checks/RawTypeCheck.java | 3 +- .../RedundantThrowsDeclarationCheck.java | 2 +- .../checks/ReplaceLambdaByMethodRefCheck.java | 2 +- .../sonar/java/checks/SillyEqualsCheck.java | 3 +- .../java/checks/SimpleClassNameCheck.java | 3 +- .../SpecializedFunctionalInterfacesCheck.java | 3 +- .../org/sonar/java/checks/ToArrayCheck.java | 5 +- .../checks/naming/BadConstantNameCheck.java | 3 +- .../naming/BadLocalVariableNameCheck.java | 3 +- ...alizableFieldInSerializableClassCheck.java | 3 +- .../checks/tests/AssertionTypesCheck.java | 3 +- .../unused/UnusedTypeParameterCheck.java | 3 +- .../ast/visitors/SonarSymbolTableVisitor.java | 7 +- .../main/java/org/sonar/java/model/JType.java | 75 ++++++++++++++++ .../java/org/sonar/java/model/JUtils.java | 63 +------------- .../java/org/sonar/java/model/Symbols.java | 37 ++++++++ .../sonar/plugins/java/api/semantic/Type.java | 87 +++++++++++++++++++ .../plugins/java/api/tree/ImportTree.java | 5 ++ .../java/api/tree/TypeParameterTree.java | 3 + .../sonar/java/model/ClassesLayoutTest.java | 4 +- .../java/org/sonar/java/model/JTypeTest.java | 14 +++ .../java/org/sonar/java/model/JUtilsTest.java | 62 +++++++------ .../org/sonar/java/model/SymbolsTest.java | 8 ++ .../java/se/checks/DivisionByZeroCheck.java | 2 +- .../main/resources/static/documentation.md | 15 ++++ 33 files changed, 305 insertions(+), 136 deletions(-) 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 82309f99c44..c0c8b5d7065 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 @@ -174,7 +174,7 @@ private static boolean isSubtypeOf(Type type, Type superType) { private static boolean autoboxing(Type argumentType, Type collectionParameterType) { return argumentType.isPrimitive() - && isSubtypeOf(JUtils.primitiveWrapperType(argumentType), collectionParameterType); + && isSubtypeOf(argumentType.primitiveWrapperType(), collectionParameterType); } private static class TypeChecker { diff --git a/java-checks/src/main/java/org/sonar/java/checks/CompareWithEqualsVisitor.java b/java-checks/src/main/java/org/sonar/java/checks/CompareWithEqualsVisitor.java index a2852264cda..0dab9a2feed 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/CompareWithEqualsVisitor.java +++ b/java-checks/src/main/java/org/sonar/java/checks/CompareWithEqualsVisitor.java @@ -20,7 +20,6 @@ package org.sonar.java.checks; import org.sonar.java.checks.helpers.MethodTreeUtils; -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.Type; @@ -65,7 +64,7 @@ private static boolean isEquals(MethodTree tree) { } protected static boolean isNullComparison(Type leftOpType, Type rightOpType) { - return JUtils.isNullType(leftOpType) || JUtils.isNullType(rightOpType); + return leftOpType.isNullType() || rightOpType.isNullType(); } protected static boolean isStringType(Type leftOpType, Type rightOpType) { @@ -73,7 +72,7 @@ protected static boolean isStringType(Type leftOpType, Type rightOpType) { } protected static boolean isBoxedType(Type leftOpType, Type rightOpType) { - return JUtils.isPrimitiveWrapper(leftOpType) && JUtils.isPrimitiveWrapper(rightOpType); + return leftOpType.isPrimitiveWrapper() && rightOpType.isPrimitiveWrapper(); } protected void reportIssue(SyntaxToken opToken) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/ConfusingVarargCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ConfusingVarargCheck.java index 614d64ee1dc..66a8f710ab7 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ConfusingVarargCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ConfusingVarargCheck.java @@ -118,7 +118,7 @@ private static String message(Type varargParameter, Type varargArgument) { message = "Remove this argument or pass an empty '%s' array to the vararg method."; } else if (isPrimitiveArray(varargArgument)) { Type argumentType = ((Type.ArrayType) varargArgument).elementType(); - return String.format("Use an array of '%s' instead of an array of '%s'.", JUtils.primitiveWrapperType(argumentType).name(), argumentType.name()); + return String.format("Use an array of '%s' instead of an array of '%s'.", argumentType.primitiveWrapperType().name(), argumentType.name()); } return String.format(message, parameterType.name()); } diff --git a/java-checks/src/main/java/org/sonar/java/checks/ConstantMathCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ConstantMathCheck.java index fbd833f1f27..b7c88dd5e49 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ConstantMathCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ConstantMathCheck.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.java.model.LiteralUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; @@ -92,7 +91,7 @@ public void visitNode(Tree tree) { private static boolean isIntOrLong(ExpressionTree expression) { Type type = expression.symbolType(); - return isIntegral(type) || (JUtils.isPrimitiveWrapper(type) && isIntegral(JUtils.primitiveType(type))); + return isIntegral(type) || (type.isPrimitiveWrapper() && isIntegral(type.primitiveType())); } private static boolean isTruncation(MethodInvocationTree methodTree) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/InnerStaticClassesCheck.java b/java-checks/src/main/java/org/sonar/java/checks/InnerStaticClassesCheck.java index dc24ac7978e..f1f2101c2a2 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/InnerStaticClassesCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/InnerStaticClassesCheck.java @@ -23,7 +23,6 @@ import java.util.LinkedList; import java.util.List; 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.Symbol; @@ -116,7 +115,7 @@ private static boolean isParameterizedWithTypeVarFromParent(ClassTree tree) { return parameterizedSuperTypes.stream() .flatMap(parameterizedTypeTree -> parameterizedTypeTree.typeArguments().stream()) .map(TypeTree::symbolType) - .anyMatch(JUtils::isTypeVar); + .anyMatch(Type::isTypeVar); } @Override diff --git a/java-checks/src/main/java/org/sonar/java/checks/MapKeyNotComparableCheck.java b/java-checks/src/main/java/org/sonar/java/checks/MapKeyNotComparableCheck.java index 83262726596..359f6124559 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/MapKeyNotComparableCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/MapKeyNotComparableCheck.java @@ -56,7 +56,7 @@ public void visitNode(Tree tree) { } private static boolean isGenericOrWildCard(TypeTree tree) { - return JUtils.isTypeVar(tree.symbolType()) || tree instanceof WildcardTree; + return tree.symbolType().isTypeVar() || tree instanceof WildcardTree; } private static Optional getMapKeyTree(ParameterizedTypeTree typeTree) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/PrimitiveTypeBoxingWithToStringCheck.java b/java-checks/src/main/java/org/sonar/java/checks/PrimitiveTypeBoxingWithToStringCheck.java index 030667cdde5..7957ea42a73 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/PrimitiveTypeBoxingWithToStringCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/PrimitiveTypeBoxingWithToStringCheck.java @@ -20,7 +20,6 @@ package org.sonar.java.checks; 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; @@ -88,7 +87,7 @@ private static boolean isValueOfInvocation(ExpressionTree abstractTypedTree) { MethodMatchers valueOfMatcher = MethodMatchers.create() .ofTypes(type.fullyQualifiedName()) .names("valueOf") - .addParametersMatcher(JUtils.primitiveType(type).fullyQualifiedName()) + .addParametersMatcher(type.primitiveType().fullyQualifiedName()) .build(); return valueOfMatcher.matches((MethodInvocationTree) abstractTypedTree); } diff --git a/java-checks/src/main/java/org/sonar/java/checks/PrimitiveWrappersInTernaryOperatorCheck.java b/java-checks/src/main/java/org/sonar/java/checks/PrimitiveWrappersInTernaryOperatorCheck.java index dcf2b7d103b..281a3aac852 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/PrimitiveWrappersInTernaryOperatorCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/PrimitiveWrappersInTernaryOperatorCheck.java @@ -20,7 +20,6 @@ package org.sonar.java.checks; 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.Type; import org.sonar.plugins.java.api.tree.ConditionalExpressionTree; @@ -49,7 +48,7 @@ public void visitNode(Tree tree) { } private static boolean dissimilarPrimitiveTypeWrappers(Type trueExprType, Type falseExprType) { - return JUtils.isPrimitiveWrapper(trueExprType) && JUtils.isPrimitiveWrapper(falseExprType) && !trueExprType.equals(falseExprType); + return trueExprType.isPrimitiveWrapper() && falseExprType.isPrimitiveWrapper() && !trueExprType.equals(falseExprType); } } diff --git a/java-checks/src/main/java/org/sonar/java/checks/RawTypeCheck.java b/java-checks/src/main/java/org/sonar/java/checks/RawTypeCheck.java index 332d731e6ff..add8b9d6db2 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/RawTypeCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/RawTypeCheck.java @@ -21,7 +21,6 @@ import javax.annotation.Nullable; 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.Type; @@ -97,7 +96,7 @@ private void checkTypeTree(@Nullable TypeTree typeTree) { private void checkIdentifier(IdentifierTree identifier) { Type type = identifier.symbolType(); - if (JUtils.isRawType(type) && !type.equals(JUtils.declaringType(type))) { + if (type.isRawType() && !type.equals(type.declaringType())) { context.reportIssue(this, identifier, "Provide the parametrized type for this generic."); } } diff --git a/java-checks/src/main/java/org/sonar/java/checks/RedundantThrowsDeclarationCheck.java b/java-checks/src/main/java/org/sonar/java/checks/RedundantThrowsDeclarationCheck.java index 80e750f4ef6..6811c29f065 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/RedundantThrowsDeclarationCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/RedundantThrowsDeclarationCheck.java @@ -151,7 +151,7 @@ private static boolean canNotBeThrown(MethodTree methodTree, Type exceptionType, || !exceptionType.isSubtypeOf("java.lang.Exception") || exceptionType.isSubtypeOf("java.lang.RuntimeException") || thrownExceptions == null - || thrownExceptions.stream().anyMatch(JUtils::isTypeVar)) { + || thrownExceptions.stream().anyMatch(Type::isTypeVar)) { return false; } diff --git a/java-checks/src/main/java/org/sonar/java/checks/ReplaceLambdaByMethodRefCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ReplaceLambdaByMethodRefCheck.java index d60507b41b5..ef45bf51171 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ReplaceLambdaByMethodRefCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ReplaceLambdaByMethodRefCheck.java @@ -199,7 +199,7 @@ private static Optional getTypeName(TypeTree type) { } private static boolean isGeneric(IdentifierTree identifierTree) { - return JUtils.isTypeVar(identifierTree.symbolType()); + return identifierTree.symbolType().isTypeVar(); } private static boolean isSingleParamExpression(ExpressionTree expression, Symbol symbol) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/SillyEqualsCheck.java b/java-checks/src/main/java/org/sonar/java/checks/SillyEqualsCheck.java index 8f3224e3ede..380895bfffe 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/SillyEqualsCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/SillyEqualsCheck.java @@ -23,7 +23,6 @@ import org.sonar.java.checks.methods.AbstractMethodDetection; import org.sonarsource.analyzer.commons.collections.ListUtils; 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.Type; import org.sonar.plugins.java.api.tree.ExpressionTree; @@ -53,7 +52,7 @@ protected void onMethodInvocationFound(MethodInvocationTree tree) { ExpressionTree firstArgument = ListUtils.getOnlyElement(tree.arguments()); Type argumentType = firstArgument.symbolType().erasure(); if (argumentType.isPrimitive()) { - argumentType = JUtils.primitiveWrapperType(argumentType); + argumentType = argumentType.primitiveWrapperType(); } Type ownerType = getMethodOwnerType(tree).erasure(); diff --git a/java-checks/src/main/java/org/sonar/java/checks/SimpleClassNameCheck.java b/java-checks/src/main/java/org/sonar/java/checks/SimpleClassNameCheck.java index fadfad9e67f..477c478b40a 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/SimpleClassNameCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/SimpleClassNameCheck.java @@ -20,7 +20,6 @@ package org.sonar.java.checks; 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.ClassTree; @@ -64,7 +63,7 @@ public void visitNode(Tree tree) { private void checkImports(List imports) { imports.stream() - .map(JUtils::importTreeSymbol) + .map(ImportTree::symbol) .filter(Objects::nonNull) .forEach(this::checkSymbol); } diff --git a/java-checks/src/main/java/org/sonar/java/checks/SpecializedFunctionalInterfacesCheck.java b/java-checks/src/main/java/org/sonar/java/checks/SpecializedFunctionalInterfacesCheck.java index d6394fec497..af1baf84b50 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/SpecializedFunctionalInterfacesCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/SpecializedFunctionalInterfacesCheck.java @@ -28,7 +28,6 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; 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.Type; @@ -200,7 +199,7 @@ private static Optional handleBiConsumerInterface(Type parametrizedType, ParameterTypeNameAndTreeType firstArgument = new ParameterTypeNameAndTreeType(parametrizedType, 0); ParameterTypeNameAndTreeType secondArgument = new ParameterTypeNameAndTreeType(parametrizedType, 1); - if (secondArgument.paramTypeName != null && !JUtils.isPrimitiveWrapper(firstArgument.paramType)) { + if (secondArgument.paramTypeName != null && !firstArgument.paramType.isPrimitiveWrapper()) { return Optional.of(String.format("Obj%sConsumer<%s>", secondArgument.paramTypeName, firstArgument.paramType)); } return Optional.empty(); diff --git a/java-checks/src/main/java/org/sonar/java/checks/ToArrayCheck.java b/java-checks/src/main/java/org/sonar/java/checks/ToArrayCheck.java index a7455899463..1d1a4688154 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/ToArrayCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/ToArrayCheck.java @@ -24,7 +24,6 @@ import org.sonar.check.Rule; import org.sonar.java.checks.helpers.QuickFixHelper; import org.sonar.java.checks.methods.AbstractMethodDetection; -import org.sonar.java.model.JUtils; import org.sonar.java.reporting.AnalyzerMessage; import org.sonar.java.reporting.JavaQuickFix; import org.sonar.java.reporting.JavaTextEdit; @@ -61,7 +60,7 @@ private void checkCast(TypeCastTree castTree, MethodInvocationTree mit) { Type elementType = ((Type.ArrayType) type).elementType(); ExpressionTree methodSelect = mit.methodSelect(); // Do not report an issue for type variables and call to toArray from the Collection itself - if (!JUtils.isTypeVar(elementType) && methodSelect.is(Tree.Kind.MEMBER_SELECT)) { + if (!elementType.isTypeVar() && methodSelect.is(Tree.Kind.MEMBER_SELECT)) { String typeName = String.format("new %s[0]", elementType.name()); QuickFixHelper.newIssue(context) .forRule(this) @@ -76,7 +75,7 @@ private void checkCast(TypeCastTree castTree, MethodInvocationTree mit) { private static JavaQuickFix getQuickFix(TypeCastTree castTree, MethodInvocationTree mit, MemberSelectExpressionTree methodSelect, String typeName) { List textEdits = new ArrayList<>(); textEdits.add(JavaTextEdit.insertAfterTree(mit.arguments().firstToken(), typeName)); - if (!JUtils.isRawType(methodSelect.expression().symbolType())) { + if (!methodSelect.expression().symbolType().isRawType()) { textEdits.add(JavaTextEdit.removeTextSpan(AnalyzerMessage.textSpanBetween(castTree, true, mit, false))); } return JavaQuickFix.newQuickFix("Pass \"%s\" as argument", typeName) 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 43d7abad985..c1b0f1afc4e 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 @@ -22,7 +22,6 @@ import org.sonar.check.Rule; import org.sonar.check.RuleProperty; import org.sonar.java.checks.serialization.SerializableContract; -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.Type; @@ -80,7 +79,7 @@ public void visitNode(Tree tree) { } private static boolean isConstantType(Type symbolType) { - return symbolType.isPrimitive() || symbolType.is("java.lang.String") || JUtils.isPrimitiveWrapper(symbolType); + return symbolType.isPrimitive() || symbolType.is("java.lang.String") || symbolType.isPrimitiveWrapper(); } private void checkName(VariableTree variableTree) { diff --git a/java-checks/src/main/java/org/sonar/java/checks/naming/BadLocalVariableNameCheck.java b/java-checks/src/main/java/org/sonar/java/checks/naming/BadLocalVariableNameCheck.java index b84011b7a27..55a036df6f9 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/naming/BadLocalVariableNameCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/naming/BadLocalVariableNameCheck.java @@ -21,7 +21,6 @@ import org.sonar.check.Rule; import org.sonar.check.RuleProperty; -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.Type; @@ -104,7 +103,7 @@ private boolean isLocalConstant(VariableTree tree) { } private static boolean isConstantType(Type symbolType) { - return symbolType.isPrimitive() || symbolType.is("java.lang.String") || JUtils.isPrimitiveWrapper(symbolType); + return symbolType.isPrimitive() || symbolType.is("java.lang.String") || symbolType.isPrimitiveWrapper(); } } diff --git a/java-checks/src/main/java/org/sonar/java/checks/serialization/SerializableFieldInSerializableClassCheck.java b/java-checks/src/main/java/org/sonar/java/checks/serialization/SerializableFieldInSerializableClassCheck.java index 0c075cb6de4..bb1cab7734d 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/serialization/SerializableFieldInSerializableClassCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/serialization/SerializableFieldInSerializableClassCheck.java @@ -27,7 +27,6 @@ import javax.annotation.Nullable; import org.sonar.check.Rule; import org.sonar.java.model.ExpressionUtils; -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; @@ -195,7 +194,7 @@ private static boolean implementsSerializable(@Nullable Type type) { if (type.isArray()) { return implementsSerializable(((Type.ArrayType) type).elementType()); } - if (type.isClass() || JUtils.isTypeVar(type)) { + if (type.isClass() || type.isTypeVar()) { return type.isSubtypeOf("java.io.Serializable"); } return false; diff --git a/java-checks/src/main/java/org/sonar/java/checks/tests/AssertionTypesCheck.java b/java-checks/src/main/java/org/sonar/java/checks/tests/AssertionTypesCheck.java index 3dda94d5d6d..119a51626ba 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/tests/AssertionTypesCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/tests/AssertionTypesCheck.java @@ -26,7 +26,6 @@ import org.sonar.java.checks.helpers.MethodTreeUtils; import org.sonar.java.checks.helpers.UnitTestUtils; 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.JavaFileScannerContext; @@ -369,7 +368,7 @@ static Type expectedArgumentType(MethodInvocationTree mit, int argumentIndex) { static Type wrapperType(Type type) { if (type.isPrimitive()) { - Type wrapperType = JUtils.primitiveWrapperType(type); + Type wrapperType = type.primitiveWrapperType(); return wrapperType != null ? wrapperType : type; } return type; diff --git a/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedTypeParameterCheck.java b/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedTypeParameterCheck.java index c030acde230..95d97ee3a35 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedTypeParameterCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/unused/UnusedTypeParameterCheck.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Locale; 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.ClassTree; @@ -46,7 +45,7 @@ public List nodesToVisit() { public void visitNode(Tree tree) { TypeParameters typeParameters = tree.is(Tree.Kind.METHOD) ? ((MethodTree) tree).typeParameters() : ((ClassTree) tree).typeParameters(); for (TypeParameterTree typeParameter : typeParameters) { - Symbol symbol = JUtils.typeParameterTreeSymbol(typeParameter); + Symbol symbol = typeParameter.symbol(); if (!symbol.isUnknown() && symbol.usages().isEmpty()) { String message = String.format(ISSUE_MESSAGE, symbol.name(), tree.kind().name().toLowerCase(Locale.ROOT)); reportIssue(typeParameter.identifier(), message); diff --git a/java-frontend/src/main/java/org/sonar/java/ast/visitors/SonarSymbolTableVisitor.java b/java-frontend/src/main/java/org/sonar/java/ast/visitors/SonarSymbolTableVisitor.java index 900fa7c0306..f5b8bd5e8f7 100644 --- a/java-frontend/src/main/java/org/sonar/java/ast/visitors/SonarSymbolTableVisitor.java +++ b/java-frontend/src/main/java/org/sonar/java/ast/visitors/SonarSymbolTableVisitor.java @@ -22,7 +22,6 @@ import java.util.List; import org.sonar.api.batch.sensor.symbol.NewSymbol; import org.sonar.api.batch.sensor.symbol.NewSymbolTable; -import org.sonar.java.model.JUtils; import org.sonar.java.model.declaration.VariableTreeImpl; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.tree.BaseTreeVisitor; @@ -67,7 +66,7 @@ public void visitClass(ClassTree tree) { createSymbol(simpleName, tree.symbol().usages()); } for (TypeParameterTree typeParameterTree : tree.typeParameters()) { - createSymbol(typeParameterTree.identifier(), JUtils.typeParameterTreeSymbol(typeParameterTree).usages()); + createSymbol(typeParameterTree.identifier(), typeParameterTree.symbol().usages()); } super.visitClass(tree); } @@ -89,7 +88,7 @@ public void visitMethod(MethodTree tree) { List usages = tree.symbol().usages(); createSymbol(tree.simpleName(), usages); for (TypeParameterTree typeParameterTree : tree.typeParameters()) { - createSymbol(typeParameterTree.identifier(), JUtils.typeParameterTreeSymbol(typeParameterTree).usages()); + createSymbol(typeParameterTree.identifier(), typeParameterTree.symbol().usages()); } super.visitMethod(tree); } @@ -110,7 +109,7 @@ public void visitImport(ImportTree tree) { } // Exclude on demands imports if (!"*".equals(identifierTree.name())) { - Symbol symbol = JUtils.importTreeSymbol(tree); + Symbol symbol = tree.symbol(); if (symbol != null) { createSymbol(identifierTree, symbol.usages()); } diff --git a/java-frontend/src/main/java/org/sonar/java/model/JType.java b/java-frontend/src/main/java/org/sonar/java/model/JType.java index aed790b93ad..6faa18a7d34 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/JType.java +++ b/java-frontend/src/main/java/org/sonar/java/model/JType.java @@ -39,6 +39,21 @@ final class JType implements Type, Type.ArrayType { private final String fullyQualifiedName; + /** + * Cache for {@link #primitiveWrapperType()}. + */ + private Type primitiveWrapperType; + + /** + * Cache for {@link #primitiveType()}. + */ + private Type primitiveType; + + /** + * Cache for {@link #declaringType()}. + */ + private Type declaringType; + /** * Cache for {@link #typeArguments()}. */ @@ -111,6 +126,66 @@ public boolean isPrimitive(Primitives primitive) { return primitive.name().toLowerCase(Locale.ROOT).equals(fullyQualifiedName()); } + @Override + public boolean isPrimitiveWrapper() { + return isClass() && JUtils.WRAPPER_TO_PRIMITIVE.containsKey(fullyQualifiedName()); + } + + @Nullable + @Override + public Type primitiveWrapperType() { + if (primitiveWrapperType == null) { + String name = JUtils.PRIMITIVE_TO_WRAPPER.get(fullyQualifiedName()); + if (name == null) { + return null; + } + primitiveWrapperType = sema.type(sema.resolveType(name)); + } + return primitiveWrapperType; + } + + @Nullable + @Override + public Type primitiveType() { + if (primitiveType == null) { + String name = JUtils.WRAPPER_TO_PRIMITIVE.get(fullyQualifiedName()); + if (name == null) { + return null; + } + primitiveType = sema.type(sema.resolveType(name)); + } + return primitiveType; + } + + @Override + public boolean isNullType() { + return !isUnknown() && typeBinding.isNullType(); + } + + @Override + public boolean isTypeVar() { + return !isUnknown() && typeBinding.isTypeVariable(); + } + + @Override + public boolean isRawType() { + if (isUnknown()) { + return false; + } + return typeBinding.isRawType(); + } + + @Override + public Type declaringType() { + if (declaringType == null) { + if (isUnknown()) { + return this; + } + declaringType = sema.type(typeBinding.getTypeDeclaration()); + } + return declaringType; + } + @Override public boolean isUnknown() { return typeBinding.isRecovered(); 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 850fe04cc44..a5ab195c0d3 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 @@ -43,7 +43,7 @@ public final class JUtils { private JUtils() { } - private static final Map WRAPPER_TO_PRIMITIVE = MapBuilder.newMap() + static final Map WRAPPER_TO_PRIMITIVE = MapBuilder.newMap() .put("java.lang.Byte", "byte") .put("java.lang.Character", "char") .put("java.lang.Short", "short") @@ -54,7 +54,7 @@ private JUtils() { .put("java.lang.Boolean", "boolean") .build(); - private static final Map PRIMITIVE_TO_WRAPPER = MapBuilder.newMap() + static final Map PRIMITIVE_TO_WRAPPER = MapBuilder.newMap() .put("byte", "java.lang.Byte") .put("char", "java.lang.Character") .put("short", "java.lang.Short") @@ -65,47 +65,15 @@ private JUtils() { .put("boolean", "java.lang.Boolean") .build(); - public static boolean isPrimitiveWrapper(Type type) { - return type.isClass() && WRAPPER_TO_PRIMITIVE.containsKey(type.fullyQualifiedName()); - } - public static Type wrapTypeIfPrimitive(Type type) { - Type wrapped = primitiveWrapperType(type); + Type wrapped = type.primitiveWrapperType(); return Objects.requireNonNullElse(wrapped, type); } - @Nullable - public static Type primitiveWrapperType(Type type) { - String name = PRIMITIVE_TO_WRAPPER.get(type.fullyQualifiedName()); - if (name == null) { - return null; - } - JSema sema = ((JType) type).sema; - return sema.type(sema.resolveType(name)); - } - - @Nullable - public static Type primitiveType(Type type) { - String name = WRAPPER_TO_PRIMITIVE.get(type.fullyQualifiedName()); - if (name == null) { - return null; - } - JSema sema = ((JType) type).sema; - return sema.type(sema.resolveType(name)); - } - - public static boolean isNullType(Type type) { - return !type.isUnknown() && ((JType) type).typeBinding.isNullType(); - } - public static boolean isIntersectionType(Type type) { return !type.isUnknown() && ((JType) type).typeBinding.isIntersectionType(); } - public static boolean isTypeVar(Type type) { - return !type.isUnknown() && ((JType) type).typeBinding.isTypeVariable(); - } - public static boolean isAnnotation(Symbol.TypeSymbol typeSymbol) { return !typeSymbol.isUnknown() && ((JTypeSymbol) typeSymbol).typeBinding().isAnnotation(); } @@ -216,22 +184,6 @@ public static boolean isParametrizedMethod(Symbol.MethodSymbol method) { || ((JMethodSymbol) method).methodBinding().isGenericMethod(); } - public static boolean isRawType(Type type) { - if (type.isUnknown()) { - return false; - } - JType t = (JType) type; - return t.typeBinding.isRawType(); - } - - public static Type declaringType(Type type) { - if (type.isUnknown()) { - return type; - } - JType t = (JType) type; - return t.sema.type(t.typeBinding.getTypeDeclaration()); - } - public static Set directSuperTypes(Type type) { if (type.isUnknown()) { return Collections.emptySet(); @@ -261,15 +213,6 @@ public static Symbol enclosingClass(Tree t) { } while (true); } - @Nullable - public static Symbol importTreeSymbol(ImportTree tree) { - return ((JavaTree.ImportTreeImpl) tree).symbol(); - } - - public static Symbol typeParameterTreeSymbol(TypeParameterTree tree) { - return ((TypeParameterTreeImpl) tree).symbol(); - } - public static SymbolMetadata parameterAnnotations(Symbol.MethodSymbol method, int param) { if (method.isUnknown()) { return Symbols.EMPTY_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 b78afd10e59..793212be0fd 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 @@ -337,6 +337,43 @@ public boolean isPrimitive(Primitives primitive) { return false; } + @Override + public boolean isPrimitiveWrapper() { + return false; + } + + @Nullable + @Override + public Type primitiveWrapperType() { + return null; + } + + @Nullable + @Override + public Type primitiveType() { + return null; + } + + @Override + public boolean isNullType() { + return false; + } + + @Override + public boolean isTypeVar() { + return false; + } + + @Override + public boolean isRawType() { + return false; + } + + @Override + public Type declaringType() { + return this; + } + @Override public boolean isUnknown() { return true; diff --git a/java-frontend/src/main/java/org/sonar/plugins/java/api/semantic/Type.java b/java-frontend/src/main/java/org/sonar/plugins/java/api/semantic/Type.java index 2cff1a8969c..295ebcaecdd 100644 --- a/java-frontend/src/main/java/org/sonar/plugins/java/api/semantic/Type.java +++ b/java-frontend/src/main/java/org/sonar/plugins/java/api/semantic/Type.java @@ -20,6 +20,7 @@ package org.sonar.plugins.java.api.semantic; import java.util.List; +import javax.annotation.Nullable; /** * Interface to access resolved type of an expression or a Type. @@ -124,6 +125,92 @@ enum Primitives { */ boolean isPrimitive(Primitives primitive); + /** + * Check if this type is a primitive wrapper. + * + *
+   *   Type type;
+   *   type.isPrimitiveWrapper();
+   *
+ * + * @return true if this is a primitive wrapper + */ + boolean isPrimitiveWrapper(); + + /** + * Returns the type of the primitive wrapper + * + *
+   *   Type type;
+   *   Type primitiveWrapperType = type.primitiveWrapperType();
+   *
+ * + * @return the type of the primitive wrapper, as Type + */ + @Nullable + Type primitiveWrapperType(); + + /** + * Returns the type of the primitive + * + *
+   *   Type type;
+   *   Type primitiveType = type.primitiveType();
+   *
+ * + * @return the type of the primitive, as Type + */ + @Nullable + Type primitiveType(); + + /** + * Returns whether this type is the null type + * + *
+   *   Type type;
+   *   type.isNullType();
+   *
+ * + * @return true if it is a null type + */ + boolean isNullType(); + + /** + * Returns whether this type represents a type variable + * + *
+   *   Type type;
+   *   type.isTypeVar();
+   *
+ * + * @return true if this is a type variable + */ + boolean isTypeVar(); + + /** + * Check if this type is a raw type + * + *
+   *   Type type;
+   *   type.isRawType();
+   *
+ * + * @return true if it is a raw type + */ + boolean isRawType(); + + /** + * Returns the declaring type of this type + * + *
+   *   Type type;
+   *   Type declaringType = type.declaringType();
+   *
+ * + * @return the declaring type of this, as Type + */ + Type declaringType(); + /** * Check if this type has been resolved. * Type can be unknown in incomplete part of Semantic Analysis or when bytecode for a type is not provided and a method cannot be resolved. diff --git a/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/ImportTree.java b/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/ImportTree.java index 71ea6b726d1..cfa763ce29f 100644 --- a/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/ImportTree.java +++ b/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/ImportTree.java @@ -22,6 +22,7 @@ import org.sonar.java.annotations.Beta; import javax.annotation.Nullable; +import org.sonar.plugins.java.api.semantic.Symbol; /** * Import declaration. @@ -51,4 +52,8 @@ public interface ImportTree extends ImportClauseTree { Tree qualifiedIdentifier(); SyntaxToken semicolonToken(); + + @Nullable + Symbol symbol(); + } diff --git a/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/TypeParameterTree.java b/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/TypeParameterTree.java index e3fc7e8b4b1..7b8bfd28c41 100644 --- a/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/TypeParameterTree.java +++ b/java-frontend/src/main/java/org/sonar/plugins/java/api/tree/TypeParameterTree.java @@ -22,6 +22,7 @@ import org.sonar.java.annotations.Beta; import javax.annotation.Nullable; +import org.sonar.plugins.java.api.semantic.Symbol; /** * Type parameter. @@ -45,4 +46,6 @@ public interface TypeParameterTree extends Tree { ListTree bounds(); + Symbol symbol(); + } 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 0cb47c6ec92..21dff8cc452 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 @@ -92,8 +92,8 @@ void method_invocation() { @Test void type() { assertAll( - () -> assertThat(instanceSize(JType.class, X86_64)).isEqualTo(48), - () -> assertThat(instanceSize(JType.class, X86_64_COOPS)).isEqualTo(32) + () -> assertThat(instanceSize(JType.class, X86_64)).isEqualTo(72), + () -> assertThat(instanceSize(JType.class, X86_64_COOPS)).isEqualTo(40) ); } diff --git a/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java b/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java index 9031f75093f..bfb835299fa 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/JTypeTest.java @@ -141,6 +141,20 @@ void isPrimitive() { ); } + @Test + void primitiveType(){ + Type byteType = type("java.lang.Byte"); + assertThat(byteType.primitiveType()).isEqualTo(type("byte")); + assertThat(byteType.primitiveType()).isNotEqualTo(type("boolean")); + } + + @Test + void declaringType(){ + Type byteType = type("java.lang.Byte"); + assertThat(byteType.declaringType()).isEqualTo(byteType); + assertThat(byteType.declaringType()).isNotEqualTo(type("java.lang.Boolean")); + } + @Test void isNumerical() { assertAll( 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 061fefbc5a5..51767367b9b 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 @@ -51,7 +51,7 @@ class PrimitiveType { @Test void java_lang_Byte() { Type wrapperType = SEMA.type(SEMA.resolveType("java.lang.Byte")); - Type primitiveType = JUtils.primitiveType(wrapperType); + Type primitiveType = wrapperType.primitiveType(); assertThat(primitiveType).isNotNull(); assertThat(primitiveType.fullyQualifiedName()).isEqualTo("byte"); @@ -59,7 +59,7 @@ void java_lang_Byte() { @Test void object_is_not_a_primitive_type() { - assertThat(JUtils.primitiveType(OBJECT_TYPE)).isNull(); + assertThat(OBJECT_TYPE.primitiveType()).isNull(); } } @@ -68,7 +68,7 @@ class PrimitiveWrapperType { @Test void java_lang_Byte() { Type primitiveType = SEMA.type(SEMA.resolveType("byte")); - Type wrapperType = JUtils.primitiveWrapperType(primitiveType); + Type wrapperType = primitiveType.primitiveWrapperType(); assertThat(wrapperType).isNotNull(); assertThat(wrapperType.fullyQualifiedName()).isEqualTo("java.lang.Byte"); @@ -76,7 +76,7 @@ void java_lang_Byte() { @Test void object_is_not_a_primitive_wrapper_type() { - assertThat(JUtils.primitiveWrapperType(OBJECT_TYPE)).isNull(); + assertThat(OBJECT_TYPE.primitiveWrapperType()).isNull(); } } @@ -86,21 +86,21 @@ class IsPrimitiveWrapper { @Test void wrapper() { - Type wrapperType = JUtils.primitiveWrapperType(primitiveType); + Type wrapperType = primitiveType.primitiveWrapperType(); assertThat(wrapperType).isNotNull(); - assertThat(JUtils.isPrimitiveWrapper(wrapperType)).isTrue(); + assertThat(wrapperType.isPrimitiveWrapper()).isTrue(); assertThat(wrapperType.fullyQualifiedName()).isEqualTo("java.lang.Byte"); } @Test void not_a_wrapper() { - assertThat(JUtils.isPrimitiveWrapper(OBJECT_TYPE)).isFalse(); + assertThat(OBJECT_TYPE.isPrimitiveWrapper()).isFalse(); } @Test void not_a_class() { Type ObjectArrayType = SEMA.type(SEMA.resolveType("java.lang.Object[]")); - assertThat(JUtils.isPrimitiveWrapper(ObjectArrayType)).isFalse(); + assertThat(ObjectArrayType.isPrimitiveWrapper()).isFalse(); } } @@ -143,23 +143,23 @@ class IsNullType { void nullType() { ReturnStatementTreeImpl s = (ReturnStatementTreeImpl) m1.block().body().get(0); AbstractTypedTree e = (AbstractTypedTree) s.expression(); - assertThat(JUtils.isNullType(cu.sema.type(e.typeBinding))) - .isEqualTo(JUtils.isNullType(e.symbolType())) + assertThat(cu.sema.type(e.typeBinding).isNullType()) + .isEqualTo(e.symbolType().isNullType()) .isTrue(); } @Test void a_non_null_type_is_not_null_type() { - assertThat(JUtils.isNullType(cu.sema.type(m1.methodBinding.getReturnType()))) - .isEqualTo(JUtils.isNullType(m1.returnType().symbolType())) + assertThat(cu.sema.type(m1.methodBinding.getReturnType()).isNullType()) + .isEqualTo(m1.returnType().symbolType().isNullType()) .isFalse(); } @Test void unresolved_type_is_not_null_type() { MethodTreeImpl m2 = nthMethod(c, 1); - assertThat(JUtils.isNullType(cu.sema.type(m2.methodBinding.getReturnType()))) - .isEqualTo(JUtils.isNullType(m2.returnType().symbolType())) + assertThat(cu.sema.type(m2.methodBinding.getReturnType()).isNullType()) + .isEqualTo(m2.returnType().symbolType().isNullType()) .isFalse(); } } @@ -209,21 +209,21 @@ class IsTypeVar { @Test void type_var() { VariableTreeImpl t = firstField(c); - assertThat(JUtils.isTypeVar(cu.sema.type(t.variableBinding.getType()))) - .isEqualTo(JUtils.isTypeVar(t.symbol().type())) + assertThat(cu.sema.type(t.variableBinding.getType()).isTypeVar()) + .isEqualTo(t.symbol().type().isTypeVar()) .isTrue(); } @Test void simple_type_is_not_a_type_var() { - assertThat(JUtils.isTypeVar(OBJECT_TYPE)).isFalse(); + assertThat(OBJECT_TYPE.isTypeVar()).isFalse(); } @Test void unresolved_type_is_not_a_type_var() { VariableTreeImpl u = nthField(c, 1); - assertThat(JUtils.isTypeVar(cu.sema.type(u.variableBinding.getType()))) - .isEqualTo(JUtils.isTypeVar(u.symbol().type())) + assertThat(cu.sema.type(u.variableBinding.getType()).isTypeVar()) + .isEqualTo(u.symbol().type().isTypeVar()) .isFalse(); } } @@ -763,14 +763,12 @@ void isRawType() { VariableTreeImpl dRaw = (VariableTreeImpl) m.parameters().get(0); VariableTreeImpl unknown = (VariableTreeImpl) m.parameters().get(1); - assertThat(JUtils.isRawType(c.symbol().type())) - .isSameAs(JUtils.isRawType(dGeneric.symbol().type())) - .isSameAs(JUtils.isRawType(unknown.symbol().type())) + assertThat(c.symbol().type().isRawType()) + .isSameAs(dGeneric.symbol().type().isRawType()) + .isSameAs(unknown.symbol().type().isRawType()) .isFalse(); - assertThat(JUtils.isRawType(dRaw.type() - .symbolType())) - .isTrue(); + assertThat(dRaw.type().symbolType().isRawType()).isTrue(); } @Test @@ -782,11 +780,11 @@ void declaringType() { VariableTreeImpl cRaw = (VariableTreeImpl) m.parameters().get(0); VariableTreeImpl unknown = (VariableTreeImpl) m.parameters().get(1); - assertThat(JUtils.declaringType(unknown.symbol().type())) + assertThat(unknown.symbol().type().declaringType()) .isSameAs(unknown.symbol().type()); - assertThat(JUtils.declaringType(cRaw.type().symbolType())) - .isSameAs(JUtils.declaringType(c.symbol().type())) + assertThat(cRaw.type().symbolType().declaringType()) + .isSameAs(c.symbol().type().declaringType()) .isSameAs(c.symbol().type()); } @@ -877,7 +875,7 @@ class ImporTreeSymbol { @Test void resolved_imports_have_type_symbols() { ImportTree listImport = (ImportTree) cu.imports().get(0); - Symbol listImportSymbol = JUtils.importTreeSymbol(listImport); + Symbol listImportSymbol = listImport.symbol(); assertThat(listImportSymbol).isNotNull(); assertThat(listImportSymbol.isTypeSymbol()).isTrue(); @@ -887,7 +885,7 @@ void resolved_imports_have_type_symbols() { @Test void unresolved_imports_have_unknown_symbols() { ImportTree unknownImport = (ImportTree) cu.imports().get(1); - Symbol unknownImportSymbol = JUtils.importTreeSymbol(unknownImport); + Symbol unknownImportSymbol = unknownImport.symbol(); assertThat(unknownImportSymbol).isNotNull(); assertThat(unknownImportSymbol.isUnknown()).isTrue(); @@ -900,9 +898,9 @@ void typeParameterTreeSymbol() { ClassTreeImpl a = firstClass(cu); TypeParameterTree t = a.typeParameters().get(0); - Symbol symbol = JUtils.typeParameterTreeSymbol(t); + Symbol symbol = t.symbol(); assertThat(symbol).isNotNull(); - assertThat(JUtils.isTypeVar(symbol.type())).isTrue(); + assertThat(symbol.type().isTypeVar()).isTrue(); } @Test 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 f994a12479d..722957e486e 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,6 +20,7 @@ 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.plugins.java.api.semantic.Symbol; @@ -56,6 +57,13 @@ void unknown_type() { assertThat(unknownType.isVoid()).isFalse(); assertThat(unknownType.isPrimitive()).isFalse(); assertThat(unknownType.isPrimitive(Primitives.BOOLEAN)).isFalse(); + assertThat(unknownType.primitiveWrapperType()).isNull(); + assertThat(unknownType.isPrimitiveWrapper()).isFalse(); + assertThat(unknownType.primitiveType()).isNull(); + assertThat(unknownType.isNullType()).isFalse(); + assertThat(unknownType.isTypeVar()).isFalse(); + assertThat(unknownType.isRawType()).isFalse(); + assertThat(unknownType.declaringType()).isEqualTo(unknownType); assertThat(unknownType.isNumerical()).isFalse(); assertThat(unknownType.fullyQualifiedName()).isEqualTo("!Unknown!"); 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 224fd95d2c4..ab1ebffb2a5 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 @@ -398,7 +398,7 @@ public void visitIdentifier(IdentifierTree identifier) { return; } Type type = identifier.symbolType(); - if (type.isPrimitive() || JUtils.isPrimitiveWrapper(type)) { + if (type.isPrimitive() || type.isPrimitiveWrapper()) { JUtils.constantValue((Symbol.VariableSymbol) symbol) .filter(Number.class::isInstance) .map(Number.class::cast) diff --git a/sonar-java-plugin/src/main/resources/static/documentation.md b/sonar-java-plugin/src/main/resources/static/documentation.md index a4524141a7b..17ce5b77d3a 100644 --- a/sonar-java-plugin/src/main/resources/static/documentation.md +++ b/sonar-java-plugin/src/main/resources/static/documentation.md @@ -142,6 +142,21 @@ The tutorial [Writing Custom Java Rules 101](https://redirect.sonarsource.com/do ### API changes +#### **7.29** + +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: `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** Update custom rules registration API `CheckRegistrar.RegistrarContext` to allow: