XmlDocKeyProvider.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Diagnostics;
  21. using System.Linq;
  22. using System.Text;
  23. using Mono.Cecil;
  24. namespace ICSharpCode.ILSpy.XmlDoc
  25. {
  26. /// <summary>
  27. /// Provides XML documentation tags.
  28. /// </summary>
  29. public sealed class XmlDocKeyProvider
  30. {
  31. #region GetKey
  32. public static string GetKey(MemberReference member)
  33. {
  34. StringBuilder b = new StringBuilder();
  35. if (member is TypeReference) {
  36. b.Append("T:");
  37. AppendTypeName(b, (TypeReference)member);
  38. } else {
  39. if (member is FieldReference)
  40. b.Append("F:");
  41. else if (member is PropertyDefinition)
  42. b.Append("P:");
  43. else if (member is EventDefinition)
  44. b.Append("E:");
  45. else if (member is MethodReference)
  46. b.Append("M:");
  47. AppendTypeName(b, member.DeclaringType);
  48. b.Append('.');
  49. b.Append(member.Name.Replace('.', '#'));
  50. IList<ParameterDefinition> parameters;
  51. TypeReference explicitReturnType = null;
  52. if (member is PropertyDefinition) {
  53. parameters = ((PropertyDefinition)member).Parameters;
  54. } else if (member is MethodReference) {
  55. MethodReference mr = (MethodReference)member;
  56. if (mr.HasGenericParameters) {
  57. b.Append("``");
  58. b.Append(mr.GenericParameters.Count);
  59. }
  60. parameters = mr.Parameters;
  61. if (mr.Name == "op_Implicit" || mr.Name == "op_Explicit") {
  62. explicitReturnType = mr.ReturnType;
  63. }
  64. } else {
  65. parameters = null;
  66. }
  67. if (parameters != null && parameters.Count > 0) {
  68. b.Append('(');
  69. for (int i = 0; i < parameters.Count; i++) {
  70. if (i > 0) b.Append(',');
  71. AppendTypeName(b, parameters[i].ParameterType);
  72. }
  73. b.Append(')');
  74. }
  75. if (explicitReturnType != null) {
  76. b.Append('~');
  77. AppendTypeName(b, explicitReturnType);
  78. }
  79. }
  80. return b.ToString();
  81. }
  82. static void AppendTypeName(StringBuilder b, TypeReference type)
  83. {
  84. if (type == null) {
  85. // could happen when a TypeSpecification has no ElementType; e.g. function pointers in C++/CLI assemblies
  86. return;
  87. }
  88. if (type is GenericInstanceType) {
  89. GenericInstanceType giType = (GenericInstanceType)type;
  90. AppendTypeNameWithArguments(b, giType.ElementType, giType.GenericArguments);
  91. } else if (type is TypeSpecification) {
  92. AppendTypeName(b, ((TypeSpecification)type).ElementType);
  93. ArrayType arrayType = type as ArrayType;
  94. if (arrayType != null) {
  95. b.Append('[');
  96. for (int i = 0; i < arrayType.Dimensions.Count; i++) {
  97. if (i > 0)
  98. b.Append(',');
  99. ArrayDimension ad = arrayType.Dimensions[i];
  100. if (ad.IsSized) {
  101. b.Append(ad.LowerBound);
  102. b.Append(':');
  103. b.Append(ad.UpperBound);
  104. }
  105. }
  106. b.Append(']');
  107. }
  108. ByReferenceType refType = type as ByReferenceType;
  109. if (refType != null) {
  110. b.Append('@');
  111. }
  112. PointerType ptrType = type as PointerType;
  113. if (ptrType != null) {
  114. b.Append('*');
  115. }
  116. } else {
  117. GenericParameter gp = type as GenericParameter;
  118. if (gp != null) {
  119. b.Append('`');
  120. if (gp.Owner.GenericParameterType == GenericParameterType.Method) {
  121. b.Append('`');
  122. }
  123. b.Append(gp.Position);
  124. } else if (type.DeclaringType != null) {
  125. AppendTypeName(b, type.DeclaringType);
  126. b.Append('.');
  127. b.Append(type.Name);
  128. } else {
  129. b.Append(type.FullName);
  130. }
  131. }
  132. }
  133. static int AppendTypeNameWithArguments(StringBuilder b, TypeReference type, IList<TypeReference> genericArguments)
  134. {
  135. int outerTypeParameterCount = 0;
  136. if (type.DeclaringType != null) {
  137. TypeReference declType = type.DeclaringType;
  138. outerTypeParameterCount = AppendTypeNameWithArguments(b, declType, genericArguments);
  139. b.Append('.');
  140. } else if (!string.IsNullOrEmpty(type.Namespace)) {
  141. b.Append(type.Namespace);
  142. b.Append('.');
  143. }
  144. int localTypeParameterCount = 0;
  145. b.Append(NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out localTypeParameterCount));
  146. if (localTypeParameterCount > 0) {
  147. int totalTypeParameterCount = outerTypeParameterCount + localTypeParameterCount;
  148. b.Append('{');
  149. for (int i = outerTypeParameterCount; i < totalTypeParameterCount && i < genericArguments.Count; i++) {
  150. if (i > outerTypeParameterCount) b.Append(',');
  151. AppendTypeName(b, genericArguments[i]);
  152. }
  153. b.Append('}');
  154. }
  155. return outerTypeParameterCount + localTypeParameterCount;
  156. }
  157. #endregion
  158. #region FindMemberByKey
  159. public static MemberReference FindMemberByKey(ModuleDefinition module, string key)
  160. {
  161. if (module == null)
  162. throw new ArgumentNullException("module");
  163. if (key == null || key.Length < 2 || key[1] != ':')
  164. return null;
  165. switch (key[0]) {
  166. case 'T':
  167. return FindType(module, key.Substring(2));
  168. case 'F':
  169. return FindMember(module, key, type => type.Fields);
  170. case 'P':
  171. return FindMember(module, key, type => type.Properties);
  172. case 'E':
  173. return FindMember(module, key, type => type.Events);
  174. case 'M':
  175. return FindMember(module, key, type => type.Methods);
  176. default:
  177. return null;
  178. }
  179. }
  180. static MemberReference FindMember(ModuleDefinition module, string key, Func<TypeDefinition, IEnumerable<MemberReference>> memberSelector)
  181. {
  182. Debug.WriteLine("Looking for member " + key);
  183. int parenPos = key.IndexOf('(');
  184. int dotPos;
  185. if (parenPos > 0) {
  186. dotPos = key.LastIndexOf('.', parenPos - 1, parenPos);
  187. } else {
  188. dotPos = key.LastIndexOf('.');
  189. }
  190. if (dotPos < 0) return null;
  191. TypeDefinition type = FindType(module, key.Substring(2, dotPos - 2));
  192. if (type == null)
  193. return null;
  194. string shortName;
  195. if (parenPos > 0) {
  196. shortName = key.Substring(dotPos + 1, parenPos - (dotPos + 1));
  197. } else {
  198. shortName = key.Substring(dotPos + 1);
  199. }
  200. Debug.WriteLine("Searching in type {0} for {1}", type.FullName, shortName);
  201. MemberReference shortNameMatch = null;
  202. foreach (MemberReference member in memberSelector(type)) {
  203. string memberKey = GetKey(member);
  204. Debug.WriteLine(memberKey);
  205. if (memberKey == key)
  206. return member;
  207. if (shortName == member.Name.Replace('.', '#'))
  208. shortNameMatch = member;
  209. }
  210. // if there's no match by ID string (key), return the match by name.
  211. return shortNameMatch;
  212. }
  213. static TypeDefinition FindType(ModuleDefinition module, string name)
  214. {
  215. int pos = name.LastIndexOf('.');
  216. string ns;
  217. if (pos >= 0) {
  218. ns = name.Substring(0, pos);
  219. name = name.Substring(pos + 1);
  220. } else {
  221. ns = string.Empty;
  222. }
  223. if (string.IsNullOrEmpty(name)) return null;
  224. TypeDefinition type = module.GetType(ns, name);
  225. if (type == null && ns.Length > 0) {
  226. // try if this is a nested type
  227. type = FindType(module, ns);
  228. if (type != null) {
  229. type = type.NestedTypes.FirstOrDefault(t => t.Name == name);
  230. }
  231. }
  232. return type;
  233. }
  234. #endregion
  235. }
  236. }