PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/msvc/task/PropSchemaGen/Program.cs

https://gitlab.com/goolic/WinObjC
C# | 254 lines | 191 code | 40 blank | 23 comment | 41 complexity | 673dfc8d91161c93008d4dc87d48df7d MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Reflection;
  7. using System.Xml.Serialization;
  8. using ClangCompile;
  9. using System.Xml;
  10. using System.IO;
  11. using Microsoft.Build.Framework;
  12. namespace PropSchemaGen
  13. {
  14. /// <summary>
  15. /// Serves as main entry and Attribute parser for ClangCompile
  16. /// </summary>
  17. class Program
  18. {
  19. // Formality is a B.
  20. static string xmlns = "clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework";
  21. /// <summary>
  22. /// Assigns each property of a class to an XML attribute for a given Element
  23. /// </summary>
  24. /// <param name="doc">XmlDocument used to create elements</param>
  25. /// <param name="obj">Class whose properties are to be serialized</param>
  26. /// <param name="elem">Element to add attributes to</param>
  27. /// <returns>The same XmlElement, for brevity of code</returns>
  28. static XmlElement PropsToXmlAttr(XmlDocument doc, object obj, XmlElement elem)
  29. {
  30. foreach (PropertyInfo pi in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance))
  31. {
  32. if (pi.GetValue(obj) != null && pi.GetValue(obj).ToString() != "")
  33. {
  34. DefaultValueAttribute dvAttr = (DefaultValueAttribute)Attribute.GetCustomAttribute(pi, typeof(DefaultValueAttribute));
  35. if (dvAttr == null)
  36. {
  37. elem.SetAttribute(pi.Name, pi.GetValue(obj).ToString());
  38. }
  39. else
  40. {
  41. if(dvAttr.Value.ToLower() == pi.GetValue(obj).ToString().ToLower()) {
  42. Console.WriteLine("Default value of {0} skipped for {1}", dvAttr.Value, pi.Name);
  43. }
  44. else
  45. {
  46. Console.WriteLine("Default value of {0} overwritten by {1} for {2}", dvAttr.Value, pi.GetValue(obj).ToString(), pi.Name);
  47. elem.SetAttribute(pi.Name, pi.GetValue(obj).ToString());
  48. }
  49. }
  50. }
  51. }
  52. return elem;
  53. }
  54. /// <summary>
  55. /// Helper that creates an element "name" under "parentName.name" and populates the attributes with obj's properties.
  56. /// </summary>
  57. /// <param name="doc">XmlDocument used to create elements</param>
  58. /// <param name="obj">Class whose properties are to be serialized</param>
  59. /// <param name="elem">Element to which a subelement will be added</param>
  60. /// <param name="name">Name of the subelement</param>
  61. /// <returns>The same XmlElement, for brevity of code</returns>
  62. static XmlElement AttrToSubElem(XmlDocument doc, object obj, XmlElement elem, string name)
  63. {
  64. XmlElement subElem = (XmlElement)elem.AppendChild(doc.CreateElement(elem.Name + "." + name, xmlns)).AppendChild(doc.CreateElement(name, xmlns));
  65. PropsToXmlAttr(doc, obj, subElem);
  66. return elem;
  67. }
  68. static void Main(string[] args)
  69. {
  70. XmlDocument doc = new XmlDocument();
  71. XmlElement projectElement = doc.CreateElement("ProjectSchemaDefinitions", xmlns);
  72. List<string> categories = new List<string>();
  73. doc.AppendChild(projectElement);
  74. // These attributes are probably common to all property schemas in Visual Studio.
  75. projectElement.SetAttribute("xmlns", "clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework");
  76. projectElement.SetAttribute("xmlns:x", "http://schemas.microsoft.com/winfx/2006/xaml");
  77. projectElement.SetAttribute("xmlns:sys", "clr-namespace:System;assembly=mscorlib");
  78. projectElement.SetAttribute("xmlns:transformCallback", "Microsoft.Cpp.Dev10.ConvertPropertyCallback");
  79. XmlElement ruleElement = (XmlElement)projectElement.AppendChild(doc.CreateElement("Rule", xmlns));
  80. ruleElement.AppendChild(doc.CreateComment("This file is generated! Modify with caution!"));
  81. RuleAttribute ruleAttr = (RuleAttribute)Attribute.GetCustomAttribute(typeof(Clang), typeof(RuleAttribute));
  82. if (ruleAttr == null)
  83. {
  84. throw new InvalidOperationException("Class requires Rule attribute!");
  85. }
  86. PropsToXmlAttr(doc, ruleAttr, ruleElement);
  87. DataSourceAttribute dataAttr = (DataSourceAttribute)Attribute.GetCustomAttribute(typeof(Clang), typeof(DataSourceAttribute));
  88. if (dataAttr == null)
  89. {
  90. throw new InvalidOperationException("Class requires DataSource attribute!");
  91. }
  92. AttrToSubElem(doc, dataAttr, ruleElement, "DataSource");
  93. XmlElement catsElement = (XmlElement)ruleElement.AppendChild(doc.CreateElement("Rule.Categories", xmlns));
  94. PropertyCategoryAttribute[] allAttributes = (PropertyCategoryAttribute[])Attribute.GetCustomAttributes(typeof(Clang), typeof(PropertyCategoryAttribute));
  95. allAttributes = allAttributes.OrderBy(x => x.Order).ToArray();
  96. Dictionary<string, PropertyCategoryAttribute> categoryMap = allAttributes.ToDictionary(x => x.Name);
  97. MemberInfo[] members = typeof(Clang).GetMembers(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
  98. foreach (PropertyCategoryAttribute catAttr in allAttributes)
  99. {
  100. XmlElement catElement = (XmlElement)catsElement.AppendChild(doc.CreateElement("Category", xmlns));
  101. PropsToXmlAttr(doc, catAttr, catElement);
  102. }
  103. foreach(MemberInfo member in members) {
  104. PropertyPageAttribute[] attrs = (PropertyPageAttribute[])Attribute.GetCustomAttributes(member, typeof(PropertyPageAttribute));
  105. foreach (PropertyPageAttribute attr in attrs)
  106. {
  107. Console.WriteLine("Member name: {0}", member.Name);
  108. if (attr.Category != null && attr.Category != "")
  109. {
  110. PropertyCategoryAttribute req;
  111. if (!categoryMap.TryGetValue(attr.Category, out req))
  112. {
  113. Console.WriteLine("Category not found: {0}", attr.Category);
  114. }
  115. }
  116. }
  117. XmlElement curElement = null;
  118. switch (member.MemberType)
  119. {
  120. case MemberTypes.Property:
  121. PropertyInfo pInfo = (PropertyInfo)member;
  122. PropertyPageAttribute propAttr = (PropertyPageAttribute)Attribute.GetCustomAttribute(member, typeof(PropertyPageAttribute));
  123. // Untracked parameter.
  124. if (propAttr == null)
  125. {
  126. continue;
  127. }
  128. if (pInfo.PropertyType.IsSubclassOf(typeof(Enum)))
  129. {
  130. Console.WriteLine("Warning: Enumerations are invalid types because VisualStudio isn't that smart. You'll have to make it a string and back it with an enum.");
  131. continue;
  132. }
  133. else if (pInfo.PropertyType.IsAssignableFrom(typeof(ITaskItem[])))
  134. {
  135. curElement = (XmlElement)ruleElement.AppendChild(doc.CreateElement("StringListProperty", xmlns));
  136. PropsToXmlAttr(doc, propAttr, curElement).SetAttribute("Name", member.Name);
  137. }
  138. else if (pInfo.PropertyType.IsAssignableFrom(typeof(String)))
  139. {
  140. EnumeratedValueAttribute enumAttr = (EnumeratedValueAttribute)Attribute.GetCustomAttribute(member, typeof(EnumeratedValueAttribute));
  141. if (enumAttr != null)
  142. {
  143. curElement = (XmlElement)ruleElement.AppendChild(doc.CreateElement("EnumProperty", xmlns));
  144. PropsToXmlAttr(doc, propAttr, curElement).SetAttribute("Name", member.Name);
  145. int foundAttr = 0;
  146. FieldInfo[] fields = enumAttr.Enumeration.GetFields(BindingFlags.Public | BindingFlags.Static);
  147. foreach (FieldInfo field in fields)
  148. {
  149. FieldAttribute attr = (FieldAttribute)field.GetCustomAttribute(typeof(FieldAttribute));
  150. if (attr != null)
  151. {
  152. foundAttr++;
  153. PropsToXmlAttr(doc, attr, (XmlElement)curElement.AppendChild(doc.CreateElement("EnumValue", xmlns))).SetAttribute("Name", field.Name);
  154. }
  155. }
  156. if (foundAttr > 0 && foundAttr != fields.Length)
  157. {
  158. Console.WriteLine("Not all fields in {0} have attributes", pInfo.Name);
  159. }
  160. }
  161. else
  162. {
  163. curElement = (XmlElement)ruleElement.AppendChild(doc.CreateElement("StringProperty", xmlns));
  164. PropsToXmlAttr(doc, propAttr, curElement).SetAttribute("Name", member.Name);
  165. }
  166. }
  167. else if (pInfo.PropertyType.IsAssignableFrom(typeof(String[])))
  168. {
  169. curElement = (XmlElement)ruleElement.AppendChild(doc.CreateElement("StringListProperty", xmlns));
  170. PropsToXmlAttr(doc, propAttr, curElement).SetAttribute("Name", member.Name);
  171. }
  172. else if (pInfo.PropertyType.IsAssignableFrom(typeof(Boolean)))
  173. {
  174. curElement = (XmlElement)ruleElement.AppendChild(doc.CreateElement("BoolProperty", xmlns));
  175. PropsToXmlAttr(doc, propAttr, curElement).SetAttribute("Name", member.Name);
  176. }
  177. break;
  178. // Fields are not exposed, only property accessors.
  179. case MemberTypes.Field:
  180. break;
  181. default:
  182. break;
  183. }
  184. if (curElement != null)
  185. {
  186. DataSourceAttribute dataSrcAttr = (DataSourceAttribute)Attribute.GetCustomAttribute(member, typeof(DataSourceAttribute));
  187. if (dataSrcAttr != null)
  188. {
  189. AttrToSubElem(doc, dataSrcAttr, curElement, "DataSource");
  190. }
  191. }
  192. }
  193. IEnumerable<Attribute> additionalAttrs = Attribute.GetCustomAttributes(typeof(Clang), typeof(ItemTypeAttribute));
  194. additionalAttrs = additionalAttrs.Concat(Attribute.GetCustomAttributes(typeof(Clang), typeof(FileExtensionAttribute)));
  195. additionalAttrs = additionalAttrs.Concat(Attribute.GetCustomAttributes(typeof(Clang), typeof(ContentTypeAttribute)));
  196. foreach (Attribute additionalAttr in additionalAttrs)
  197. {
  198. string attrName = additionalAttr.GetType().Name;
  199. attrName = attrName.Substring(0, attrName.Length - "Attribute".Length);
  200. // So lollers. C# is great.
  201. PropsToXmlAttr(doc, additionalAttr, (XmlElement)projectElement.AppendChild(doc.CreateElement(attrName, xmlns)));
  202. }
  203. FileStream fs = new FileStream(@"..\..\sbclang.xml", FileMode.Create);
  204. XmlWriterSettings xmlSettings = new XmlWriterSettings();
  205. xmlSettings.NewLineOnAttributes = true;
  206. xmlSettings.Indent = true;
  207. xmlSettings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
  208. XmlWriter writer = XmlWriter.Create(fs, xmlSettings);
  209. doc.Save(writer);
  210. Console.WriteLine("All done! Press any key to exit.");
  211. Console.ReadKey();
  212. }
  213. }
  214. }