2
0

ScanBaseTypes.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Clang.Ast;
  5. using ICSharpCode.NRefactory.CSharp;
  6. using Sharpie.Bind;
  7. namespace SharpieBinder
  8. {
  9. /// <summary>
  10. /// Finds a few types that we use later to make decisions, and scans for methods for get/set patterns
  11. /// </summary>
  12. class ScanBaseTypes : AstVisitor
  13. {
  14. //
  15. // These are the types that we have to lookup earlier, before we run the scan in CxxBinder
  16. //
  17. static public CXXRecordDecl UrhoRefCounted, EventHandlerType, UrhoObjectType;
  18. // Provides a way of mapping names to declarations, we load this as we process
  19. // and use this information later in CxxBinder
  20. public static Dictionary<string, CXXRecordDecl> nameToDecl = new Dictionary<string, CXXRecordDecl>();
  21. public override void VisitCXXRecordDecl(CXXRecordDecl decl, VisitKind visitKind)
  22. {
  23. if (visitKind != VisitKind.Enter || !decl.IsCompleteDefinition || decl.Name == null)
  24. return;
  25. nameToDecl[decl.QualifiedName] = decl;
  26. switch (decl.QualifiedName) {
  27. case "Urho3D::RefCounted":
  28. UrhoRefCounted = decl;
  29. break;
  30. case "Urho3D::Object":
  31. UrhoObjectType = decl;
  32. break;
  33. case "Urho3D::EventHandler":
  34. EventHandlerType = decl;
  35. break;
  36. }
  37. }
  38. public class GetterSetter
  39. {
  40. public CXXMethodDecl Getter, Setter;
  41. public TypeDeclaration HostType;
  42. public AstType MethodReturn;
  43. public bool SetMethodPublic;
  44. public string Name;
  45. }
  46. // typeName to propertyName to returnType to GetterSetter pairs
  47. public static Dictionary<string, Dictionary<string, Dictionary<QualType, GetterSetter>>> allProperties =
  48. new Dictionary<string, Dictionary<string, Dictionary<QualType, GetterSetter>>>();
  49. public override void VisitCXXMethodDecl(CXXMethodDecl decl, VisitKind visitKind)
  50. {
  51. if (visitKind != VisitKind.Enter)
  52. return;
  53. var isConstructor = decl is CXXConstructorDecl;
  54. if (decl is CXXDestructorDecl || isConstructor)
  55. return;
  56. if (decl.IsCopyAssignmentOperator || decl.IsMoveAssignmentOperator)
  57. return;
  58. if (decl.Parent == null)
  59. return;
  60. if (!decl.Parent.QualifiedName.StartsWith("Urho3D::"))
  61. return;
  62. // Only get methods prefixed with Get with no parameters
  63. // and Set methods that return void and take a single parameter
  64. var name = decl.Name;
  65. // Handle Get methods that are not really getters
  66. // This is a get method that does not get anything
  67. bool legacySetMethod = false;
  68. QualType type;
  69. if (name.StartsWith("Get") || name.StartsWith("Is")) {
  70. if (decl.Parameters.Count() != 0)
  71. return;
  72. if (decl.ReturnQualType.ToString() == "void")
  73. return;
  74. if (name == "IsElementEventSender" ||
  75. name == "IsOpen" ||
  76. name == "IsPressed")
  77. return;
  78. type = decl.ReturnQualType;
  79. } else if (name.StartsWith("Set")) {
  80. if (decl.Parameters.Count() != 1)
  81. return;
  82. if ((name == "SetTypeName" || name == "SetType") && decl.Parent.Name == "UnknownComponent")
  83. return;
  84. if (decl.Access != AccessSpecifier.Public)
  85. return;
  86. if (!(decl.ReturnQualType.Bind() is Sharpie.Bind.Types.VoidType))
  87. {
  88. legacySetMethod = true;
  89. }
  90. type = decl.Parameters.FirstOrDefault().QualType;
  91. } else
  92. return;
  93. Dictionary<string, Dictionary<QualType, GetterSetter>> typeProperties;
  94. if (!allProperties.TryGetValue(decl.Parent.Name, out typeProperties)) {
  95. typeProperties = new Dictionary<string, Dictionary<QualType, GetterSetter>>();
  96. allProperties[decl.Parent.Name] = typeProperties;
  97. }
  98. var propName = name.Substring(name.StartsWith("Is") ? 2 : 3);
  99. Dictionary<QualType, GetterSetter> property;
  100. if (!typeProperties.TryGetValue(propName, out property)) {
  101. property = new Dictionary<QualType, GetterSetter>();
  102. typeProperties[propName] = property;
  103. }
  104. GetterSetter gs;
  105. if (!property.TryGetValue(type, out gs)) {
  106. gs = new GetterSetter() { Name = propName };
  107. }
  108. if (legacySetMethod)
  109. gs.SetMethodPublic = legacySetMethod;
  110. if (name.StartsWith("Get") || name.StartsWith("Is")) {
  111. if (propName != decl.Parent.Name || propName == "Text")
  112. // do not generate Getter if propertyName equals to typename (Text type already has a workaround for this case)
  113. gs.Getter = decl;
  114. } else {
  115. gs.Setter = decl;
  116. }
  117. property[type] = gs;
  118. }
  119. // Contains a list of all methods that will be part of a property
  120. static Dictionary<CXXMethodDecl, GetterSetter> allPropertyMethods = new Dictionary<CXXMethodDecl, GetterSetter>();
  121. public static GetterSetter GetPropertyInfo(CXXMethodDecl decl)
  122. {
  123. GetterSetter gs;
  124. if (allPropertyMethods.TryGetValue(decl, out gs))
  125. return gs;
  126. return null;
  127. }
  128. //
  129. // After we collected the information, remove pairs that only had a setter, but no getter
  130. //
  131. public void PrepareProperties()
  132. {
  133. var typeRemovals = new List<string>();
  134. foreach (var typeKV in allProperties) {
  135. var propertyRemovals = new List<string>();
  136. foreach (var propNameKV in typeKV.Value) {
  137. var qualTypeRemoval = new List<QualType>();
  138. foreach (var propTypeKV in propNameKV.Value) {
  139. if (propTypeKV.Value.Getter == null)
  140. qualTypeRemoval.Add(propTypeKV.Key);
  141. }
  142. foreach (var qualType in qualTypeRemoval)
  143. propNameKV.Value.Remove(qualType);
  144. if (propNameKV.Value.Count == 0)
  145. propertyRemovals.Add(propNameKV.Key);
  146. }
  147. foreach (var property in propertyRemovals)
  148. typeKV.Value.Remove(property);
  149. if (typeKV.Value.Count == 0)
  150. typeRemovals.Add(typeKV.Key);
  151. }
  152. foreach (var type in typeRemovals)
  153. allProperties.Remove(type);
  154. foreach (var typeKV in allProperties) {
  155. foreach (var propNameKV in typeKV.Value) {
  156. foreach (var gs in propNameKV.Value.Values) {
  157. allPropertyMethods[gs.Getter] = gs;
  158. if (gs.Setter != null)
  159. allPropertyMethods[gs.Setter] = gs;
  160. }
  161. }
  162. }
  163. }
  164. }
  165. }