diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 178b7311d..7f4740b59 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -1063,7 +1063,7 @@ namespace ICSharpCode.Decompiler.Ast } } - static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef) + internal static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef) { TypeDefinition typeDef = cecilMethodDef.DeclaringType; string indexerName = null; diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs b/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs index adedbf744..e294c8193 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs @@ -81,13 +81,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms case "AndAssign": return ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseAnd); case "ArrayAccess": + return NotImplemented(invocation); case "ArrayIndex": + return ConvertArrayIndex(invocation); case "ArrayLength": - return NotImplemented(invocation); + return ConvertArrayLength(invocation); case "Assign": return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Assign); case "Call": - return NotImplemented(invocation); + return ConvertCall(invocation); case "Coalesce": return ConvertBinaryOperator(invocation, BinaryOperatorType.NullCoalescing); case "Condition": @@ -98,7 +100,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms else return NotSupported(expr); case "Convert": + return ConvertCast(invocation, false); case "ConvertChecked": + return ConvertCast(invocation, true); case "Default": return NotImplemented(invocation); case "Divide": @@ -117,6 +121,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms return ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThan); case "GreaterThanOrEqual": return ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThanOrEqual); + case "Invoke": + return ConvertInvoke(invocation); case "Lambda": return ConvertLambda(invocation); case "LeftShift": @@ -140,22 +146,27 @@ namespace ICSharpCode.Decompiler.Ast.Transforms case "MultiplyAssignChecked": return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, true); case "Negate": + return ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, false); case "NegateChecked": - return NotImplemented(invocation); + return ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, true); case "New": return ConvertNewObject(invocation); + case "NewArrayInit": + return ConvertNewArrayInit(invocation); case "Not": - return NotImplemented(invocation); + return ConvertUnaryOperator(invocation, UnaryOperatorType.Not); case "NotEqual": return ConvertBinaryOperator(invocation, BinaryOperatorType.InEquality); case "OnesComplement": - return NotImplemented(invocation); + return ConvertUnaryOperator(invocation, UnaryOperatorType.BitNot); case "Or": return ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseOr); case "OrAssign": return ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseOr); case "OrElse": return ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalOr); + case "Property": + return ConvertProperty(invocation); case "Quote": return NotImplemented(invocation); case "RightShift": @@ -241,7 +252,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms #region Convert Field static readonly Expression getFieldFromHandlePattern = - new TypePattern(typeof(FieldInfo)).ToType().Invoke("GetFieldFromHandle", new LdTokenPattern("field").ToExpression().Member("FieldHandle")); + new TypePattern(typeof(FieldInfo)).ToType().Invoke( + "GetFieldFromHandle", + new LdTokenPattern("field").ToExpression().Member("FieldHandle"), + new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) + ); Expression ConvertField(InvocationExpression invocation) { @@ -257,18 +272,155 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (fr == null) return null; - Expression target = Convert(invocation.Arguments.ElementAt(0)); - if (target == null) + Expression target = invocation.Arguments.ElementAt(0); + Expression convertedTarget; + if (target is NullReferenceExpression) { + if (m.Has("declaringType")) + convertedTarget = new TypeReferenceExpression(m.Get("declaringType").Single().Clone()); + else + convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(fr.DeclaringType)); + } else { + convertedTarget = Convert(target); + if (convertedTarget == null) + return null; + } + + return convertedTarget.Member(fr.Name).WithAnnotation(fr); + } + #endregion + + #region Convert Property + static readonly Expression getMethodFromHandlePattern = + new TypePattern(typeof(MethodBase)).ToType().Invoke( + "GetMethodFromHandle", + new LdTokenPattern("method").ToExpression().Member("MethodHandle"), + new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) + ).CastTo(new TypePattern(typeof(MethodInfo))); + + Expression ConvertProperty(InvocationExpression invocation) + { + if (invocation.Arguments.Count != 2) + return NotSupported(invocation); + + Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); + if (!m.Success) + return NotSupported(invocation); + + MethodReference mr = m.Get("method").Single().Annotation(); + if (mr == null) return null; - return target.Member(fr.Name).WithAnnotation(fr); + Expression target = invocation.Arguments.ElementAt(0); + Expression convertedTarget; + if (target is NullReferenceExpression) { + if (m.Has("declaringType")) + convertedTarget = new TypeReferenceExpression(m.Get("declaringType").Single().Clone()); + else + convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType)); + } else { + convertedTarget = Convert(target); + if (convertedTarget == null) + return null; + } + + string name = mr.Name; + if (name.StartsWith("get_", StringComparison.Ordinal) || name.StartsWith("set_", StringComparison.Ordinal)) + name = name.Substring(4); + return convertedTarget.Member(name).WithAnnotation(mr); + } + #endregion + + #region Convert Call + Expression ConvertCall(InvocationExpression invocation) + { + if (invocation.Arguments.Count < 2) + return NotSupported(invocation); + + Expression target; + int firstArgumentPosition; + + Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(0)); + if (m.Success) { + target = null; + firstArgumentPosition = 1; + } else { + m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); + if (!m.Success) + return NotSupported(invocation); + target = invocation.Arguments.ElementAt(0); + firstArgumentPosition = 2; + } + + MethodReference mr = m.Get("method").Single().Annotation(); + if (mr == null) + return null; + + Expression convertedTarget; + if (target == null || target is NullReferenceExpression) { + // static method + if (m.Has("declaringType")) + convertedTarget = new TypeReferenceExpression(m.Get("declaringType").Single().Clone()); + else + convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType)); + } else { + convertedTarget = Convert(target); + if (convertedTarget == null) + return null; + } + + MemberReferenceExpression mre = convertedTarget.Member(mr.Name); + GenericInstanceMethod gim = mr as GenericInstanceMethod; + if (gim != null) { + foreach (TypeReference tr in gim.GenericArguments) { + mre.TypeArguments.Add(AstBuilder.ConvertType(tr)); + } + } + IList arguments = null; + if (invocation.Arguments.Count == firstArgumentPosition + 1) { + Expression argumentArray = invocation.Arguments.ElementAt(firstArgumentPosition); + arguments = ConvertExpressionsArray(argumentArray); + } + if (arguments == null) { + arguments = new List(); + foreach (Expression argument in invocation.Arguments.Skip(firstArgumentPosition)) { + Expression convertedArgument = Convert(argument); + if (convertedArgument == null) + return null; + arguments.Add(convertedArgument); + } + } + MethodDefinition methodDef = mr.Resolve(); + if (methodDef != null && methodDef.IsGetter) { + PropertyDefinition indexer = AstMethodBodyBuilder.GetIndexer(methodDef); + if (indexer != null) + return new IndexerExpression(mre.Target.Detach(), arguments).WithAnnotation(indexer); + } + return new InvocationExpression(mre, arguments).WithAnnotation(mr); + } + + Expression ConvertInvoke(InvocationExpression invocation) + { + if (invocation.Arguments.Count != 2) + return NotSupported(invocation); + + Expression convertedTarget = Convert(invocation.Arguments.ElementAt(0)); + IList convertedArguments = ConvertExpressionsArray(invocation.Arguments.ElementAt(1)); + if (convertedTarget != null && convertedArguments != null) + return new InvocationExpression(convertedTarget, convertedArguments); + else + return null; } #endregion #region Convert Binary Operator + static readonly Pattern trueOrFalse = new Choice { + new PrimitiveExpression(true), + new PrimitiveExpression(false) + }; + Expression ConvertBinaryOperator(InvocationExpression invocation, BinaryOperatorType op, bool? isChecked = null) { - if (invocation.Arguments.Count != 2) + if (invocation.Arguments.Count < 2) return NotSupported(invocation); Expression left = Convert(invocation.Arguments.ElementAt(0)); @@ -281,15 +433,66 @@ namespace ICSharpCode.Decompiler.Ast.Transforms BinaryOperatorExpression boe = new BinaryOperatorExpression(left, op, right); if (isChecked != null) boe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); - return boe; + + switch (invocation.Arguments.Count) { + case 2: + return boe; + case 3: + Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(2)); + if (m.Success) + return boe.WithAnnotation(m.Get("method").Single().Annotation()); + else + return null; + case 4: + if (!trueOrFalse.IsMatch(invocation.Arguments.ElementAt(2))) + return null; + m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(3)); + if (m.Success) + return boe.WithAnnotation(m.Get("method").Single().Annotation()); + else + return null; + default: + return NotSupported(invocation); + } } + #endregion + #region Convert Assignment Operator Expression ConvertAssignmentOperator(InvocationExpression invocation, AssignmentOperatorType op, bool? isChecked = null) { return NotImplemented(invocation); } #endregion + #region Convert Unary Operator + Expression ConvertUnaryOperator(InvocationExpression invocation, UnaryOperatorType op, bool? isChecked = null) + { + if (invocation.Arguments.Count < 1) + return NotSupported(invocation); + + Expression expr = Convert(invocation.Arguments.ElementAt(0)); + if (expr == null) + return null; + + UnaryOperatorExpression uoe = new UnaryOperatorExpression(op, expr); + if (isChecked != null) + uoe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); + + switch (invocation.Arguments.Count) { + case 1: + return uoe; + case 2: + Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); + if (m.Success) + return uoe.WithAnnotation(m.Get("method").Single().Annotation()); + else + return null; + default: + return NotSupported(invocation); + } + } + #endregion + #region Convert New Object static readonly Expression newObjectCtorPattern = new TypePattern(typeof(MethodBase)).ToType().Invoke ( @@ -311,16 +514,19 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (ctor == null) return null; + AstType declaringTypeNode; TypeReference declaringType; if (m.Has("declaringType")) { - declaringType = m.Get("declaringType").Single().Annotation(); + declaringTypeNode = m.Get("declaringType").Single().Clone(); + declaringType = declaringTypeNode.Annotation(); } else { + declaringTypeNode = AstBuilder.ConvertType(ctor.DeclaringType); declaringType = ctor.DeclaringType; } - if (declaringType == null) + if (declaringTypeNode == null) return null; - ObjectCreateExpression oce = new ObjectCreateExpression(AstBuilder.ConvertType(declaringType)); + ObjectCreateExpression oce = new ObjectCreateExpression(declaringTypeNode); if (invocation.Arguments.Count >= 2) { IList arguments = ConvertExpressionsArray(invocation.Arguments.ElementAtOrDefault(1)); if (arguments == null) @@ -351,6 +557,22 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } #endregion + #region Convert Cast + Expression ConvertCast(InvocationExpression invocation, bool isChecked) + { + if (invocation.Arguments.Count != 2) + return null; + Expression converted = Convert(invocation.Arguments.ElementAt(0)); + AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); + if (converted != null && type != null) { + CastExpression cast = converted.CastTo(type); + cast.AddAnnotation(isChecked ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); + return cast; + } + return null; + } + #endregion + #region ConvertExpressionsArray static readonly Pattern expressionArrayPattern = new Choice { new ArrayCreateExpression { @@ -386,16 +608,23 @@ namespace ICSharpCode.Decompiler.Ast.Transforms #region Convert TypeAs/TypeIs static readonly TypeOfPattern typeOfPattern = new TypeOfPattern("type"); + AstType ConvertTypeReference(Expression typeOfExpression) + { + Match m = typeOfPattern.Match(typeOfExpression); + if (m.Success) + return m.Get("type").Single().Clone(); + else + return null; + } + Expression ConvertTypeAs(InvocationExpression invocation) { if (invocation.Arguments.Count != 2) return null; - Match m = typeOfPattern.Match(invocation.Arguments.ElementAt(1)); - if (m.Success) { - Expression converted = Convert(invocation.Arguments.First()); - if (converted != null) - return new AsExpression(converted, m.Get("type").Single().Clone()); - } + Expression converted = Convert(invocation.Arguments.ElementAt(0)); + AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); + if (converted != null && type != null) + return new AsExpression(converted, type); return null; } @@ -403,15 +632,61 @@ namespace ICSharpCode.Decompiler.Ast.Transforms { if (invocation.Arguments.Count != 2) return null; - Match m = typeOfPattern.Match(invocation.Arguments.ElementAt(1)); - if (m.Success) { - Expression converted = Convert(invocation.Arguments.First()); - if (converted != null) { - return new IsExpression { - Expression = converted, - Type = m.Get("type").Single().Clone() - }; - } + Expression converted = Convert(invocation.Arguments.ElementAt(0)); + AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); + if (converted != null && type != null) + return new IsExpression { Expression = converted, Type = type }; + return null; + } + #endregion + + #region Convert Array + Expression ConvertArrayIndex(InvocationExpression invocation) + { + if (invocation.Arguments.Count != 2) + return NotSupported(invocation); + + Expression targetConverted = Convert(invocation.Arguments.First()); + if (targetConverted == null) + return null; + + Expression index = invocation.Arguments.ElementAt(1); + Expression indexConverted = Convert(index); + if (indexConverted != null) { + return new IndexerExpression(targetConverted, indexConverted); + } + IList indexesConverted = ConvertExpressionsArray(index); + if (indexConverted != null) { + return new IndexerExpression(targetConverted, indexesConverted); + } + return null; + } + + Expression ConvertArrayLength(InvocationExpression invocation) + { + if (invocation.Arguments.Count != 1) + return NotSupported(invocation); + + Expression targetConverted = Convert(invocation.Arguments.Single()); + if (targetConverted != null) + return targetConverted.Member("Length"); + else + return null; + } + + Expression ConvertNewArrayInit(InvocationExpression invocation) + { + if (invocation.Arguments.Count != 2) + return NotSupported(invocation); + + AstType elementType = ConvertTypeReference(invocation.Arguments.ElementAt(0)); + IList elements = ConvertExpressionsArray(invocation.Arguments.ElementAt(1)); + if (elementType != null && elements != null) { + return new ArrayCreateExpression { + Type = elementType, + AdditionalArraySpecifiers = { new ArraySpecifier() }, + Initializer = new ArrayInitializerExpression(elements) + }; } return null; } diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs b/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs index 59999e3fa..4561da817 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using ICSharpCode.NRefactory.PatternMatching; using Mono.Cecil; using Ast = ICSharpCode.NRefactory.CSharp; @@ -50,15 +51,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) { base.VisitInvocationExpression(invocationExpression, data); - - return ProcessInvocationExpression(invocationExpression); + ProcessInvocationExpression(invocationExpression); + return null; } - internal static object ProcessInvocationExpression(InvocationExpression invocationExpression) - { + internal static void ProcessInvocationExpression(InvocationExpression invocationExpression) + { MethodReference methodRef = invocationExpression.Annotation(); if (methodRef == null) - return null; + return; var arguments = invocationExpression.Arguments.ToArray(); // Reduce "String.Concat(a, b)" to "a + b" @@ -70,7 +71,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]); } invocationExpression.ReplaceWith(expr); - return null; + return; } switch (methodRef.FullName) { @@ -78,7 +79,34 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (arguments.Length == 1) { if (typeHandleOnTypeOfPattern.IsMatch(arguments[0])) { invocationExpression.ReplaceWith(((MemberReferenceExpression)arguments[0]).Target); - return null; + return; + } + } + break; + case "System.Reflection.FieldInfo System.Reflection.FieldInfo::GetFieldFromHandle(System.RuntimeFieldHandle)": + if (arguments.Length == 1) { + MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression; + if (mre != null && mre.MemberName == "FieldHandle" && mre.Target.Annotation() != null) { + invocationExpression.ReplaceWith(mre.Target); + return; + } + } + break; + case "System.Reflection.FieldInfo System.Reflection.FieldInfo::GetFieldFromHandle(System.RuntimeFieldHandle,System.RuntimeTypeHandle)": + 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() != null) { + if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression) { + Expression oldArg = ((InvocationExpression)mre1.Target).Arguments.Single(); + FieldReference field = oldArg.Annotation(); + if (field != null) { + AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach(); + oldArg.ReplaceWith(declaringType.Member(field.Name).WithAnnotation(field)); + invocationExpression.ReplaceWith(mre1.Target); + return; + } + } } } break; @@ -90,7 +118,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms invocationExpression.ReplaceWith( new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).WithAnnotation(methodRef) ); - return null; + return; } UnaryOperatorType? uop = GetUnaryOperatorTypeFromMetadataName(methodRef.Name); if (uop != null && arguments.Length == 1) { @@ -98,7 +126,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms invocationExpression.ReplaceWith( new UnaryOperatorExpression(uop.Value, arguments[0]).WithAnnotation(methodRef) ); - return null; + return; } if (methodRef.Name == "op_Explicit" && arguments.Length == 1) { arguments[0].Remove(); // detach argument @@ -106,18 +134,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms arguments[0].CastTo(AstBuilder.ConvertType(methodRef.ReturnType, methodRef.MethodReturnType)) .WithAnnotation(methodRef) ); - return null; + return; } if (methodRef.Name == "op_Implicit" && arguments.Length == 1) { invocationExpression.ReplaceWith(arguments[0]); - return null; + return; } if (methodRef.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == AstNode.Roles.Condition) { invocationExpression.ReplaceWith(arguments[0]); - return null; + return; } - return null; + return; } static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name) @@ -292,6 +320,34 @@ namespace ICSharpCode.Decompiler.Ast.Transforms return left is ThisReferenceExpression || left is IdentifierExpression || left is TypeReferenceExpression || left is BaseReferenceExpression; } + static readonly Expression getMethodOrConstructorFromHandlePattern = + new TypePattern(typeof(MethodBase)).ToType().Invoke( + "GetMethodFromHandle", + new NamedNode("ldtokenNode", new LdTokenPattern("method")).ToExpression().Member("MethodHandle"), + new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) + ).CastTo(new Choice { + new TypePattern(typeof(MethodInfo)), + new TypePattern(typeof(ConstructorInfo)) + }); + + public override object VisitCastExpression(CastExpression castExpression, object data) + { + base.VisitCastExpression(castExpression, data); + // Handle methodof + Match m = getMethodOrConstructorFromHandlePattern.Match(castExpression); + if (m.Success) { + MethodReference method = m.Get("method").Single().Annotation(); + if (m.Has("declaringType")) { + Expression newNode = m.Get("declaringType").Single().Detach().Member(method.Name); + newNode = newNode.Invoke(method.Parameters.Select(p => new TypeReferenceExpression(AstBuilder.ConvertType(p.ParameterType, p)))); + newNode.AddAnnotation(method); + m.Get("method").Single().ReplaceWith(newNode); + } + castExpression.ReplaceWith(m.Get("ldtokenNode").Single()); + } + return null; + } + void IAstTransform.Run(AstNode node) { node.AcceptVisitor(this, null); diff --git a/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs b/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs index e52eb4d0a..9d325e9e9 100644 --- a/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs +++ b/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs @@ -22,324 +22,349 @@ using System.Linq; using System.Linq.Expressions; using System.Xml; -namespace ICSharpCode.Decompiler.Tests +public class ExpressionTrees { - public class ExpressionTrees + class GenericClass { - int field; + public static X StaticField; + public X InstanceField; + public static X StaticProperty { get; set; } + public X InstanceProperty { get; set; } - static object ToCode(object x, Expression> expr) + public static bool GenericMethod() { - return expr; - } - - static object ToCode(object x, Expression> expr) - { - return expr; - } - - static object X() - { - return null; - } - - public void Parameter(bool a) - { - ToCode(X(), () => a); - } - - public void LocalVariable() - { - bool a = true; - ToCode(X(), () => a); - } - - public void LambdaParameter() - { - ToCode(X(), (bool a) => a); - } - - public void AddOperator(int x) - { - ToCode(X(), () => 1 + x + 2); - } - - public void AnonymousClasses() - { - ToCode(X(), () => new { X = 3, A = "a" }); - } - - public void ArrayIndex() - { - ToCode(X(), () => new[] { 3, 4, 5 }[0 + (int)(DateTime.Now.Ticks % 3)]); - } - - public void ArrayLengthAndDoubles() - { - ToCode(X(), () => new[] { 1.0, 2.01, 3.5 }.Concat(new[] { 1.0, 2.0 }).ToArray().Length); - } - - public void AsOperator() - { - ToCode(X(), () => new object() as string); - } - - public void ComplexGenericName() - { - ToCode(X(), () => ((Func)(x => x > 0))(0)); - } - - public void DefaultValue() - { - ToCode(X(), () => new TimeSpan(1, 2, 3) == default(TimeSpan)); - } - - public void EnumConstant() - { - ToCode(X(), () => new object().Equals(MidpointRounding.ToEven)); - } - - public void IndexerAccess() - { - var dict = Enumerable.Range(1, 20).ToDictionary(n => n.ToString()); - ToCode(X(), () => dict["3"] == 3); - } - - public void IsOperator() - { - ToCode(X(), () => new object() is string); - } - - public void ListInitializer() - { - ToCode(X(), () => new Dictionary { { 1, 1 }, { 2, 2 }, { 3, 4 } }.Count == 3); - } - - public void ListInitializer2() - { - ToCode(X(), () => new List(50) { 1, 2, 3 }.Count == 3); - } - - public void ListInitializer3() - { - ToCode(X(), () => new List { 1, 2, 3 }.Count == 3); - } - - public void LiteralCharAndProperty() - { - ToCode(X(), () => new string(' ', 3).Length == 1); - } - - public void CharNoCast() - { - ToCode(X(), () => "abc"[1] == 'b'); - } - - public void StringsImplicitCast() - { - int i = 1; - string x = "X"; - ToCode(X(), () => (("a\n\\b" ?? x) + x).Length == 2 ? false : true && (1m + -i > 0 || false)); - } - - public void NotImplicitCast() - { - byte z = 42; - ToCode(X(), () => ~z == 0); - } - - public void MembersBuiltin() - { - ToCode(X(), () => 1.23m.ToString()); - ToCode(X(), () => AttributeTargets.All.HasFlag((Enum)AttributeTargets.Assembly)); - ToCode(X(), () => "abc".Length == 3); - ToCode(X(), () => 'a'.CompareTo('b') < 0); - } - - public void MembersDefault() - { - ToCode(X(), () => default(DateTime).Ticks == 0); - ToCode(X(), () => default(int[]).Length == 0); - ToCode(X(), () => default(Type).IsLayoutSequential); - ToCode(X(), () => default(List).Count); - ToCode(X(), () => default(int[]).Clone() == null); - ToCode(X(), () => default(Type).IsInstanceOfType(new object())); - ToCode(X(), () => default(List).AsReadOnly()); - } - - public void DoAssert() - { - field = 37; - ToCode(X(), () => field != C()); - ToCode(X(), () => !ReferenceEquals(this, new ExpressionTrees())); - ToCode(X(), () => MyEquals(this) && !MyEquals(default(ExpressionTrees))); - } - - int C() - { - return field + 5; - } - - bool MyEquals(ExpressionTrees other) - { - return other != null && field == other.field; - } - - public void MethodGroupAsExtensionMethod() - { - ToCode(X(), () => (Func)new[] { 2000, 2004, 2008, 2012 }.Any); - } - - public void MethodGroupConstant() - { - ToCode(X(), () => Array.TrueForAll(new[] { 2000, 2004, 2008, 2012 }, DateTime.IsLeapYear)); - - HashSet set = new HashSet(); - ToCode(X(), () => new[] { 2000, 2004, 2008, 2012 }.All(set.Add)); - - Func, bool> sink = f => f(null, null); - ToCode(X(), () => sink(int.Equals)); - } - - public void MultipleCasts() - { - ToCode(X(), () => 1 == (int)(object)1); - } - - public void MultipleDots() - { - ToCode(X(), () => 3.ToString().ToString().Length > 0); - } - - public void NestedLambda() - { - Func, int> call = f => f(); - //no params - ToCode(X(), () => call(() => 42)); - //one param - ToCode(X(), () => new[] { 37, 42 }.Select(x => x * 2)); - //two params - ToCode(X(), () => new[] { 37, 42 }.Select((x, i) => x * 2)); - } - - public void CurriedLambda() - { - ToCode>>(X(), a => b => c => a + b + c); - } - - bool Fizz(Func a) - { - return a(42); - } - - bool Buzz(Func a) - { - return a(42); - } - - bool Fizz(Func a) - { - return a("42"); - } - - public void NestedLambda2() - { - ToCode(X(), () => Fizz(x => x == "a")); - ToCode(X(), () => Fizz(x => x == 37)); - - ToCode(X(), () => Fizz((int x) => true)); - ToCode(X(), () => Buzz(x => true)); - } - - public void NewArrayAndExtensionMethod() - { - ToCode(X(), () => new[] { 1.0, 2.01, 3.5 }.SequenceEqual(new[] { 1.0, 2.01, 3.5 })); - } - - public void NewMultiDimArray() - { - ToCode(X(), () => new int[3, 4].Length == 1); - } - - public void NewObject() - { - ToCode(X(), () => new object() != new object()); - } - - public void NotOperator() - { - bool x = true; - int y = 3; - byte z = 42; - ToCode(X(), () => ~(int)z == 0); - ToCode(X(), () => ~y == 0); - ToCode(X(), () => !x); - } - - public void ObjectInitializers() - { - XmlReaderSettings s = new XmlReaderSettings { - CloseInput = false, - CheckCharacters = false - }; - ToCode(X(), () => new XmlReaderSettings { CloseInput = s.CloseInput, CheckCharacters = s.CheckCharacters }.Equals(s)); - } - - public void Quoted() - { - ToCode(X(), () => (Expression>)((n, s) => s + n.ToString()) != null); - } - - public void Quoted2() - { - ToCode(X(), () => ToCode(X(), () => true).Equals(null)); - } - - public void QuotedWithAnonymous() - { - ToCode(X(), () => new[] { new { X = "a", Y = "b" } }.Select(o => o.X + o.Y).Single()); - } - - public void StaticCall() - { - ToCode(X(), () => Equals(3, 0)); - } - - public void ThisCall() - { - ToCode(X(), () => !Equals(3)); - } - - public void ThisExplicit() - { - ToCode(X(), () => object.Equals(this, 3)); - } - - public void TypedConstant() - { - ToCode(X(), () => new[] { typeof(int), typeof(string) }); - } - - public void StaticCallImplicitCast() - { - ToCode(X(), () => Equals(3, 0)); + return false; } + } + + int field; + + static object ToCode(object x, Expression> expr) + { + return expr; + } + + static object ToCode(object x, Expression> expr) + { + return expr; + } + + static object X() + { + return null; + } + + public void Parameter(bool a) + { + ToCode(X(), () => a); + } + + public void LocalVariable() + { + bool a = true; + ToCode(X(), () => a); + } + + public void LambdaParameter() + { + ToCode(X(), (bool a) => a); + } + + public void AddOperator(int x) + { + ToCode(X(), () => 1 + x + 2); + } + + public void AnonymousClasses() + { + ToCode(X(), () => new { X = 3, A = "a" }); + } + + public void ArrayIndex() + { + ToCode(X(), () => new[] { 3, 4, 5 }[0 + (int)(DateTime.Now.Ticks % 3)]); + } + + public void ArrayLengthAndDoubles() + { + ToCode(X(), () => new[] { 1.0, 2.01, 3.5 }.Concat(new[] { 1.0, 2.0 }).ToArray().Length); + } + + public void AsOperator() + { + ToCode(X(), () => new object() as string); + } + + public void ComplexGenericName() + { + ToCode(X(), () => ((Func)(x => x > 0))(0)); + } + + public void DefaultValue() + { + ToCode(X(), () => new TimeSpan(1, 2, 3) == default(TimeSpan)); + } + + public void EnumConstant() + { + ToCode(X(), () => new object().Equals(MidpointRounding.ToEven)); + } + + public void IndexerAccess() + { + var dict = Enumerable.Range(1, 20).ToDictionary(n => n.ToString()); + ToCode(X(), () => dict["3"] == 3); + } + + public void IsOperator() + { + ToCode(X(), () => new object() is string); + } + + public void ListInitializer() + { + ToCode(X(), () => new Dictionary { { 1, 1 }, { 2, 2 }, { 3, 4 } }.Count == 3); + } + + public void ListInitializer2() + { + ToCode(X(), () => new List(50) { 1, 2, 3 }.Count == 3); + } + + public void ListInitializer3() + { + ToCode(X(), () => new List { 1, 2, 3 }.Count == 3); + } + + public void LiteralCharAndProperty() + { + ToCode(X(), () => new string(' ', 3).Length == 1); + } + + public void CharNoCast() + { + ToCode(X(), () => "abc"[1] == 'b'); + } + + public void StringsImplicitCast() + { + int i = 1; + string x = "X"; + ToCode(X(), () => (("a\n\\b" ?? x) + x).Length == 2 ? false : true && (1m + -i > 0 || false)); + } + + public void NotImplicitCast() + { + byte z = 42; + ToCode(X(), () => ~z == 0); + } + + public void MembersBuiltin() + { + ToCode(X(), () => 1.23m.ToString()); + ToCode(X(), () => AttributeTargets.All.HasFlag((Enum)AttributeTargets.Assembly)); + ToCode(X(), () => "abc".Length == 3); + ToCode(X(), () => 'a'.CompareTo('b') < 0); + } + + public void MembersDefault() + { + ToCode(X(), () => default(DateTime).Ticks == 0); + ToCode(X(), () => default(int[]).Length == 0); + ToCode(X(), () => default(Type).IsLayoutSequential); + ToCode(X(), () => default(List).Count); + ToCode(X(), () => default(int[]).Clone() == null); + ToCode(X(), () => default(Type).IsInstanceOfType(new object())); + ToCode(X(), () => default(List).AsReadOnly()); + } + + public void DoAssert() + { + field = 37; + ToCode(X(), () => field != C()); + ToCode(X(), () => !ReferenceEquals(this, new ExpressionTrees())); + ToCode(X(), () => MyEquals(this) && !MyEquals(default(ExpressionTrees))); + } + + int C() + { + return field + 5; + } + + bool MyEquals(ExpressionTrees other) + { + return other != null && field == other.field; + } + + public void MethodGroupAsExtensionMethod() + { + ToCode(X(), () => (Func)new[] { 2000, 2004, 2008, 2012 }.Any); + } + + public void MethodGroupConstant() + { + ToCode(X(), () => Array.TrueForAll(new[] { 2000, 2004, 2008, 2012 }, DateTime.IsLeapYear)); - public void StaticMembers() - { - ToCode(X(), () => (DateTime.Now > DateTime.Now + TimeSpan.FromMilliseconds(10.001)).ToString() == "False"); - } + HashSet set = new HashSet(); + ToCode(X(), () => new[] { 2000, 2004, 2008, 2012 }.All(set.Add)); - public void Strings() - { - int i = 1; - string x = "X"; - ToCode(X(), () => (("a\n\\b" ?? x) + x).Length == 2 ? false : true && (1m + (decimal)-i > 0m || false)); - } + Func, bool> sink = f => f(null, null); + ToCode(X(), () => sink(int.Equals)); + } + + public void MultipleCasts() + { + ToCode(X(), () => 1 == (int)(object)1); + } + + public void MultipleDots() + { + ToCode(X(), () => 3.ToString().ToString().Length > 0); + } + + public void NestedLambda() + { + Func, int> call = f => f(); + //no params + ToCode(X(), () => call(() => 42)); + //one param + ToCode(X(), () => new[] { 37, 42 }.Select(x => x * 2)); + //two params + ToCode(X(), () => new[] { 37, 42 }.Select((x, i) => x * 2)); + } + + public void CurriedLambda() + { + ToCode>>(X(), a => b => c => a + b + c); + } + + bool Fizz(Func a) + { + return a(42); + } + + bool Buzz(Func a) + { + return a(42); + } + + bool Fizz(Func a) + { + return a("42"); + } + + public void NestedLambda2() + { + ToCode(X(), () => Fizz(x => x == "a")); + ToCode(X(), () => Fizz(x => x == 37)); - public void StringAccessor() - { - ToCode(X(), () => (int)"abc"[1] == 98); - } + ToCode(X(), () => Fizz((int x) => true)); + ToCode(X(), () => Buzz(x => true)); + } + + public void NewArrayAndExtensionMethod() + { + ToCode(X(), () => new[] { 1.0, 2.01, 3.5 }.SequenceEqual(new[] { 1.0, 2.01, 3.5 })); + } + + public void NewMultiDimArray() + { + ToCode(X(), () => new int[3, 4].Length == 1); + } + + public void NewObject() + { + ToCode(X(), () => new object() != new object()); + } + + public void NotOperator() + { + bool x = true; + int y = 3; + byte z = 42; + ToCode(X(), () => ~(int)z == 0); + ToCode(X(), () => ~y == 0); + ToCode(X(), () => !x); + } + + public void ObjectInitializers() + { + XmlReaderSettings s = new XmlReaderSettings { + CloseInput = false, + CheckCharacters = false + }; + ToCode(X(), () => new XmlReaderSettings { CloseInput = s.CloseInput, CheckCharacters = s.CheckCharacters }.Equals(s)); + } + + public void Quoted() + { + ToCode(X(), () => (Expression>)((n, s) => s + n.ToString()) != null); + } + + public void Quoted2() + { + ToCode(X(), () => ToCode(X(), () => true).Equals(null)); + } + + public void QuotedWithAnonymous() + { + ToCode(X(), () => new[] { new { X = "a", Y = "b" } }.Select(o => o.X + o.Y).Single()); + } + + public void StaticCall() + { + ToCode(X(), () => Equals(3, 0)); + } + + public void ThisCall() + { + ToCode(X(), () => !Equals(3)); + } + + public void ThisExplicit() + { + ToCode(X(), () => object.Equals(this, 3)); + } + + public void TypedConstant() + { + ToCode(X(), () => new[] { typeof(int), typeof(string) }); + } + + public void StaticCallImplicitCast() + { + ToCode(X(), () => Equals(3, 0)); + } + + public void StaticMembers() + { + ToCode(X(), () => (DateTime.Now > DateTime.Now + TimeSpan.FromMilliseconds(10.001)).ToString() == "False"); + } + + public void Strings() + { + int i = 1; + string x = "X"; + ToCode(X(), () => (("a\n\\b" ?? x) + x).Length == 2 ? false : true && (1m + (decimal)-i > 0m || false)); + } + + public void StringAccessor() + { + ToCode(X(), () => (int)"abc"[1] == 98); + } + + public void GenericClassInstance() + { + ToCode(X(), () => new GenericClass().InstanceField + new GenericClass().InstanceProperty); + } + + public void GenericClassStatic() + { + ToCode(X(), () => GenericClass.StaticField + GenericClass.StaticProperty); + } + + public void InvokeGenericMethod() + { + ToCode(X(), () => GenericClass.GenericMethod()); } }