ScanBaseTypes.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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")) {
  68. if (decl.Parameters.Count() != 0)
  69. return;
  70. if (decl.ReturnQualType.ToString() == "void")
  71. return;
  72. type = decl.ReturnQualType;
  73. } else if (name.StartsWith("Set")) {
  74. if (decl.Parameters.Count() != 1)
  75. return;
  76. if (!(decl.ReturnQualType.Bind() is Sharpie.Bind.Types.VoidType))
  77. return;
  78. if ((name == "SetTypeName" || name == "SetType") && decl.Parent.Name == "UnknownComponent")
  79. return;
  80. if (decl.Access != AccessSpecifier.Public)
  81. return;
  82. type = decl.Parameters.FirstOrDefault().QualType;
  83. } else
  84. return;
  85. Dictionary<string, Dictionary<QualType, GetterSetter>> typeProperties;
  86. if (!allProperties.TryGetValue(decl.Parent.Name, out typeProperties)) {
  87. typeProperties = new Dictionary<string, Dictionary<QualType, GetterSetter>>();
  88. allProperties[decl.Parent.Name] = typeProperties;
  89. }
  90. var propName = name.Substring(3);
  91. Dictionary<QualType, GetterSetter> property;
  92. if (!typeProperties.TryGetValue(propName, out property)) {
  93. property = new Dictionary<QualType, GetterSetter>();
  94. typeProperties[propName] = property;
  95. }
  96. GetterSetter gs;
  97. if (!property.TryGetValue(type, out gs)) {
  98. gs = new GetterSetter() { Name = propName };
  99. }
  100. if (name.StartsWith("Get")) {
  101. if (gs.Getter != null)
  102. throw new Exception("Can not happen");
  103. gs.Getter = decl;
  104. } else {
  105. if (gs.Setter != null) {
  106. throw new Exception("Can not happen");
  107. }
  108. gs.Setter = decl;
  109. }
  110. property[type] = gs;
  111. }
  112. // Contains a list of all methods that will be part of a property
  113. static Dictionary<CXXMethodDecl, GetterSetter> allPropertyMethods = new Dictionary<CXXMethodDecl, GetterSetter>();
  114. public static GetterSetter GetPropertyInfo(CXXMethodDecl decl)
  115. {
  116. GetterSetter gs;
  117. if (allPropertyMethods.TryGetValue(decl, out gs))
  118. return gs;
  119. return null;
  120. }
  121. //
  122. // After we collected the information, remove pairs that only had a setter, but no getter
  123. //
  124. public void PrepareProperties()
  125. {
  126. var typeRemovals = new List<string>();
  127. foreach (var typeKV in allProperties) {
  128. var propertyRemovals = new List<string>();
  129. foreach (var propNameKV in typeKV.Value) {
  130. var qualTypeRemoval = new List<QualType>();
  131. foreach (var propTypeKV in propNameKV.Value) {
  132. if (propTypeKV.Value.Getter == null)
  133. qualTypeRemoval.Add(propTypeKV.Key);
  134. }
  135. foreach (var qualType in qualTypeRemoval)
  136. propNameKV.Value.Remove(qualType);
  137. if (propNameKV.Value.Count == 0)
  138. propertyRemovals.Add(propNameKV.Key);
  139. }
  140. foreach (var property in propertyRemovals)
  141. typeKV.Value.Remove(property);
  142. if (typeKV.Value.Count == 0)
  143. typeRemovals.Add(typeKV.Key);
  144. }
  145. foreach (var type in typeRemovals)
  146. allProperties.Remove(type);
  147. foreach (var typeKV in allProperties) {
  148. foreach (var propNameKV in typeKV.Value) {
  149. foreach (var gs in propNameKV.Value.Values) {
  150. allPropertyMethods[gs.Getter] = gs;
  151. if (gs.Setter != null)
  152. allPropertyMethods[gs.Setter] = gs;
  153. }
  154. }
  155. }
  156. }
  157. }
  158. }