示例#1
0
        private Exprent ProcessExprentRecursive(Exprent exprent)
        {
            bool replaced = true;

            while (replaced)
            {
                replaced = false;
                foreach (Exprent expr in exprent.GetAllExprents())
                {
                    Exprent retexpr = ProcessExprentRecursive(expr);
                    if (retexpr != null)
                    {
                        exprent.ReplaceExprent(expr, retexpr);
                        replaced        = true;
                        exprentReplaced = true;
                        break;
                    }
                }
            }
            if (exprent.type == Exprent.Exprent_Assignment)
            {
                AssignmentExprent @as = (AssignmentExprent)exprent;
                if (@as.GetRight().type == Exprent.Exprent_Function)
                {
                    FunctionExprent func     = (FunctionExprent)@as.GetRight();
                    VarType         midlayer = null;
                    if (func.GetFuncType() >= FunctionExprent.Function_I2l && func.GetFuncType() <= FunctionExprent
                        .Function_I2s)
                    {
                        midlayer = func.GetSimpleCastType();
                        if (func.GetLstOperands()[0].type == Exprent.Exprent_Function)
                        {
                            func = (FunctionExprent)func.GetLstOperands()[0];
                        }
                        else
                        {
                            return(null);
                        }
                    }
                    if (func.GetFuncType() == FunctionExprent.Function_Add || func.GetFuncType() == FunctionExprent
                        .Function_Sub)
                    {
                        Exprent econd  = func.GetLstOperands()[0];
                        Exprent econst = func.GetLstOperands()[1];
                        if (econst.type != Exprent.Exprent_Const && econd.type == Exprent.Exprent_Const &&
                            func.GetFuncType() == FunctionExprent.Function_Add)
                        {
                            econd  = econst;
                            econst = func.GetLstOperands()[0];
                        }
                        if (econst.type == Exprent.Exprent_Const && ((ConstExprent)econst).HasValueOne())
                        {
                            Exprent left     = @as.GetLeft();
                            VarType condtype = econd.GetExprType();
                            if (left.Equals(econd) && (midlayer == null || midlayer.Equals(condtype)))
                            {
                                FunctionExprent ret = new FunctionExprent(func.GetFuncType() == FunctionExprent.Function_Add
                                                                         ? FunctionExprent.Function_Ppi : FunctionExprent.Function_Mmi, econd, func.bytecode
                                                                          );
                                ret.SetImplicitType(condtype);
                                exprentReplaced = true;
                                return(ret);
                            }
                        }
                    }
                }
            }
            return(null);
        }
示例#2
0
        private static bool FindAndRemoveParameterCheck(Statement stat, StructMethod mt)
        {
            Statement st = stat.GetFirst();

            while (st.type == Statement.Type_Sequence)
            {
                st = st.GetFirst();
            }
            if (st.type == Statement.Type_If)
            {
                IfStatement ifstat           = (IfStatement)st;
                Statement   ifbranch         = ifstat.GetIfstat();
                Exprent     if_condition     = ifstat.GetHeadexprent().GetCondition();
                bool        is_notnull_check = false;
                // TODO: FUNCTION_NE also possible if reversed order (in theory)
                if (ifbranch != null && if_condition.type == Exprent.Exprent_Function && ((FunctionExprent
                                                                                           )if_condition).GetFuncType() == FunctionExprent.Function_Eq && ifbranch.type ==
                    Statement.Type_Basicblock && ifbranch.GetExprents().Count == 1 && ifbranch.GetExprents
                        ()[0].type == Exprent.Exprent_Exit)
                {
                    FunctionExprent func         = (FunctionExprent)if_condition;
                    Exprent         first_param  = func.GetLstOperands()[0];
                    Exprent         second_param = func.GetLstOperands()[1];
                    if (second_param.type == Exprent.Exprent_Const && second_param.GetExprType().type
                        == ICodeConstants.Type_Null)
                    {
                        // TODO: reversed parameter order
                        if (first_param.type == Exprent.Exprent_Var)
                        {
                            VarExprent       var     = (VarExprent)first_param;
                            bool             thisvar = !mt.HasModifier(ICodeConstants.Acc_Static);
                            MethodDescriptor md      = MethodDescriptor.ParseDescriptor(mt.GetDescriptor());
                            // parameter annotations
                            StructAnnotationParameterAttribute param_annotations = mt.GetAttribute(StructGeneralAttribute
                                                                                                   .Attribute_Runtime_Invisible_Parameter_Annotations);
                            if (param_annotations != null)
                            {
                                List <List <AnnotationExprent> > param_annotations_lists = param_annotations.GetParamAnnotations
                                                                                               ();
                                int method_param_number = [email protected];
                                int index = thisvar ? 1 : 0;
                                for (int i = 0; i < method_param_number; i++)
                                {
                                    if (index == var.GetIndex())
                                    {
                                        if (param_annotations_lists.Count >= method_param_number - i)
                                        {
                                            int shift = method_param_number - param_annotations_lists.Count;
                                            // NOTE: workaround for compiler bug, count annotations starting with the last parameter
                                            List <AnnotationExprent> annotations = param_annotations_lists[i - shift];
                                            foreach (AnnotationExprent ann in annotations)
                                            {
                                                if (ann.GetClassName().Equals("org/jetbrains/annotations/NotNull"))
                                                {
                                                    is_notnull_check = true;
                                                    break;
                                                }
                                            }
                                        }
                                        break;
                                    }
                                    index += md.@params[i].stackSize;
                                }
                            }
                        }
                    }
                }
                if (!is_notnull_check)
                {
                    return(false);
                }
                RemoveParameterCheck(stat);
                return(true);
            }
            return(false);
        }
示例#3
0
        private static Exprent IdentifySecondaryFunctions(Exprent exprent, bool 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);
                    }
                    break;
                }

                case FunctionExprent.Function_Eq:
                case FunctionExprent.Function_Ne:
                case FunctionExprent.Function_Gt:
                case FunctionExprent.Function_Ge:
                case FunctionExprent.Function_Lt:
                case FunctionExprent.Function_Le:
                {
                    Exprent expr1 = fexpr.GetLstOperands()[0];
                    Exprent expr2 = fexpr.GetLstOperands()[1];
                    if (expr1.type == Exprent.Exprent_Const)
                    {
                        expr2 = expr1;
                        expr1 = fexpr.GetLstOperands()[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;
                            int?[] destcons = mapNumComparisons.GetOrNull(fexpr.GetFuncType());
                            if (destcons != null)
                            {
                                int index = cexpr.GetIntValue() + 1;
                                if (index >= 0 && index <= 2)
                                {
                                    int?destcon = destcons[index];
                                    if (destcon != null)
                                    {
                                        desttype = destcon.Value;
                                    }
                                }
                            }
                            if (desttype >= 0)
                            {
                                return(new FunctionExprent(desttype, funcexpr.GetLstOperands(), funcexpr.bytecode
                                                           ));
                            }
                        }
                    }
                    break;
                }
                }
            }
            bool replaced = true;

            while (replaced)
            {
                replaced = false;
                foreach (Exprent expr in 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_1     = (FunctionExprent)exprent;
                List <Exprent>  lstOperands = fexpr_1.GetLstOperands();
                switch (fexpr_1.GetFuncType())
                {
                case FunctionExprent.Function_Xor:
                {
                    for (int i = 0; i < 2; i++)
                    {
                        Exprent operand     = lstOperands[i];
                        VarType operandtype = operand.GetExprType();
                        if (operand.type == Exprent.Exprent_Const && operandtype.type != ICodeConstants.Type_Boolean)
                        {
                            ConstExprent cexpr = (ConstExprent)operand;
                            long         val;
                            if (operandtype.type == ICodeConstants.Type_Long)
                            {
                                val = (long)cexpr.GetValue();
                            }
                            else
                            {
                                val = (int)cexpr.GetValue();
                            }
                            if (val == -1)
                            {
                                List <Exprent> lstBitNotOperand = new List <Exprent>();
                                lstBitNotOperand.Add(lstOperands[1 - i]);
                                return(new FunctionExprent(FunctionExprent.Function_Bit_Not, lstBitNotOperand, fexpr_1
                                                           .bytecode));
                            }
                        }
                    }
                    break;
                }

                case FunctionExprent.Function_Eq:
                case FunctionExprent.Function_Ne:
                {
                    if (lstOperands[0].GetExprType().type == ICodeConstants.Type_Boolean && lstOperands
                        [1].GetExprType().type == ICodeConstants.Type_Boolean)
                    {
                        for (int i = 0; i < 2; i++)
                        {
                            if (lstOperands[i].type == Exprent.Exprent_Const)
                            {
                                ConstExprent cexpr = (ConstExprent)lstOperands[i];
                                int          val   = (int)cexpr.GetValue();
                                if ((fexpr_1.GetFuncType() == FunctionExprent.Function_Eq && val == 1) || (fexpr_1
                                                                                                           .GetFuncType() == FunctionExprent.Function_Ne && val == 0))
                                {
                                    return(lstOperands[1 - i]);
                                }
                                else
                                {
                                    List <Exprent> lstNotOperand = new List <Exprent>();
                                    lstNotOperand.Add(lstOperands[1 - i]);
                                    return(new FunctionExprent(FunctionExprent.Function_Bool_Not, lstNotOperand, fexpr_1
                                                               .bytecode));
                                }
                            }
                        }
                    }
                    break;
                }

                case FunctionExprent.Function_Bool_Not:
                {
                    if (lstOperands[0].type == Exprent.Exprent_Const)
                    {
                        int val = ((ConstExprent)lstOperands[0]).GetIntValue();
                        if (val == 0)
                        {
                            return(new ConstExprent(VarType.Vartype_Boolean, 1, fexpr_1.bytecode));
                        }
                        else
                        {
                            return(new ConstExprent(VarType.Vartype_Boolean, 0, fexpr_1.bytecode));
                        }
                    }
                    break;
                }

                case FunctionExprent.Function_Iif:
                {
                    Exprent expr1_1 = lstOperands[1];
                    Exprent expr2_1 = lstOperands[2];
                    if (expr1_1.type == Exprent.Exprent_Const && expr2_1.type == Exprent.Exprent_Const)
                    {
                        ConstExprent cexpr1 = (ConstExprent)expr1_1;
                        ConstExprent cexpr2 = (ConstExprent)expr2_1;
                        if (cexpr1.GetExprType().type == ICodeConstants.Type_Boolean && cexpr2.GetExprType
                                ().type == ICodeConstants.Type_Boolean)
                        {
                            if (cexpr1.GetIntValue() == 0 && cexpr2.GetIntValue() != 0)
                            {
                                return(new FunctionExprent(FunctionExprent.Function_Bool_Not, lstOperands[0], fexpr_1
                                                           .bytecode));
                            }
                            else if (cexpr1.GetIntValue() != 0 && cexpr2.GetIntValue() == 0)
                            {
                                return(lstOperands[0]);
                            }
                        }
                    }
                    break;
                }

                case FunctionExprent.Function_Lcmp:
                case FunctionExprent.Function_Fcmpl:
                case FunctionExprent.Function_Fcmpg:
                case FunctionExprent.Function_Dcmpl:
                case FunctionExprent.Function_Dcmpg:
                {
                    int var = DecompilerContext.GetCounterContainer().GetCounterAndIncrement(CounterContainer
                                                                                             .Var_Counter);
                    VarType         type = lstOperands[0].GetExprType();
                    FunctionExprent iff  = new FunctionExprent(FunctionExprent.Function_Iif, Sharpen.Arrays.AsList <Exprent>
                                                                   (new FunctionExprent(FunctionExprent.Function_Lt, Sharpen.Arrays.AsList <Exprent>(new VarExprent
                                                                                                                                                         (var, type, varProc), ConstExprent.GetZeroConstant(type.type)), null), new ConstExprent
                                                                       (VarType.Vartype_Int, -1, null), new ConstExprent(VarType.Vartype_Int, 1, null))
                                                               , null);
                    FunctionExprent head = new FunctionExprent(FunctionExprent.Function_Eq, Sharpen.Arrays.AsList <Exprent>
                                                                   (new AssignmentExprent(new VarExprent(var, type, varProc), new FunctionExprent(FunctionExprent
                                                                                                                                                  .Function_Sub, Sharpen.Arrays.AsList(lstOperands[0], lstOperands[1]), null), null
                                                                                          ), ConstExprent.GetZeroConstant(type.type)), null);
                    varProc.SetVarType(new VarVersionPair(var, 0), type);
                    return(new FunctionExprent(FunctionExprent.Function_Iif, Sharpen.Arrays.AsList <Exprent>(head
                                                                                                             , new ConstExprent(VarType.Vartype_Int, 0, null), iff), fexpr_1.bytecode));
                }
                }
                break;
            }

            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()[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[1]))
                        {
                            cond = lstFuncOperands[0];
                            break;
                        }
                        goto case FunctionExprent.Function_Sub;
                    }

                    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[0]))
                        {
                            cond = lstFuncOperands[1];
                        }
                        break;
                    }
                    }
                    if (cond != null && (midlayer == null || midlayer.Equals(cond.GetExprType())))
                    {
                        asexpr.SetRight(cond);
                        asexpr.SetCondType(func.GetFuncType());
                    }
                }
                break;
            }

            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);
                    }
                }
                break;
            }
            }
            return(null);
        }
示例#4
0
        private static bool RemoveReturnCheck(Statement stat, StructMethod mt)
        {
            Statement parent = stat.GetParent();

            if (parent != null && parent.type == Statement.Type_If && stat.type == Statement.
                Type_Basicblock && stat.GetExprents().Count == 1)
            {
                Exprent exprent = stat.GetExprents()[0];
                if (exprent.type == Exprent.Exprent_Exit)
                {
                    ExitExprent exit_exprent = (ExitExprent)exprent;
                    if (exit_exprent.GetExitType() == ExitExprent.Exit_Return)
                    {
                        Exprent exprent_value = exit_exprent.GetValue();
                        //if(exprent_value.type == Exprent.EXPRENT_VAR) {
                        //	VarExprent var_value = (VarExprent)exprent_value;
                        IfStatement ifparent     = (IfStatement)parent;
                        Exprent     if_condition = ifparent.GetHeadexprent().GetCondition();
                        if (ifparent.GetElsestat() == stat && if_condition.type == Exprent.Exprent_Function &&
                            ((FunctionExprent)if_condition).GetFuncType() == FunctionExprent.Function_Eq)
                        {
                            // TODO: reversed order possible (in theory)
                            FunctionExprent func         = (FunctionExprent)if_condition;
                            Exprent         first_param  = func.GetLstOperands()[0];
                            Exprent         second_param = func.GetLstOperands()[1];
                            StatEdge        ifedge       = ifparent.GetIfEdge();
                            StatEdge        elseedge     = ifparent.GetElseEdge();
                            Statement       ifbranch     = ifparent.GetIfstat();
                            Statement       elsebranch   = ifparent.GetElsestat();
                            if (second_param.type == Exprent.Exprent_Const && second_param.GetExprType().type
                                == ICodeConstants.Type_Null)
                            {
                                // TODO: reversed parameter order
                                //if(first_param.type == Exprent.EXPRENT_VAR && ((VarExprent)first_param).getIndex() == var_value.getIndex()) {
                                if (first_param.Equals(exprent_value))
                                {
                                    // TODO: check for absence of side effects like method invocations etc.
                                    if (ifbranch.type == Statement.Type_Basicblock && ifbranch.GetExprents().Count ==
                                        1 && ifbranch.GetExprents()[0].type == Exprent.Exprent_Exit)
                                    {
                                        // TODO: special check for IllegalStateException
                                        ifparent.GetFirst().RemoveSuccessor(ifedge);
                                        ifparent.GetFirst().RemoveSuccessor(elseedge);
                                        ifparent.GetStats().RemoveWithKey(ifbranch.id);
                                        ifparent.GetStats().RemoveWithKey(elsebranch.id);
                                        if (!(ifbranch.GetAllSuccessorEdges().Count == 0))
                                        {
                                            ifbranch.RemoveSuccessor(ifbranch.GetAllSuccessorEdges()[0]);
                                        }
                                        if (!(ifparent.GetFirst().GetExprents().Count == 0))
                                        {
                                            elsebranch.GetExprents().InsertRange(0, ifparent.GetFirst().GetExprents());
                                        }
                                        ifparent.GetParent().ReplaceStatement(ifparent, elsebranch);
                                        ifparent.GetParent().SetAllParent();
                                        return(true);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else if (parent != null && parent.type == Statement.Type_Sequence && stat.type ==
                     Statement.Type_Basicblock && stat.GetExprents().Count == 1)
            {
                //}
                Exprent exprent = stat.GetExprents()[0];
                if (exprent.type == Exprent.Exprent_Exit)
                {
                    ExitExprent exit_exprent = (ExitExprent)exprent;
                    if (exit_exprent.GetExitType() == ExitExprent.Exit_Return)
                    {
                        Exprent           exprent_value = exit_exprent.GetValue();
                        SequenceStatement sequence      = (SequenceStatement)parent;
                        int sequence_stats_number       = sequence.GetStats().Count;
                        if (sequence_stats_number > 1 && sequence.GetStats().GetLast() == stat && sequence
                            .GetStats()[sequence_stats_number - 2].type == Statement.Type_If)
                        {
                            IfStatement ifstat       = (IfStatement)sequence.GetStats()[sequence_stats_number - 2];
                            Exprent     if_condition = ifstat.GetHeadexprent().GetCondition();
                            if (ifstat.iftype == IfStatement.Iftype_If && if_condition.type == Exprent.Exprent_Function &&
                                ((FunctionExprent)if_condition).GetFuncType() == FunctionExprent.Function_Eq)
                            {
                                // TODO: reversed order possible (in theory)
                                FunctionExprent func         = (FunctionExprent)if_condition;
                                Exprent         first_param  = func.GetLstOperands()[0];
                                Exprent         second_param = func.GetLstOperands()[1];
                                Statement       ifbranch     = ifstat.GetIfstat();
                                if (second_param.type == Exprent.Exprent_Const && second_param.GetExprType().type
                                    == ICodeConstants.Type_Null)
                                {
                                    // TODO: reversed parameter order
                                    if (first_param.Equals(exprent_value))
                                    {
                                        // TODO: check for absence of side effects like method invocations etc.
                                        if (ifbranch.type == Statement.Type_Basicblock && ifbranch.GetExprents().Count ==
                                            1 && ifbranch.GetExprents()[0].type == Exprent.Exprent_Exit)
                                        {
                                            // TODO: special check for IllegalStateException
                                            ifstat.RemoveSuccessor(ifstat.GetAllSuccessorEdges()[0]);
                                            // remove 'else' edge
                                            if (!(ifstat.GetFirst().GetExprents().Count == 0))
                                            {
                                                stat.GetExprents().InsertRange(0, ifstat.GetFirst().GetExprents());
                                            }
                                            foreach (StatEdge edge in ifstat.GetAllPredecessorEdges())
                                            {
                                                ifstat.RemovePredecessor(edge);
                                                edge.GetSource().ChangeEdgeNode(Statement.Direction_Forward, edge, stat);
                                                stat.AddPredecessor(edge);
                                            }
                                            sequence.GetStats().RemoveWithKey(ifstat.id);
                                            sequence.SetFirst(sequence.GetStats()[0]);
                                            return(true);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            foreach (Statement st in stat.GetStats())
            {
                if (RemoveReturnCheck(st, mt))
                {
                    return(true);
                }
            }
            return(false);
        }
示例#5
0
        public static Exprent ContractStringConcat(Exprent expr)
        {
            Exprent exprTmp = null;
            VarType cltype  = null;

            // first quick test
            if (expr.type == Exprent.Exprent_Invocation)
            {
                InvocationExprent iex = (InvocationExprent)expr;
                if ("toString".Equals(iex.GetName()))
                {
                    if (builderClass.Equals(iex.GetClassname()))
                    {
                        cltype = builderType;
                    }
                    else if (bufferClass.Equals(iex.GetClassname()))
                    {
                        cltype = bufferType;
                    }
                    if (cltype != null)
                    {
                        exprTmp = iex.GetInstance();
                    }
                }
                else if ("makeConcatWithConstants".Equals(iex.GetName()))
                {
                    // java 9 style
                    List <Exprent> parameters = ExtractParameters(iex.GetBootstrapArguments(), iex);
                    if (parameters.Count >= 2)
                    {
                        return(CreateConcatExprent(parameters, expr.bytecode));
                    }
                }
            }
            if (exprTmp == null)
            {
                return(expr);
            }
            // iterate in depth, collecting possible operands
            List <Exprent> lstOperands = new List <Exprent>();

            while (true)
            {
                int found = 0;
                switch (exprTmp.type)
                {
                case Exprent.Exprent_Invocation:
                {
                    InvocationExprent iex = (InvocationExprent)exprTmp;
                    if (IsAppendConcat(iex, cltype))
                    {
                        lstOperands.Add(0, iex.GetLstParameters()[0]);
                        exprTmp = iex.GetInstance();
                        found   = 1;
                    }
                    break;
                }

                case Exprent.Exprent_New:
                {
                    NewExprent nex = (NewExprent)exprTmp;
                    if (IsNewConcat(nex, cltype))
                    {
                        VarType[] @params = nex.GetConstructor().GetDescriptor().@params;
                        if (@params.Length == 1)
                        {
                            lstOperands.Add(0, nex.GetConstructor().GetLstParameters()[0]);
                        }
                        found = 2;
                    }
                    break;
                }
                }
                if (found == 0)
                {
                    return(expr);
                }
                else if (found == 2)
                {
                    break;
                }
            }
            int first2str = 0;
            int index     = 0;

            while (index < lstOperands.Count && index < 2)
            {
                if (lstOperands[index].GetExprType().Equals(VarType.Vartype_String))
                {
                    first2str |= (index + 1);
                }
                index++;
            }
            if (first2str == 0)
            {
                lstOperands.Add(0, new ConstExprent(VarType.Vartype_String, string.Empty, expr.bytecode
                                                    ));
            }
            // remove redundant String.valueOf
            for (int i = 0; i < lstOperands.Count; i++)
            {
                Exprent rep = RemoveStringValueOf(lstOperands[i]);
                bool    ok  = (i > 1);
                if (!ok)
                {
                    bool isstr = rep.GetExprType().Equals(VarType.Vartype_String);
                    ok = isstr || first2str != i + 1;
                    if (i == 0)
                    {
                        first2str &= 2;
                    }
                }
                if (ok)
                {
                    lstOperands[i] = rep;
                }
            }
            return(CreateConcatExprent(lstOperands, expr.bytecode));
        }