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()); }
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()"); }