public ClassReference14Processor() {

    InvocationExprent invfor = new InvocationExprent();
    invfor.setName("forName");
    invfor.setClassname("java/lang/Class");
    invfor.setStringDescriptor("(Ljava/lang/String;)Ljava/lang/Class;");
    invfor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;"));
    invfor.setStatic(true);
    invfor.setLstParameters(
        Arrays.asList(new Exprent[] {new VarExprent(0, VarType.VARTYPE_STRING, null)}));

    bodyexprent = new ExitExprent(ExitExprent.EXIT_RETURN, invfor, VarType.VARTYPE_CLASS, null);

    InvocationExprent constr = new InvocationExprent();
    constr.setName("<init>");
    constr.setClassname("java/lang/NoClassDefFoundError");
    constr.setStringDescriptor("()V");
    constr.setFunctype(InvocationExprent.TYP_INIT);
    constr.setDescriptor(MethodDescriptor.parseDescriptor("()V"));

    NewExprent newexpr =
        new NewExprent(
            new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"),
            new ArrayList<Exprent>(),
            null);
    newexpr.setConstructor(constr);

    InvocationExprent invcause = new InvocationExprent();
    invcause.setName("initCause");
    invcause.setClassname("java/lang/NoClassDefFoundError");
    invcause.setStringDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
    invcause.setDescriptor(
        MethodDescriptor.parseDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;"));
    invcause.setInstance(newexpr);
    invcause.setLstParameters(
        Arrays.asList(
            new Exprent[] {
              new VarExprent(
                  2,
                  new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"),
                  null)
            }));

    handlerexprent = new ExitExprent(ExitExprent.EXIT_THROW, invcause, null, null);
  }
Пример #2
0
  private static void appendRenameComment(
      TextBuffer buffer, String oldName, MType type, int indent) {
    if (oldName == null) return;

    buffer.appendIndent(indent);
    buffer.append("// $FF: renamed from: ");

    switch (type) {
      case CLASS:
        buffer.append(ExprProcessor.buildJavaClassName(oldName));
        break;

      case FIELD:
        String[] fParts = oldName.split(" ");
        FieldDescriptor fd = FieldDescriptor.parseDescriptor(fParts[2]);
        buffer.append(fParts[1]);
        buffer.append(' ');
        buffer.append(getTypePrintOut(fd.type));
        break;

      default:
        String[] mParts = oldName.split(" ");
        MethodDescriptor md = MethodDescriptor.parseDescriptor(mParts[2]);
        buffer.append(mParts[1]);
        buffer.append(" (");
        boolean first = true;
        for (VarType paramType : md.params) {
          if (!first) {
            buffer.append(", ");
          }
          first = false;
          buffer.append(getTypePrintOut(paramType));
        }
        buffer.append(") ");
        buffer.append(getTypePrintOut(md.ret));
    }

    buffer.appendLineSeparator();
  }
Пример #3
0
  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();
  }
Пример #4
0
  private boolean methodToJava(
      ClassNode node,
      StructMethod mt,
      TextBuffer buffer,
      int indent,
      BytecodeMappingTracer tracer) {
    ClassWrapper wrapper = node.getWrapper();
    StructClass cl = wrapper.getClassStruct();
    MethodWrapper methodWrapper = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());

    boolean hideMethod = false;
    int start_index_method = buffer.length();

    MethodWrapper outerWrapper =
        (MethodWrapper) DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
    DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);

    try {
      boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
      boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION);
      boolean isEnum =
          cl.hasModifier(CodeConstants.ACC_ENUM)
              && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
      boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
      boolean clinit = false, init = false, dinit = false;

      MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());

      int flags = mt.getAccessFlags();
      if ((flags & CodeConstants.ACC_NATIVE) != 0) {
        flags &=
            ~CodeConstants
                .ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp
      }
      if (CodeConstants.CLINIT_NAME.equals(mt.getName())) {
        flags &=
            CodeConstants
                .ACC_STATIC; // ignore all modifiers except 'static' in a static initializer
      }

      if (isDeprecated) {
        appendDeprecation(buffer, indent);
      }

      if (interceptor != null) {
        String oldName =
            interceptor.getOldName(
                cl.qualifiedName + " " + mt.getName() + " " + mt.getDescriptor());
        appendRenameComment(buffer, oldName, MType.METHOD, indent);
      }

      boolean isSynthetic =
          (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
      boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
      if (isSynthetic) {
        appendComment(buffer, "synthetic method", indent);
      }
      if (isBridge) {
        appendComment(buffer, "bridge method", indent);
      }

      appendAnnotations(buffer, mt, indent);

      buffer.appendIndent(indent);

      appendModifiers(buffer, flags, METHOD_ALLOWED, isInterface, METHOD_EXCLUDED);

      if (isInterface && mt.containsCode()) {
        // 'default' modifier (Java 8)
        buffer.append("default ");
      }

      String name = mt.getName();
      if (CodeConstants.INIT_NAME.equals(name)) {
        if (node.type == ClassNode.CLASS_ANONYMOUS) {
          name = "";
          dinit = true;
        } else {
          name = node.simpleName;
          init = true;
        }
      } else if (CodeConstants.CLINIT_NAME.equals(name)) {
        name = "";
        clinit = true;
      }

      GenericMethodDescriptor descriptor = null;
      if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
        StructGenericSignatureAttribute attr =
            (StructGenericSignatureAttribute) mt.getAttributes().getWithKey("Signature");
        if (attr != null) {
          descriptor = GenericMain.parseMethodSignature(attr.getSignature());
          if (descriptor != null) {
            int actualParams = md.params.length;
            List<VarVersionPair> sigFields = methodWrapper.signatureFields;
            if (sigFields != null) {
              actualParams = 0;
              for (VarVersionPair field : methodWrapper.signatureFields) {
                if (field == null) {
                  actualParams++;
                }
              }
            } else if (isEnum && init) actualParams -= 2;
            if (actualParams != descriptor.params.size()) {
              String message =
                  "Inconsistent generic signature in method "
                      + mt.getName()
                      + " "
                      + mt.getDescriptor()
                      + " in "
                      + cl.qualifiedName;
              DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
              descriptor = null;
            }
          }
        }
      }

      boolean throwsExceptions = false;
      int paramCount = 0;

      if (!clinit && !dinit) {
        boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);

        if (descriptor != null && !descriptor.fparameters.isEmpty()) {
          appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds);
          buffer.append(' ');
        }

        if (!init) {
          if (descriptor != null) {
            buffer.append(GenericMain.getGenericCastTypeName(descriptor.ret));
          } else {
            buffer.append(ExprProcessor.getCastTypeName(md.ret));
          }
          buffer.append(' ');
        }

        buffer.append(toValidJavaIdentifier(name));
        buffer.append('(');

        // parameters
        List<VarVersionPair> signFields = methodWrapper.signatureFields;

        int lastVisibleParameterIndex = -1;
        for (int i = 0; i < md.params.length; i++) {
          if (signFields == null || signFields.get(i) == null) {
            lastVisibleParameterIndex = i;
          }
        }

        boolean firstParameter = true;
        int index = isEnum && init ? 3 : thisVar ? 1 : 0;
        boolean hasDescriptor = descriptor != null;
        int start = isEnum && init && !hasDescriptor ? 2 : 0;
        int params = hasDescriptor ? descriptor.params.size() : md.params.length;
        for (int i = start; i < params; i++) {
          if (hasDescriptor || (signFields == null || signFields.get(i) == null)) {
            if (!firstParameter) {
              buffer.append(", ");
            }

            appendParameterAnnotations(buffer, mt, paramCount);

            if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0))
                == VarTypeProcessor.VAR_EXPLICIT_FINAL) {
              buffer.append("final ");
            }

            if (descriptor != null) {
              GenericType parameterType = descriptor.params.get(i);

              boolean isVarArg =
                  (i == lastVisibleParameterIndex
                      && mt.hasModifier(CodeConstants.ACC_VARARGS)
                      && parameterType.arrayDim > 0);
              if (isVarArg) {
                parameterType = parameterType.decreaseArrayDim();
              }

              String typeName = GenericMain.getGenericCastTypeName(parameterType);
              if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName)
                  && DecompilerContext.getOption(
                      IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
                typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
              }

              buffer.append(typeName);

              if (isVarArg) {
                buffer.append("...");
              }
            } else {
              VarType parameterType = md.params[i];

              boolean isVarArg =
                  (i == lastVisibleParameterIndex
                      && mt.hasModifier(CodeConstants.ACC_VARARGS)
                      && parameterType.arrayDim > 0);
              if (isVarArg) {
                parameterType = parameterType.decreaseArrayDim();
              }

              String typeName = ExprProcessor.getCastTypeName(parameterType);
              if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName)
                  && DecompilerContext.getOption(
                      IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
                typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
              }

              buffer.append(typeName);

              if (isVarArg) {
                buffer.append("...");
              }
            }

            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;
            paramCount++;
          }

          index += md.params[i].stackSize;
        }

        buffer.append(')');

        StructExceptionsAttribute attr =
            (StructExceptionsAttribute) mt.getAttributes().getWithKey("Exceptions");
        if ((descriptor != null && !descriptor.exceptions.isEmpty()) || attr != null) {
          throwsExceptions = true;
          buffer.append(" throws ");

          for (int i = 0; i < attr.getThrowsExceptions().size(); i++) {
            if (i > 0) {
              buffer.append(", ");
            }
            if (descriptor != null && !descriptor.exceptions.isEmpty()) {
              GenericType type = descriptor.exceptions.get(i);
              buffer.append(GenericMain.getGenericCastTypeName(type));
            } else {
              VarType type = new VarType(attr.getExcClassname(i, cl.getPool()), true);
              buffer.append(ExprProcessor.getCastTypeName(type));
            }
          }
        }
      }

      tracer.incrementCurrentSourceLine(buffer.countLines(start_index_method));

      if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE))
          != 0) { // native or abstract method (explicit or interface)
        if (isAnnotation) {
          StructAnnDefaultAttribute attr =
              (StructAnnDefaultAttribute) mt.getAttributes().getWithKey("AnnotationDefault");
          if (attr != null) {
            buffer.append(" default ");
            buffer.append(
                attr.getDefaultValue()
                    .toJava(indent + 1, new BytecodeMappingTracer())); // dummy tracer
          }
        }

        buffer.append(';');
        buffer.appendLineSeparator();
        tracer.incrementCurrentSourceLine();
      } else {
        if (!clinit && !dinit) {
          buffer.append(' ');
        }

        // We do not have line information for method start, lets have it here for now
        StructLineNumberTableAttribute lineNumberTable =
            (StructLineNumberTableAttribute)
                mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
        if (lineNumberTable != null
            && DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) {
          buffer.setCurrentLine(lineNumberTable.getFirstLine() - 1);
        }
        buffer.append('{').appendLineSeparator();
        tracer.incrementCurrentSourceLine();

        RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;

        if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence
          try {
            int startLine = tracer.getCurrentSourceLine();

            TextBuffer code = root.toJava(indent + 1, tracer);

            hideMethod =
                (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount))
                    && code.length() == 0;

            if (!hideMethod
                && lineNumberTable != null
                && DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) {
              mapLines(code, lineNumberTable, tracer, startLine);
            }

            buffer.append(code);
          } catch (Throwable ex) {
            DecompilerContext.getLogger()
                .writeMessage(
                    "Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.",
                    ex);
            methodWrapper.decompiledWithErrors = true;
          }
        }

        if (methodWrapper.decompiledWithErrors) {
          buffer.appendIndent(indent + 1);
          buffer.append("// $FF: Couldn't be decompiled");
          buffer.appendLineSeparator();
          tracer.incrementCurrentSourceLine();
        }

        if (root != null) {
          tracer.addMapping(root.getDummyExit().bytecode);
        }
        buffer.appendIndent(indent).append('}').appendLineSeparator();
        tracer.incrementCurrentSourceLine();
      }
    } finally {
      DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
    }

    // save total lines
    // TODO: optimize
    // tracer.setCurrentSourceLine(buffer.countLines(start_index_method));

    return !hideMethod;
  }
Пример #5
0
  private static void methodLambdaToJava(
      ClassNode lambdaNode,
      ClassWrapper classWrapper,
      StructMethod mt,
      TextBuffer buffer,
      int indent,
      boolean codeOnly,
      BytecodeMappingTracer tracer) {
    MethodWrapper methodWrapper = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());

    MethodWrapper outerWrapper =
        (MethodWrapper) DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
    DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);

    try {
      String method_name = lambdaNode.lambdaInformation.method_name;
      MethodDescriptor md_content =
          MethodDescriptor.parseDescriptor(lambdaNode.lambdaInformation.content_method_descriptor);
      MethodDescriptor md_lambda =
          MethodDescriptor.parseDescriptor(lambdaNode.lambdaInformation.method_descriptor);

      if (!codeOnly) {
        buffer.appendIndent(indent);
        buffer.append("public ");
        buffer.append(method_name);
        buffer.append("(");

        boolean firstParameter = true;
        int index = lambdaNode.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 typeName = ExprProcessor.getCastTypeName(md_content.params[i].copy());
            if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName)
                && DecompilerContext.getOption(
                    IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
              typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
            }

            buffer.append(typeName);
            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(") {").appendLineSeparator();

        indent += 1;
      }

      RootStatement root = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
      if (!methodWrapper.decompiledWithErrors) {
        if (root != null) { // check for existence
          try {
            buffer.append(root.toJava(indent, tracer));
          } catch (Throwable ex) {
            DecompilerContext.getLogger()
                .writeMessage(
                    "Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.",
                    ex);
            methodWrapper.decompiledWithErrors = true;
          }
        }
      }

      if (methodWrapper.decompiledWithErrors) {
        buffer.appendIndent(indent);
        buffer.append("// $FF: Couldn't be decompiled");
        buffer.appendLineSeparator();
      }

      if (root != null) {
        tracer.addMapping(root.getDummyExit().bytecode);
      }

      if (!codeOnly) {
        indent -= 1;
        buffer.appendIndent(indent).append('}').appendLineSeparator();
      }
    } finally {
      DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
    }
  }