private static void processClassRec(
      ClassNode node,
      final HashMap<ClassWrapper, MethodWrapper> mapClassMeths,
      final HashSet<ClassWrapper> setFound) {

    final ClassWrapper wrapper = node.wrapper;

    // search code
    for (MethodWrapper meth : wrapper.getMethods()) {

      RootStatement root = meth.root;
      if (root != null) {

        DirectGraph graph = meth.getOrBuildGraph();

        graph.iterateExprents(
            new DirectGraph.ExprentIterator() {
              public int processExprent(Exprent exprent) {
                for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
                  if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
                    setFound.add(ent.getKey());
                  }
                }
                return 0;
              }
            });
      }
    }

    // search initializers
    for (int j = 0; j < 2; j++) {
      VBStyleCollection<Exprent, String> initializers =
          j == 0 ? wrapper.getStaticFieldInitializers() : wrapper.getDynamicFieldInitializers();

      for (int i = 0; i < initializers.size(); i++) {
        for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
          Exprent exprent = initializers.get(i);
          if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
            setFound.add(ent.getKey());
          }

          String cl = isClass14Invocation(exprent, ent.getKey(), ent.getValue());
          if (cl != null) {
            initializers.set(
                i, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/'), exprent.bytecode));
            setFound.add(ent.getKey());
          }
        }
      }
    }

    // iterate nested classes
    for (ClassNode nd : node.nested) {
      processClassRec(nd, mapClassMeths, setFound);
    }
  }
  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();
    }
  }