Example #1
0
        void ProcessInvocationExpression(InvocationExpression invocationExpression)
        {
            var method = invocationExpression.GetSymbol() as IMethod;

            if (method == null)
            {
                return;
            }
            var arguments = invocationExpression.Arguments.ToArray();

            // Reduce "String.Concat(a, b)" to "a + b"
            if (method.Name == "Concat" && method.DeclaringType.FullName == "System.String" && CheckArgumentsForStringConcat(arguments))
            {
                invocationExpression.Arguments.Clear();                 // detach arguments from invocationExpression
                Expression expr = arguments[0];
                for (int i = 1; i < arguments.Length; i++)
                {
                    expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]);
                }
                expr.CopyAnnotationsFrom(invocationExpression);
                invocationExpression.ReplaceWith(expr);
                return;
            }

            switch (method.FullName)
            {
            case "System.Type.GetTypeFromHandle":
                if (arguments.Length == 1)
                {
                    if (typeHandleOnTypeOfPattern.IsMatch(arguments[0]))
                    {
                        Expression target = ((MemberReferenceExpression)arguments[0]).Target;
                        target.CopyInstructionsFrom(invocationExpression);
                        invocationExpression.ReplaceWith(target);
                        return;
                    }
                }
                break;

            case "System.Reflection.FieldInfo.GetFieldFromHandle":
                if (arguments.Length == 1)
                {
                    MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression;
                    if (mre != null && mre.MemberName == "FieldHandle" && mre.Target.Annotation <LdTokenAnnotation>() != null)
                    {
                        invocationExpression.ReplaceWith(mre.Target);
                        return;
                    }
                }
                else if (arguments.Length == 2)
                {
                    MemberReferenceExpression mre1 = arguments[0] as MemberReferenceExpression;
                    MemberReferenceExpression mre2 = arguments[1] as MemberReferenceExpression;
                    if (mre1 != null && mre1.MemberName == "FieldHandle" && mre1.Target.Annotation <LdTokenAnnotation>() != null)
                    {
                        if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression)
                        {
                            Expression     oldArg = ((InvocationExpression)mre1.Target).Arguments.Single();
                            FieldReference field  = oldArg.Annotation <FieldReference>();
                            if (field != null)
                            {
                                AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach();
                                oldArg.ReplaceWith(new MemberReferenceExpression(new TypeReferenceExpression(declaringType), field.Name).CopyAnnotationsFrom(oldArg));
                                invocationExpression.ReplaceWith(mre1.Target);
                                return;
                            }
                        }
                    }
                }
                break;

            case "System.Activator.CreateInstance":
                if (arguments.Length == 0 && method.TypeArguments.Count == 1 && IsInstantiableTypeParameter(method.TypeArguments[0]))
                {
                    invocationExpression.ReplaceWith(new ObjectCreateExpression(context.TypeSystemAstBuilder.ConvertType(method.TypeArguments.First())));
                }
                break;

            case "System.String.Format":
                if (context.Settings.StringInterpolation && arguments.Length > 1 &&
                    arguments[0] is PrimitiveExpression stringExpression && stringExpression.Value is string &&
                    arguments.Skip(1).All(a => !a.DescendantsAndSelf.OfType <PrimitiveExpression>().Any(p => p.Value is string)))
                {
                    var tokens = new List <(TokenKind, int, string)>();
                    int i      = 0;
                    foreach (var(kind, data) in TokenizeFormatString((string)stringExpression.Value))
                    {
                        int index;
                        switch (kind)
                        {
                        case TokenKind.Error:
                            return;

                        case TokenKind.String:
                            tokens.Add((kind, -1, data));
                            break;

                        case TokenKind.Argument:
                            if (!int.TryParse(data, out index) || index != i)
                            {
                                return;
                            }
                            i++;
                            tokens.Add((kind, index, null));
                            break;

                        case TokenKind.ArgumentWithFormat:
                            string[] arg = data.Split(new[] { ':' }, 2);
                            if (arg.Length != 2 || arg[1].Length == 0)
                            {
                                return;
                            }
                            if (!int.TryParse(arg[0], out index) || index != i)
                            {
                                return;
                            }
                            i++;
                            tokens.Add((kind, index, arg[1]));
                            break;
        void ProcessInvocationExpression(InvocationExpression invocationExpression)
        {
            var method = invocationExpression.GetSymbol() as IMethod;

            if (method == null)
            {
                return;
            }
            var arguments = invocationExpression.Arguments.ToArray();

            // Reduce "String.Concat(a, b)" to "a + b"
            if (IsStringConcat(method) && CheckArgumentsForStringConcat(arguments))
            {
                bool isInExpressionTree = invocationExpression.Ancestors.OfType <LambdaExpression>().Any(
                    lambda => lambda.Annotation <IL.ILFunction>()?.Kind == IL.ILFunctionKind.ExpressionTree);
                Expression expr = arguments[0].Detach();
                if (!isInExpressionTree)
                {
                    expr = RemoveRedundantToStringInConcat(expr, method, isLastArgument: false).Detach();
                }
                for (int i = 1; i < arguments.Length; i++)
                {
                    var arg = arguments[i].Detach();
                    if (!isInExpressionTree)
                    {
                        arg = RemoveRedundantToStringInConcat(arg, method, isLastArgument: i == arguments.Length - 1).Detach();
                    }
                    expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arg);
                }
                expr.CopyAnnotationsFrom(invocationExpression);
                invocationExpression.ReplaceWith(expr);
                return;
            }

            switch (method.FullName)
            {
            case "System.Type.GetTypeFromHandle":
                if (arguments.Length == 1)
                {
                    if (typeHandleOnTypeOfPattern.IsMatch(arguments[0]))
                    {
                        Expression target = ((MemberReferenceExpression)arguments[0]).Target;
                        target.CopyInstructionsFrom(invocationExpression);
                        invocationExpression.ReplaceWith(target);
                        return;
                    }
                }
                break;

            /*
             * case "System.Reflection.FieldInfo.GetFieldFromHandle":
             * // TODO : This is dead code because LdTokenAnnotation is not added anywhere:
             * if (arguments.Length == 1) {
             *      MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression;
             *      if (mre != null && mre.MemberName == "FieldHandle" && mre.Target.Annotation<LdTokenAnnotation>() != null) {
             *              invocationExpression.ReplaceWith(mre.Target);
             *              return;
             *      }
             * } else if (arguments.Length == 2) {
             *      MemberReferenceExpression mre1 = arguments[0] as MemberReferenceExpression;
             *      MemberReferenceExpression mre2 = arguments[1] as MemberReferenceExpression;
             *      if (mre1 != null && mre1.MemberName == "FieldHandle" && mre1.Target.Annotation<LdTokenAnnotation>() != null) {
             *              if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression) {
             *                      Expression oldArg = ((InvocationExpression)mre1.Target).Arguments.Single();
             *                      FieldReference field = oldArg.Annotation<FieldReference>();
             *                      if (field != null) {
             *                              AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach();
             *                              oldArg.ReplaceWith(new MemberReferenceExpression(new TypeReferenceExpression(declaringType), field.Name).CopyAnnotationsFrom(oldArg));
             *                              invocationExpression.ReplaceWith(mre1.Target);
             *                              return;
             *                      }
             *              }
             *      }
             * }
             * break;
             */
            case "System.Activator.CreateInstance":
                if (arguments.Length == 0 && method.TypeArguments.Count == 1 && IsInstantiableTypeParameter(method.TypeArguments[0]))
                {
                    invocationExpression.ReplaceWith(new ObjectCreateExpression(context.TypeSystemAstBuilder.ConvertType(method.TypeArguments.First())));
                }
                break;
            }

            BinaryOperatorType?bop = GetBinaryOperatorTypeFromMetadataName(method.Name);

            if (bop != null && arguments.Length == 2)
            {
                invocationExpression.Arguments.Clear();                 // detach arguments from invocationExpression
                invocationExpression.ReplaceWith(
                    new BinaryOperatorExpression(
                        arguments[0].UnwrapInDirectionExpression(),
                        bop.Value,
                        arguments[1].UnwrapInDirectionExpression()
                        ).CopyAnnotationsFrom(invocationExpression)
                    );
                return;
            }
            UnaryOperatorType?uop = GetUnaryOperatorTypeFromMetadataName(method.Name);

            if (uop != null && arguments.Length == 1)
            {
                if (uop == UnaryOperatorType.Increment || uop == UnaryOperatorType.Decrement)
                {
                    // `op_Increment(a)` is not equivalent to `++a`,
                    // because it doesn't assign the incremented value to a.
                    if (method.DeclaringType.IsKnownType(KnownTypeCode.Decimal))
                    {
                        // Legacy csc optimizes "d + 1m" to "op_Increment(d)",
                        // so reverse that optimization here:
                        invocationExpression.ReplaceWith(
                            new BinaryOperatorExpression(
                                arguments[0].UnwrapInDirectionExpression().Detach(),
                                (uop == UnaryOperatorType.Increment ? BinaryOperatorType.Add : BinaryOperatorType.Subtract),
                                new PrimitiveExpression(1m)
                                ).CopyAnnotationsFrom(invocationExpression)
                            );
                    }
                    return;
                }
                arguments[0].Remove();                 // detach argument
                invocationExpression.ReplaceWith(
                    new UnaryOperatorExpression(uop.Value, arguments[0].UnwrapInDirectionExpression()).CopyAnnotationsFrom(invocationExpression)
                    );
                return;
            }
            if (method.Name == "op_Explicit" && arguments.Length == 1)
            {
                arguments[0].Remove();                 // detach argument
                invocationExpression.ReplaceWith(
                    new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.ReturnType), arguments[0].UnwrapInDirectionExpression())
                    .CopyAnnotationsFrom(invocationExpression)
                    );
                return;
            }
            if (method.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == Roles.Condition)
            {
                invocationExpression.ReplaceWith(arguments[0].UnwrapInDirectionExpression());
                return;
            }

            return;
        }
        void ProcessInvocationExpression(InvocationExpression invocationExpression)
        {
            var method = invocationExpression.GetSymbol() as IMethod;

            if (method == null)
            {
                return;
            }
            var arguments = invocationExpression.Arguments.ToArray();

            // Reduce "String.Concat(a, b)" to "a + b"
            if (method.Name == "Concat" && method.DeclaringType.FullName == "System.String" && CheckArgumentsForStringConcat(arguments))
            {
                invocationExpression.Arguments.Clear();                 // detach arguments from invocationExpression
                Expression expr = arguments[0];
                for (int i = 1; i < arguments.Length; i++)
                {
                    expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]);
                }
                expr.CopyAnnotationsFrom(invocationExpression);
                invocationExpression.ReplaceWith(expr);
                return;
            }

            switch (method.FullName)
            {
            case "System.Type.GetTypeFromHandle":
                if (arguments.Length == 1)
                {
                    if (typeHandleOnTypeOfPattern.IsMatch(arguments[0]))
                    {
                        Expression target = ((MemberReferenceExpression)arguments[0]).Target;
                        target.CopyInstructionsFrom(invocationExpression);
                        invocationExpression.ReplaceWith(target);
                        return;
                    }
                }
                break;

            /*
             * case "System.Reflection.FieldInfo.GetFieldFromHandle":
             * // TODO : This is dead code because LdTokenAnnotation is not added anywhere:
             * if (arguments.Length == 1) {
             *      MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression;
             *      if (mre != null && mre.MemberName == "FieldHandle" && mre.Target.Annotation<LdTokenAnnotation>() != null) {
             *              invocationExpression.ReplaceWith(mre.Target);
             *              return;
             *      }
             * } else if (arguments.Length == 2) {
             *      MemberReferenceExpression mre1 = arguments[0] as MemberReferenceExpression;
             *      MemberReferenceExpression mre2 = arguments[1] as MemberReferenceExpression;
             *      if (mre1 != null && mre1.MemberName == "FieldHandle" && mre1.Target.Annotation<LdTokenAnnotation>() != null) {
             *              if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression) {
             *                      Expression oldArg = ((InvocationExpression)mre1.Target).Arguments.Single();
             *                      FieldReference field = oldArg.Annotation<FieldReference>();
             *                      if (field != null) {
             *                              AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach();
             *                              oldArg.ReplaceWith(new MemberReferenceExpression(new TypeReferenceExpression(declaringType), field.Name).CopyAnnotationsFrom(oldArg));
             *                              invocationExpression.ReplaceWith(mre1.Target);
             *                              return;
             *                      }
             *              }
             *      }
             * }
             * break;
             */
            case "System.Activator.CreateInstance":
                if (arguments.Length == 0 && method.TypeArguments.Count == 1 && IsInstantiableTypeParameter(method.TypeArguments[0]))
                {
                    invocationExpression.ReplaceWith(new ObjectCreateExpression(context.TypeSystemAstBuilder.ConvertType(method.TypeArguments.First())));
                }
                break;
            }

            BinaryOperatorType?bop = GetBinaryOperatorTypeFromMetadataName(method.Name);

            if (bop != null && arguments.Length == 2)
            {
                invocationExpression.Arguments.Clear();                 // detach arguments from invocationExpression
                invocationExpression.ReplaceWith(
                    new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).CopyAnnotationsFrom(invocationExpression)
                    );
                return;
            }
            UnaryOperatorType?uop = GetUnaryOperatorTypeFromMetadataName(method.Name);

            if (uop != null && arguments.Length == 1)
            {
                arguments[0].Remove();                 // detach argument
                invocationExpression.ReplaceWith(
                    new UnaryOperatorExpression(uop.Value, arguments[0]).CopyAnnotationsFrom(invocationExpression)
                    );
                return;
            }
            if (method.Name == "op_Explicit" && arguments.Length == 1)
            {
                arguments[0].Remove();                 // detach argument
                invocationExpression.ReplaceWith(
                    new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.ReturnType), arguments[0])
                    .CopyAnnotationsFrom(invocationExpression)
                    );
                return;
            }
            if (method.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == Roles.Condition)
            {
                invocationExpression.ReplaceWith(arguments[0]);
                return;
            }

            return;
        }