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(); } }
private static String isClass14Invocation( Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) { if (exprent.type == Exprent.EXPRENT_FUNCTION) { FunctionExprent fexpr = (FunctionExprent) exprent; if (fexpr.getFuncType() == FunctionExprent.FUNCTION_IIF) { if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) { FunctionExprent headexpr = (FunctionExprent) fexpr.getLstOperands().get(0); if (headexpr.getFuncType() == FunctionExprent.FUNCTION_EQ) { if (headexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD && headexpr.getLstOperands().get(1).type == Exprent.EXPRENT_CONST && ((ConstExprent) headexpr.getLstOperands().get(1)) .getConstType() .equals(VarType.VARTYPE_NULL)) { FieldExprent field = (FieldExprent) headexpr.getLstOperands().get(0); ClassNode fieldnode = DecompilerContext.getClassProcessor() .getMapRootClasses() .get(field.getClassname()); if (fieldnode != null && fieldnode.classStruct.qualifiedName.equals( wrapper.getClassStruct().qualifiedName)) { // source class StructField fd = wrapper .getClassStruct() .getField( field.getName(), field.getDescriptor().descriptorString); // FIXME: can be null! why?? if (fd != null && fd.hasModifier(CodeConstants.ACC_STATIC) && (fd.isSynthetic() || DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) { if (fexpr.getLstOperands().get(1).type == Exprent.EXPRENT_ASSIGNMENT && fexpr.getLstOperands().get(2).equals(field)) { AssignmentExprent asexpr = (AssignmentExprent) fexpr.getLstOperands().get(1); if (asexpr.getLeft().equals(field) && asexpr.getRight().type == Exprent.EXPRENT_INVOCATION) { InvocationExprent invexpr = (InvocationExprent) asexpr.getRight(); if (invexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName) && invexpr.getName().equals(meth.methodStruct.getName()) && invexpr .getStringDescriptor() .equals(meth.methodStruct.getDescriptor())) { if (invexpr.getLstParameters().get(0).type == Exprent.EXPRENT_CONST) { wrapper .getHiddenMembers() .add( InterpreterUtil.makeUniqueKey( fd.getName(), fd.getDescriptor())); // hide synthetic field return ((ConstExprent) invexpr.getLstParameters().get(0)) .getValue() .toString(); } } } } } } } } } } } return null; }
public void classToJava( ClassNode node, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) { ClassNode outerNode = (ClassNode) DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node); int startLine = tracer != null ? tracer.getCurrentSourceLine() : 0; BytecodeMappingTracer dummy_tracer = new BytecodeMappingTracer(startLine); try { // last minute processing invokeProcessors(node); ClassWrapper wrapper = node.getWrapper(); StructClass cl = wrapper.getClassStruct(); DecompilerContext.getLogger().startWriteClass(cl.qualifiedName); // write class definition int start_class_def = buffer.length(); writeClassDefinition(node, buffer, indent); // // count lines in class definition the easiest way // startLine = buffer.substring(start_class_def).toString().split(lineSeparator, // -1).length - 1; boolean hasContent = false; // fields boolean enumFields = false; dummy_tracer.incrementCurrentSourceLine(buffer.countLines(start_class_def)); for (StructField fd : cl.getFields()) { boolean hide = fd.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) || wrapper .getHiddenMembers() .contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); if (hide) continue; boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); if (isEnum) { if (enumFields) { buffer.append(',').appendLineSeparator(); dummy_tracer.incrementCurrentSourceLine(); } enumFields = true; } else if (enumFields) { buffer.append(';'); buffer.appendLineSeparator(); buffer.appendLineSeparator(); dummy_tracer.incrementCurrentSourceLine(2); enumFields = false; } fieldToJava(wrapper, cl, fd, buffer, indent + 1, dummy_tracer); // FIXME: insert real tracer hasContent = true; } if (enumFields) { buffer.append(';').appendLineSeparator(); dummy_tracer.incrementCurrentSourceLine(); } // FIXME: fields don't matter at the moment startLine += buffer.countLines(start_class_def); // methods for (StructMethod mt : cl.getMethods()) { boolean hide = mt.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) || mt.hasModifier(CodeConstants.ACC_BRIDGE) && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE) || wrapper .getHiddenMembers() .contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor())); if (hide) continue; int position = buffer.length(); int storedLine = startLine; if (hasContent) { buffer.appendLineSeparator(); startLine++; } BytecodeMappingTracer method_tracer = new BytecodeMappingTracer(startLine); boolean methodSkipped = !methodToJava(node, mt, buffer, indent + 1, method_tracer); if (!methodSkipped) { hasContent = true; addTracer(cl, mt, method_tracer); startLine = method_tracer.getCurrentSourceLine(); } else { buffer.setLength(position); startLine = storedLine; } } // member classes for (ClassNode inner : node.nested) { if (inner.type == ClassNode.CLASS_MEMBER) { StructClass innerCl = inner.classStruct; boolean isSynthetic = (inner.access & CodeConstants.ACC_SYNTHETIC) != 0 || innerCl.isSynthetic() || inner.namelessConstructorStub; boolean hide = isSynthetic && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) || wrapper.getHiddenMembers().contains(innerCl.qualifiedName); if (hide) continue; if (hasContent) { buffer.appendLineSeparator(); startLine++; } BytecodeMappingTracer class_tracer = new BytecodeMappingTracer(startLine); classToJava(inner, buffer, indent + 1, class_tracer); startLine = buffer.countLines(); hasContent = true; } } buffer.appendIndent(indent).append('}'); if (node.type != ClassNode.CLASS_ANONYMOUS) { buffer.appendLineSeparator(); } } finally { DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode); } DecompilerContext.getLogger().endWriteClass(); }