private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) {
    ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(invexpr.getClassName());

    MethodWrapper methsource = null;
    if (node != null && node.getWrapper() != null) {
      methsource = node.getWrapper().getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor());
    }

    if (methsource == null || !mapMethodType.containsKey(methsource)) {
      return null;
    }

    // if same method, return
    if (node.classStruct.qualifiedName.equals(caller.classStruct.qualifiedName) &&
        methsource.methodStruct.getName().equals(methdest.methodStruct.getName()) &&
        methsource.methodStruct.getDescriptor().equals(methdest.methodStruct.getDescriptor())) {
      // no recursive invocations permitted!
      return null;
    }

    MethodAccess type = mapMethodType.get(methsource);

    //		// FIXME: impossible case. MethodAccess.NORMAL is not saved in the map
    //		if(type == MethodAccess.NORMAL) {
    //			return null;
    //		}

    if (!sameTree(caller, node)) {
      return null;
    }

    DirectGraph graph = methsource.getOrBuildGraph();
    Exprent source = graph.first.exprents.get(0);

    Exprent retexprent = null;

    switch (type) {
      case FIELD_GET -> {
        ExitExprent exsource = (ExitExprent)source;
        if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this
          VarExprent var = (VarExprent)exsource.getValue();
          String varname = methsource.varproc.getVarName(new VarVersionPair(var));

          if (!methdest.setOuterVarNames.contains(varname)) {
            VarNamesCollector vnc = new VarNamesCollector();
            vnc.addName(varname);

            methdest.varproc.refreshVarNames(vnc);
            methdest.setOuterVarNames.add(varname);
          }

          int index = methdest.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
          VarExprent ret = new VarExprent(index, var.getVarType(), methdest.varproc);
          methdest.varproc.setVarName(new VarVersionPair(index, 0), varname);

          retexprent = ret;
        }
        else { // field
          FieldExprent ret = (FieldExprent)exsource.getValue().copy();
          if (!ret.isStatic()) {
            ret.replaceExprent(ret.getInstance(), invexpr.getParameters().get(0));
          }
          retexprent = ret;
        }
      }
      case FIELD_SET -> {
        AssignmentExprent ret;
        if (source.type == Exprent.EXPRENT_EXIT) {
          ExitExprent extex = (ExitExprent)source;
          ret = (AssignmentExprent)extex.getValue().copy();
        }
        else {
          ret = (AssignmentExprent)source.copy();
        }
        FieldExprent fexpr = (FieldExprent)ret.getLeft();

        if (fexpr.isStatic()) {
          ret.replaceExprent(ret.getRight(), invexpr.getParameters().get(0));
        }
        else {
          ret.replaceExprent(ret.getRight(), invexpr.getParameters().get(1));
          fexpr.replaceExprent(fexpr.getInstance(), invexpr.getParameters().get(0));
        }

        // do not use copied bytecodes
        ret.getLeft().bytecode = null;
        ret.getRight().bytecode = null;

        retexprent = ret;
      }
      case FUNCTION -> retexprent = replaceFunction(invexpr, source);
      case METHOD -> {
        if (source.type == Exprent.EXPRENT_EXIT) {
          source = ((ExitExprent)source).getValue();
        }

        InvocationExprent invret = (InvocationExprent)source.copy();

        int index = 0;
        if (!invret.isStatic()) {
          invret.replaceExprent(invret.getInstance(), invexpr.getParameters().get(0));
          index = 1;
        }

        for (int i = 0; i < invret.getParameters().size(); i++) {
          invret.replaceExprent(invret.getParameters().get(i), invexpr.getParameters().get(i + index));
        }

        retexprent = invret;
      }
    }


    if (retexprent != null) {
      // preserve original bytecodes
      retexprent.bytecode = null;
      retexprent.addBytecodeOffsets(invexpr.bytecode);

      // hide synthetic access method
      boolean hide = true;

      if (node.type == ClassNode.CLASS_ROOT || (node.access & CodeConstants.ACC_STATIC) != 0) {
        StructMethod mt = methsource.methodStruct;
        if (!mt.isSynthetic()) {
          hide = false;
        }
      }
      if (hide) {
        node.getWrapper().getHiddenMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor()));
      }
    }

    return retexprent;
  }
private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr)