private static boolean replaceInvocations( Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) { boolean res = false; while (true) { boolean found = false; for (Exprent expr : exprent.getAllExprents()) { String cl = isClass14Invocation(expr, wrapper, meth); if (cl != null) { exprent.replaceExprent( expr, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/'), expr.bytecode)); found = true; res = true; break; } res |= replaceInvocations(expr, wrapper, meth); } if (!found) { break; } } return res; }
public void classLambdaToJava( ClassNode node, TextBuffer buffer, Exprent method_object, int indent, BytecodeMappingTracer origTracer) { ClassWrapper wrapper = node.getWrapper(); if (wrapper == null) { return; } boolean lambdaToAnonymous = DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS); ClassNode outerNode = (ClassNode) DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node); BytecodeMappingTracer tracer = new BytecodeMappingTracer(origTracer.getCurrentSourceLine()); try { StructClass cl = wrapper.getClassStruct(); DecompilerContext.getLogger().startWriteClass(node.simpleName); if (node.lambdaInformation.is_method_reference) { if (!node.lambdaInformation.is_content_method_static && method_object != null) { // reference to a virtual method buffer.append(method_object.toJava(indent, tracer)); } else { // reference to a static method buffer.append( ExprProcessor.getCastTypeName( new VarType(node.lambdaInformation.content_class_name, false))); } buffer.append("::"); buffer.append(node.lambdaInformation.content_method_name); } else { // lambda method StructMethod mt = cl.getMethod(node.lambdaInformation.content_method_key); MethodWrapper methodWrapper = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()); MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node.lambdaInformation.content_method_descriptor); MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node.lambdaInformation.method_descriptor); if (!lambdaToAnonymous) { buffer.append('('); boolean firstParameter = true; int index = node.lambdaInformation.is_content_method_static ? 0 : 1; int start_index = md_content.params.length - md_lambda.params.length; for (int i = 0; i < md_content.params.length; i++) { if (i >= start_index) { if (!firstParameter) { buffer.append(", "); } String parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0)); buffer.append( parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors firstParameter = false; } index += md_content.params[i].stackSize; } buffer.append(") ->"); } buffer.append(" {").appendLineSeparator(); tracer.incrementCurrentSourceLine(); methodLambdaToJava(node, wrapper, mt, buffer, indent + 1, !lambdaToAnonymous, tracer); buffer.appendIndent(indent).append("}"); addTracer(cl, mt, tracer); } } finally { DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode); } DecompilerContext.getLogger().endWriteClass(); }
private void fieldToJava( ClassWrapper wrapper, StructClass cl, StructField fd, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) { int start = buffer.length(); boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE); boolean isDeprecated = fd.getAttributes().containsKey("Deprecated"); boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); if (isDeprecated) { appendDeprecation(buffer, indent); } if (interceptor != null) { String oldName = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor()); appendRenameComment(buffer, oldName, MType.FIELD, indent); } if (fd.isSynthetic()) { appendComment(buffer, "synthetic field", indent); } appendAnnotations(buffer, fd, indent); buffer.appendIndent(indent); if (!isEnum) { appendModifiers(buffer, fd.getAccessFlags(), FIELD_ALLOWED, isInterface, FIELD_EXCLUDED); } VarType fieldType = new VarType(fd.getDescriptor(), false); GenericFieldDescriptor descriptor = null; if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) { StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute) fd.getAttributes().getWithKey("Signature"); if (attr != null) { descriptor = GenericMain.parseFieldSignature(attr.getSignature()); } } if (!isEnum) { if (descriptor != null) { buffer.append(GenericMain.getGenericCastTypeName(descriptor.type)); } else { buffer.append(ExprProcessor.getCastTypeName(fieldType)); } buffer.append(' '); } buffer.append(fd.getName()); tracer.incrementCurrentSourceLine(buffer.countLines(start)); Exprent initializer; if (fd.hasModifier(CodeConstants.ACC_STATIC)) { initializer = wrapper .getStaticFieldInitializers() .getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); } else { initializer = wrapper .getDynamicFieldInitializers() .getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); } if (initializer != null) { if (isEnum && initializer.type == Exprent.EXPRENT_NEW) { NewExprent nexpr = (NewExprent) initializer; nexpr.setEnumConst(true); buffer.append(nexpr.toJava(indent, tracer)); } else { buffer.append(" = "); // FIXME: special case field initializer. Can map to more than one method (constructor) and // bytecode intruction. buffer.append(initializer.toJava(indent, tracer)); } } else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) { StructConstantValueAttribute attr = (StructConstantValueAttribute) fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE); if (attr != null) { PrimitiveConstant constant = cl.getPool().getPrimitiveConstant(attr.getIndex()); buffer.append(" = "); buffer.append(new ConstExprent(fieldType, constant.value, null).toJava(indent, tracer)); } } if (!isEnum) { buffer.append(";").appendLineSeparator(); tracer.incrementCurrentSourceLine(); } }