#pragma warning disable format // Copyright (c) AlphaSierraPapa for the SharpDevelop Team // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software // without restriction, including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons // to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Xml; namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { public class ExpressionTrees { private class GenericClass { public static X StaticField; public X InstanceField; public static X StaticProperty { get; set; } public X InstanceProperty { get; set; } public static bool GenericMethod() { return false; } } internal class GenericClassWithCtor { } internal class GenericClassWithMultipleCtors { public GenericClassWithMultipleCtors() { } public GenericClassWithMultipleCtors(int x) { } } private class AssertTest { private struct DataStruct { private int dummy; } private struct WrapperStruct { internal DataStruct Data; } private class SomeClass { internal WrapperStruct DataWrapper; } private SomeClass someClass; public void Test() { GetMember(() => someClass.DataWrapper.Data); } public static MemberInfo GetMember(Expression> p) { return null; } } public class Administrator { public int ID { get; set; } public string TrueName { get; set; } public string Phone { get; set; } } public class Contract { public int ID { get; set; } public string ContractNo { get; set; } public string HouseAddress { get; set; } public DateTime SigningTime { get; set; } public string BuyerName { get; set; } public string BuyerTelephone { get; set; } public string Customer { get; set; } public string CustTelephone { get; set; } public int AdminID { get; set; } public int StoreID { get; set; } } public class Database { public IQueryable Contracts { get; set; } public IQueryable Loan { get; set; } public IQueryable Administrator { get; set; } public IQueryable Store { get; set; } } public class Loan { public string ContractNo { get; set; } public DateTime? ShenDate { get; set; } public DateTime? LoanDate { get; set; } public string Credit { get; set; } public string LoanBank { get; set; } public string Remarks { get; set; } } public class Store { public int ID { get; set; } public string Name { get; set; } } internal class MyClass { public static MyClass operator +(MyClass a, MyClass b) { return new MyClass(); } } internal class SimpleType { public const int ConstField = 1; public static readonly int StaticReadonlyField = 2; public static int StaticField = 3; public readonly int ReadonlyField = 2; public int Field = 3; #if CS60 public static int StaticReadonlyProperty => 0; #else public static int StaticReadonlyProperty { get { return 0; } } #endif public static int StaticProperty { get; set; } #if CS60 public int ReadonlyProperty => 0; #else public int ReadonlyProperty { get { return 0; } } #endif public int Property { get; set; } } internal class SimpleTypeWithCtor { public SimpleTypeWithCtor(int i) { } } internal class SimpleTypeWithMultipleCtors { public SimpleTypeWithMultipleCtors() { } public SimpleTypeWithMultipleCtors(int i) { } } private int field; private Database db; private dynamic ViewBag; public static readonly object[] SupportedMethods = new object[2] { ToCode(null, () => ((IQueryable)null).Aggregate((object o1, object o2) => null)), ToCode(null, () => ((IEnumerable)null).Aggregate((object o1, object o2) => null)) }; public static readonly object[] SupportedMethods2 = new object[4] { ToCode(null, () => ((IQueryable)null).Aggregate(null, (object o1, object o2) => null)), ToCode(null, () => ((IQueryable)null).Aggregate((object)null, (Expression>)((object o1, object o2) => null), (Expression>)((object o) => null))), ToCode(null, () => ((IEnumerable)null).Aggregate(null, (object o1, object o2) => null)), ToCode(null, () => ((IEnumerable)null).Aggregate((object)null, (Func)((object o1, object o2) => null), (Func)((object o) => null))) }; public static void TestCall(object a) { } public static void TestCall(ref object a) { } private void Issue1249(int ID) { if (ID == 0) { ViewBag.data = "''"; return; } var model = (from a in db.Contracts where a.ID == ID select new { ID = a.ID, ContractNo = a.ContractNo, HouseAddress = a.HouseAddress, AdminID = (from b in db.Administrator where b.ID == a.AdminID select b.TrueName).FirstOrDefault(), StoreID = (from b in db.Store where b.ID == a.StoreID select b.Name).FirstOrDefault(), SigningTime = a.SigningTime, YeWuPhone = (from b in db.Administrator where b.ID == a.AdminID select b.Phone).FirstOrDefault(), BuyerName = a.BuyerName, BuyerTelephone = a.BuyerTelephone, Customer = a.Customer, CustTelephone = a.CustTelephone, Credit = (from b in db.Loan where b.ContractNo == a.ContractNo select b.Credit).FirstOrDefault(), LoanBank = (from b in db.Loan where b.ContractNo == a.ContractNo select b.LoanBank).FirstOrDefault(), Remarks = (from b in db.Loan where b.ContractNo == a.ContractNo select b.Remarks).FirstOrDefault() }).FirstOrDefault(); ViewBag.data = model.ToJson(); DateTime? dateTime = (from b in db.Loan where b.ContractNo == model.ContractNo select b.ShenDate).FirstOrDefault(); DateTime? dateTime2 = (from b in db.Loan where b.ContractNo == model.ContractNo select b.LoanDate).FirstOrDefault(); ViewBag.ShenDate = ((!dateTime.HasValue) ? "" : dateTime.ParseDateTime().ToString("yyyy-MM-dd")); ViewBag.LoanDate = ((!dateTime2.HasValue) ? "" : dateTime2.ParseDateTime().ToString("yyyy-MM-dd")); } private static object ToCode(object x, Expression> expr) { return expr; } private static object ToCode(object x, Expression> expr) { return expr; } private static object ToCode(object x, Expression> expr) { return expr; } private static object ToCode(object x, Expression> expr) { return expr; } private 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 int[3] { 3, 4, 5 })[0 + (int)(DateTime.Now.Ticks % 3)]); } public void ArrayLengthAndDoubles() { ToCode(X(), () => new double[3] { 1.0, 2.01, 3.5 }.Concat(new double[2] { 1.0, 2.0 }).ToArray().Length); } public void AsOperator() { ToCode(X(), () => new object() as string); } public void ComplexGenericName() { ToCode(X(), () => ((Func)((int 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() { Dictionary dict = Enumerable.Range(1, 20).ToDictionary((int 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 + (decimal)(-i) > 0m || false))); } public void NotImplicitCast() { byte z = 42; ToCode(X(), () => ~z == 0); } public void MembersBuiltin() { ToCode(X(), () => 1.23m.ToString()); ToCode(X(), () => AttributeTargets.All.HasFlag(AttributeTargets.Assembly)); ToCode(X(), () => "abc".Length == 3); ToCode(X(), () => 'a'.CompareTo('b') < 0); } public void MembersDefault() { ToCode(X(), () => default(DateTime).Ticks == 0); ToCode(X(), () => ((Array)null).Length == 0); ToCode(X(), () => ((Type)null).IsLayoutSequential); ToCode(X(), () => ((List)null).Count); ToCode(X(), () => ((Array)null).Clone() == null); ToCode(X(), () => ((Type)null).IsInstanceOfType(new object())); ToCode(X(), () => ((List)null).AsReadOnly()); } public void DoAssert() { ToCode(X(), () => field != C()); ToCode(X(), () => !object.ReferenceEquals(this, new ExpressionTrees())); ToCode(X(), () => MyEquals(this) && !MyEquals(null)); } private int C() { throw new NotImplementedException(); } private bool MyEquals(ExpressionTrees other) { throw new NotImplementedException(); } public void MethodGroupAsExtensionMethod() { ToCode(X(), (Expression>>)(() => ((IEnumerable)new int[4] { 2000, 2004, 2008, 2012 }).Any)); } public void MethodGroupConstant() { ToCode(X(), () => Array.TrueForAll(new int[4] { 2000, 2004, 2008, 2012 }, DateTime.IsLeapYear)); HashSet set = new HashSet(); ToCode(X(), () => new int[4] { 2000, 2004, 2008, 2012 }.All(set.Add)); Func, bool> sink = (Func f) => f(null, null); ToCode(X(), () => sink(object.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 = (Func f) => f(); //no params ToCode(X(), () => call(() => 42)); //one param ToCode(X(), () => new int[2] { 37, 42 }.Select((int x) => x * 2)); //two params ToCode(X(), () => new int[2] { 37, 42 }.Select((int x, int i) => x * 2)); } public void CurriedLambda() { ToCode(X(), (Expression>>>)((int a) => (int b) => (int c) => a + b + c)); } private bool Fizz(Func a) { return a(42); } private bool Buzz(Func a) { return a(42); } private bool Fizz(Func a) { return a("42"); } private bool Fizz(Func a) { return a(null); } public void NestedLambda2() { ToCode(X(), () => Fizz((string x) => x == "a")); ToCode(X(), () => Fizz((string x) => x != "a")); ToCode(X(), () => Fizz((Action x) => x == new Action(NestedLambda2))); ToCode(X(), () => Fizz((Action x) => x != new Action(NestedLambda2))); ToCode(X(), () => Fizz((int x) => x == 37)); ToCode(X(), () => Fizz((int x) => true)); ToCode(X(), () => Buzz((int x) => true)); } public void NewArrayAndExtensionMethod() { ToCode(X(), () => new double[3] { 1.0, 2.01, 3.5 }.SequenceEqual(new double[3] { 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(), () => ~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>)((int n, string 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(), () => object.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 Type[2] { typeof(int), typeof(string) }); } public void StaticCallImplicitCast() { ToCode(X(), () => object.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 GenericClassInstance() { ToCode(X(), () => (double)new GenericClass().InstanceField + new GenericClass().InstanceProperty); } public void GenericClassStatic() { ToCode(X(), () => (double)GenericClass.StaticField + GenericClass.StaticProperty); } public void InvokeGenericMethod() { ToCode(X(), () => GenericClass.GenericMethod()); } private static void Test(T delegateExpression, Expression expressionTree) { } public static void ArrayIndexer() { Test>((int[] array) => array[0], (int[] array) => array[0]); Test>((int[] array, int index) => array[index], (int[] array, int index) => array[index]); Test>((int[,] array) => array[0, 5], (int[,] array) => array[0, 5]); Test>((int[,] array, int index) => array[index, 7], (int[,] array, int index) => array[index, 7]); Test>((int[][] array, int index) => array[index][7], (int[][] array, int index) => array[index][7]); } public static void ArrayLength() { Test>((int[] array) => array.Length, (int[] array) => array.Length); Test>(() => ((Array)null).Length, () => ((Array)null).Length); } public static void NewObj() { Test>(() => new SimpleType(), () => new SimpleType()); Test>(() => new SimpleTypeWithCtor(5), () => new SimpleTypeWithCtor(5)); Test>(() => new SimpleTypeWithMultipleCtors(), () => new SimpleTypeWithMultipleCtors()); Test>(() => new SimpleTypeWithMultipleCtors(5), () => new SimpleTypeWithMultipleCtors(5)); Test>(() => new GenericClass(), () => new GenericClass()); Test>(() => new GenericClassWithCtor(), () => new GenericClassWithCtor()); Test>(() => new GenericClassWithMultipleCtors(5), () => new GenericClassWithMultipleCtors(5)); } public unsafe static void TypeOfExpr() { Test>(() => typeof(int), () => typeof(int)); Test>(() => typeof(object), () => typeof(object)); Test>(() => typeof(List<>), () => typeof(List<>)); Test>(() => typeof(List), () => typeof(List)); Test>(() => typeof(int*), () => typeof(int*)); } public static void AsTypeExpr() { Test>((object obj) => obj as MyClass, (object obj) => obj as MyClass); Test>((object obj) => obj as int?, (object obj) => obj as int?); Test>>((object obj) => obj as GenericClass, (object obj) => obj as GenericClass); } public static void IsTypeExpr() { Test>((object obj) => obj is MyClass, (object obj) => obj is MyClass); Test>((object obj) => obj is int?, (object obj) => obj is int?); } public static void UnaryLogicalOperators() { Test>((bool a) => !a, (bool a) => !a); } public static void ConditionalOperator() { ToCode(null, (bool a) => a ? 5 : 10); ToCode(null, (object a) => a ?? new MyClass()); } public static void ComparisonOperators() { ToCode(null, (int a, int b) => a == b); ToCode(null, (int a, int b) => a != b); ToCode(null, (int a, int b) => a < b); ToCode(null, (int a, int b) => a <= b); ToCode(null, (int a, int b) => a > b); ToCode(null, (int a, int b) => a >= b); ToCode(null, (int a, int b) => a == 1 && b == 2); ToCode(null, (int a, int b) => a == 1 || b == 2); ToCode(null, (int a, short b) => a == b); ToCode(null, (ushort a, int b) => a != b); ToCode(null, (int a, long b) => (long)a < b); ToCode(null, (ulong a, uint b) => a <= (ulong)b); ToCode(null, (int a, uint b) => (long)a <= (long)b); ToCode(null, (int a, long b) => (long)a > b); ToCode(null, (short a, long b) => (long)a >= b); ToCode(null, (int a, int b) => a == 1 && b == 2); ToCode(null, (int a, int b) => a == 1 || b == 2); } public static void LiftedComparisonOperators() { ToCode(X(), (int? a, int? b) => a == b); ToCode(X(), (int? a, int? b) => a != b); ToCode(X(), (int? a, int? b) => a < b); ToCode(X(), (int? a, int? b) => a <= b); ToCode(X(), (int? a, int? b) => a > b); ToCode(X(), (int? a, int? b) => a >= b); } public static void UnaryArithmeticOperators() { Test>((int a) => a, (int a) => a); Test>((int a) => -a, (int a) => -a); } public static void BinaryArithmeticOperators() { Test>((int a, int b) => a + b, (int a, int b) => a + b); Test>((int a, int b) => a - b, (int a, int b) => a - b); Test>((int a, int b) => a * b, (int a, int b) => a * b); Test>((int a, int b) => a / b, (int a, int b) => a / b); Test>((int a, int b) => a % b, (int a, int b) => a % b); Test>((long a, int b) => a + b, (long a, int b) => a + (long)b); Test>((long a, int b) => a - b, (long a, int b) => a - (long)b); Test>((long a, int b) => a * b, (long a, int b) => a * (long)b); Test>((long a, int b) => a / b, (long a, int b) => a / (long)b); Test>((long a, int b) => a % b, (long a, int b) => a % (long)b); Test>((short a, int b) => a + b, (short a, int b) => a + b); Test>((int a, short b) => a - b, (int a, short b) => a - b); Test>((short a, int b) => a * b, (short a, int b) => a * b); Test>((int a, short b) => a / b, (int a, short b) => a / b); Test>((short a, int b) => a % b, (short a, int b) => a % b); } public static void BitOperators() { Test>((int a) => ~a, (int a) => ~a); Test>((int a, int b) => a & b, (int a, int b) => a & b); Test>((int a, int b) => a | b, (int a, int b) => a | b); Test>((int a, int b) => a ^ b, (int a, int b) => a ^ b); } public static void ShiftOperators() { Test>((int a) => a >> 2, (int a) => a >> 2); Test>((int a) => a << 2, (int a) => a << 2); Test>((long a) => a >> 2, (long a) => a >> 2); Test>((long a) => a << 2, (long a) => a << 2); } public static void SimpleExpressions() { Test>(() => 0, () => 0); Test>((int a) => a, (int a) => a); } public static void Capturing() { int captured = 5; Test>(() => captured, () => captured); } public static void FieldAndPropertyAccess() { ToCode(null, () => 1); ToCode(null, () => SimpleType.StaticField); ToCode(null, () => SimpleType.StaticReadonlyField); ToCode(null, () => SimpleType.StaticProperty); ToCode(null, () => SimpleType.StaticReadonlyProperty); ToCode(null, (SimpleType a) => a.Field); ToCode(null, (SimpleType a) => a.Property); ToCode(null, (SimpleType a) => a.ReadonlyField); ToCode(null, (SimpleType a) => a.ReadonlyProperty); } public static void Call() { ToCode(null, (string a) => Console.WriteLine(a)); Test>((string a) => a.ToString(), (string a) => a.ToString()); Test>((int a) => a.ToString(), (int a) => a.ToString()); Test>((string a) => a.ToArray(), (string a) => a.ToArray()); Test>(() => 'a'.CompareTo('b') < 0, () => 'a'.CompareTo('b') < 0); Test>(delegate (object lockObj, bool lockTaken) { Monitor.Enter(lockObj, ref lockTaken); }, (object lockObj, bool lockTaken) => Monitor.Enter(lockObj, ref lockTaken)); Test>((string str, int num) => int.TryParse(str, out num), (string str, int num) => int.TryParse(str, out num)); Test>((string str, SimpleType t) => int.TryParse(str, out t.Field), (string str, SimpleType t) => int.TryParse(str, out t.Field)); Test>(delegate (object o) { TestCall(o); }, (object o) => TestCall(o)); Test>(delegate (object o) { TestCall(ref o); }, (object o) => TestCall(ref o)); } public static void Quote() { Test>(() => (Expression>)((int n, string s) => s + n.ToString()) != null, () => (Expression>)((int n, string s) => s + n.ToString()) != null); } public static void ArrayInitializer() { Test>(() => new int[3] { 1, 2, 3 }, () => new int[3] { 1, 2, 3 }); Test>(() => new int[3], () => new int[3]); Test>(() => new int[3, 5], () => new int[3, 5]); Test>(() => new int[3][], () => new int[3][]); Test>(() => new int[1][] { new int[3] { 1, 2, 3 } }, () => new int[1][] { new int[3] { 1, 2, 3 } }); } public static void AnonymousTypes() { Test>(() => new { A = 5, B = "Test" }, () => new { A = 5, B = "Test" }); } public static void ObjectInit() { ToCode(null, () => new SimpleType { Property = 4, Field = 3 }); } public static void StringConcat() { Test>(null, (string a, object b) => a + b); Test>(null, (string a, object b) => a + b.ToString()); Test>(null, (string a, int b) => a + b); Test>(null, (string a, int b) => a + b.ToString()); } public async Task Issue1524(string str) { await Task.Delay(100); #if CS70 if (string.IsNullOrEmpty(str) && int.TryParse(str, out var id)) { #else int id; if (string.IsNullOrEmpty(str) && int.TryParse(str, out id)) { #endif (from a in new List().AsQueryable() where a == id select a).FirstOrDefault(); } } public void NullCoalescing() { Test>((string a, string b) => a ?? b, (string a, string b) => a ?? b); Test>((int? a) => a ?? 1, (int? a) => a ?? 1); } } internal static class Extensions { public static dynamic ToJson(this object o) { return null; } public static DateTime ParseDateTime(this object str) { return default(DateTime); } } }