DumpAssemblyAPI.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Text;
  6. using static System.FormattableString;
  7. namespace SharpGLTF
  8. {
  9. /// <summary>
  10. /// Utility class to dump the public API of an assembly
  11. /// </summary>
  12. static class DumpAssemblyAPI
  13. {
  14. // https://www.hanselman.com/blog/ManagingChangeWithNETAssemblyDiffTools.aspx
  15. public static IEnumerable<String> GetAssemblySignature(Assembly assembly)
  16. {
  17. return assembly.ExportedTypes
  18. .SelectMany(item => GetTypeSignature(item.GetTypeInfo()).Select(l => "NS " + item.Namespace + " { " + l + " }" ) );
  19. }
  20. public static IEnumerable<String> GetTypeSignature(TypeInfo tinfo)
  21. {
  22. if (tinfo.IsNestedPrivate) yield break;
  23. if (tinfo.IsNestedAssembly) yield break;
  24. string baseName = string.Empty;
  25. if (tinfo.IsInterface) baseName = "INTERFACE";
  26. else if (tinfo.IsEnum) baseName = "ENUM";
  27. else if (tinfo.IsValueType) baseName = "STRUCT";
  28. else if (tinfo.IsClass)
  29. {
  30. baseName = "CLASS";
  31. if (tinfo.IsSealed && tinfo.IsAbstract) baseName += ":STATIC";
  32. else
  33. {
  34. if (tinfo.IsSealed) baseName += ":SEALED";
  35. if (tinfo.IsAbstract) baseName += ":ABSTRACT";
  36. }
  37. }
  38. if (tinfo.IsNestedFamily) baseName += ":PROTECTED";
  39. baseName += " " + tinfo.GetQualifiedName();
  40. if (tinfo.IsEnum)
  41. {
  42. foreach(var val in Enum.GetValues(tinfo.AsType()))
  43. {
  44. yield return baseName + " { " + val + $"={(int)val}" + " }";
  45. }
  46. yield break;
  47. }
  48. if (tinfo.IsClass)
  49. {
  50. // base classes
  51. var baseType = tinfo.BaseType;
  52. while (baseType != null && baseType != typeof(object))
  53. {
  54. yield return baseName + " { USING " + baseType.GetQualifiedName() + " }";
  55. baseType = baseType.BaseType;
  56. }
  57. }
  58. foreach (var ifaceType in tinfo.GetInterfaces())
  59. {
  60. if (ifaceType.IsNotPublic) continue;
  61. yield return baseName + " { USING " + ifaceType.GetQualifiedName() + " }";
  62. }
  63. foreach (var m in tinfo.DeclaredMembers)
  64. {
  65. var signatures = GetMemberSignature(m);
  66. if (signatures == null) continue;
  67. foreach (var s in signatures)
  68. {
  69. yield return baseName + " { " + s + " }";
  70. }
  71. }
  72. }
  73. public static IEnumerable<String> GetMemberSignature(MemberInfo minfo)
  74. {
  75. if (minfo is FieldInfo finfo) return GetFieldSignature(finfo);
  76. if (minfo is TypeInfo tinfo) return GetTypeSignature(tinfo);
  77. if (minfo is PropertyInfo pinfo) return GetPropertySignature(pinfo);
  78. if (minfo is MethodInfo xinfo) return GetMethodSignature(xinfo);
  79. if (minfo is ConstructorInfo cinfo) return GetMethodSignature(cinfo);
  80. if (minfo is EventInfo einfo) return GetEventSignature(einfo);
  81. return null;
  82. }
  83. public static IEnumerable<String> GetFieldSignature(FieldInfo finfo)
  84. {
  85. if (!IsVisible(finfo)) yield break;
  86. var name = "FIELD";
  87. if (finfo.IsLiteral) name += ":CONST";
  88. else if (finfo.IsStatic) name += ":STATIC";
  89. if (finfo.IsInitOnly) name += ":READONLY";
  90. name += $" {finfo.Name} {finfo.FieldType.GetQualifiedName()}";
  91. yield return name;
  92. }
  93. public static IEnumerable<String> GetEventSignature(EventInfo einfo)
  94. {
  95. // if (!IsVisible(einfo)) yield break;
  96. var name = "EVENT";
  97. name += $" {einfo.Name} {einfo.EventHandlerType.GetQualifiedName()}";
  98. yield return name;
  99. }
  100. public static IEnumerable<String> GetPropertySignature(PropertyInfo pinfo)
  101. {
  102. var pname = $"{pinfo.Name} {pinfo.PropertyType.GetQualifiedName()}";
  103. var getter = pinfo.GetGetMethod();
  104. if (IsVisible(getter,true)) yield return "METHOD:GET"+ GetMethodModifiers(getter) + " " + pname;
  105. var setter = pinfo.GetSetMethod();
  106. if (IsVisible(setter, true)) yield return "METHOD:SET"+ GetMethodModifiers(setter) +" " + pname;
  107. }
  108. public static IEnumerable<String> GetMethodSignature(MethodBase minfo)
  109. {
  110. string mname = "METHOD";
  111. if (minfo is MethodInfo mminfo)
  112. {
  113. var isExtension = mminfo.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), true);
  114. if (isExtension) mname += ":EXTENSION";
  115. else mname += GetMethodModifiers(minfo);
  116. mname += " ";
  117. if (!IsVisible(minfo)) yield break;
  118. mname += mminfo.Name + $" {mminfo.ReturnType.GetQualifiedName()}";
  119. }
  120. if (minfo is ConstructorInfo cinfo)
  121. {
  122. if (!IsVisible(minfo,true)) yield break;
  123. mname += ":CONSTRUCTOR";
  124. }
  125. mname += " ";
  126. var mparams = minfo.GetParameters()
  127. .Select(item => GetParameterSignature(item))
  128. .ToList();
  129. yield return mname + "(" + string.Join(", ", mparams) + ")";
  130. }
  131. public static String GetParameterSignature(ParameterInfo pinfo)
  132. {
  133. var prefix = string.Empty;
  134. if (pinfo.GetCustomAttribute(typeof(ParamArrayAttribute)) != null) prefix += "params ";
  135. if (pinfo.ParameterType.IsByRef)
  136. {
  137. if (pinfo.IsIn) prefix += "in ";
  138. else if (pinfo.IsOut) prefix += "out ";
  139. else prefix += "ref ";
  140. }
  141. var postfix = string.Empty;
  142. if (pinfo.HasDefaultValue)
  143. {
  144. if (pinfo.DefaultValue == null) postfix = "=null";
  145. else postfix = "=" + pinfo.DefaultValue.ToString();
  146. }
  147. return prefix + pinfo.ParameterType.GetQualifiedName() + postfix;
  148. }
  149. public static Boolean IsVisible(MethodBase minfo, Boolean withSpecials = false)
  150. {
  151. if (minfo == null) return false;
  152. if (minfo.IsSpecialName && !withSpecials) return false;
  153. if (minfo.IsPrivate) return false;
  154. if (minfo.IsAssembly) return false;
  155. if (minfo.IsFamilyOrAssembly) return false;
  156. return true;
  157. }
  158. public static Boolean IsVisible(FieldInfo finfo)
  159. {
  160. if (finfo == null) return false;
  161. if (finfo.IsPrivate) return false;
  162. if (finfo.IsAssembly) return false;
  163. if (finfo.IsFamilyOrAssembly) return false;
  164. return true;
  165. }
  166. public static String GetMethodModifiers(MethodBase minfo)
  167. {
  168. if (minfo.IsPrivate) return string.Empty;
  169. var mod = string.Empty;
  170. if (minfo.IsFamily) mod += ":PROTECTED";
  171. if (minfo.IsStatic) mod += ":STATIC";
  172. if (minfo.IsAbstract) mod += ":ABSTRACT";
  173. else if (minfo.IsVirtual) mod += ":VIRTUAL";
  174. return mod;
  175. }
  176. public static String GetQualifiedName(this Type tinfo)
  177. {
  178. return tinfo.GetTypeInfo().GetQualifiedName();
  179. }
  180. public static String GetQualifiedName(this TypeInfo tinfo)
  181. {
  182. var postfix = string.Empty;
  183. // unwrap jagged array
  184. while (tinfo.IsArray)
  185. {
  186. postfix += "[" + string.Join("", Enumerable.Repeat(",", tinfo.GetArrayRank() - 1)) + "]";
  187. tinfo = tinfo.GetElementType().GetTypeInfo();
  188. }
  189. var name = tinfo.Name;
  190. // remove pointer semantics
  191. name = name.Replace("&", "");
  192. // add jagged array postfix
  193. name += postfix;
  194. // handle generic types
  195. if (tinfo.IsGenericType || tinfo.IsGenericTypeDefinition)
  196. {
  197. name = name.Replace("`1", "");
  198. name = name.Replace("`2", "");
  199. name = name.Replace("`3", "");
  200. name = name.Replace("`4", "");
  201. name = name.Replace("`5", "");
  202. name = name.Replace("`6", "");
  203. name = name.Replace("`7", "");
  204. name = name.Replace("`8", "");
  205. var gpm = tinfo
  206. .GenericTypeArguments
  207. .Concat(tinfo.GenericTypeParameters)
  208. .Select(item => GetQualifiedName(item))
  209. .ToList();
  210. if (gpm.Count > 0) name += "<" + string.Join(",", gpm) + ">";
  211. }
  212. return name;
  213. }
  214. }
  215. }