
org.sonar.java.checks.AbstractCallToDeprecatedCodeChecker Maven / Gradle / Ivy
The newest version!
/*
* SonarQube Java
* Copyright (C) 2012-2025 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 Sonar Source-Available License Version 1, as published by SonarSource SA.
*
* 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 Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
package org.sonar.java.checks;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.semantic.SymbolMetadata.AnnotationValue;
import org.sonar.plugins.java.api.tree.ClassTree;
import org.sonar.plugins.java.api.tree.IdentifierTree;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.VariableTree;
public abstract class AbstractCallToDeprecatedCodeChecker extends IssuableSubscriptionVisitor {
private int nestedDeprecationLevel = 0;
@Override
public final void leaveFile(JavaFileScannerContext context) {
nestedDeprecationLevel = 0;
}
@Override
public final List nodesToVisit() {
return Arrays.asList(Tree.Kind.IDENTIFIER, Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE, Tree.Kind.METHOD, Tree.Kind.CONSTRUCTOR);
}
@Override
public final void visitNode(Tree tree) {
if (nestedDeprecationLevel == 0) {
if (tree.is(Tree.Kind.IDENTIFIER)) {
IdentifierTree identifierTree = (IdentifierTree) tree;
if (isSimpleNameOfVariableTreeOrVariableIsDeprecated(identifierTree)) {
return;
}
tryGetDeprecatedSymbol(identifierTree).ifPresent(deprecatedSymbol -> checkDeprecatedIdentifier(identifierTree, deprecatedSymbol));
} else if (tree.is(Tree.Kind.METHOD)) {
MethodTree methodTree = (MethodTree) tree;
List deprectatedMethods = deprecatedMethodSymbols(methodTree);
if (!deprectatedMethods.isEmpty()) {
checkOverridingMethod(methodTree, deprectatedMethods);
}
}
}
if (isDeprecatedMethod(tree) || isDeprecatedClassTree(tree)) {
nestedDeprecationLevel++;
}
}
@Override
public final void leaveNode(Tree tree) {
if (isDeprecatedMethod(tree) || isDeprecatedClassTree(tree)) {
nestedDeprecationLevel--;
}
}
private static Optional tryGetDeprecatedSymbol(IdentifierTree identifierTree) {
Symbol symbol = identifierTree.symbol();
if (symbol.isDeprecated()) {
return Optional.of(symbol);
}
if (isConstructor(symbol) && symbol.owner().isDeprecated()) {
return Optional.of(symbol.owner());
}
if (isDeprecatedEnumConstant(symbol)) {
return Optional.of(symbol.type().symbol());
}
return Optional.empty();
}
public static boolean isConstructor(Symbol symbol) {
return symbol.isMethodSymbol() && "".equals(symbol.name());
}
private static boolean isDeprecatedEnumConstant(Symbol symbol) {
return symbol.isVariableSymbol() && symbol.isEnum() && symbol.type().symbol().isDeprecated();
}
abstract void checkDeprecatedIdentifier(IdentifierTree identifierTree, Symbol deprecatedSymbol);
private static boolean isSimpleNameOfVariableTreeOrVariableIsDeprecated(IdentifierTree identifierTree) {
Tree parent = identifierTree.parent();
return parent.is(Tree.Kind.VARIABLE) && (identifierTree.equals(((VariableTree) parent).simpleName()) || ((VariableTree) parent).symbol().isDeprecated());
}
private static List deprecatedMethodSymbols(MethodTree methodTree) {
Symbol.MethodSymbol methodSymbol = methodTree.symbol();
if (methodSymbol.isDeprecated()) {
return Collections.emptyList();
}
return methodSymbol.overriddenSymbols()
.stream()
.filter(Symbol.MethodSymbol::isDeprecated)
.toList();
}
abstract void checkOverridingMethod(MethodTree methodTree, List deprecatedSymbol);
private static boolean isDeprecatedMethod(Tree tree) {
return tree.is(Tree.Kind.METHOD, Tree.Kind.CONSTRUCTOR) && ((MethodTree) tree).symbol().isDeprecated();
}
private static boolean isDeprecatedClassTree(Tree tree) {
return tree.is(Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE) && ((ClassTree) tree).symbol().isDeprecated();
}
boolean isFlaggedForRemoval(Symbol deprecatedSymbol) {
List valuesForAnnotation = deprecatedSymbol.metadata().valuesForAnnotation("java.lang.Deprecated");
if (valuesForAnnotation == null) {
return false;
}
return valuesForAnnotation.stream()
.filter(annotationValue -> "forRemoval".equals(annotationValue.name()))
.anyMatch(annotationValue -> Boolean.TRUE.equals(annotationValue.value()));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy