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 static void updateVersions(
      DirectGraph graph, final Map<VarVersionPair, Integer> versions) {
    graph.iterateExprents(
        new DirectGraph.ExprentIterator() {
          @Override
          public int processExprent(Exprent exprent) {
            List<Exprent> lst = exprent.getAllExprents(true);
            lst.add(exprent);

            for (Exprent expr : lst) {
              if (expr.type == Exprent.EXPRENT_VAR) {
                VarExprent var = (VarExprent) expr;
                Integer version = versions.get(new VarVersionPair(var));
                if (version != null) {
                  var.setVersion(version);
                }
              }
            }

            return 0;
          }
        });
  }
  private void setNewVarIndices(VarTypeProcessor typeProcessor, DirectGraph graph) {
    final Map<VarVersionPair, VarType> mapExprentMaxTypes = typeProcessor.getMapExprentMaxTypes();
    Map<VarVersionPair, VarType> mapExprentMinTypes = typeProcessor.getMapExprentMinTypes();
    Map<VarVersionPair, Integer> mapFinalVars = typeProcessor.getMapFinalVars();

    CounterContainer counters = DecompilerContext.getCounterContainer();

    final Map<VarVersionPair, Integer> mapVarPaar = new HashMap<VarVersionPair, Integer>();
    Map<Integer, Integer> mapOriginalVarIndices = new HashMap<Integer, Integer>();

    // map var-version pairs on new var indexes
    Set<VarVersionPair> set = new HashSet<VarVersionPair>(mapExprentMinTypes.keySet());
    for (VarVersionPair pair : set) {

      if (pair.version >= 0) {
        int newIndex =
            pair.version == 1
                ? pair.var
                : counters.getCounterAndIncrement(CounterContainer.VAR_COUNTER);

        VarVersionPair newVar = new VarVersionPair(newIndex, 0);

        mapExprentMinTypes.put(newVar, mapExprentMinTypes.get(pair));
        mapExprentMaxTypes.put(newVar, mapExprentMaxTypes.get(pair));

        if (mapFinalVars.containsKey(pair)) {
          mapFinalVars.put(newVar, mapFinalVars.remove(pair));
        }

        mapVarPaar.put(pair, newIndex);
        mapOriginalVarIndices.put(newIndex, pair.var);
      }
    }

    // set new vars
    graph.iterateExprents(
        new DirectGraph.ExprentIterator() {
          @Override
          public int processExprent(Exprent exprent) {
            List<Exprent> lst = exprent.getAllExprents(true);
            lst.add(exprent);

            for (Exprent expr : lst) {
              if (expr.type == Exprent.EXPRENT_VAR) {
                VarExprent newVar = (VarExprent) expr;
                Integer newVarIndex = mapVarPaar.get(new VarVersionPair(newVar));
                if (newVarIndex != null) {
                  newVar.setIndex(newVarIndex);
                  newVar.setVersion(0);
                }
              } else if (expr.type == Exprent.EXPRENT_CONST) {
                VarType maxType = mapExprentMaxTypes.get(new VarVersionPair(expr.id, -1));
                if (maxType != null && maxType.equals(VarType.VARTYPE_CHAR)) {
                  ((ConstExprent) expr).setConstType(maxType);
                }
              }
            }

            return 0;
          }
        });

    this.mapOriginalVarIndices = mapOriginalVarIndices;
  }