in src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java [120:369]
private static Exprent identifySecondaryFunctions(Exprent exprent, boolean statement_level, VarProcessor varProc) {
if (exprent.type == Exprent.EXPRENT_FUNCTION) {
FunctionExprent fexpr = (FunctionExprent)exprent;
switch (fexpr.getFuncType()) {
case FunctionExprent.FUNCTION_BOOL_NOT -> {
Exprent retparam = propagateBoolNot(fexpr);
if (retparam != null) {
return retparam;
}
}
case FunctionExprent.FUNCTION_EQ, FunctionExprent.FUNCTION_NE, FunctionExprent.FUNCTION_GT,
FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_LE -> {
Exprent expr1 = fexpr.getLstOperands().get(0);
Exprent expr2 = fexpr.getLstOperands().get(1);
if (expr1.type == Exprent.EXPRENT_CONST) {
expr2 = expr1;
expr1 = fexpr.getLstOperands().get(1);
}
if (expr1.type == Exprent.EXPRENT_FUNCTION && expr2.type == Exprent.EXPRENT_CONST) {
FunctionExprent funcexpr = (FunctionExprent)expr1;
ConstExprent cexpr = (ConstExprent)expr2;
int functype = funcexpr.getFuncType();
if (functype == FunctionExprent.FUNCTION_LCMP || functype == FunctionExprent.FUNCTION_FCMPG ||
functype == FunctionExprent.FUNCTION_FCMPL || functype == FunctionExprent.FUNCTION_DCMPG ||
functype == FunctionExprent.FUNCTION_DCMPL) {
int desttype = -1;
Integer[] destcons = mapNumComparisons.get(fexpr.getFuncType());
if (destcons != null) {
int index = cexpr.getIntValue() + 1;
if (index >= 0 && index <= 2) {
Integer destcon = destcons[index];
if (destcon != null) {
desttype = destcon;
}
}
}
if (desttype >= 0) {
if (functype != FunctionExprent.FUNCTION_LCMP) {
boolean oneForNan = functype == FunctionExprent.FUNCTION_DCMPL || functype == FunctionExprent.FUNCTION_FCMPL;
boolean trueForOne = desttype == FunctionExprent.FUNCTION_LT || desttype == FunctionExprent.FUNCTION_LE;
boolean trueForNan = oneForNan == trueForOne;
if (trueForNan) {
List<Exprent> operands = new ArrayList<>();
operands.add(new FunctionExprent(funcsnot[desttype - FunctionExprent.FUNCTION_EQ],
funcexpr.getLstOperands(), funcexpr.bytecode));
return new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, operands, funcexpr.bytecode);
}
}
return new FunctionExprent(desttype, funcexpr.getLstOperands(), funcexpr.bytecode);
}
}
}
}
}
}
boolean replaced = true;
while (replaced) {
replaced = false;
for (Exprent expr : exprent.getAllExprents()) {
Exprent retexpr = identifySecondaryFunctions(expr, false, varProc);
if (retexpr != null) {
exprent.replaceExprent(expr, retexpr);
replaced = true;
break;
}
}
}
switch (exprent.type) {
case Exprent.EXPRENT_FUNCTION -> {
FunctionExprent fexpr = (FunctionExprent)exprent;
List<Exprent> lstOperands = fexpr.getLstOperands();
switch (fexpr.getFuncType()) {
case FunctionExprent.FUNCTION_XOR -> {
for (int i = 0; i < 2; i++) {
Exprent operand = lstOperands.get(i);
VarType operandtype = operand.getExprType();
if (operand.type == Exprent.EXPRENT_CONST &&
operandtype.getType() != CodeConstants.TYPE_BOOLEAN) {
ConstExprent cexpr = (ConstExprent)operand;
long val;
if (operandtype.getType() == CodeConstants.TYPE_LONG) {
val = (Long)cexpr.getValue();
}
else {
val = (Integer)cexpr.getValue();
}
if (val == -1) {
List<Exprent> lstBitNotOperand = new ArrayList<>();
lstBitNotOperand.add(lstOperands.get(1 - i));
return new FunctionExprent(FunctionExprent.FUNCTION_BIT_NOT, lstBitNotOperand, fexpr.bytecode);
}
}
}
}
case FunctionExprent.FUNCTION_EQ, FunctionExprent.FUNCTION_NE -> {
if (lstOperands.get(0).getExprType().getType() == CodeConstants.TYPE_BOOLEAN &&
lstOperands.get(1).getExprType().getType() == CodeConstants.TYPE_BOOLEAN) {
for (int i = 0; i < 2; i++) {
if (lstOperands.get(i).type == Exprent.EXPRENT_CONST) {
ConstExprent cexpr = (ConstExprent)lstOperands.get(i);
int val = (Integer)cexpr.getValue();
if ((fexpr.getFuncType() == FunctionExprent.FUNCTION_EQ && val == 1) ||
(fexpr.getFuncType() == FunctionExprent.FUNCTION_NE && val == 0)) {
return lstOperands.get(1 - i);
}
else {
List<Exprent> lstNotOperand = new ArrayList<>();
lstNotOperand.add(lstOperands.get(1 - i));
return new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, lstNotOperand, fexpr.bytecode);
}
}
}
}
}
case FunctionExprent.FUNCTION_BOOL_NOT -> {
if (lstOperands.get(0).type == Exprent.EXPRENT_CONST) {
int val = ((ConstExprent)lstOperands.get(0)).getIntValue();
if (val == 0) {
return new ConstExprent(VarType.VARTYPE_BOOLEAN, 1, fexpr.bytecode);
}
else {
return new ConstExprent(VarType.VARTYPE_BOOLEAN, 0, fexpr.bytecode);
}
}
}
case FunctionExprent.FUNCTION_IIF -> {
Exprent expr1 = lstOperands.get(1);
Exprent expr2 = lstOperands.get(2);
if (expr1.type == Exprent.EXPRENT_CONST && expr2.type == Exprent.EXPRENT_CONST) {
ConstExprent cexpr1 = (ConstExprent)expr1;
ConstExprent cexpr2 = (ConstExprent)expr2;
if (cexpr1.getExprType().getType() == CodeConstants.TYPE_BOOLEAN &&
cexpr2.getExprType().getType() == CodeConstants.TYPE_BOOLEAN) {
if (cexpr1.getIntValue() == 0 && cexpr2.getIntValue() != 0) {
return new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, lstOperands.get(0), fexpr.bytecode);
}
else if (cexpr1.getIntValue() != 0 && cexpr2.getIntValue() == 0) {
return lstOperands.get(0);
}
}
}
}
case FunctionExprent.FUNCTION_LCMP, FunctionExprent.FUNCTION_FCMPL, FunctionExprent.FUNCTION_FCMPG, FunctionExprent.FUNCTION_DCMPL, FunctionExprent.FUNCTION_DCMPG -> {
int var = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
VarType type = lstOperands.get(0).getExprType();
FunctionExprent iff = new FunctionExprent(FunctionExprent.FUNCTION_IIF, Arrays.asList(
new FunctionExprent(FunctionExprent.FUNCTION_LT, Arrays.asList(new VarExprent(var, type, varProc),
ConstExprent.getZeroConstant(type.getType())), null),
new ConstExprent(VarType.VARTYPE_INT, -1, null),
new ConstExprent(VarType.VARTYPE_INT, 1, null)), null);
FunctionExprent head = new FunctionExprent(FunctionExprent.FUNCTION_EQ, Arrays.asList(
new AssignmentExprent(new VarExprent(var, type, varProc),
new FunctionExprent(FunctionExprent.FUNCTION_SUB, Arrays.asList(lstOperands.get(0), lstOperands.get(1)),
null),
null),
ConstExprent.getZeroConstant(type.getType())), null);
varProc.setVarType(new VarVersion(var, 0), type);
return new FunctionExprent(FunctionExprent.FUNCTION_IIF, Arrays.asList(
head, new ConstExprent(VarType.VARTYPE_INT, 0, null), iff), fexpr.bytecode);
}
}
}
case Exprent.EXPRENT_ASSIGNMENT -> { // check for conditional assignment
AssignmentExprent asexpr = (AssignmentExprent)exprent;
Exprent right = asexpr.getRight();
Exprent left = asexpr.getLeft();
if (right.type == Exprent.EXPRENT_FUNCTION) {
FunctionExprent func = (FunctionExprent)right;
VarType midlayer = null;
if (func.getFuncType() >= FunctionExprent.FUNCTION_I2L &&
func.getFuncType() <= FunctionExprent.FUNCTION_I2S) {
right = func.getLstOperands().get(0);
midlayer = func.getSimpleCastType();
if (right.type == Exprent.EXPRENT_FUNCTION) {
func = (FunctionExprent)right;
}
else {
return null;
}
}
List<Exprent> lstFuncOperands = func.getLstOperands();
Exprent cond = null;
switch (func.getFuncType()) {
case FunctionExprent.FUNCTION_ADD:
case FunctionExprent.FUNCTION_AND:
case FunctionExprent.FUNCTION_OR:
case FunctionExprent.FUNCTION_XOR:
if (left.equals(lstFuncOperands.get(1))) {
cond = lstFuncOperands.get(0);
break;
}
case FunctionExprent.FUNCTION_SUB:
case FunctionExprent.FUNCTION_MUL:
case FunctionExprent.FUNCTION_DIV:
case FunctionExprent.FUNCTION_REM:
case FunctionExprent.FUNCTION_SHL:
case FunctionExprent.FUNCTION_SHR:
case FunctionExprent.FUNCTION_USHR:
if (left.equals(lstFuncOperands.get(0))) {
cond = lstFuncOperands.get(1);
}
}
if (cond != null && (midlayer == null || midlayer.equals(cond.getExprType()))) {
asexpr.setRight(cond);
asexpr.setCondType(func.getFuncType());
}
}
}
case Exprent.EXPRENT_INVOCATION -> {
if (!statement_level) { // simplify if exprent is a real expression. The opposite case is pretty absurd, can still happen however (and happened at least once).
Exprent retexpr = ConcatenationHelper.contractStringConcat(exprent);
if (!exprent.equals(retexpr)) {
return retexpr;
}
}
}
}
return null;
}