using System; using System.Collections.Generic; using System.Reflection; public delegate void EventHandler(); public class ViableCallable { public void Run(C1 x1, C1 x2, dynamic dyn, T3 t3) { // Viable callables: {C2,C3,C4,C5,C6,C7}.M() x1.M(default(T1), 8); // Viable callables: {C2,C3,C4,C5,C6,C7}.{get_Prop(),set_Prop()} x1.Prop = x1.Prop; // Viable callables: {C2,C3,C4,C5,C6,C7}.{get_Item(),set_Item()} x1[default(T2)] = x1[default(T2)]; // Viable callables: {C2,C3,C4,C5,C6,C7}.{add_Event(),remove_Event()} x1.Event += () => { }; x1.Event -= () => { }; // Viable callables: {C4,C6}.M() (not C7.M(), as C7 is not constructed for any T) x2.M(new T1[0], false); // Viable callables: {C4,C6}.{get_Prop(),set_Prop()} x2.Prop = x2.Prop; // Viable callables: {C4,C6}.{get_Item(),set_Item()} x2[default(T2)] = x2[default(T2)]; // Viable callables: {C4,C6}.{add_Event(),remove_Event()} x2.Event += () => { }; x2.Event -= () => { }; // Viable callables: {C2,C6}.M() C1 x3 = Mock>(); x3.M("abc", 42); // Viable callables: {C2,C6}.{get_Prop(),set_Prop()} x3.Prop = x3.Prop; // Viable callables: {C2,C6}.{get_Item(),set_Item()} x3[0] = x3[0]; // Viable callables: {C2,C6}.{add_Event(),remove_Event()} x3.Event += () => { }; x3.Event -= () => { }; // Viable callables: {C2,C3,C6}.M() C1 x4 = Mock>(); x4.M("abc", 42d); // Viable callables: {C2,C3,C6}.{get_Prop(),set_Prop()} x4.Prop = x4.Prop; // Viable callables: {C2,C3,C6}.{get_Item(),set_Item()} x4[0M] = x4[0M]; // Viable callables: {C2,C3,C6}.{add_Event(),remove_Event()} x4.Event += () => { }; x4.Event -= () => { }; // Viable callables: {C4,C6}.M() C1 x5 = Mock>(); x5.M(new int[] { 42 }, null); // Viable callables: {C4,C6}.{get_Prop(),set_Prop()} x5.Prop = x5.Prop; // Viable callables: {C4,C6}.{get_Item(),set_Item()} x5[false] = x5[false]; // Viable callables: {C4,C6}.{add_Event(),remove_Event()} x5.Event += () => { }; x5.Event -= () => { }; // Viable callables: {C2,C5,C6}.M() C1 x6 = Mock>(); x6.M("", null); // Viable callables: {C2,C5,C6}.{get_Prop(),set_Prop()} x6.Prop = x6.Prop; // Viable callables: {C2,C5,C6}.{get_Item(),set_Item()} x6[false] = x6[false]; // Viable callables: {C2,C5,C6}.{add_Event(),remove_Event()} x6.Event += () => { }; x6.Event -= () => { }; // Viable callables: C6.M() C1 x7 = new C6(); x7.M(default(T1), ""); // Viable callables: C6.{get_Prop(),set_Prop()} x7.Prop = x7.Prop; // Viable callables: C6.{get_Item(),set_Item()} x7[false] = x7[false]; // Viable callables: C6.{add_Event(),remove_Event()} x7.Event += () => { }; x7.Event -= () => { }; // Viable callables: {C8,C9}.M() dynamic d = Mock(); d.M(Mock>>()); // Viable callables: {C8,C9}.{get_Prop(),set_Prop()} d.Prop1 = d.Prop1; // Viable callables: {C8,C9}.{get_Item(),set_Item()} d[0] = d[0]; // Viable callables: (none) d.M(Mock>>()); // Viable callables: C5.M() d = 42; C5.M(d); // Viable callables: C5.set_Prop2() d = ""; C5.Prop2 = d; // Viable callables: C5.{add_Event(),remove_Event()} d = (EventHandler)(() => { }); C5.Event2 += d; C5.Event2 -= d; // Viable callables: (none) d = ""; C5.M(d); // Viable callables: (none) d = 0; C5.Prop2 = d; // Viable callables: (none) C5.Event2 += d; C5.Event2 -= d; // Viable callables: C8.M2() d = new decimal[] { 0M }; C8.M2(d); // Viable callables: C8.M2() d = new string[] { "" }; C8.M2(d); // Viable callables: (none) d = ""; C8.M2(d); // Viable callables: C6.M() d = new C6(); d.M(default(T1), ""); // Viable callables: C6.{get_Prop(),set_Prop()} d.Prop = d.Prop; // Viable callables: C6.{get_Item(),set_Item()} d[(byte)0] = d[(byte)0]; // Viable callables: C6.{add_Event(),remove_Event()} d.Event += (EventHandler)(() => { }); d.Event -= (EventHandler)(() => { }); // Viable callables: C8.M3(), C9.M3() d = Mock(); d.M3(); d.M3(0); d.M3(0, 0.0); // Viable callables: {C8,C9,C10}.M3() dyn.M3(); dyn.M3(0); dyn.M3(0, 0.0); // Viable callables: {C8,C9,C10}.{get_Prop1(),set_Prop1()} dyn.Prop1 = dyn.Prop1; // Viable callables: {C2,C3,C6,C7,C8,C9,C10}.{get_Item(),set_Item()} dyn[0] = dyn[0]; // Viable callables: {C2,C3,C5,C6,C7,C8,C9}.{add_Event(),remove_Event()} dyn.Event += (EventHandler)(() => { }); dyn.Event -= (EventHandler)(() => { }); // Viable callables: C8.M4() dyn.M4(0, Mock>()); dyn.M4(0, new string[] { "" }); // Viable callables: C10.set_Prop1() dyn.Prop1 = false; // Viable callables: (none) dyn.M4(-1, new string[] { "" }); dyn.M4(0, new int[] { 0 }); // Viable callables: (none) dyn.Prop1 = 0; // Viable callables: {C2,C6}.{get_Item(),set_Item()} dyn[""] = dyn[""]; // Operator calls using dynamic types: all target int operators d = 0; d = d + 1; d = 0; d = 1 - d; d = 0; d = d + t3; // mixed with a type parameter // Operator calls using reflection: targets C10 addition operator var c = new C10(); typeof(C10).InvokeMember("op_Addition", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, new object[] { c, c }); // Property call using reflection: targets C10 property getter/setter typeof(C10).InvokeMember("get_Prop3", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, new object[0]); typeof(C10).InvokeMember("set_Prop3", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, new object[] { "" }); // Indexer call using reflection: targets C10 indexer getter/setter typeof(C10).InvokeMember("get_Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, c, new object[] { 0 }); typeof(C10).InvokeMember("set_Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, c, new object[] { 0, true }); // Event handler call using reflection: targets C10 event adder/remover EventHandler e = () => { }; typeof(C10).InvokeMember("add_Event", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, c, new object[] { e }); typeof(C10).InvokeMember("remove_Event", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, c, new object[] { e }); } public static T Mock() { throw new Exception(); } void CreateTypeInstance() { new C2(); new C2(); new C2(); new C4(); new C6(); new C6(); new C6(); new C6(); new C7(); // Need to reference built-in operators for them to be extracted if (2 + 3 - 1 > 0) ; // No construction of C8/C9; reflection/dynamic calls should not rely on existence of types } } public abstract class C1 { public abstract T2 M(T1 x, T3 y); public abstract T1 Prop { get; set; } public abstract T1 this[T2 x] { get; set; } public abstract event EventHandler Event; public void Run(T1 x) { // Viable callables: C2.M(), C3.M(), C4.M(), C5.M(), C6.M(), C7.M() M(x, 8); } } public class C2 : C1 { public override T M(string x, T3 y) { throw new Exception(); } public override string Prop { get; set; } public override string this[T x] { get { throw new Exception(); } set { throw new Exception(); } } public override event EventHandler Event { add { } remove { } } } public class C3 : C1 { public override decimal M(string x, T3 y) { throw new Exception(); } public override string Prop { get; set; } public override string this[decimal x] { get { throw new Exception(); } set { throw new Exception(); } } public override event EventHandler Event { add { } remove { } } } public class C4 : C1 { public override bool M(T[] x, T3 y) { throw new Exception(); } public override T[] Prop { get; set; } public override T[] this[bool x] { get { throw new Exception(); } set { throw new Exception(); } } public override event EventHandler Event { add { } remove { } } } public class C5 : C1 { public override bool M(string x, T3 y) { throw new Exception(); } public static void M(int x) { } public override string Prop { get; set; } public static string Prop2 { get; set; } public override string this[bool x] { get { throw new Exception(); } set { throw new Exception(); } } public override event EventHandler Event { add { } remove { } } public static event EventHandler Event2 { add { } remove { } } } public class C6 : C1 { public override T2 M(T1 x, T3 y) { throw new Exception(); } public override T1 Prop { get; set; } public override T1 this[T2 x] { get { throw new Exception(); } set { throw new Exception(); } } public override event EventHandler Event { add { } remove { } } public void Run(T1 x) { // Viable callables: C6.M(), C7.M() M(x, 8); // Viable callables: C6.M(), C7.M() this.M(x, 8); } } public class C7 : C6 { public override byte M(T1 x, T3 y) { throw new Exception(); } public override T1 Prop { get; set; } public override T1 this[byte x] { get { throw new Exception(); } set { throw new Exception(); } } public override event EventHandler Event { add { } remove { } } public void Run(T1 x) { // Viable callables: C7.M() M(x, 8); // Viable callables: C7.M() this.M(x, 8); // Viable callables: C6.M() base.M(x, 8); } } public class C8 { public virtual void M(IEnumerable> x) { } public static void M2(T[] x) { } public void M3(params double[] x) { } public void M4(byte b, IEnumerable s) { } public virtual string Prop1 { get; set; } public static string Prop2 { get; set; } public string Prop3 { get; set; } public virtual string this[int x] { get { throw new Exception(); } set { throw new Exception(); } } public virtual event EventHandler Event { add { } remove { } } } public class C9 : C8 { public override void M(IEnumerable> x) { } public void M3(params T[] x) { } public override string Prop1 { get; set; } public string Prop3 { get; set; } public override string this[int x] { get { throw new Exception(); } set { throw new Exception(); } } public override event EventHandler Event { add { } remove { } } } public class C10 { public void M3(params double[] x) { } public static C10 operator +(C10 x, C10 y) { return x; } public bool Prop1 { get; set; } public static string Prop3 { get; set; } public bool this[int x] { get { return false; } set { return; } } public event EventHandler Event { add { } remove { } } } public class C11 { void M(dynamic d) { } public void Run() { dynamic d = this; int x = 0; x += 42; // Viable callables: C11.M() d.M(x); // Viable callables: C11.C11() new C11(d); d = 0; // Viable callables: (none) new C11(d); } C11(C11 x) { } } public class C12 { interface I { void M(); } class C13 : I { public void M() { } } class C14 : I { public void M() { } } void Run(T1 x) where T1 : I { // Viable callables: C13.M() x.M(); } void Run2(T2 x) where T2 : I { Run(x); } void Run3() { Run2(new C13()); } } public class C15 { interface I { void M(); } class A1 { public virtual void M() { } } class A2 : A1, I { } class A3 : A2 { new public void M() { } } class A4 : A2, I { new public virtual void M() { } } class A5 : A4 { public override void M() { } } class A6 : A1 { public override void M() { } } void Run(I i) { // Viable callables: {A1,A4,A5}.M() i.M(); i = new A3(); // Viable callables: A1.M() i.M(); i = new A4(); // Viable callables: A4.M() i.M(); i = ViableCallable.Mock(); // Viable callables: {A4,A5}.M() i.M(); } } abstract class C16 { public virtual T2 M1(T1 x) => throw null; public virtual T M2(Func x) => x(); } class C17 : C16 { void M1(int i) { // Viable callables: C16.M1() this.M1(""); // Viable callables: C17.M2() this.M2(() => i); } public override T M2(Func x) => x(); void M3(T t, string s) where T : C17 { // Viable callable: C17.M2() t.M2(() => s); } void M4(C16 c) where T : struct { // Viable callable: C16.M2() [also reports C17.M2(); false positive] c.M2(() => default(T)); } void M5(C16 c) where T : class { // Viable callables: {C16,C17}.M1() c.M2(() => default(T)); } }