using System; using System.Collections.Generic; using System.Reflection; namespace UniversalEditor.Plugins.Executable.UserInterface.Editors.Executable { public abstract class CodeProvider { /// /// Gets the /// /// The CS harp. public static CodeProviders.CSharpCodeProvider CSharp { get; } = new CodeProviders.CSharpCodeProvider(); public abstract string Title { get; } public abstract string CodeFileExtension { get; } protected abstract string GetAccessModifiersInternal(bool isPublic, bool isFamily, bool isAssembly, bool isPrivate, bool isAbstract, bool isSealed); public string GetAccessModifiers(EventInfo ei) { MethodInfo miAdd = ei.GetAddMethod(); MethodInfo miRemove = ei.GetRemoveMethod(); MethodInfo miRaise = ei.GetRaiseMethod(); bool IsPublic = false; bool IsFamily = false; bool IsAssembly = false; bool IsPrivate = false; if (miAdd != null) { IsPublic = miAdd.IsPublic; IsFamily = miAdd.IsFamily; IsAssembly = miAdd.IsAssembly; IsPrivate = miAdd.IsPrivate; } else if (miRemove != null) { IsPublic = miRemove.IsPublic; IsFamily = miRemove.IsFamily; IsAssembly = miRemove.IsAssembly; IsPrivate = miRemove.IsPrivate; } else if (miRaise != null) { IsPublic = miRaise.IsPublic; IsFamily = miRaise.IsFamily; IsAssembly = miRaise.IsAssembly; IsPrivate = miRaise.IsPrivate; } else { } return GetAccessModifiersInternal(IsPublic, IsFamily, IsAssembly, IsPrivate, false, false); } public string GetAccessModifiers(MethodInfo mi) { bool IsPublic = mi.IsPublic; bool IsFamily = mi.IsFamily; bool IsAssembly = mi.IsAssembly; bool IsPrivate = mi.IsPrivate; return GetAccessModifiersInternal(IsPublic, IsFamily, IsAssembly, IsPrivate, mi.IsAbstract, false); } public string GetAccessModifiers(FieldInfo mi) { bool IsPublic = mi.IsPublic; bool IsFamily = mi.IsFamily; bool IsAssembly = mi.IsAssembly; bool IsPrivate = mi.IsPrivate; return GetAccessModifiersInternal(IsPublic, IsFamily, IsAssembly, IsPrivate, false, false); } public string GetAccessModifiers(PropertyInfo mi) { bool IsPublic = (mi.GetGetMethod()?.IsPublic).GetValueOrDefault() || (mi.GetSetMethod()?.IsPublic).GetValueOrDefault(); bool IsFamily = (mi.GetGetMethod()?.IsFamily).GetValueOrDefault() && (mi.GetSetMethod()?.IsFamily).GetValueOrDefault(); bool IsAssembly = (mi.GetGetMethod()?.IsAssembly).GetValueOrDefault() && (mi.GetSetMethod()?.IsAssembly).GetValueOrDefault(); bool IsPrivate = (mi.GetGetMethod()?.IsPrivate).GetValueOrDefault() && (mi.GetSetMethod()?.IsPrivate).GetValueOrDefault(); return GetAccessModifiersInternal(IsPublic, IsFamily, IsAssembly, IsPrivate, false, false); } public string GetAccessModifiers(Type mi) { bool IsPublic = mi.IsPublic; bool IsAbstract = mi.IsAbstract; bool IsSealed = mi.IsSealed; return GetAccessModifiersInternal(IsPublic, false, false, false, IsAbstract, IsSealed); } protected abstract string GetBeginBlockInternal(int indentLevel); public string GetBeginBlock(int indentLevel) { return GetBeginBlockInternal(indentLevel); } protected abstract string GetBeginBlockInternal(Type type, int indentLevel); public string GetBeginBlock(Type type, int indentLevel) { return GetBeginBlockInternal(type, indentLevel); } protected abstract string GetEndBlockInternal(string elementName, int indentLevel); public string GetEndBlock(Type type, int indentLevel) { return GetEndBlockInternal(GetElementName(type), indentLevel); } protected abstract string GetBeginBlockInternal(System.Reflection.MethodInfo mi, int indentLevel); public string GetBeginBlock(System.Reflection.MethodInfo mi, int indentLevel) { return GetBeginBlockInternal(mi, indentLevel); } protected abstract string GetEndBlockInternal(System.Reflection.MethodInfo mi, int indentLevel); public string GetEndBlock(System.Reflection.MethodInfo mi, int indentLevel) { return GetEndBlockInternal(GetElementName(mi), indentLevel); } protected abstract string GetElementNameInternal(System.Reflection.MethodInfo mi); public string GetElementName(System.Reflection.MethodInfo mi) { return GetElementNameInternal(mi); } protected abstract string GetElementNameInternal(Type type); public string GetElementName(Type type) { return GetElementNameInternal(type); } protected abstract string GetSourceCodeInternal(Type mi, int indentLevel); public string GetSourceCode(Type mi, int indentLevel) { return GetSourceCodeInternal(mi, indentLevel); } protected abstract string GetSourceCodeInternal(System.Reflection.EventInfo item, int indentLevel); public string GetSourceCode(System.Reflection.EventInfo item, int indentLevel) { return GetSourceCodeInternal(item, indentLevel); } protected abstract string GetSourceCodeInternal(System.Reflection.FieldInfo mi, int indentLevel); public string GetSourceCode(System.Reflection.FieldInfo mi, int indentLevel) { return GetSourceCodeInternal(mi, indentLevel); } protected abstract string GetSourceCodeInternal(System.Reflection.MethodInfo mi, int indentLevel); public string GetSourceCode(System.Reflection.MethodInfo mi, int indentLevel) { return GetSourceCodeInternal(mi, indentLevel); } protected abstract string GetSourceCodeInternal(System.Reflection.PropertyInfo item, bool autoProperty, int indentLevel); public string GetSourceCode(System.Reflection.PropertyInfo item, bool autoProperty, int indentLevel) { return GetSourceCodeInternal(item, autoProperty, indentLevel); } protected abstract string GetTypeNameInternal(Type type); public string GetTypeName(Type type) { return GetTypeNameInternal(type); } protected abstract string GetMethodSignatureInternal(System.Reflection.MethodInfo mi); public string GetMethodSignature(System.Reflection.MethodInfo mi) { return GetMethodSignatureInternal(mi); } private static BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; public MethodInfo[] GetMethods(Type type) { MethodInfo[] meths = type.GetMethods(bindingFlags); List list = new List(); for (int j = 0; j < meths.Length; j++) { if (meths[j].IsSpecialName && (meths[j].Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase) || meths[j].Name.StartsWith("get_", StringComparison.OrdinalIgnoreCase)) && (type.GetProperty(meths[j].Name.Substring(4), bindingFlags) != null)) { // we can be REASONABLY sure that this is a property setter / getter, // and as we've already gotten all the properties, ignore it continue; } list.Add(meths[j]); } return list.ToArray(); } public FieldInfo[] GetFields(Type type, out List AutoPropertyNames) { List list = new List(); AutoPropertyNames = new List(); FieldInfo[] fields = type.GetFields(bindingFlags); for (int j = 0; j < fields.Length; j++) { if (fields[j].Name.StartsWith("<", StringComparison.OrdinalIgnoreCase) && fields[j].Name.Contains(">")) { // might be a backing field int k__backingfield_name_start = fields[j].Name.IndexOf('<'); int k__backingfield_name_end = fields[j].Name.IndexOf('>', k__backingfield_name_start); string k__backingfield_name = fields[j].Name.Substring(k__backingfield_name_start + 1, k__backingfield_name_end - k__backingfield_name_start - 1); PropertyInfo pi = type.GetProperty(k__backingfield_name, bindingFlags); if (pi != null) { AutoPropertyNames.Add(pi.Name); continue; } } else { list.Add(fields[j]); } } return list.ToArray(); } public string GetILOpcodeStr(short opcode) { return GetILOpcodeStr((ILOpcode)opcode); } public string GetILOpcodeStr(ILOpcode opcode) { switch (opcode) { case ILOpcode.Add: return "add"; case ILOpcode.AddOvf: return "add.ovf"; case ILOpcode.AddOvfUn: return "add.ovf.un"; case ILOpcode.And: return "and"; case ILOpcode.ArgList: return "arglist"; case ILOpcode.Beq: return "beq "; case ILOpcode.BeqS: return "beq "; case ILOpcode.Bge: return "bge "; case ILOpcode.BgeS: return "bge.s "; case ILOpcode.BgeUn: return "bge.un "; case ILOpcode.BgeUnS: return "bge.un.s "; case ILOpcode.Bgt: return "bgt "; case ILOpcode.BgtS: return "bgt.s "; case ILOpcode.BgtUn: return "bgt.un "; case ILOpcode.BgtUnS: return "bgt.un.s "; case ILOpcode.Ble: return "ble "; case ILOpcode.BleS: return "ble.s "; case ILOpcode.BleUn: return "ble.un "; case ILOpcode.BleUnS: return "ble.un.s "; case ILOpcode.Blt: return "blt "; case ILOpcode.BltS: return "blt.s "; case ILOpcode.BltUn: return "blt.un "; case ILOpcode.BltUnS: return "blt.un.s "; case ILOpcode.BneUn: return "bne.un "; case ILOpcode.BneUnS: return "bne.un.s "; case ILOpcode.Box: return "box "; case ILOpcode.Br: return "br "; case ILOpcode.BrS: return "br.s "; case ILOpcode.Break: return "break"; case ILOpcode.BrFalse: return "brfalse "; case ILOpcode.BrFalseS: return "brfalse.s "; case ILOpcode.BrTrue: return "brtrue "; case ILOpcode.BrTrueS: return "brtrue.s "; case ILOpcode.Call: return "call "; case ILOpcode.CallI: return "calli "; case ILOpcode.CallVirt: return "callvirt "; case ILOpcode.CastClass: return "castclass "; case ILOpcode.Ceq: return "ceq"; case ILOpcode.Cgt: return "cgt"; case ILOpcode.CgtUn: return "cgt.un"; case ILOpcode.CkFinite: return "ckfinite"; case ILOpcode.Clt: return "clt"; case ILOpcode.CltUn: return "clt.un"; case ILOpcode.Constrained: return "constrained "; case ILOpcode.ConvI: return "conv.i"; case ILOpcode.ConvI1: return "conv.i1"; case ILOpcode.ConvI2: return "conv.i2"; case ILOpcode.ConvI4: return "conv.i4"; case ILOpcode.ConvI8: return "conv.i8"; case ILOpcode.ConvOvfI: return "conv.ovf.i"; case ILOpcode.ConvOvfIUn: return "conv.ovf.i.un"; case ILOpcode.ConvOvfI1: return "conv.ovf.i1"; case ILOpcode.ConvOvfI1Un: return "conv.ovf.i1.un"; case ILOpcode.ConvOvfI2: return "conv.ovf.i2"; case ILOpcode.ConvOvfI2Un: return "conv.ovf.i2.un"; case ILOpcode.ConvOvfI4: return "conv.ovf.i4"; case ILOpcode.ConvOvfI4Un: return "conv.ovf.i4.un"; case ILOpcode.ConvOvfI8: return "conv.ovf.i8"; case ILOpcode.ConvOvfI8Un: return "conv.ovf.i8.un"; case ILOpcode.ConvOvfU: return "conv.ovf.u"; case ILOpcode.ConvOvfUUn: return "conv.ovf.u.un"; case ILOpcode.ConvOvfU1: return "conv.ovf.u1"; case ILOpcode.ConvOvfU1Un: return "conv.ovf.u1.un"; case ILOpcode.ConvOvfU2: return "conv.ovf.u2"; case ILOpcode.ConvOvfU2Un: return "conv.ovf.u2.un"; case ILOpcode.ConvOvfU4: return "conv.ovf.u4"; case ILOpcode.ConvOvfU4Un: return "conv.ovf.u4.un"; case ILOpcode.ConvOvfU8: return "conv.ovf.u8"; case ILOpcode.ConvOvfU8Un: return "conv.ovf.u8.un"; case ILOpcode.ConvRUn: return "conv.r.un"; case ILOpcode.ConvR4: return "conv.r4"; case ILOpcode.ConvR8: return "conv.r8"; case ILOpcode.ConvU: return "conv.u"; case ILOpcode.ConvU1: return "conv.u1"; case ILOpcode.ConvU2: return "conv.u2"; case ILOpcode.ConvU4: return "conv.u4"; case ILOpcode.ConvU8: return "conv.u8"; case ILOpcode.CpBlk: return "cpblk"; case ILOpcode.CpObj: return "cpobj "; case ILOpcode.Div: return "div"; case ILOpcode.DivUn: return "div.un"; case ILOpcode.Dup: return "dup"; case ILOpcode.EndFault: return "endfault"; case ILOpcode.EndFilter: return "endfilter"; // case ILOpcode.EndFinally: return "endfinally"; // same as endfault? case ILOpcode.InitBlk: return "initblk"; case ILOpcode.InitObj: return "initobj "; case ILOpcode.IsInst: return "isinst "; case ILOpcode.Jmp: return "jmp"; case ILOpcode.LdArg: return "ldarg "; case ILOpcode.LdArg0: return "ldarg.0"; case ILOpcode.LdArg1: return "ldarg.1"; case ILOpcode.LdArg2: return "ldarg.2"; case ILOpcode.LdArg3: return "ldarg.3"; case ILOpcode.LdArgS: return "ldarg.s "; case ILOpcode.LdArgA: return "ldarg.a "; case ILOpcode.LdArgAS: return "ldarg.a.s "; case ILOpcode.LdCI4: return "ldc.i4 "; case ILOpcode.LdCI4_M1: return "ldc.i4.m1"; case ILOpcode.LdCI4_0: return "ldc.i4.0"; case ILOpcode.LdCI4_1: return "ldc.i4.1"; case ILOpcode.LdCI4_2: return "ldc.i4.2"; case ILOpcode.LdCI4_3: return "ldc.i4.3"; case ILOpcode.LdCI4_4: return "ldc.i4.4"; case ILOpcode.LdCI4_5: return "ldc.i4.5"; case ILOpcode.LdCI4_6: return "ldc.i4.6"; case ILOpcode.LdCI4_7: return "ldc.i4.7"; case ILOpcode.LdCI4_8: return "ldc.i4.8"; case ILOpcode.LdCI4S: return "ldc.i4.s "; case ILOpcode.LdCI8: return "ldc.i8 "; case ILOpcode.LdCR4: return "ldc.r4 "; case ILOpcode.LdCR8: return "ldc.r8 "; case ILOpcode.LdElem: return "ldelem "; case ILOpcode.LdElemI: return "ldelem.i"; case ILOpcode.LdElemI1: return "ldelem.i1"; case ILOpcode.LdElemU1: return "ldelem.u1"; case ILOpcode.LdElemI2: return "ldelem.i2"; case ILOpcode.LdElemU2: return "ldelem.u2"; case ILOpcode.LdElemI4: return "ldelem.i4"; case ILOpcode.LdElemU4: return "ldelem.u4"; case ILOpcode.LdElemI8: return "ldelem.i8"; case ILOpcode.LdElemR4: return "ldelem.r4"; case ILOpcode.LdElemR8: return "ldelem.r8"; case ILOpcode.LdElemRef: return "ldelem.ref"; case ILOpcode.LdElemA: return "ldelema "; case ILOpcode.LdFld: return "ldfld "; case ILOpcode.LdFldA: return "ldflda "; case ILOpcode.LdFtn: return "ldftn "; case ILOpcode.LdIndI: return "ldind.i"; case ILOpcode.LdIndI1: return "ldind.i1"; case ILOpcode.LdIndU1: return "ldind.u1"; case ILOpcode.LdIndI2: return "ldind.i2"; case ILOpcode.LdIndU2: return "ldind.u2"; case ILOpcode.LdIndI4: return "ldind.i4"; case ILOpcode.LdIndU4: return "ldind.u4"; case ILOpcode.LdIndI8: return "ldind.i8"; case ILOpcode.LdIndR4: return "ldind.r4"; case ILOpcode.LdIndR8: return "ldind.r8"; case ILOpcode.LdLen: return "ldlen"; case ILOpcode.LdLoc: return "ldloc "; case ILOpcode.LdLoc0: return "ldloc.0"; case ILOpcode.LdLoc1: return "ldloc.1"; case ILOpcode.LdLoc2: return "ldloc.2"; case ILOpcode.LdLoc3: return "ldloc.3"; case ILOpcode.LdLocS: return "ldloc.s "; case ILOpcode.LdLocA: return "ldloca "; case ILOpcode.LdLocAS: return "ldloca.s "; case ILOpcode.LdNull: return "ldnull"; case ILOpcode.LdObj: return "ldobj "; case ILOpcode.LdSFld: return "ldsfld "; case ILOpcode.LdSFldA: return "ldsflda "; case ILOpcode.LdStr: return "ldstr "; case ILOpcode.LdToken: return "ldtoken "; case ILOpcode.LdVirtFtn: return "ldvirtftn "; case ILOpcode.Leave: return "leave "; case ILOpcode.LeaveS: return "leave "; case ILOpcode.LocAlloc: return "localloc"; case ILOpcode.MkRefAny: return "mkrefany "; case ILOpcode.Mul: return "mul"; case ILOpcode.MulOvf: return "mul.ovf"; case ILOpcode.MulOvfUn: return "mul.ovf.un"; case ILOpcode.Neg: return "neg"; case ILOpcode.NewArr: return "newarr "; case ILOpcode.NewObj: return "newobj "; case ILOpcode.No: return "no.{typecheck, rangecheck, nullcheck}"; case ILOpcode.Nop: return "nop"; case ILOpcode.Not: return "not"; case ILOpcode.Or: return "or"; case ILOpcode.Pop: return "pop"; case ILOpcode.Readonly: return "readonly."; case ILOpcode.RefAnyType: return "refanytype"; case ILOpcode.RefAnyVal: return "refanyval "; case ILOpcode.Rem: return "rem"; case ILOpcode.RemUn: return "rem.un"; case ILOpcode.Ret: return "ret"; case ILOpcode.Rethrow: return "rethrow"; case ILOpcode.Shl: return "shl"; case ILOpcode.Shr: return "shl"; case ILOpcode.ShrUn: return "shl"; case ILOpcode.SizeOf: return "sizeof "; case ILOpcode.StArg: return "starg "; case ILOpcode.StArgS: return "starg.s "; case ILOpcode.StElem: return "stelem "; case ILOpcode.StElemI: return "stelem.i"; case ILOpcode.StElemI1: return "stelem.i1"; case ILOpcode.StElemI2: return "stelem.i2"; case ILOpcode.StElemI4: return "stelem.i4"; case ILOpcode.StElemI8: return "stelem.i8"; case ILOpcode.StElemR4: return "stelem.r4"; case ILOpcode.StElemR8: return "stelem.r8"; case ILOpcode.StElemRef: return "stelem.ref"; case ILOpcode.StFld: return "stfld "; case ILOpcode.StIndI: return "stind.i"; case ILOpcode.StIndI1: return "stind.i1"; case ILOpcode.StIndI2: return "stind.i2"; case ILOpcode.StIndI4: return "stind.i4"; case ILOpcode.StIndI8: return "stind.i8"; case ILOpcode.StIndR4: return "stind.r4"; case ILOpcode.StIndR8: return "stind.r8"; case ILOpcode.StIndRef: return "stind.ref"; case ILOpcode.StLoc: return "stloc "; case ILOpcode.StLoc0: return "stloc.0"; case ILOpcode.StLoc1: return "stloc.1"; case ILOpcode.StLoc2: return "stloc.2"; case ILOpcode.StLoc3: return "stloc.3"; case ILOpcode.StLocS: return "stloc.s "; case ILOpcode.StObj: return "stobj "; case ILOpcode.StSFld: return "stsfld "; case ILOpcode.Sub: return "sub"; case ILOpcode.SubOvf: return "sub.ovf"; case ILOpcode.SubOvfUn: return "sub.ovf.un"; case ILOpcode.Switch: return "switch "; case ILOpcode.Tail: return "tail."; case ILOpcode.Throw: return "throw"; case ILOpcode.Unaligned: return "unaligned.(alignment)"; case ILOpcode.Unbox: return "unbox "; case ILOpcode.UnboxAny: return "unbox.any "; case ILOpcode.Volatile: return "volatile."; case ILOpcode.Xor: return "xor"; } return ""; } public string GetVariableName(MethodInfo mi, LocalVariableInfo localVariableInfo) { // TODO: read the PDB file (if exists) to get the local variable info return "local_" + localVariableInfo.LocalIndex.ToString(); } } }