public void ShouldTranslateAComplexMethodArgument()
        {
            var intVariable        = Expression.Variable(typeof(int), "intValue");
            var dictionaryVariable = Expression.Variable(typeof(Dictionary <string, int>), "dictionary_String_IntValues");
            var tryGetValueMethod  = dictionaryVariable.Type.GetPublicInstanceMethod("TryGetValue", 2);
            var key             = Expression.Constant("NumberThatIWantToGet");
            var tryGetValueCall = Expression.Call(dictionaryVariable, tryGetValueMethod, key, intVariable);

            var defaultInt          = Expression.Default(typeof(int));
            var valueOrDefault      = Expression.Condition(tryGetValueCall, intVariable, defaultInt);
            var valueOrDefaultBlock = Expression.Block(new[] { intVariable }, valueOrDefault);

            var helperCtor = typeof(HelperClass).GetPublicInstanceConstructors().First();
            var helper     = Expression.New(helperCtor, defaultInt, defaultInt, defaultInt);
            var intsMethod = helper.Type.GetPublicInstanceMethod(nameof(HelperClass.GiveMeSomeInts));
            var methodCall = Expression.Call(helper, intsMethod, defaultInt, valueOrDefaultBlock, defaultInt);

            var translated = ToReadableString(methodCall);

            const string EXPECTED = @"
new HelperClass(default(int), default(int), default(int)).GiveMeSomeInts(
    default(int),
    {
        int intValue;
        return dictionary_String_IntValues.TryGetValue(""NumberThatIWantToGet"", out intValue)
            ? intValue
            : default(int);
    },
    default(int))";

            translated.ShouldBe(EXPECTED.TrimStart());
        }
        public void ShouldTranslateAVariableBlockLambdaWithAReturnExpression()
        {
            var listVariable = Expression.Variable(typeof(List <int>), "list");
            var createList   = CreateLambda(() => new List <int> {
                1, 2, 3
            });

            var listAssignment = Expression.Assign(listVariable, createList.Body);

            var toArrayMethod      = typeof(Enumerable).GetPublicStaticMethod("ToArray");
            var typedToArrayMethod = toArrayMethod.MakeGenericMethod(typeof(int));
            var listToArray        = Expression.Call(typedToArrayMethod, listVariable);

            var listBlock  = Expression.Block(new[] { listVariable }, listAssignment, listToArray);
            var listLambda = Expression.Lambda <Func <int[]> >(listBlock);

            var translated = ToReadableString(listLambda);

            const string EXPECTED = @"() =>
{
    var list = new List<int> { 1, 2, 3 };

    return list.ToArray();
}";

            translated.ShouldBe(EXPECTED.TrimStart());
        }
        public void ShouldSplitMultipleArgumentListsOntoMultipleLines()
        {
            var intsMethod = typeof(HelperClass)
                             .GetPublicInstanceMethod("GiveMeFourInts");

            var helperVariable = Expression.Variable(typeof(HelperClass), "helper");
            var intVariable    = Expression.Variable(typeof(int), "intVariable");

            var intsMethodCall = Expression.Call(
                helperVariable,
                intsMethod,
                intVariable,
                intVariable,
                intVariable,
                intVariable);

            var translated = ToReadableString(intsMethodCall);

            const string EXPECTED = @"
helper.GiveMeFourInts(
    intVariable,
    intVariable,
    intVariable,
    intVariable)";

            translated.ShouldBe(EXPECTED.TrimStart());
        }
        public void ShouldNotVarAssignAnOuterBlockDeclaredVariable()
        {
            var nameVariable           = Expression.Variable(typeof(string), "name");
            var writeNameTwiceVariable = Expression.Variable(typeof(Action), "writeNameTwice");
            var writeLine                = CreateLambda(() => Console.WriteLine(default(string)));
            var writeLineMethod          = ((MethodCallExpression)writeLine.Body).Method;
            var writeLineCall            = Expression.Call(writeLineMethod, nameVariable);
            var writeNameTwice           = Expression.Block(writeLineCall, writeLineCall);
            var writeNameTwiceLambda     = Expression.Lambda(writeNameTwice);
            var writeNameTwiceAssignment = Expression.Assign(writeNameTwiceVariable, writeNameTwiceLambda);
            var nameAssignment           = Expression.Assign(nameVariable, Expression.Constant("Alice"));
            var writeNameTwiceCall       = Expression.Invoke(writeNameTwiceVariable);

            var block = Expression.Block(
                new[] { nameVariable, writeNameTwiceVariable },
                Expression.Block(writeNameTwiceAssignment),
                Expression.Block(nameAssignment, writeNameTwiceCall));

            var translated = ToReadableString(block);

            const string EXPECTED = @"
string name;
Action writeNameTwice = () =>
{
    Console.WriteLine(name);
    Console.WriteLine(name);
};

name = ""Alice"";
writeNameTwice.Invoke();";

            translated.ShouldBe(EXPECTED.TrimStart());
        }
        public void ShouldIncludeRefParameterKeywords()
        {
            var helperVariable = Expression.Variable(typeof(IndexedProperty), "ip");
            var three          = Expression.Constant(3);
            var valueVariable  = Expression.Variable(typeof(object), "value");
            var tryGetMethod   = typeof(IndexedProperty).GetPublicInstanceMethod("RefGet");
            var tryGetCall     = Expression.Call(helperVariable, tryGetMethod, three, valueVariable);

            var translated = ToReadableString(tryGetCall);

            translated.ShouldBe("ip.RefGet(3, ref value)");
        }
        public void ShouldTranslateExplicitMethodOperatorUse()
        {
            var intVariable   = Expression.Variable(typeof(int), "i");
            var intOperator   = typeof(CustomAdder).GetExplicitOperator(o => o.To <int>());
            var adderInstance = Expression.New(typeof(CustomAdder).GetPublicInstanceConstructor());
            var operatorCall  = Expression.Call(intOperator, adderInstance);
            var assignment    = Expression.Assign(intVariable, operatorCall);

            var translated = ToReadableString(assignment);

            translated.ShouldBe("i = (int)new CustomAdder()");
        }
        public void ShouldTranslateImplicitMethodOperatorUse()
        {
            var stringVariable = Expression.Variable(typeof(string), "str");
            var stringOperator = typeof(CustomAdder).GetImplicitOperator(o => o.To <string>());
            var adderInstance  = Expression.New(typeof(CustomAdder).GetPublicInstanceConstructor());
            var operatorCall   = Expression.Call(stringOperator, adderInstance);
            var assignment     = Expression.Assign(stringVariable, operatorCall);

            var translated = ToReadableString(assignment);

            translated.ShouldBe("str = new CustomAdder()");
        }
        private static Expression GetReturnStatementBlock(out ParameterExpression existingInts)
        {
            existingInts = Expression.Variable(typeof(List <int>), "ints");

            var existingIntsEnumerator = Expression.Variable(typeof(List <int> .Enumerator), "enumerator");
            var getEnumeratorMethod    = existingInts.Type.GetPublicInstanceMethod("GetEnumerator");
            var getEnumeratorCall      = Expression.Call(existingInts, getEnumeratorMethod);
            var enumeratorAssignment   = Expression.Assign(existingIntsEnumerator, getEnumeratorCall);

            var enumeratorMoveNextMethod = existingIntsEnumerator.Type.GetPublicInstanceMethod("MoveNext");
            var enumeratorMoveNextCall   = Expression.Call(existingIntsEnumerator, enumeratorMoveNextMethod);

            var enumeratorItem    = Expression.Variable(typeof(int), "item");
            var enumeratorCurrent = Expression.Property(existingIntsEnumerator, "Current");
            var itemAssignment    = Expression.Assign(enumeratorItem, enumeratorCurrent);

            var intsAddMethod = existingInts.Type.GetPublicInstanceMethod("Add");
            var intsAddCall   = Expression.Call(existingInts, intsAddMethod, enumeratorItem);

            var addItemBlock = Expression.Block(
                new[] { enumeratorItem },
                itemAssignment,
                intsAddCall);

            var loopBreakTarget = Expression.Label(typeof(void), "LoopBreak");

            var conditionallyAddItems = Expression.Condition(
                Expression.IsTrue(enumeratorMoveNextCall),
                addItemBlock,
                Expression.Break(loopBreakTarget));

            var addItemsLoop = Expression.Loop(conditionallyAddItems, loopBreakTarget);

            var populateExistingInts = Expression.Block(
                new[] { existingIntsEnumerator },
                enumeratorAssignment,
                addItemsLoop);

            var conditionFalseBlock = Expression.Block(
                populateExistingInts,
                existingInts);

            var valueConditional = Expression.Condition(
                Expression.Equal(existingInts, Expression.Default(existingInts.Type)),
                Expression.New(conditionFalseBlock.Type),
                conditionFalseBlock);

            return(valueConditional);
        }
        public void ShouldNotTerminateMethodCallArguments()
        {
            var objectVariable     = Expression.Variable(typeof(object), "o");
            var objectCastToInt    = Expression.Convert(objectVariable, typeof(int));
            var intToStringMethod  = typeof(int).GetPublicInstanceMethods("ToString").First();
            var intToStringCall    = Expression.Call(objectCastToInt, intToStringMethod);
            var intToStringBlock   = Expression.Block(intToStringCall);
            var openTextFile       = CreateLambda((string str) => File.OpenText(str));
            var openTextFileMethod = ((MethodCallExpression)openTextFile.Body).Method;
            var openTextFileCall   = Expression.Call(openTextFileMethod, intToStringBlock);

            var translated = ToReadableString(openTextFileCall);

            translated.ShouldBe("File.OpenText(((int)o).ToString())");
        }
        public void ShouldTranslateMultilineBlockSingleMethodArguments()
        {
            var intVariable          = Expression.Variable(typeof(int), "i");
            var variableInit         = Expression.Assign(intVariable, Expression.Constant(3));
            var variableMultiplyFive = Expression.Multiply(intVariable, Expression.Constant(5));
            var variableAdditionOne  = Expression.Assign(intVariable, variableMultiplyFive);
            var variableDivideThree  = Expression.Divide(intVariable, Expression.Constant(3));
            var variableAdditionTwo  = Expression.Assign(intVariable, variableDivideThree);

            var argumentBlock = Expression.Block(
                new[] { intVariable },
                variableInit,
                variableAdditionOne,
                variableAdditionTwo,
                intVariable);

            var catchBlock = Expression.Catch(
                typeof(Exception),
                Expression.Block(ReadableExpression.Comment("So what!"), Expression.Constant(0)));

            var tryCatch = Expression.TryCatch(argumentBlock, catchBlock);

            var collectionVariable = Expression.Variable(typeof(ICollection <int>), "ints");
            var addMethod          = collectionVariable.Type.GetPublicInstanceMethod("Add");
            var addMethodCall      = Expression.Call(collectionVariable, addMethod, tryCatch);

            const string EXPECTED = @"
ints.Add(
{
    try
    {
        var i = 3;
        i = i * 5;
        i = i / 3;

        return i;
    }
    catch
    {
        // So what!
        return 0;
    }
})";

            var translated = ToReadableString(addMethodCall);

            translated.ShouldBe(EXPECTED.TrimStart());
        }
        public void ShouldTranslateAssignmentsOfNestedVariableBlocksWithANestedTernaryReturnValue()
        {
            var objectVariable = Expression.Variable(typeof(object), "id");
            var objectValue    = Expression.Variable(typeof(object), "value");
            var longVariable   = Expression.Variable(typeof(long), "number");
            var longValue      = Expression.Variable(typeof(long), "numberValue");

            var longTryParse = Expression.Call(
                null,
                typeof(long).GetPublicStaticMethod("TryParse", parameterCount: 2),
                Expression.Call(objectVariable, typeof(object).GetPublicInstanceMethod("ToString")),
                longValue);

            var objectNotNull = Expression.NotEqual(objectVariable, Expression.Default(typeof(object)));
            var defaultlong   = Expression.Default(typeof(long));

            var objectAslongOrDefault = Expression.Condition(
                objectNotNull,
                Expression.Condition(longTryParse, longValue, defaultlong),
                defaultlong);

            var longParseInnerBlock = Expression.Block(new[] { longValue }, objectAslongOrDefault);

            var longParseOuterBlock = Expression.Block(
                new[] { objectVariable },
                Expression.Assign(objectVariable, objectValue),
                longParseInnerBlock);

            var longAssignment = Expression.Assign(longVariable, longParseOuterBlock);

            var translated = ToReadableString(longAssignment);

            const string EXPECTED = @"
number =
{
    var id = value;

    long numberValue;
    return (id != null)
        ? long.TryParse(id.ToString(), out numberValue) ? numberValue : default(long)
        : default(long);
}";

            translated.ShouldBe(EXPECTED.TrimStart());
        }
Ejemplo n.º 12
0
        public void ShouldNotWrapMethodCallTernaryConditionsInParentheses()
        {
            var method = typeof(MethodCallHelper).GetPublicInstanceMethod("MultipleParameterMethod");

            var methodCall = Expression.Call(
                Expression.Variable(typeof(MethodCallHelper), "helper"),
                method,
                Expression.Constant("hello"),
                Expression.Constant(123));

            var ternary = Expression.Condition(
                methodCall,
                Expression.Constant(1),
                Expression.Constant(2));

            var translated = ToReadableString(ternary);

            translated.ShouldBe("helper.MultipleParameterMethod(\"hello\", 123) ? 1 : 2");
        }
        public void ShouldSplitLongArgumentListsOntoMultipleLines()
        {
            var intsMethod = typeof(HelperClass)
                             .GetPublicInstanceMethod("GiveMeSomeInts");

            var helperVariable = Expression.Variable(typeof(HelperClass), "helper");
            var longVariable   = Expression.Variable(typeof(int), "thisVariableReallyHasAVeryLongNameIndeed");
            var intsMethodCall = Expression.Call(helperVariable, intsMethod, longVariable, longVariable, longVariable);

            var translated = ToReadableString(intsMethodCall);

            const string EXPECTED = @"
helper.GiveMeSomeInts(
    thisVariableReallyHasAVeryLongNameIndeed,
    thisVariableReallyHasAVeryLongNameIndeed,
    thisVariableReallyHasAVeryLongNameIndeed)";

            translated.ShouldBe(EXPECTED.TrimStart());
        }
        public void ShouldAssignAVariableInAMethodCallArgument()
        {
            var stringVariable          = Expression.Variable(typeof(string), "value");
            var setStringVariableToNull = Expression.Assign(stringVariable, Expression.Default(typeof(string)));

            var intVariable = Expression.Variable(typeof(int), "i");

            var intToStringMethod = typeof(int)
                                    .GetMethods()
                                    .First(m =>
                                           (m.Name == "ToString") &&
                                           (m.GetParameters().FirstOrDefault()?.ParameterType == typeof(string)));

            var intToString = Expression.Call(intVariable, intToStringMethod, setStringVariableToNull);

            var translated = ToReadableString(intToString);

            translated.ShouldBe("i.ToString(value = null)");
        }
        public void ShouldTranslateAssignmentsOfNestedVariableBlocksWithATernaryReturnValue()
        {
            var objectVariable = Expression.Variable(typeof(object), "id");
            var objectValue    = Expression.Variable(typeof(object), "value");
            var intVariable    = Expression.Variable(typeof(int), "num");
            var intValue       = Expression.Variable(typeof(int), "numValue");

            var objectNotNull = Expression.NotEqual(objectVariable, Expression.Default(typeof(object)));
            var defaultInt    = Expression.Default(typeof(int));

            var intTryParse = Expression.Call(
                typeof(int).GetPublicStaticMethod("TryParse", parameterCount: 2),
                Expression.Condition(
                    objectNotNull,
                    Expression.Call(objectVariable, typeof(object).GetPublicInstanceMethod("ToString")),
                    Expression.Default(typeof(string))),
                intValue);

            var objectAsIntOrDefault = Expression.Condition(intTryParse, intValue, defaultInt);

            var intParseInnerBlock = Expression.Block(new[] { intValue }, objectAsIntOrDefault);

            var intParseOuterBlock = Expression.Block(
                new[] { objectVariable },
                Expression.Assign(objectVariable, objectValue),
                intParseInnerBlock);

            var intAssignment = Expression.Assign(intVariable, intParseOuterBlock);

            var translated = ToReadableString(intAssignment);

            const string EXPECTED = @"
num =
{
    var id = value;

    int numValue;
    return int.TryParse((id != null) ? id.ToString() : null, out numValue) ? numValue : default(int);
}";

            translated.ShouldBe(EXPECTED.TrimStart());
        }
        public void ShouldTranslatedMultipleLineValueBlockAssignments()
        {
            var linqSelect   = CreateLambda((string[] ints) => ints.Select(int.Parse));
            var selectMethod = ((MethodCallExpression)linqSelect.Body).Method;

            var getStringArray = CreateLambda(() => new[] { "1", "2", "blah" });
            var stringArray    = getStringArray.Body;

            // ReSharper disable once RedundantAssignment
            var intTryParse     = CreateLambda((string str, int value) => int.TryParse(str, out value) ? value : 0);
            var stringParameter = intTryParse.Parameters[0];
            var intVariable     = intTryParse.Parameters[1];
            var tryParseTernary = intTryParse.Body;

            var tryParseBlock  = Expression.Block(new[] { intVariable }, tryParseTernary);
            var tryParseLambda = Expression.Lambda <Func <string, int> >(tryParseBlock, stringParameter);

            var selectCall = Expression.Call(selectMethod, stringArray, tryParseLambda);

            var linqToArray   = CreateLambda((IEnumerable <int> ints) => ints.ToArray());
            var toArrayMethod = ((MethodCallExpression)linqToArray.Body).Method;

            var toArrayCall = Expression.Call(toArrayMethod, selectCall);

            var resultVariable  = Expression.Variable(typeof(IList <int>), "result");
            var assignment      = Expression.Assign(resultVariable, toArrayCall);
            var assignmentBlock = Expression.Block(assignment);

            var translation = ToReadableString(assignmentBlock);

            const string EXPECTED = @"
IList<int> result = new[] { ""1"", ""2"", ""blah"" }
    .Select(str =>
    {
        int value;
        return int.TryParse(str, out value) ? value : 0;
    })
    .ToArray();";

            translation.ShouldBe(EXPECTED.TrimStart());
        }
        public void ShouldOnlyRemoveParenthesesIfNecessary()
        {
            var intVariable      = Expression.Variable(typeof(int), "i");
            var intVariableIsOne = Expression.Equal(intVariable, Expression.Constant(1));

            var objectVariable    = Expression.Variable(typeof(object), "o");
            var objectCastToInt   = Expression.Convert(objectVariable, typeof(int));
            var intToStringMethod = typeof(object).GetPublicInstanceMethod("ToString");
            var intToStringCall   = Expression.Call(objectCastToInt, intToStringMethod);

            var emptyString = CreateLambda(() => string.Empty);

            var toStringOrEmptyString = Expression.Condition(
                intVariableIsOne,
                emptyString.Body,
                intToStringCall);

            var translated = ToReadableString(toStringOrEmptyString);

            translated.ShouldBe("(i == 1) ? string.Empty : ((int)o).ToString()");
        }