in src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java [203:355]
public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) {
boolean literal = DecompilerContext.getOption(IFernflowerPreferences.LITERALS_AS_IS);
boolean ascii = DecompilerContext.getOption(IFernflowerPreferences.ASCII_STRING_CHARACTERS);
tracer.addMapping(bytecode);
if (constType.getType() != CodeConstants.TYPE_NULL && value == null) {
return new TextBuffer(ExprProcessor.getCastTypeName(constType, Collections.emptyList()));
}
return switch (constType.getType()) {
case CodeConstants.TYPE_BOOLEAN -> new TextBuffer(Boolean.toString((Integer)value != 0));
case CodeConstants.TYPE_CHAR -> {
Integer val = (Integer)value;
String ret = CHAR_ESCAPES.get(val);
if (ret == null) {
char c = (char)val.intValue();
if (isPrintableAscii(c) || !ascii && TextUtil.isPrintableUnicode(c)) {
ret = String.valueOf(c);
}
else {
ret = TextUtil.charToUnicodeLiteral(c);
}
}
yield new TextBuffer(ret).enclose("'", "'");
}
case CodeConstants.TYPE_BYTE -> new TextBuffer(value.toString());
case CodeConstants.TYPE_BYTECHAR, CodeConstants.TYPE_SHORT -> {
int shortVal = (Integer)value;
if (!literal) {
if (shortVal == Short.MAX_VALUE && !inConstantVariable(SHORT_SIG, MAX_VAL)) {
yield new FieldExprent(MAX_VAL, SHORT_SIG, true, null, FieldDescriptor.SHORT_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (shortVal == Short.MIN_VALUE && !inConstantVariable(SHORT_SIG, MIN_VAL)) {
yield new FieldExprent(MIN_VAL, SHORT_SIG, true, null, FieldDescriptor.SHORT_DESCRIPTOR, bytecode).toJava(0, tracer);
}
}
yield new TextBuffer(value.toString());
}
case CodeConstants.TYPE_SHORTCHAR, CodeConstants.TYPE_INT -> {
int intVal = (Integer)value;
if (!literal) {
if (intVal == Integer.MAX_VALUE && !inConstantVariable(INT_SIG, MAX_VAL)) {
yield new FieldExprent(MAX_VAL, INT_SIG, true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (intVal == Integer.MIN_VALUE && !inConstantVariable(INT_SIG, MIN_VAL)) {
yield new FieldExprent(MIN_VAL, INT_SIG, true, null, FieldDescriptor.INTEGER_DESCRIPTOR, bytecode).toJava(0, tracer);
}
}
yield new TextBuffer(value.toString());
}
case CodeConstants.TYPE_LONG -> {
long longVal = (Long)value;
if (!literal) {
if (longVal == Long.MAX_VALUE && !inConstantVariable(LONG_SIG, MAX_VAL)) {
yield new FieldExprent(MAX_VAL, LONG_SIG, true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (longVal == Long.MIN_VALUE && !inConstantVariable(LONG_SIG, MIN_VAL)) {
yield new FieldExprent(MIN_VAL, LONG_SIG, true, null, FieldDescriptor.LONG_DESCRIPTOR, bytecode).toJava(0, tracer);
}
}
yield new TextBuffer(value.toString()).append('L');
}
case CodeConstants.TYPE_FLOAT -> createFloat(literal, (Float)value, tracer);
case CodeConstants.TYPE_DOUBLE -> {
double doubleVal = (Double)value;
boolean withSuffix = DecompilerContext.getOption(IFernflowerPreferences.STANDARDIZE_FLOATING_POINT_NUMBERS);
if (!literal) {
if (Double.isNaN(doubleVal) && !inConstantVariable(DOUBLE_SIG, NAN)) {
yield new FieldExprent(NAN, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (doubleVal == Double.POSITIVE_INFINITY && !inConstantVariable(DOUBLE_SIG, POS_INF)) {
yield new FieldExprent(POS_INF, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (doubleVal == Double.NEGATIVE_INFINITY && !inConstantVariable(DOUBLE_SIG, NEG_INF)) {
yield new FieldExprent(NEG_INF, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (doubleVal == Double.MAX_VALUE && !inConstantVariable(DOUBLE_SIG, MAX_VAL)) {
yield new FieldExprent(MAX_VAL, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (doubleVal == Double.MIN_VALUE && !inConstantVariable(DOUBLE_SIG, MIN_VAL)) {
yield new FieldExprent(MIN_VAL, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (doubleVal == Double.MIN_NORMAL && !inConstantVariable(DOUBLE_SIG, MIN_NORM)) {
yield new FieldExprent(MIN_NORM, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (doubleVal == Math.E && !inConstantVariable(MATH_SIG, E)) {
yield new FieldExprent(E, MATH_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer);
}
else if (doubleVal == -Double.MAX_VALUE && !inConstantVariable(DOUBLE_SIG, MAX_VAL)) {
yield new FieldExprent(MAX_VAL, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer).prepend("-");
}
else if (doubleVal == -Double.MIN_NORMAL) {
yield new FieldExprent(MIN_NORM, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer).prepend("-");
}
else if (doubleVal == -Double.MIN_VALUE) {
yield new FieldExprent(MIN_VAL, DOUBLE_SIG, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0, tracer).prepend("-");
}
else if (PI_DOUBLES.containsKey(doubleVal)) {
String[] parts = PI_DOUBLES.get(doubleVal);
yield getPiDouble(tracer).enclose(parts[0], parts[1]);
}
else if (DOUBLE_CONSTANTS.containsKey(doubleVal)) {
yield new TextBuffer(DOUBLE_CONSTANTS.get(doubleVal));
}
}
else if (Double.isNaN(doubleVal)) {
yield withSuffix ? new TextBuffer("0.0D / 0.0D") : new TextBuffer("0.0 / 0.0");
}
else if (doubleVal == Double.POSITIVE_INFINITY) {
yield withSuffix ? new TextBuffer("1.0D / 0.0D") : new TextBuffer("1.0 / 0.0") ;
}
else if (doubleVal == Double.NEGATIVE_INFINITY) {
yield withSuffix ? new TextBuffer("-1.0D / 0.0D") : new TextBuffer("-1.0 / 0.0");
}
TextBuffer doubleBuffer = new TextBuffer(trimDouble(Double.toString(doubleVal), doubleVal));
if (withSuffix) {
doubleBuffer = doubleBuffer.append('D');
}
if (!literal) {
// Check for cases where a float literal has been upcasted to a double.
// (for instance, double d = .01F results in 0.009999999776482582D without this)
float nearestFloatVal = (float)doubleVal;
if (doubleVal == (double)nearestFloatVal) {
// Value can be represented precisely as both a float and a double.
// Now check if the string representation as a float is nicer/shorter.
// If they're the same, there's no point in the cast and such (e.g. don't decompile 1.0D as (double)1.0F).
TextBuffer floatBuffer = createFloat(literal, nearestFloatVal, tracer);
if (floatBuffer.length() != doubleBuffer.length()) {
// Include a cast to prevent using the wrong method call in ambiguous cases.
yield floatBuffer.prepend("(double)");
}
}
}
yield doubleBuffer;
}
case CodeConstants.TYPE_NULL -> new TextBuffer("null");
case CodeConstants.TYPE_OBJECT -> {
if (constType.equals(VarType.VARTYPE_STRING)) {
yield new TextBuffer(convertStringToJava(value.toString(), ascii)).enclose("\"", "\"");
}
else if (constType.equals(VarType.VARTYPE_CLASS)) {
String stringVal = value.toString();
VarType type = new VarType(stringVal, !stringVal.startsWith("["));
yield new TextBuffer(ExprProcessor.getCastTypeName(type, Collections.emptyList())).append(".class");
}
throw new RuntimeException("invalid constant type: " + constType);
}
default -> throw new RuntimeException("invalid constant type: " + constType);
};
}