
org.sonar.java.model.JUtils Maven / Gradle / Ivy
/*
* SonarQube Java
* Copyright (C) 2012-2024 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.model;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nullable;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.semantic.SymbolMetadata;
import org.sonar.plugins.java.api.semantic.Type;
import org.sonar.plugins.java.api.tree.ClassTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonarsource.analyzer.commons.collections.MapBuilder;
public final class JUtils {
private JUtils() {
}
static final Map WRAPPER_TO_PRIMITIVE = MapBuilder.newMap()
.put("java.lang.Byte", "byte")
.put("java.lang.Character", "char")
.put("java.lang.Short", "short")
.put("java.lang.Integer", "int")
.put("java.lang.Long", "long")
.put("java.lang.Float", "float")
.put("java.lang.Double", "double")
.put("java.lang.Boolean", "boolean")
.build();
static final Map PRIMITIVE_TO_WRAPPER = MapBuilder.newMap()
.put("byte", "java.lang.Byte")
.put("char", "java.lang.Character")
.put("short", "java.lang.Short")
.put("int", "java.lang.Integer")
.put("long","java.lang.Long")
.put("float", "java.lang.Float")
.put("double", "java.lang.Double")
.put("boolean", "java.lang.Boolean")
.build();
public static Type wrapTypeIfPrimitive(Type type) {
Type wrapped = type.primitiveWrapperType();
return Objects.requireNonNullElse(wrapped, type);
}
public static boolean isIntersectionType(Type type) {
return !type.isUnknown() && ((JType) type).typeBinding.isIntersectionType();
}
public static void collectSuperTypes(Set result, JSema sema, ITypeBinding typeBinding) {
ITypeBinding s = typeBinding.getSuperclass();
if (s != null) {
result.add(sema.type(s));
collectSuperTypes(result, sema, s);
}
for (ITypeBinding i : typeBinding.getInterfaces()) {
result.add(sema.type(i));
collectSuperTypes(result, sema, i);
}
}
public static Symbol getPackage(Symbol symbol) {
while (!symbol.isPackageSymbol()) {
symbol = symbol.owner();
}
return symbol;
}
@Nullable
public static Object defaultValue(Symbol.MethodSymbol method) {
if (method.isUnknown()) {
return null;
}
return ((JMethodSymbol) method).methodBinding().getDefaultValue();
}
public static Set directSuperTypes(Type type) {
if (type.isUnknown()) {
return Collections.emptySet();
}
Set result = new HashSet<>();
JType t = (JType) type;
ITypeBinding superclass = t.typeBinding.getSuperclass();
if (superclass != null) {
result.add(t.sema.type(superclass));
}
for (ITypeBinding i : t.typeBinding.getInterfaces()) {
result.add(t.sema.type(i));
}
return result;
}
@Nullable
public static Symbol enclosingClass(Tree t) {
do {
if (t == null) {
return null;
}
if (t.is(Tree.Kind.CLASS, Tree.Kind.ENUM, Tree.Kind.INTERFACE, Tree.Kind.ANNOTATION_TYPE)) {
return ((ClassTree) t).symbol();
}
t = t.parent();
} while (true);
}
public static SymbolMetadata parameterAnnotations(Symbol.MethodSymbol method, int param) {
if (method.isUnknown()) {
return Symbols.EMPTY_METADATA;
}
return method.declarationParameters().get(param).metadata();
}
public static boolean hasUnknownTypePreventingOverrideResolution(Symbol.MethodSymbol symbol) {
Symbol owner = symbol.owner();
if (owner == null || !owner.isTypeSymbol()) {
// Broken hierarchy
return true;
}
boolean hasUnknownParameterType = symbol.parameterTypes().stream().anyMatch(Type::isUnknown);
if (hasUnknownParameterType) {
return hasUnknownTypeInHierarchyOrAnyMatchingMethod((Symbol.TypeSymbol) owner, symbol);
} else {
return hasUnknownTypeInHierarchy((Symbol.TypeSymbol) owner);
}
}
public static boolean hasUnknownTypeInHierarchy(Symbol.TypeSymbol typeSymbol) {
if (typeSymbol.isUnknown()) {
return true;
}
if (typeSymbol.interfaces().stream().map(Type::symbol).anyMatch(JUtils::hasUnknownTypeInHierarchy)) {
return true;
}
Type superClass = typeSymbol.superClass();
if (superClass == null) {
return false;
}
return hasUnknownTypeInHierarchy(superClass.symbol());
}
/**
* @param typeSymbol to lookup recursively for unknown symbol on itself, its interfaces and its super classes hierarchy.
* @param methodSymbol a method having at least one unknown parameter type that prevent the overriding resolution
* to find any exact match. This methodSymbol will be used to find a potential match, just by
* comparing the name and parameter count.
* @return true if the given typeSymbol and its inheritance hierarchy is 100% known and no method in the inheritance
* cloud match (name and parameter count) the given methodSymbol. In this case, we are sure the methodSymbol does not
* override any another methods.
*/
private static boolean hasUnknownTypeInHierarchyOrAnyMatchingMethod(Symbol.TypeSymbol typeSymbol, Symbol.MethodSymbol methodSymbol) {
if (typeSymbol.isUnknown()) {
return true;
}
if (typeSymbol != methodSymbol.owner() && typeSymbol.memberSymbols().stream()
.anyMatch(member -> member.isMethodSymbol() &&
((Symbol.MethodSymbol) member).parameterTypes().size() == methodSymbol.parameterTypes().size() &&
methodSymbol.name().equals(member.name()))) {
return true;
}
if (typeSymbol.interfaces().stream().map(Type::symbol)
.anyMatch(interfaceSymbol -> hasUnknownTypeInHierarchyOrAnyMatchingMethod(interfaceSymbol, methodSymbol))) {
return true;
}
Type superClass = typeSymbol.superClass();
if (superClass == null) {
return false;
}
return hasUnknownTypeInHierarchyOrAnyMatchingMethod(superClass.symbol(), methodSymbol);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy