Browse Source

C#: Preserve order of exported fields/categories

Paul Joannon 3 years ago
parent
commit
cf99d92a39

+ 8 - 0
modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs

@@ -275,5 +275,13 @@ namespace Godot.SourceGenerators
                 yield return new GodotFieldData(field, marshalType.Value);
             }
         }
+
+        public static string Path(this Location location)
+            => location.SourceTree?.GetLineSpan(location.SourceSpan).Path
+            ?? location.GetLineSpan().Path;
+
+        public static int StartLine(this Location location)
+            => location.SourceTree?.GetLineSpan(location.SourceSpan).StartLinePosition.Line
+            ?? location.GetLineSpan().StartLinePosition.Line;
     }
 }

+ 22 - 0
modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs

@@ -59,4 +59,26 @@ namespace Godot.SourceGenerators
         public IFieldSymbol FieldSymbol { get; }
         public MarshalType Type { get; }
     }
+
+    public struct GodotPropertyOrFieldData
+    {
+        public GodotPropertyOrFieldData(ISymbol symbol, MarshalType type)
+        {
+            Symbol = symbol;
+            Type = type;
+        }
+
+        public GodotPropertyOrFieldData(GodotPropertyData propertyData)
+            : this(propertyData.PropertySymbol, propertyData.Type)
+        {
+        }
+
+        public GodotPropertyOrFieldData(GodotFieldData fieldData)
+            : this(fieldData.FieldSymbol, fieldData.Type)
+        {
+        }
+
+        public ISymbol Symbol { get; }
+        public MarshalType Type { get; }
+    }
 }

+ 11 - 18
modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs

@@ -225,28 +225,21 @@ namespace Godot.SourceGenerators
                     .Append(dictionaryType)
                     .Append("();\n");
 
-                foreach (var property in godotClassProperties)
-                {
-                    foreach (var groupingInfo in DetermineGroupingPropertyInfo(property.PropertySymbol))
-                        AppendGroupingPropertyInfo(source, groupingInfo);
-
-                    var propertyInfo = DeterminePropertyInfo(context, typeCache,
-                        property.PropertySymbol, property.Type);
-
-                    if (propertyInfo == null)
-                        continue;
-
-                    AppendPropertyInfo(source, propertyInfo.Value);
-                }
-
-                foreach (var field in godotClassFields)
+                // To retain the definition order (and display categories correctly), we want to
+                //  iterate over fields and properties at the same time, sorted by line number.
+                var godotClassPropertiesAndFields = Enumerable.Empty<GodotPropertyOrFieldData>()
+                    .Concat(godotClassProperties.Select(propertyData => new GodotPropertyOrFieldData(propertyData)))
+                    .Concat(godotClassFields.Select(fieldData => new GodotPropertyOrFieldData(fieldData)))
+                    .OrderBy(data => data.Symbol.Locations[0].Path())
+                    .ThenBy(data => data.Symbol.Locations[0].StartLine());
+
+                foreach (var member in godotClassPropertiesAndFields)
                 {
-
-                    foreach (var groupingInfo in DetermineGroupingPropertyInfo(field.FieldSymbol))
+                    foreach (var groupingInfo in DetermineGroupingPropertyInfo(member.Symbol))
                         AppendGroupingPropertyInfo(source, groupingInfo);
 
                     var propertyInfo = DeterminePropertyInfo(context, typeCache,
-                        field.FieldSymbol, field.Type);
+                        member.Symbol, member.Type);
 
                     if (propertyInfo == null)
                         continue;