private static void insertLocalVars(ClassNode parent, ClassNode child) {
    // enclosing method, is null iff member class
    MethodWrapper enclosingMethod = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod);

    // iterate all child methods
    for (MethodWrapper method : child.getWrapper().getMethods()) {
      if (method.root != null) { // neither abstract nor native
        Map<VarVersionPair, String> mapNewNames = new HashMap<>();  // local var names
        Map<VarVersionPair, VarType> mapNewTypes = new HashMap<>();  // local var types

        Map<Integer, VarVersionPair> mapParamsToNewVars = new HashMap<>();
        if (method.synthParameters != null) {
          int index = 0, varIndex = 1;
          MethodDescriptor md = MethodDescriptor.parseDescriptor(method.methodStruct.getDescriptor());

          for (VarVersionPair pair : method.synthParameters) {
            if (pair != null) {
              VarVersionPair newVar = new VarVersionPair(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);

              mapParamsToNewVars.put(varIndex, newVar);

              String varName = null;
              VarType varType = null;

              if (child.type != ClassNode.CLASS_MEMBER) {
                varName = enclosingMethod.varproc.getVarName(pair);
                varType = enclosingMethod.varproc.getVarType(pair);

                enclosingMethod.varproc.setVarFinal(pair, VarProcessor.VAR_EXPLICIT_FINAL);
              }

              if (pair.var == -1 || "this".equals(varName)) {
                if (parent.simpleName == null) {
                  // anonymous enclosing class, no access to this
                  varName = VarExprent.VAR_NAMELESS_ENCLOSURE;
                }
                else {
                  varName = parent.simpleName + ".this";
                }
                method.varproc.getThisVars().put(newVar, parent.classStruct.qualifiedName);
              }

              mapNewNames.put(newVar, varName);
              mapNewTypes.put(newVar, varType);
            }

            varIndex += md.params[index++].getStackSize();
          }
        }

        Map<String, VarVersionPair> mapFieldsToNewVars = new HashMap<>();
        for (ClassNode classNode = child; classNode != null; classNode = classNode.parent) {
          for (Entry<String, VarVersionPair> entry : classNode.mapFieldsToVars.entrySet()) {
            VarVersionPair newVar = new VarVersionPair(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);

            mapFieldsToNewVars.put(InterpreterUtil.makeUniqueKey(classNode.classStruct.qualifiedName, entry.getKey()), newVar);

            String varName = null;
            VarType varType = null;

            if (classNode.type != ClassNode.CLASS_MEMBER) {
              MethodWrapper enclosing_method = classNode.parent.getWrapper().getMethods().getWithKey(classNode.enclosingMethod);

              varName = enclosing_method.varproc.getVarName(entry.getValue());
              varType = enclosing_method.varproc.getVarType(entry.getValue());

              enclosing_method.varproc.setVarFinal(entry.getValue(), VarProcessor.VAR_EXPLICIT_FINAL);
            }

            if (entry.getValue().var == -1 || "this".equals(varName)) {
              if (classNode.parent.simpleName == null) {
                // anonymous enclosing class, no access to this
                varName = VarExprent.VAR_NAMELESS_ENCLOSURE;
              }
              else {
                varName = classNode.parent.simpleName + ".this";
              }
              method.varproc.getThisVars().put(newVar, classNode.parent.classStruct.qualifiedName);
            }

            mapNewNames.put(newVar, varName);
            mapNewTypes.put(newVar, varType);

            // hide synthetic field
            if (classNode == child) { // fields higher up the chain were already handled with their classes
              StructField fd = child.classStruct.getFields().getWithKey(entry.getKey());
              child.getWrapper().getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
            }
          }
        }

        Set<String> setNewOuterNames = new HashSet<>(mapNewNames.values());
        setNewOuterNames.removeAll(method.setOuterVarNames);

        method.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames));
        method.setOuterVarNames.addAll(setNewOuterNames);

        for (Entry<VarVersionPair, String> entry : mapNewNames.entrySet()) {
          VarVersionPair pair = entry.getKey();
          VarType type = mapNewTypes.get(pair);

          method.varproc.setVarName(pair, entry.getValue());
          if (type != null) {
            method.varproc.setVarType(pair, type);
          }
        }

        method.getOrBuildGraph().iterateExprents(new DirectGraph.ExprentIterator() {
          @Override
          public int processExprent(Exprent exprent) {
            if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
              AssignmentExprent assignExpr = (AssignmentExprent)exprent;
              if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) {
                FieldExprent fExpr = (FieldExprent)assignExpr.getLeft();
                String qName = child.classStruct.qualifiedName;
                if (fExpr.getClassname().equals(qName) &&  // process this class only
                    mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(qName, fExpr.getName(), fExpr.getDescriptor().descriptorString))) {
                  return 2;
                }
              }
            }

            if (child.type == ClassNode.CLASS_ANONYMOUS &&
                CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) &&
                exprent.type == Exprent.EXPRENT_INVOCATION) {
              InvocationExprent invokeExpr = (InvocationExprent)exprent;
              if (invokeExpr.getFuncType() == InvocationExprent.TYPE_INIT) {
                // invocation of the super constructor in an anonymous class
                child.superInvocation = invokeExpr; // FIXME: save original names of parameters
                return 2;
              }
            }

            replaceExprent(exprent);

            return 0;
          }

          private Exprent replaceExprent(Exprent exprent) {
            if (exprent.type == Exprent.EXPRENT_VAR) {
              int varIndex = ((VarExprent)exprent).getIndex();
              if (mapParamsToNewVars.containsKey(varIndex)) {
                VarVersionPair newVar = mapParamsToNewVars.get(varIndex);
                method.varproc.getExternalVars().add(newVar);
                return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc);
              }
            }
            else if (exprent.type == Exprent.EXPRENT_FIELD) {
              FieldExprent fExpr = (FieldExprent)exprent;
              String key = InterpreterUtil.makeUniqueKey(fExpr.getClassname(), fExpr.getName(), fExpr.getDescriptor().descriptorString);
              if (mapFieldsToNewVars.containsKey(key)) {
                //if(fExpr.getClassname().equals(child.classStruct.qualifiedName) &&
                //		mapFieldsToNewVars.containsKey(key)) {
                VarVersionPair newVar = mapFieldsToNewVars.get(key);
                method.varproc.getExternalVars().add(newVar);
                return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc);
              }
            }

            boolean replaced = true;
            while (replaced) {
              replaced = false;

              for (Exprent expr : exprent.getAllExprents()) {
                Exprent retExpr = replaceExprent(expr);
                if (retExpr != null) {
                  exprent.replaceExprent(expr, retExpr);
                  replaced = true;
                  break;
                }
              }
            }

            return null;
          }
        });
      }
    }
  }
private static void insertLocalVars(ClassNode parent, ClassNode child)