Exprent (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; }