TextBuffer (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 = ClassWriter.getGenericClassDescriptor(child.classStruct); if (descriptor != null) { if (descriptor.superinterfaces.isEmpty()) { buf.append(GenericMain.getGenericCastTypeName(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(GenericMain.getGenericCastTypeName(descriptor.superinterfaces.get(0), Collections.emptyList())); } } else { buf.append(typename); } } } buf.append('('); if (!lambda && constructor != null) { List<Exprent> parameters = constructor.getParameters(); List<VarVersionPair> 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<VarVersionPair> mask = ExprUtil.getSyntheticParametersMask(constructor.getClassName(), constructor.getStringDescriptor(), parameters.size()); int start = enumConst ? 2 : 0; if (!enumConst || start < parameters.size()) { 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; }