Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jfxcore.compiler.util.TypeHelper Maven / Gradle / Ivy
// Copyright (c) 2022, 2023, JFXcore. All rights reserved.
// Use of this source code is governed by the BSD-3-Clause license that can be found in the LICENSE file.
package org.jfxcore.compiler.util;
import java.lang.String;
import java.lang.Object;
import java.lang.RuntimeException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMember;
import javassist.Modifier;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.ParameterAnnotationsAttribute;
import javassist.bytecode.SignatureAttribute;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.AnnotationMemberValue;
import javassist.bytecode.annotation.ArrayMemberValue;
import javassist.bytecode.annotation.BooleanMemberValue;
import javassist.bytecode.annotation.ByteMemberValue;
import javassist.bytecode.annotation.CharMemberValue;
import javassist.bytecode.annotation.ClassMemberValue;
import javassist.bytecode.annotation.DoubleMemberValue;
import javassist.bytecode.annotation.EnumMemberValue;
import javassist.bytecode.annotation.FloatMemberValue;
import javassist.bytecode.annotation.IntegerMemberValue;
import javassist.bytecode.annotation.LongMemberValue;
import javassist.bytecode.annotation.MemberValue;
import javassist.bytecode.annotation.MemberValueVisitor;
import javassist.bytecode.annotation.ShortMemberValue;
import javassist.bytecode.annotation.StringMemberValue;
import org.jetbrains.annotations.Nullable;
import org.jfxcore.compiler.ast.Node;
import org.jfxcore.compiler.ast.ResolvedTypeNode;
import org.jfxcore.compiler.ast.TypeNode;
import org.jfxcore.compiler.ast.ValueNode;
import org.jfxcore.compiler.diagnostic.Location;
import org.jfxcore.compiler.parse.TypeParser;
import static org.jfxcore.compiler.util.Classes.*;
public class TypeHelper {
/**
* Determines whether a type is the box type of a primitive type.
*/
public static boolean isPrimitiveBox(CtClass boxType, CtClass primitiveType) {
return switch (boxType.getName()) {
case BooleanName -> primitiveType.getName().equals("boolean");
case ByteName -> primitiveType.getName().equals("byte");
case CharacterName -> primitiveType.getName().equals("char");
case ShortName -> primitiveType.getName().equals("short");
case IntegerName -> primitiveType.getName().equals("int");
case LongName -> primitiveType.getName().equals("long");
case FloatName -> primitiveType.getName().equals("float");
case DoubleName -> primitiveType.getName().equals("double");
case NumberName -> switch (primitiveType.getName()) {
case "byte", "short", "int", "long", "float", "double" -> true;
default -> false;
};
default -> false;
};
}
/**
* Returns the primitive numeric type for the specified numeric type.
* If the specified type is not a numeric type, null
is returned.
*/
public static @Nullable CtClass getPrimitiveType(CtClass type) {
return switch (type.getName()) {
case "boolean", BooleanName -> CtClass.booleanType;
case "byte", ByteName -> CtClass.byteType;
case "char", CharacterName -> CtClass.charType;
case "short", ShortName -> CtClass.shortType;
case "int", IntegerName -> CtClass.intType;
case "long", LongName -> CtClass.longType;
case "float", FloatName -> CtClass.floatType;
case "double", DoubleName -> CtClass.doubleType;
default -> null;
};
}
/**
* If the specified type is a primitive type, returns the primitive box.
* Otherwise, returns the same type.
*/
public static CtClass getBoxedType(CtClass type) {
if (type == CtClass.booleanType) {
return Classes.BooleanType();
} else if (type == CtClass.byteType) {
return Classes.ByteType();
} if (type == CtClass.charType) {
return Classes.CharacterType();
} if (type == CtClass.shortType) {
return Classes.ShortType();
} if (type == CtClass.intType) {
return Classes.IntegerType();
} if (type == CtClass.longType) {
return Classes.LongType();
} if (type == CtClass.floatType) {
return Classes.FloatType();
} if (type == CtClass.doubleType) {
return Classes.DoubleType();
}
return type;
}
/**
* Returns whether the specified type is a boxed or primitive integral number.
*/
public static boolean isIntegral(CtClass type) {
return isIntegralPrimitive(type) || isIntegralBox(type);
}
/**
* Returns whether the specified type is a primitive integral number.
*/
public static boolean isIntegralPrimitive(CtClass type) {
return type == CtClass.byteType
|| type == CtClass.charType
|| type == CtClass.shortType
|| type == CtClass.intType
|| type == CtClass.longType;
}
/**
* Returns whether the specified type is a boxed integral number.
*/
public static boolean isIntegralBox(CtClass type) {
return equals(type, ByteType())
|| equals(type, CharacterType())
|| equals(type, ShortType())
|| equals(type, IntegerType())
|| equals(type, LongType());
}
/**
* Returns whether the specified type is a boxed or primitive floating-point number.
*/
public static boolean isFP(CtClass type) {
return isFPPrimitive(type) || isFPBox(type);
}
/**
* Returns whether the specified type is a primitive floating-point number.
*/
public static boolean isFPPrimitive(CtClass type) {
return type == CtClass.floatType || type == CtClass.doubleType;
}
/**
* Returns whether the specified type is a boxed floating-point number.
*/
public static boolean isFPBox(CtClass type) {
return equals(type, FloatType()) || equals(type, DoubleType());
}
/**
* Returns whether the specified type is a primitive or boxed number.
*/
public static boolean isNumeric(CtClass type) {
return isNumericPrimitive(type) || isNumericBox(type);
}
/**
* Returns whether the specified type is a primitive number.
*/
public static boolean isNumericPrimitive(CtClass type) {
return isIntegralPrimitive(type) || isFPPrimitive(type);
}
/**
* Returns whether the specified type is a boxed number.
*/
public static boolean isNumericBox(CtClass type) {
return isIntegralBox(type) || isFPBox(type) || equals(type, NumberType());
}
/**
* Returns whether the specified type is a primitive box.
*/
public static boolean isPrimitiveBox(CtClass type) {
return isNumericBox(type) || equals(type, Classes.BooleanType());
}
/**
* If the specified type is short, byte or char, returns int.
* If the specified type is Short, Byte or Character, returns Integer.
* Otherwise, returns the specified type.
*/
public static TypeInstance getWidenedNumericType(TypeInstance type) {
switch (type.getName()) {
case "short":
case "byte":
case "char":
return TypeInstance.intType();
case ShortName:
case ByteName:
case CharacterName:
return TypeInstance.IntegerType();
}
return type;
}
/**
* If the specified type is short, byte or char, returns int.
* If the specified type is Short, Byte or Character, returns Integer.
* Otherwise, returns the specified type.
*/
public static CtClass getWidenedNumericType(CtClass type) {
switch (type.getName()) {
case "short":
case "byte":
case "char":
return CtClass.intType;
case ShortName:
case ByteName:
case CharacterName:
return Classes.IntegerType();
}
return type;
}
/**
* Returns whether the specified type has a constructor that accepts an {@code @NamedArg}
* parameter with the specified name.
*/
public static boolean hasNamedConstructorParam(CtClass type, String paramName) {
for (CtConstructor constructor : type.getConstructors()) {
if (!Modifier.isPublic(constructor.getModifiers())) {
continue;
}
ParameterAnnotationsAttribute attr = (ParameterAnnotationsAttribute)constructor
.getMethodInfo2().getAttribute(ParameterAnnotationsAttribute.visibleTag);
if (attr == null) {
continue;
}
Annotation[][] annotations = attr.getAnnotations();
for (int i = 0; i < annotations.length; ++i) {
Annotation namedArgAnnotation = null;
for (Annotation item : annotations[i]) {
if (item.getTypeName().equals(Classes.NamedArgAnnotationName)) {
namedArgAnnotation = item;
break;
}
}
if (namedArgAnnotation != null) {
String value = TypeHelper.getAnnotationString(namedArgAnnotation, "value");
if (paramName.equals(value)) {
return true;
}
}
}
}
return false;
}
public static class MemberValueVisitorAdapter implements MemberValueVisitor {
@Override public void visitAnnotationMemberValue(AnnotationMemberValue node) {}
@Override public void visitArrayMemberValue(ArrayMemberValue node) {}
@Override public void visitBooleanMemberValue(BooleanMemberValue node) {}
@Override public void visitByteMemberValue(ByteMemberValue node) {}
@Override public void visitCharMemberValue(CharMemberValue node) {}
@Override public void visitDoubleMemberValue(DoubleMemberValue node) {}
@Override public void visitEnumMemberValue(EnumMemberValue node) {}
@Override public void visitFloatMemberValue(FloatMemberValue node) {}
@Override public void visitIntegerMemberValue(IntegerMemberValue node) {}
@Override public void visitLongMemberValue(LongMemberValue node) {}
@Override public void visitShortMemberValue(ShortMemberValue node) {}
@Override public void visitClassMemberValue(ClassMemberValue node) {}
@Override public void visitStringMemberValue(StringMemberValue node) {}
}
/**
* Returns the value of the specified annotation member.
*/
public static String getAnnotationString(Annotation annotation, String memberName) {
String[] value = new String[1];
MemberValue memberValue = annotation.getMemberValue(memberName);
if (memberValue == null) {
return null;
}
memberValue.accept(new MemberValueVisitorAdapter() {
@Override
public void visitStringMemberValue(StringMemberValue node) {
value[0] = node.getValue();
}
});
return value[0];
}
/**
* Returns the value of the specified annotation member.
*/
public static int getAnnotationInt(Annotation annotation, String memberName) {
int[] value = new int[1];
MemberValue memberValue = annotation.getMemberValue(memberName);
if (memberValue == null) {
return 0;
}
memberValue.accept(new MemberValueVisitorAdapter() {
@Override
public void visitIntegerMemberValue(IntegerMemberValue node) {
value[0] = node.getValue();
}
});
return value[0];
}
/**
* Returns the value of the specified annotation member.
*/
public static int[] getAnnotationIntArray(Annotation annotation, String memberName) {
List list = new ArrayList<>();
MemberValue memberValue = annotation.getMemberValue(memberName);
if (memberValue == null) {
return new int[0];
}
memberValue.accept(new MemberValueVisitorAdapter() {
@Override
public void visitArrayMemberValue(ArrayMemberValue node) {
Arrays.stream(node.getValue()).forEach(value -> value.accept(new MemberValueVisitorAdapter() {
@Override
public void visitIntegerMemberValue(IntegerMemberValue node) {
list.add(node.getValue());
}
}));
}
});
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); ++i) {
result[i] = list.get(i);
}
return result;
}
/**
* Returns the value of the specified annotation member.
*/
public static String[] getAnnotationStringArray(Annotation annotation, String memberName) {
List list = new ArrayList<>();
MemberValue memberValue = annotation.getMemberValue(memberName);
if (memberValue == null) {
return new String[0];
}
memberValue.accept(new MemberValueVisitorAdapter() {
@Override
public void visitArrayMemberValue(ArrayMemberValue node) {
Arrays.stream(node.getValue()).forEach(value -> value.accept(new MemberValueVisitorAdapter() {
@Override
public void visitStringMemberValue(StringMemberValue node) {
list.add(node.getValue());
}
}));
}
});
return list.toArray(String[]::new);
}
public static @Nullable TypeInstance tryGetArrayComponentType(CtBehavior method, int paramIndex) {
try {
SignatureAttribute.MethodSignature signature =
SignatureAttribute.toMethodSignature(method.getSignature());
SignatureAttribute.Type type = signature.getParameterTypes()[paramIndex];
if (type instanceof SignatureAttribute.ArrayType arrayType) {
if (arrayType.getDimension() != 1) {
return null;
}
TypeParser parser = new TypeParser(arrayType.getComponentType().jvmTypeName(), new Location(0, 0));
return parser.parse().get(0);
}
return null;
} catch (BadBytecode ex) {
throw ExceptionHelper.unchecked(ex);
}
}
public static List getTypeArguments(TypeInstance type, CtClass targetType) {
if (equals(type.jvmType(), targetType)) {
return type.getArguments();
}
for (TypeInstance superType : type.getSuperTypes()) {
List arguments = getTypeArguments(superType, targetType);
if (!arguments.isEmpty()) {
return arguments;
}
}
return List.of();
}
public static TypeInstance getTypeInstance(Node node) {
if (!(node instanceof ValueNode)) {
throw new RuntimeException("Expected " + ValueNode.class.getSimpleName());
}
TypeNode typeNode = ((ValueNode)node).getType();
if (!(typeNode instanceof ResolvedTypeNode)) {
throw new RuntimeException("Expected " + ResolvedTypeNode.class.getSimpleName());
}
return ((ResolvedTypeNode)typeNode).getTypeInstance();
}
public static CtClass getJvmType(Node node) {
if (!(node instanceof ValueNode)) {
throw new RuntimeException("Expected " + ValueNode.class.getSimpleName());
}
TypeNode typeNode = ((ValueNode)node).getType();
if (!(typeNode instanceof ResolvedTypeNode)) {
throw new RuntimeException("Expected " + ResolvedTypeNode.class.getSimpleName());
}
return ((ResolvedTypeNode)typeNode).getJvmType();
}
public static int getDimensions(CtClass type) {
String name = type.getName();
for (int i = name.length() - 2, d = 0; i > 1; i -= 2, ++d) {
if (name.charAt(i) != '[' || name.charAt(i + 1) != ']') {
return d;
}
}
return 0;
}
public static int getSlots(CtClass type) {
return type == CtClass.longType || type == CtClass.doubleType ? 2 : 1;
}
public static int hashCode(Collection types) {
int result = 1;
for (Object type : types) {
int c;
if (type instanceof CtClass) {
c = hashCode((CtClass)type);
} else if (type instanceof CtMember) {
c = hashCode((CtMember)type);
} else {
throw new IllegalArgumentException();
}
result = 31 * result + c;
}
return result;
}
public static int hashCode(CtClass type) {
return type != null ? type.getName().hashCode() : 0;
}
public static int hashCode(CtMember member) {
if (member == null) {
return 0;
}
if (member instanceof CtField) {
int result = 31 + hashCode(member.getDeclaringClass());
return 31 * result + member.getName().hashCode();
}
return ((CtBehavior)member).getLongName().hashCode();
}
public static boolean equals(Collection type0, Collection type1) {
if (type0.size() != type1.size()) {
return false;
}
Iterator it0 = type0.iterator();
Iterator it1 = type0.iterator();
while (it0.hasNext()) {
if (!equals(it0.next(), it1.next())) {
return false;
}
}
return true;
}
public static boolean equals(CtClass type0, CtClass type1) {
if (type0 == null && type1 != null || type0 != null && type1 == null) {
return false;
}
if (type0 == null) {
return true;
}
return type0.getName().equals(type1.getName());
}
public static boolean equals(CtMember member0, CtMember member1) {
if (member0 == null && member1 != null || member0 != null && member1 == null) {
return false;
}
if (member0 == null) {
return true;
}
if (!equals(member0.getDeclaringClass(), member1.getDeclaringClass())) {
return false;
}
if (member0 instanceof CtField && member1 instanceof CtField) {
return member0.getName().equals(member1.getName());
}
if (member0 instanceof CtBehavior && member1 instanceof CtBehavior) {
return ((CtBehavior)member0).getLongName().equals(((CtBehavior)member1).getLongName());
}
return false;
}
}