in src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java [166:394]
public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) {
TextBuffer buf = new TextBuffer();
if (anonymous) {
ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.getValue());
boolean selfReference = DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE) == child;
// IDEA-204310 - avoid backtracking later on for lambdas (causes spurious imports)
if (!enumConst && (!lambda || DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS))) {
String enclosing = null;
if (!lambda && constructor != null) {
enclosing = getQualifiedNewInstance(child.anonymousClassType.getValue(), constructor.getParameters(), indent, tracer);
if (enclosing != null) {
buf.append(enclosing).append('.');
}
}
buf.append("new ");
if (selfReference) {
buf.append("<anonymous constructor>");
} else {
String typename = ExprProcessor.getCastTypeName(child.anonymousClassType, Collections.emptyList());
if (enclosing != null) {
ClassNode anonymousNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(child.anonymousClassType.getValue());
if (anonymousNode != null) {
typename = anonymousNode.simpleName;
}
else {
typename = typename.substring(typename.lastIndexOf('.') + 1);
}
}
GenericClassDescriptor descriptor = child.getWrapper().getClassStruct().getSignature();
if (descriptor != null) {
if (descriptor.superinterfaces.isEmpty()) {
buf.append(ExprProcessor.getCastTypeName(descriptor.superclass, Collections.emptyList()));
}
else {
if (descriptor.superinterfaces.size() > 1 && !lambda) {
DecompilerContext.getLogger().writeMessage("Inconsistent anonymous class signature: " + child.classStruct.qualifiedName,
IFernflowerLogger.Severity.WARN);
}
buf.append(ExprProcessor.getCastTypeName(descriptor.superinterfaces.get(0), Collections.emptyList()));
}
}
else {
buf.append(typename);
}
}
}
appendParameters(buf, genericArgs);
buf.append('(');
if (!lambda && constructor != null) {
List<Exprent> parameters = constructor.getParameters();
List<VarVersion> mask = child.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, constructor.getStringDescriptor()).synthParameters;
if (mask == null) {
InvocationExprent superCall = child.superInvocation;
mask = ExprUtil.getSyntheticParametersMask(superCall.getClassName(), superCall.getStringDescriptor(), parameters.size());
}
int start = enumConst ? 2 : 0;
boolean firstParam = true;
for (int i = start; i < parameters.size(); i++) {
if (mask == null || mask.get(i) == null) {
if (!firstParam) {
buf.append(", ");
}
ExprProcessor.getCastedExprent(parameters.get(i), constructor.getDescriptor().params[i], buf, indent, true, tracer);
firstParam = false;
}
}
}
buf.append(')');
if (enumConst && buf.length() == 2) {
buf.setLength(0);
}
if (lambda) {
if (!DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
buf.setLength(0); // remove the usual 'new <class>()', it will be replaced with lambda style '() ->'
}
Exprent methodObject = constructor == null ? null : constructor.getInstance();
TextBuffer clsBuf = new TextBuffer();
new ClassWriter().classLambdaToJava(child, clsBuf, methodObject, indent, tracer);
buf.append(clsBuf);
tracer.incrementCurrentSourceLine(clsBuf.countLines());
}
else if (!selfReference) {
TextBuffer clsBuf = new TextBuffer();
new ClassWriter().classToJava(child, clsBuf, indent, tracer);
buf.append(clsBuf);
tracer.incrementCurrentSourceLine(clsBuf.countLines());
}
}
else if (directArrayInit) {
VarType leftType = newType.decreaseArrayDim();
buf.append('{');
for (int i = 0; i < lstArrayElements.size(); i++) {
if (i > 0) {
buf.append(", ");
}
ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false, tracer);
}
buf.append('}');
}
else if (newType.getArrayDim() == 0) {
if (!enumConst) {
String enclosing = null;
if (constructor != null) {
enclosing = getQualifiedNewInstance(newType.getValue(), constructor.getParameters(), indent, tracer);
if (enclosing != null) {
buf.append(enclosing).append('.');
}
}
buf.append("new ");
String typename = ExprProcessor.getTypeName(newType, Collections.emptyList());
if (enclosing != null) {
ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.getValue());
if (newNode != null) {
typename = newNode.simpleName;
}
else {
typename = typename.substring(typename.lastIndexOf('.') + 1);
}
}
buf.append(typename);
}
if (constructor != null) {
List<Exprent> parameters = constructor.getParameters();
List<VarVersion> mask = ExprUtil.getSyntheticParametersMask(constructor.getClassName(), constructor.getStringDescriptor(), parameters.size());
int start = enumConst ? 2 : 0;
if (!enumConst || start < parameters.size()) {
appendParameters(buf, genericArgs);
buf.append('(');
boolean firstParam = true;
for (int i = start; i < parameters.size(); i++) {
if (mask == null || mask.get(i) == null) {
Exprent expr = parameters.get(i);
VarType leftType = constructor.getDescriptor().params[i];
if (i == parameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL && probablySyntheticParameter(
leftType.getValue())) {
break; // skip last parameter of synthetic constructor call
}
if (!firstParam) {
buf.append(", ");
}
ExprProcessor.getCastedExprent(expr, leftType, buf, indent, true, false, true, true, tracer);
firstParam = false;
}
}
buf.append(')');
}
}
}
else if (isVarArgParam) {
// just print the array elements
VarType leftType = newType.decreaseArrayDim();
for (int i = 0; i < lstArrayElements.size(); i++) {
if (i > 0) {
buf.append(", ");
}
// new String[][]{{"abc"}, {"DEF"}} => new String[]{"abc"}, new String[]{"DEF"}
Exprent element = lstArrayElements.get(i);
if (element.type == EXPRENT_NEW) {
((NewExprent) element).setDirectArrayInit(false);
}
ExprProcessor.getCastedExprent(element, leftType, buf, indent, false, tracer);
}
// if there is just one element of Object[] type it needs to be casted to resolve ambiguity
if (lstArrayElements.size() == 1) {
VarType elementType = lstArrayElements.get(0).getExprType();
if (elementType.getType() == CodeConstants.TYPE_OBJECT && elementType.getValue().equals("java/lang/Object") && elementType.getArrayDim() >= 1) {
buf.prepend("(Object)");
}
}
}
else {
buf.append("new ").append(ExprProcessor.getTypeName(newType, Collections.emptyList()));
if (lstArrayElements.isEmpty()) {
for (int i = 0; i < newType.getArrayDim(); i++) {
buf.append('[');
if (i < lstDims.size()) {
buf.append(lstDims.get(i).toJava(indent, tracer));
}
buf.append(']');
}
}
else {
for (int i = 0; i < newType.getArrayDim(); i++) {
buf.append("[]");
}
VarType leftType = newType.decreaseArrayDim();
buf.append('{');
for (int i = 0; i < lstArrayElements.size(); i++) {
if (i > 0) {
buf.append(", ");
}
ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false, tracer);
}
buf.append('}');
}
}
return buf;
}