PageRenderTime 54ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Types/DocBuilder.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 740 lines | 580 code | 107 blank | 53 comment | 143 complexity | 683d3034b9fcb0dc7b73c0c009de4715 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.IO;
  19. using System.Reflection;
  20. using System.Text;
  21. using System.Threading;
  22. using System.Xml;
  23. using System.Xml.XPath;
  24. using Microsoft.Scripting;
  25. using Microsoft.Scripting.Hosting;
  26. using Microsoft.Scripting.Runtime;
  27. using Microsoft.Scripting.Utils;
  28. namespace IronPython.Runtime.Types {
  29. static class DocBuilder {
  30. internal static string GetDefaultDocumentation(string methodName) {
  31. switch (methodName) {
  32. case "__abs__": return "x.__abs__() <==> abs(x)";
  33. case "__add__": return "x.__add__(y) <==> x+y";
  34. case "__call__": return "x.__call__(...) <==> x(...)";
  35. case "__cmp__": return "x.__cmp__(y) <==> cmp(x,y)";
  36. case "__delitem__": return "x.__delitem__(y) <==> del x[y]";
  37. case "__div__": return "x.__div__(y) <==> x/y";
  38. case "__eq__": return "x.__eq__(y) <==> x==y";
  39. case "__floordiv__": return "x.__floordiv__(y) <==> x//y";
  40. case "__getitem__": return "x.__getitem__(y) <==> x[y]";
  41. case "__gt__": return "x.__gt__(y) <==> x>y";
  42. case "__hash__": return "x.__hash__() <==> hash(x)";
  43. case "__init__": return "x.__init__(...) initializes x; see x.__class__.__doc__ for signature";
  44. case "__len__": return "x.__len__() <==> len(x)";
  45. case "__lshift__": return "x.__rshift__(y) <==> x<<y";
  46. case "__lt__": return "x.__lt__(y) <==> x<y";
  47. case "__mod__": return "x.__mod__(y) <==> x%y";
  48. case "__mul__": return "x.__mul__(y) <==> x*y";
  49. case "__neg__": return "x.__neg__() <==> -x";
  50. case "__pow__": return "x.__pow__(y[, z]) <==> pow(x, y[, z])";
  51. case "__reduce__":
  52. case "__reduce_ex__": return "helper for pickle";
  53. case "__rshift__": return "x.__rshift__(y) <==> x>>y";
  54. case "__setitem__": return "x.__setitem__(i, y) <==> x[i]=";
  55. case "__str__": return "x.__str__() <==> str(x)";
  56. case "__sub__": return "x.__sub__(y) <==> x-y";
  57. case "__truediv__": return "x.__truediv__(y) <==> x/y";
  58. }
  59. return null;
  60. }
  61. private static string DocOneInfoForProperty(Type declaringType, string propertyName, MethodInfo getter, MethodInfo setter, object[] attrs) {
  62. if (attrs == null || attrs.Length == 0) {
  63. StringBuilder autoDoc = new StringBuilder();
  64. string summary = null;
  65. #if !SILVERLIGHT // XML doc
  66. string returns = null;
  67. GetXmlDocForProperty(declaringType, propertyName, out summary, out returns);
  68. #endif
  69. if (summary != null) {
  70. autoDoc.AppendLine(summary);
  71. autoDoc.AppendLine();
  72. }
  73. if (getter != null) {
  74. autoDoc.Append("Get: ");
  75. autoDoc.AppendLine(CreateAutoDoc(getter, propertyName, 0));
  76. }
  77. if (setter != null) {
  78. autoDoc.Append("Set: ");
  79. autoDoc.Append(CreateAutoDoc(setter, propertyName, 1));
  80. autoDoc.AppendLine(" = value");
  81. }
  82. return autoDoc.ToString();
  83. }
  84. StringBuilder docStr = new StringBuilder();
  85. for (int i = 0; i < attrs.Length; i++) {
  86. docStr.Append(((DocumentationAttribute)attrs[i]).Documentation);
  87. docStr.Append(Environment.NewLine);
  88. }
  89. return docStr.ToString();
  90. }
  91. public static string DocOneInfo(ExtensionPropertyInfo info) {
  92. return DocOneInfoForProperty(info.DeclaringType, info.Name, info.Getter, info.Setter, null);
  93. }
  94. public static string DocOneInfo(PropertyInfo info) {
  95. object[] attrs = info.GetCustomAttributes(typeof(DocumentationAttribute), false);
  96. return DocOneInfoForProperty(info.DeclaringType, info.Name, info.GetGetMethod(), info.GetSetMethod(), attrs);
  97. }
  98. public static string DocOneInfo(FieldInfo info) {
  99. object[] attrs = info.GetCustomAttributes(typeof(DocumentationAttribute), false);
  100. return DocOneInfoForProperty(info.DeclaringType, info.Name, null, null, attrs);
  101. }
  102. public static string DocOneInfo(MethodBase info, string name) {
  103. // Look for methods tagged with [Documentation("doc string for foo")]
  104. object[] attrs = info.GetCustomAttributes(typeof(DocumentationAttribute), false);
  105. if (attrs.Length > 0) {
  106. Debug.Assert(attrs.Length == 1);
  107. DocumentationAttribute doc = attrs[0] as DocumentationAttribute;
  108. return doc.Documentation;
  109. }
  110. string defaultDoc = GetDefaultDocumentation(name);
  111. if (defaultDoc != null) {
  112. return defaultDoc;
  113. }
  114. return CreateAutoDoc(info, name, 0);
  115. }
  116. public static string CreateAutoDoc(MethodBase info) {
  117. return CreateAutoDoc(info, null, 0);
  118. }
  119. public static string CreateAutoDoc(EventInfo info) {
  120. string summary = null;
  121. #if !SILVERLIGHT // XML doc
  122. string returns;
  123. GetXmlDoc(info, out summary, out returns);
  124. #endif
  125. return summary;
  126. }
  127. public static string CreateAutoDoc(Type t) {
  128. string summary = null;
  129. #if !SILVERLIGHT // XML doc
  130. GetXmlDoc(t, out summary);
  131. #endif
  132. if (t.IsEnum) {
  133. #if SILVERLIGHT // GetNames/GetValues
  134. FieldInfo[] fields = t.GetFields(BindingFlags.Static | BindingFlags.Public);
  135. string[] names = new string[fields.Length];
  136. for (int i = 0; i < fields.Length; i++) {
  137. object value = Convert.ChangeType(fields[i].GetValue(null), Enum.GetUnderlyingType(t), Thread.CurrentThread.CurrentCulture);
  138. names[i] = String.Concat(fields[i].Name, " (", value.ToString(), ")");
  139. }
  140. #else
  141. string[] names = Enum.GetNames(t);
  142. Array values = Enum.GetValues(t);
  143. for (int i = 0; i < names.Length; i++) {
  144. names[i] = String.Concat(names[i],
  145. " (",
  146. Convert.ChangeType(values.GetValue(i), Enum.GetUnderlyingType(t)).ToString(),
  147. ")");
  148. }
  149. #endif
  150. Array.Sort<string>(names);
  151. summary = String.Concat(
  152. summary,
  153. Environment.NewLine, Environment.NewLine,
  154. "enum ", t.IsDefined(typeof(FlagsAttribute), false) ? "(flags) ": "", GetPythonTypeName(t), ", values: ",
  155. String.Join(", ", names));
  156. }
  157. return summary;
  158. }
  159. public static OverloadDoc GetOverloadDoc(MethodBase info, string name, int endParamSkip) {
  160. return GetOverloadDoc(info, name, endParamSkip, true);
  161. }
  162. /// <summary>
  163. /// Creates a DLR OverloadDoc object which describes information about this overload.
  164. /// </summary>
  165. /// <param name="info">The method to document</param>
  166. /// <param name="name">The name of the method if it should override the name in the MethodBase</param>
  167. /// <param name="endParamSkip">Parameters to skip at the end - used for removing the value on a setter method</param>
  168. /// <param name="includeSelf">true to include self on instance methods</param>
  169. public static OverloadDoc GetOverloadDoc(MethodBase info, string name, int endParamSkip, bool includeSelf) {
  170. string summary = null, returns = null;
  171. List<KeyValuePair<string, string>> parameters = null;
  172. #if !SILVERLIGHT // XML doc
  173. GetXmlDoc(info, out summary, out returns, out parameters);
  174. #endif
  175. StringBuilder retType = new StringBuilder();
  176. int returnCount = 0;
  177. MethodInfo mi = info as MethodInfo;
  178. if (mi != null) {
  179. if (mi.ReturnType != typeof(void)) {
  180. retType.Append(GetPythonTypeName(mi.ReturnType));
  181. returnCount++;
  182. var typeAttrs = mi.ReturnParameter.GetCustomAttributes(typeof(SequenceTypeInfoAttribute), true);
  183. if (typeAttrs.Length > 0) {
  184. retType.Append(" (of ");
  185. SequenceTypeInfoAttribute typeAttr = (SequenceTypeInfoAttribute)typeAttrs[0];
  186. for (int curTypeAttr = 0; curTypeAttr < typeAttr.Types.Count; curTypeAttr++) {
  187. if (curTypeAttr != 0) {
  188. retType.Append(", ");
  189. }
  190. retType.Append(GetPythonTypeName(typeAttr.Types[curTypeAttr]));
  191. }
  192. retType.Append(")");
  193. }
  194. var dictTypeAttrs = mi.ReturnParameter.GetCustomAttributes(typeof(DictionaryTypeInfoAttribute), true);
  195. if (dictTypeAttrs.Length > 0) {
  196. var dictTypeAttr = (DictionaryTypeInfoAttribute)dictTypeAttrs[0];
  197. retType.Append(String.Format(" (of {0} to {1})", GetPythonTypeName(dictTypeAttr.KeyType), GetPythonTypeName(dictTypeAttr.ValueType)));
  198. }
  199. }
  200. if (name == null) {
  201. var hashIndex = mi.Name.IndexOf('#');
  202. if (hashIndex == -1) {
  203. name = mi.Name;
  204. } else {
  205. name = mi.Name.Substring(0, hashIndex);
  206. }
  207. }
  208. } else if(name == null) {
  209. name = "__new__";
  210. }
  211. // For generic methods display either type parameters (for unbound methods) or
  212. // type arguments (for bound ones).
  213. if (mi != null && mi.IsGenericMethod) {
  214. Type[] typePars = mi.GetGenericArguments();
  215. bool unbound = mi.ContainsGenericParameters;
  216. StringBuilder tmp = new StringBuilder();
  217. tmp.Append(name);
  218. tmp.Append("[");
  219. if (typePars.Length > 1)
  220. tmp.Append("(");
  221. bool insertComma = false;
  222. foreach (Type t in typePars) {
  223. if (insertComma)
  224. tmp.Append(", ");
  225. if (unbound)
  226. tmp.Append(t.Name);
  227. else
  228. tmp.Append(GetPythonTypeName(t));
  229. insertComma = true;
  230. }
  231. if (typePars.Length > 1)
  232. tmp.Append(")");
  233. tmp.Append("]");
  234. name = tmp.ToString();
  235. }
  236. List<ParameterDoc> paramDoc = new List<ParameterDoc>();
  237. if (mi == null) {
  238. if (name == "__new__") {
  239. // constructor, auto-insert cls
  240. paramDoc.Add(new ParameterDoc("cls", "type"));
  241. }
  242. } else if (!mi.IsStatic && includeSelf) {
  243. paramDoc.Add(new ParameterDoc("self", GetPythonTypeName(mi.DeclaringType)));
  244. }
  245. ParameterInfo[] pis = info.GetParameters();
  246. for (int i = 0; i < pis.Length - endParamSkip; i++) {
  247. ParameterInfo pi = pis[i];
  248. if (i == 0 && pi.ParameterType == typeof(CodeContext)) {
  249. // hide CodeContext parameters
  250. continue;
  251. }
  252. if ((pi.Attributes & ParameterAttributes.Out) == ParameterAttributes.Out || pi.ParameterType.IsByRef) {
  253. if (returnCount == 1) {
  254. retType.Insert(0, "(");
  255. }
  256. if (returnCount != 0) retType.Append(", ");
  257. returnCount++;
  258. retType.Append(GetPythonTypeName(pi.ParameterType));
  259. if ((pi.Attributes & ParameterAttributes.Out) == ParameterAttributes.Out) continue;
  260. }
  261. ParameterFlags flags = ParameterFlags.None;
  262. if (pi.IsDefined(typeof(ParamArrayAttribute), false)) {
  263. flags |= ParameterFlags.ParamsArray;
  264. } else if (pi.IsDefined(typeof(ParamDictionaryAttribute), false)) {
  265. flags |= ParameterFlags.ParamsDict;
  266. }
  267. string paramDocString = null;
  268. if (parameters != null) {
  269. foreach (var paramXmlDoc in parameters) {
  270. if (paramXmlDoc.Key == pi.Name) {
  271. paramDocString = paramXmlDoc.Value;
  272. break;
  273. }
  274. }
  275. }
  276. paramDoc.Add(
  277. new ParameterDoc(
  278. pi.Name ?? "", // manufactured methods, such as string[].ctor(int) can have no parameter names.
  279. GetPythonTypeName(pi.ParameterType),
  280. paramDocString,
  281. flags
  282. )
  283. );
  284. }
  285. if (returnCount > 1) {
  286. retType.Append(')');
  287. }
  288. ParameterDoc retDoc = new ParameterDoc(String.Empty, retType.ToString(), returns);
  289. return new OverloadDoc(
  290. name,
  291. summary,
  292. paramDoc,
  293. retDoc
  294. );
  295. }
  296. internal static string CreateAutoDoc(MethodBase info, string name, int endParamSkip) {
  297. #if !SILVERLIGHT // Console
  298. int lineWidth;
  299. try {
  300. lineWidth = Console.WindowWidth - 30;
  301. } catch {
  302. // console output has been redirected.
  303. lineWidth = 80;
  304. }
  305. #else
  306. int lineWidth = 80;
  307. #endif
  308. var docInfo = GetOverloadDoc(info, name, endParamSkip);
  309. StringBuilder ret = new StringBuilder();
  310. ret.Append(docInfo.Name);
  311. ret.Append("(");
  312. string comma = "";
  313. foreach (var param in docInfo.Parameters) {
  314. ret.Append(comma);
  315. if ((param.Flags & ParameterFlags.ParamsArray) != 0) {
  316. ret.Append('*');
  317. } else if ((param.Flags & ParameterFlags.ParamsDict) != 0) {
  318. ret.Append("**");
  319. }
  320. ret.Append(param.Name);
  321. if (!String.IsNullOrEmpty(param.TypeName)) {
  322. ret.Append(": ");
  323. ret.Append(param.TypeName);
  324. }
  325. comma = ", ";
  326. }
  327. ret.Append(")");
  328. if (!String.IsNullOrEmpty(docInfo.ReturnParameter.TypeName)) {
  329. ret.Append(" -> ");
  330. ret.AppendLine(docInfo.ReturnParameter.TypeName);
  331. }
  332. // Append XML Doc Info if available
  333. if (!String.IsNullOrEmpty(docInfo.Documentation)) {
  334. ret.AppendLine();
  335. ret.AppendLine(StringUtils.SplitWords(docInfo.Documentation, true, lineWidth));
  336. }
  337. bool emittedParamDoc = false;
  338. foreach (var param in docInfo.Parameters) {
  339. if (!String.IsNullOrEmpty(param.Documentation)) {
  340. if (!emittedParamDoc) {
  341. ret.AppendLine();
  342. emittedParamDoc = true;
  343. }
  344. ret.Append(" ");
  345. ret.Append(param.Name);
  346. ret.Append(": ");
  347. ret.AppendLine(StringUtils.SplitWords(param.Documentation, false, lineWidth));
  348. }
  349. }
  350. if (!String.IsNullOrEmpty(docInfo.ReturnParameter.Documentation)) {
  351. ret.Append(" Returns: ");
  352. ret.AppendLine(StringUtils.SplitWords(docInfo.ReturnParameter.Documentation, false, lineWidth));
  353. }
  354. return ret.ToString();
  355. }
  356. private static string GetPythonTypeName(Type type) {
  357. if (type.IsByRef) {
  358. type = type.GetElementType();
  359. }
  360. return DynamicHelpers.GetPythonTypeFromType(type).Name;
  361. }
  362. #if !SILVERLIGHT // XML doc
  363. private static readonly object _CachedDocLockObject = new object();
  364. private static readonly List<Assembly> _AssembliesWithoutXmlDoc = new List<Assembly>();
  365. [MultiRuntimeAware]
  366. private static XPathDocument _CachedDoc;
  367. [MultiRuntimeAware]
  368. private static string _CachedDocName;
  369. private static string GetXmlName(Type type) {
  370. StringBuilder res = new StringBuilder();
  371. res.Append("T:");
  372. AppendTypeFormat(type, res);
  373. return res.ToString();
  374. }
  375. private static string GetXmlName(EventInfo field) {
  376. StringBuilder res = new StringBuilder();
  377. res.Append("E:");
  378. AppendTypeFormat(field.DeclaringType, res);
  379. res.Append('.');
  380. res.Append(field.Name);
  381. return res.ToString();
  382. }
  383. private static string GetXmlNameForProperty(Type declaringType, string propertyName) {
  384. StringBuilder res = new StringBuilder();
  385. res.Append("P:");
  386. res.Append(declaringType.Namespace);
  387. res.Append('.');
  388. res.Append(declaringType.Name);
  389. res.Append('.');
  390. res.Append(propertyName);
  391. return res.ToString();
  392. }
  393. private static string GetXmlName(MethodBase info) {
  394. StringBuilder res = new StringBuilder();
  395. res.Append("M:");
  396. res.Append(info.DeclaringType.Namespace);
  397. res.Append('.');
  398. res.Append(info.DeclaringType.Name);
  399. res.Append('.');
  400. res.Append(info.Name);
  401. ParameterInfo[] pi = info.GetParameters();
  402. if (pi.Length > 0) {
  403. res.Append('(');
  404. for (int i = 0; i < pi.Length; i++) {
  405. Type curType = pi[i].ParameterType;
  406. if (i != 0) res.Append(',');
  407. AppendTypeFormat(curType, res);
  408. }
  409. res.Append(')');
  410. }
  411. return res.ToString();
  412. }
  413. /// <summary>
  414. /// Converts a Type object into a string suitable for lookup in the help file. All generic types are
  415. /// converted down to their generic type definition.
  416. /// </summary>
  417. private static void AppendTypeFormat(Type curType, StringBuilder res) {
  418. if (curType.IsGenericType) {
  419. curType = curType.GetGenericTypeDefinition();
  420. }
  421. if (curType.IsGenericParameter) {
  422. res.Append(ReflectionUtils.GenericArityDelimiter);
  423. res.Append(curType.GenericParameterPosition);
  424. } else if (curType.ContainsGenericParameters) {
  425. res.Append(curType.Namespace);
  426. res.Append('.');
  427. res.Append(curType.Name.Substring(0, curType.Name.Length - 2));
  428. res.Append('{');
  429. Type[] types = curType.GetGenericArguments();
  430. for (int j = 0; j < types.Length; j++) {
  431. if (j != 0) res.Append(',');
  432. if (types[j].IsGenericParameter) {
  433. res.Append(ReflectionUtils.GenericArityDelimiter);
  434. res.Append(types[j].GenericParameterPosition);
  435. } else {
  436. AppendTypeFormat(types[j], res);
  437. }
  438. }
  439. res.Append('}');
  440. } else {
  441. res.Append(curType.FullName);
  442. }
  443. }
  444. static string GetXmlDocLocation(Assembly assem) {
  445. if (_AssembliesWithoutXmlDoc.Contains(assem)) {
  446. return null;
  447. }
  448. string location = null;
  449. try {
  450. location = assem.Location;
  451. } catch (System.Security.SecurityException) {
  452. // FileIOPermission is required to access the file
  453. } catch (NotSupportedException) {
  454. // Dynamic assemblies do not support Assembly.Location
  455. }
  456. if (location == null) _AssembliesWithoutXmlDoc.Add(assem);
  457. return location;
  458. }
  459. private const string _frameworkReferencePath = @"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0";
  460. /// <summary>
  461. /// Gets the XPathDocument for the specified assembly, or null if one is not available.
  462. /// </summary>
  463. private static XPathDocument GetXPathDocument(Assembly asm) {
  464. System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
  465. string location = GetXmlDocLocation(asm);
  466. if (location == null) {
  467. return null;
  468. }
  469. string baseDir = Path.GetDirectoryName(location);
  470. string baseFile = Path.GetFileNameWithoutExtension(location) + ".xml";
  471. string xml = Path.Combine(Path.Combine(baseDir, ci.Name), baseFile);
  472. if (!System.IO.File.Exists(xml)) {
  473. int hyphen = ci.Name.IndexOf('-');
  474. if (hyphen != -1) {
  475. xml = Path.Combine(Path.Combine(baseDir, ci.Name.Substring(0, hyphen)), baseFile);
  476. }
  477. if (!System.IO.File.Exists(xml)) {
  478. xml = Path.Combine(baseDir, baseFile);
  479. if (!System.IO.File.Exists(xml)) {
  480. #if !CLR2
  481. // On .NET 4.0 documentation is in the reference assembly location
  482. xml = Path.Combine(
  483. Path.Combine(
  484. Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
  485. _frameworkReferencePath
  486. ),
  487. baseFile
  488. );
  489. if (!File.Exists(xml))
  490. #endif
  491. {
  492. _AssembliesWithoutXmlDoc.Add(asm);
  493. return null;
  494. }
  495. }
  496. }
  497. }
  498. XPathDocument xpd;
  499. lock (_CachedDocLockObject) {
  500. if (_CachedDocName == xml) {
  501. xpd = _CachedDoc;
  502. } else {
  503. xpd = new XPathDocument(xml);
  504. }
  505. _CachedDoc = xpd;
  506. _CachedDocName = xml;
  507. }
  508. return xpd;
  509. }
  510. /// <summary>
  511. /// Gets the Xml documentation for the specified MethodBase.
  512. /// </summary>
  513. private static void GetXmlDoc(MethodBase info, out string summary, out string returns, out List<KeyValuePair<string, string>> parameters) {
  514. summary = null;
  515. returns = null;
  516. parameters = null;
  517. XPathDocument xpd = GetXPathDocument(info.DeclaringType.Assembly);
  518. if (xpd == null) return;
  519. XPathNavigator xpn = xpd.CreateNavigator();
  520. string path = "/doc/members/member[@name='" + GetXmlName(info) + "']/*";
  521. XPathNodeIterator iter = xpn.Select(path);
  522. while (iter.MoveNext()) {
  523. switch (iter.Current.Name) {
  524. case "summary": summary = XmlToString(iter); break;
  525. case "returns": returns = XmlToString(iter); break;
  526. case "param":
  527. string name = null;
  528. string paramText = XmlToString(iter);
  529. if (iter.Current.MoveToFirstAttribute()) {
  530. name = iter.Current.Value;
  531. }
  532. if (name != null) {
  533. if (parameters == null) {
  534. parameters = new List<KeyValuePair<string, string>>();
  535. }
  536. parameters.Add(new KeyValuePair<string, string>(name, paramText.Trim()));
  537. }
  538. break;
  539. case "exception":
  540. break;
  541. }
  542. }
  543. }
  544. /// <summary>
  545. /// Gets the Xml documentation for the specified Type.
  546. /// </summary>
  547. private static void GetXmlDoc(Type type, out string summary) {
  548. summary = null;
  549. XPathDocument xpd = GetXPathDocument(type.Assembly);
  550. if (xpd == null) return;
  551. XPathNavigator xpn = xpd.CreateNavigator();
  552. string path = "/doc/members/member[@name='" + GetXmlName(type) + "']/*";
  553. XPathNodeIterator iter = xpn.Select(path);
  554. while (iter.MoveNext()) {
  555. switch (iter.Current.Name) {
  556. case "summary": summary = XmlToString(iter); break;
  557. }
  558. }
  559. }
  560. /// <summary>
  561. /// Gets the Xml documentation for the specified Field.
  562. /// </summary>
  563. private static void GetXmlDocForProperty(Type declaringType, string propertyName, out string summary, out string returns) {
  564. summary = null;
  565. returns = null;
  566. XPathDocument xpd = GetXPathDocument(declaringType.Assembly);
  567. if (xpd == null) return;
  568. XPathNavigator xpn = xpd.CreateNavigator();
  569. string path = "/doc/members/member[@name='" + GetXmlNameForProperty(declaringType, propertyName) + "']/*";
  570. XPathNodeIterator iter = xpn.Select(path);
  571. while (iter.MoveNext()) {
  572. switch (iter.Current.Name) {
  573. case "summary": summary = XmlToString(iter); break;
  574. case "returns": returns = XmlToString(iter); break;
  575. }
  576. }
  577. }
  578. /// <summary>
  579. /// Gets the Xml documentation for the specified Field.
  580. /// </summary>
  581. private static void GetXmlDoc(EventInfo info, out string summary, out string returns) {
  582. summary = null;
  583. returns = null;
  584. XPathDocument xpd = GetXPathDocument(info.DeclaringType.Assembly);
  585. if (xpd == null) return;
  586. XPathNavigator xpn = xpd.CreateNavigator();
  587. string path = "/doc/members/member[@name='" + GetXmlName(info) + "']/*";
  588. XPathNodeIterator iter = xpn.Select(path);
  589. while (iter.MoveNext()) {
  590. switch (iter.Current.Name) {
  591. case "summary": summary = XmlToString(iter) + Environment.NewLine; break;
  592. }
  593. }
  594. }
  595. /// <summary>
  596. /// Converts the XML as stored in the config file into a human readable string.
  597. /// </summary>
  598. private static string XmlToString(XPathNodeIterator iter) {
  599. XmlReader xr = iter.Current.ReadSubtree();
  600. StringBuilder text = new StringBuilder();
  601. if (xr.Read()) {
  602. for (; ; ) {
  603. switch (xr.NodeType) {
  604. case XmlNodeType.Text:
  605. text.Append(xr.ReadString());
  606. continue;
  607. case XmlNodeType.Element:
  608. switch (xr.Name) {
  609. case "see":
  610. if (xr.MoveToFirstAttribute() && xr.ReadAttributeValue()) {
  611. int arity = xr.Value.IndexOf(ReflectionUtils.GenericArityDelimiter);
  612. if (arity != -1)
  613. text.Append(xr.Value, 2, arity - 2);
  614. else
  615. text.Append(xr.Value, 2, xr.Value.Length - 2);
  616. }
  617. break;
  618. case "paramref":
  619. if (xr.MoveToAttribute("name")) {
  620. text.Append(xr.Value);
  621. }
  622. break;
  623. }
  624. break;
  625. }
  626. if (!xr.Read()) break;
  627. }
  628. }
  629. return text.ToString().Trim();
  630. }
  631. #endif
  632. }
  633. }