using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using static System.FormattableString; namespace SharpGLTF { /// /// Utility class to dump the public API of an assembly /// static class DumpAssemblyAPI { // https://www.hanselman.com/blog/ManagingChangeWithNETAssemblyDiffTools.aspx public static IEnumerable GetAssemblySignature(Assembly assembly) { return assembly.ExportedTypes .SelectMany(item => GetTypeSignature(item.GetTypeInfo()).Select(l => "NS " + item.Namespace + " { " + l + " }" ) ); } public static IEnumerable GetTypeSignature(TypeInfo tinfo) { if (tinfo.IsNestedPrivate) yield break; if (tinfo.IsNestedAssembly) yield break; string baseName = string.Empty; if (tinfo.IsInterface) baseName = "INTERFACE"; else if (tinfo.IsEnum) baseName = "ENUM"; else if (tinfo.IsValueType) baseName = "STRUCT"; else if (tinfo.IsClass) { baseName = "CLASS"; if (tinfo.IsSealed && tinfo.IsAbstract) baseName += ":STATIC"; else { if (tinfo.IsSealed) baseName += ":SEALED"; if (tinfo.IsAbstract) baseName += ":ABSTRACT"; } } if (tinfo.IsNestedFamily) baseName += ":PROTECTED"; baseName += " " + tinfo.GetQualifiedName(); if (tinfo.IsEnum) { foreach(var val in Enum.GetValues(tinfo.AsType())) { yield return baseName + " { " + val + $"={(int)val}" + " }"; } yield break; } if (tinfo.IsClass) { // base classes var baseType = tinfo.BaseType; while (baseType != null && baseType != typeof(object)) { yield return baseName + " { USING " + baseType.GetQualifiedName() + " }"; baseType = baseType.BaseType; } } foreach (var ifaceType in tinfo.GetInterfaces()) { if (ifaceType.IsNotPublic) continue; yield return baseName + " { USING " + ifaceType.GetQualifiedName() + " }"; } foreach (var m in tinfo.DeclaredMembers) { var signatures = GetMemberSignature(m); if (signatures == null) continue; foreach (var s in signatures) { yield return baseName + " { " + s + " }"; } } } public static IEnumerable GetMemberSignature(MemberInfo minfo) { if (minfo is FieldInfo finfo) return GetFieldSignature(finfo); if (minfo is TypeInfo tinfo) return GetTypeSignature(tinfo); if (minfo is PropertyInfo pinfo) return GetPropertySignature(pinfo); if (minfo is MethodInfo xinfo) return GetMethodSignature(xinfo); if (minfo is ConstructorInfo cinfo) return GetMethodSignature(cinfo); if (minfo is EventInfo einfo) return GetEventSignature(einfo); return null; } public static IEnumerable GetFieldSignature(FieldInfo finfo) { if (!IsVisible(finfo)) yield break; var name = "FIELD"; if (finfo.IsLiteral) name += ":CONST"; else if (finfo.IsStatic) name += ":STATIC"; if (finfo.IsInitOnly) name += ":READONLY"; name += $" {finfo.Name} {finfo.FieldType.GetQualifiedName()}"; yield return name; } public static IEnumerable GetEventSignature(EventInfo einfo) { // if (!IsVisible(einfo)) yield break; var name = "EVENT"; name += $" {einfo.Name} {einfo.EventHandlerType.GetQualifiedName()}"; yield return name; } public static IEnumerable GetPropertySignature(PropertyInfo pinfo) { var pname = $"{pinfo.Name} {pinfo.PropertyType.GetQualifiedName()}"; var getter = pinfo.GetGetMethod(); if (IsVisible(getter,true)) yield return "METHOD:GET"+ GetMethodModifiers(getter) + " " + pname; var setter = pinfo.GetSetMethod(); if (IsVisible(setter, true)) yield return "METHOD:SET"+ GetMethodModifiers(setter) +" " + pname; } public static IEnumerable GetMethodSignature(MethodBase minfo) { string mname = "METHOD"; if (minfo is MethodInfo mminfo) { var isExtension = mminfo.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), true); if (isExtension) mname += ":EXTENSION"; else mname += GetMethodModifiers(minfo); mname += " "; if (!IsVisible(minfo)) yield break; mname += mminfo.Name + $" {mminfo.ReturnType.GetQualifiedName()}"; } if (minfo is ConstructorInfo cinfo) { if (!IsVisible(minfo,true)) yield break; mname += ":CONSTRUCTOR"; } mname += " "; var mparams = minfo.GetParameters() .Select(item => GetParameterSignature(item)) .ToList(); yield return mname + "(" + string.Join(", ", mparams) + ")"; } public static String GetParameterSignature(ParameterInfo pinfo) { var prefix = string.Empty; if (pinfo.GetCustomAttribute(typeof(ParamArrayAttribute)) != null) prefix += "params "; if (pinfo.ParameterType.IsByRef) { if (pinfo.IsIn) prefix += "in "; else if (pinfo.IsOut) prefix += "out "; else prefix += "ref "; } var postfix = string.Empty; if (pinfo.HasDefaultValue) { if (pinfo.DefaultValue == null) postfix = "=null"; else postfix = "=" + pinfo.DefaultValue.ToString(); } return prefix + pinfo.ParameterType.GetQualifiedName() + postfix; } public static Boolean IsVisible(MethodBase minfo, Boolean withSpecials = false) { if (minfo == null) return false; if (minfo.IsSpecialName && !withSpecials) return false; if (minfo.IsPrivate) return false; if (minfo.IsAssembly) return false; if (minfo.IsFamilyOrAssembly) return false; return true; } public static Boolean IsVisible(FieldInfo finfo) { if (finfo == null) return false; if (finfo.IsPrivate) return false; if (finfo.IsAssembly) return false; if (finfo.IsFamilyOrAssembly) return false; return true; } public static String GetMethodModifiers(MethodBase minfo) { if (minfo.IsPrivate) return string.Empty; var mod = string.Empty; if (minfo.IsFamily) mod += ":PROTECTED"; if (minfo.IsStatic) mod += ":STATIC"; if (minfo.IsAbstract) mod += ":ABSTRACT"; else if (minfo.IsVirtual) mod += ":VIRTUAL"; return mod; } public static String GetQualifiedName(this Type tinfo) { return tinfo.GetTypeInfo().GetQualifiedName(); } public static String GetQualifiedName(this TypeInfo tinfo) { var postfix = string.Empty; // unwrap jagged array while (tinfo.IsArray) { postfix += "[" + string.Join("", Enumerable.Repeat(",", tinfo.GetArrayRank() - 1)) + "]"; tinfo = tinfo.GetElementType().GetTypeInfo(); } var name = tinfo.Name; // remove pointer semantics name = name.Replace("&", ""); // add jagged array postfix name += postfix; // handle generic types if (tinfo.IsGenericType || tinfo.IsGenericTypeDefinition) { name = name.Replace("`1", ""); name = name.Replace("`2", ""); name = name.Replace("`3", ""); name = name.Replace("`4", ""); name = name.Replace("`5", ""); name = name.Replace("`6", ""); name = name.Replace("`7", ""); name = name.Replace("`8", ""); var gpm = tinfo .GenericTypeArguments .Concat(tinfo.GenericTypeParameters) .Select(item => GetQualifiedName(item)) .ToList(); if (gpm.Count > 0) name += "<" + string.Join(",", gpm) + ">"; } return name; } } }