ScanBaseTypes.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 string Name;
  44. }
  45. // typeName to propertyName to returnType to GetterSetter pairs
  46. public static Dictionary<string, Dictionary<string, Dictionary<QualType, GetterSetter>>> allProperties =
  47. new Dictionary<string, Dictionary<string, Dictionary<QualType, GetterSetter>>>();
  48. public override void VisitCXXMethodDecl(CXXMethodDecl decl, VisitKind visitKind)
  49. {
  50. if (visitKind != VisitKind.Enter)
  51. return;
  52. var isConstructor = decl is CXXConstructorDecl;
  53. if (decl is CXXDestructorDecl || isConstructor)
  54. return;
  55. if (decl.IsCopyAssignmentOperator || decl.IsMoveAssignmentOperator)
  56. return;
  57. if (decl.Parent == null)
  58. return;
  59. if (!decl.Parent.QualifiedName.StartsWith("Urho3D::"))
  60. return;
  61. // Only get methods prefixed with Get with no parameters
  62. // and Set methods that return void and take a single parameter
  63. var name = decl.Name;
  64. // Handle Get methods that are not really getters
  65. // This is a get method that does not get anything
  66. QualType type;
  67. if (name.StartsWith("Get") || name.StartsWith("Is")) {
  68. if (decl.Parameters.Count() != 0)
  69. return;
  70. if (decl.ReturnQualType.ToString() == "void")
  71. return;
  72. if (name == "IsElementEventSender" ||
  73. name == "IsOpen" ||
  74. name == "IsPressed")
  75. return;
  76. type = decl.ReturnQualType;
  77. } else if (name.StartsWith("Set")) {
  78. if (decl.Parameters.Count() != 1)
  79. return;
  80. if (!(decl.ReturnQualType.Bind() is Sharpie.Bind.Types.VoidType))
  81. return;
  82. if ((name == "SetTypeName" || name == "SetType") && decl.Parent.Name == "UnknownComponent")
  83. return;
  84. if (decl.Access != AccessSpecifier.Public)
  85. return;
  86. type = decl.Parameters.FirstOrDefault().QualType;
  87. } else
  88. return;
  89. Dictionary<string, Dictionary<QualType, GetterSetter>> typeProperties;
  90. if (!allProperties.TryGetValue(decl.Parent.Name, out typeProperties)) {
  91. typeProperties = new Dictionary<string, Dictionary<QualType, GetterSetter>>();
  92. allProperties[decl.Parent.Name] = typeProperties;
  93. }
  94. var propName = name.Substring(name.StartsWith("Is") ? 2 : 3);
  95. Dictionary<QualType, GetterSetter> property;
  96. if (!typeProperties.TryGetValue(propName, out property)) {
  97. property = new Dictionary<QualType, GetterSetter>();
  98. typeProperties[propName] = property;
  99. }
  100. GetterSetter gs;
  101. if (!property.TryGetValue(type, out gs)) {
  102. gs = new GetterSetter() { Name = propName };
  103. }
  104. if (name.StartsWith("Get") || name.StartsWith("Is")) {
  105. Console.WriteLine($"Getter exists for {name}");
  106. gs.Getter = decl;
  107. } else {
  108. if (gs.Setter != null) {
  109. Console.WriteLine($"Setter exists for {name}");
  110. }
  111. gs.Setter = decl;
  112. }
  113. property[type] = gs;
  114. }
  115. // Contains a list of all methods that will be part of a property
  116. static Dictionary<CXXMethodDecl, GetterSetter> allPropertyMethods = new Dictionary<CXXMethodDecl, GetterSetter>();
  117. public static GetterSetter GetPropertyInfo(CXXMethodDecl decl)
  118. {
  119. GetterSetter gs;
  120. if (allPropertyMethods.TryGetValue(decl, out gs))
  121. return gs;
  122. return null;
  123. }
  124. //
  125. // After we collected the information, remove pairs that only had a setter, but no getter
  126. //
  127. public void PrepareProperties()
  128. {
  129. var typeRemovals = new List<string>();
  130. foreach (var typeKV in allProperties) {
  131. var propertyRemovals = new List<string>();
  132. foreach (var propNameKV in typeKV.Value) {
  133. var qualTypeRemoval = new List<QualType>();
  134. foreach (var propTypeKV in propNameKV.Value) {
  135. if (propTypeKV.Value.Getter == null)
  136. qualTypeRemoval.Add(propTypeKV.Key);
  137. }
  138. foreach (var qualType in qualTypeRemoval)
  139. propNameKV.Value.Remove(qualType);
  140. if (propNameKV.Value.Count == 0)
  141. propertyRemovals.Add(propNameKV.Key);
  142. }
  143. foreach (var property in propertyRemovals)
  144. typeKV.Value.Remove(property);
  145. if (typeKV.Value.Count == 0)
  146. typeRemovals.Add(typeKV.Key);
  147. }
  148. foreach (var type in typeRemovals)
  149. allProperties.Remove(type);
  150. foreach (var typeKV in allProperties) {
  151. foreach (var propNameKV in typeKV.Value) {
  152. foreach (var gs in propNameKV.Value.Values) {
  153. allPropertyMethods[gs.Getter] = gs;
  154. if (gs.Setter != null)
  155. allPropertyMethods[gs.Setter] = gs;
  156. }
  157. }
  158. }
  159. }
  160. }
  161. }