Skip to content

Commit 2c626de

Browse files
authored
Preserve docs on generated enum members (#3361)
1 parent 46e049b commit 2c626de

File tree

2 files changed

+74
-58
lines changed

2 files changed

+74
-58
lines changed

utils/SkiaSharpGenerator/Generate/DocumentationStore.cs

Lines changed: 68 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,20 @@
88

99
namespace SkiaSharpGenerator;
1010

11-
public sealed class DocumentationStore
11+
public sealed class DocumentationStore(string sourceFile)
1212
{
13-
private string _source;
14-
private readonly Dictionary<string, string> _docs = new Dictionary<string, string>(StringComparer.Ordinal);
13+
private readonly string _source = File.ReadAllText(sourceFile);
14+
private readonly Dictionary<string, string> _docs = new(StringComparer.Ordinal);
1515

16-
public static string Type(string name) =>
16+
public static string Type(string name) =>
1717
$"T:{name}";
1818
public static string Field(string typeName, string fieldName) =>
1919
$"F:{typeName}.{fieldName}";
2020
public static string Property(string typeName, string propertyName) =>
2121
$"P:{typeName}.{propertyName}";
22-
public static string Method(string typeName, string methodName, params string[] paramTypes) =>
22+
public static string Method(string typeName, string methodName, params string[] paramTypes) =>
2323
$"M:{typeName}.{methodName}({string.Join(",", paramTypes)})";
2424

25-
public DocumentationStore(string sourceFile)
26-
{
27-
_source = File.ReadAllText(sourceFile);
28-
}
29-
3025
public void Load()
3126
{
3227
var options = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Parse);
@@ -66,96 +61,108 @@ private void ProcessMember(MemberDeclarationSyntax member, string? currentType)
6661
ProcessMember(m, typeName);
6762
}
6863
}
64+
else if (member is EnumDeclarationSyntax ed)
65+
{
66+
var enumName = ed.Identifier.Text;
67+
foreach (var em in ed.Members)
68+
{
69+
ProcessMember(em, enumName);
70+
}
71+
}
6972
}
7073
}
7174

7275
private void AddIfAny(MemberDeclarationSyntax member, string? currentType)
7376
{
74-
var xml = Extract(member);
75-
if (xml == null)
76-
return;
77+
if (GetDocKey(member, currentType) is { } key && Extract(member) is { } xml)
78+
{
79+
_docs[key] = xml;
80+
}
81+
}
7782

78-
string? key = null;
83+
private static string? GetDocKey(MemberDeclarationSyntax member, string? currentType)
84+
{
7985
if (member is ClassDeclarationSyntax c)
80-
key = Type(c.Identifier.Text);
86+
return Type(c.Identifier.Text);
8187
else if (member is StructDeclarationSyntax s)
82-
key = Type(s.Identifier.Text);
88+
return Type(s.Identifier.Text);
8389
else if (member is InterfaceDeclarationSyntax i)
84-
key = Type(i.Identifier.Text);
90+
return Type(i.Identifier.Text);
8591
else if (member is EnumDeclarationSyntax e)
86-
key = Type(e.Identifier.Text);
92+
return Type(e.Identifier.Text);
93+
else if (member is EnumMemberDeclarationSyntax em && em.Parent is EnumDeclarationSyntax ep)
94+
return Field(ep.Identifier.Text, em.Identifier.Text);
8795
else if (member is DelegateDeclarationSyntax d)
88-
key = Type(d.Identifier.Text);
96+
return Type(d.Identifier.Text);
8997
else if (currentType != null && member is FieldDeclarationSyntax f)
90-
key = Field(currentType, f.Declaration.Variables.First().Identifier.Text);
98+
return Field(currentType, f.Declaration.Variables.First().Identifier.Text);
9199
else if (currentType != null && member is PropertyDeclarationSyntax p)
92-
key = Property(currentType, p.Identifier.Text);
100+
return Property(currentType, p.Identifier.Text);
93101
else if (currentType != null && member is MethodDeclarationSyntax m)
94102
{
95103
var paramTypes = m.ParameterList.Parameters
96104
.Select(p => NormalizeType(p.Type))
97105
.ToArray();
98-
key = Method(currentType, m.Identifier.Text, paramTypes);
106+
return Method(currentType, m.Identifier.Text, paramTypes);
99107
}
100108
else if (currentType != null && member is OperatorDeclarationSyntax op)
101109
{
102110
var paramTypes = op.ParameterList.Parameters
103111
.Select(p => NormalizeType(p.Type))
104112
.ToArray();
105-
key = Method(currentType, GetOperatorMetadataName(op), paramTypes);
113+
return Method(currentType, GetOperatorMetadataName(op), paramTypes);
106114
}
107115
else if (currentType != null && member is ConversionOperatorDeclarationSyntax cop)
108116
{
109117
var paramTypes = cop.ParameterList.Parameters
110118
.Select(p => NormalizeType(p.Type))
111119
.ToArray();
112-
key = Method(currentType, cop.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ImplicitKeyword) ? "op_Implicit" : "op_Explicit", paramTypes);
120+
return Method(currentType, cop.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ImplicitKeyword) ? "op_Implicit" : "op_Explicit", paramTypes);
113121
}
114-
115-
if (key != null)
116-
_docs[key] = xml;
122+
else
123+
return null;
117124
}
118125

119-
private static string GetOperatorMetadataName(OperatorDeclarationSyntax op)
120-
{
121-
var paramCount = op.ParameterList.Parameters.Count;
122-
switch (op.OperatorToken.Kind())
126+
private static string GetOperatorMetadataName(OperatorDeclarationSyntax op) =>
127+
op.OperatorToken.Kind() switch
123128
{
124-
case SyntaxKind.PlusToken: return paramCount == 1 ? "op_UnaryPlus" : "op_Addition";
125-
case SyntaxKind.MinusToken: return paramCount == 1 ? "op_UnaryNegation" : "op_Subtraction";
126-
case SyntaxKind.AsteriskToken: return "op_Multiply";
127-
case SyntaxKind.SlashToken: return "op_Division";
128-
case SyntaxKind.PercentToken: return "op_Modulus";
129-
case SyntaxKind.AmpersandToken: return "op_BitwiseAnd";
130-
case SyntaxKind.BarToken: return "op_BitwiseOr";
131-
case SyntaxKind.CaretToken: return "op_ExclusiveOr";
132-
case SyntaxKind.LessThanLessThanToken: return "op_LeftShift";
133-
case SyntaxKind.GreaterThanGreaterThanToken: return "op_RightShift";
134-
case SyntaxKind.EqualsEqualsToken: return "op_Equality";
135-
case SyntaxKind.ExclamationEqualsToken: return "op_Inequality";
136-
case SyntaxKind.LessThanToken: return "op_LessThan";
137-
case SyntaxKind.GreaterThanToken: return "op_GreaterThan";
138-
case SyntaxKind.LessThanEqualsToken: return "op_LessThanOrEqual";
139-
case SyntaxKind.GreaterThanEqualsToken: return "op_GreaterThanOrEqual";
140-
case SyntaxKind.PlusPlusToken: return "op_Increment";
141-
case SyntaxKind.MinusMinusToken: return "op_Decrement";
142-
case SyntaxKind.ExclamationToken: return "op_LogicalNot";
143-
case SyntaxKind.TildeToken: return "op_OnesComplement";
144-
case SyntaxKind.TrueKeyword: return "op_True";
145-
case SyntaxKind.FalseKeyword: return "op_False";
146-
default: return "op_Unknown"; // fallback; unlikely but ensures a key if docs exist
147-
}
148-
}
129+
SyntaxKind.PlusToken => op.ParameterList.Parameters.Count == 1 ? "op_UnaryPlus" : "op_Addition",
130+
SyntaxKind.MinusToken => op.ParameterList.Parameters.Count == 1 ? "op_UnaryNegation" : "op_Subtraction",
131+
SyntaxKind.AsteriskToken => "op_Multiply",
132+
SyntaxKind.SlashToken => "op_Division",
133+
SyntaxKind.PercentToken => "op_Modulus",
134+
SyntaxKind.AmpersandToken => "op_BitwiseAnd",
135+
SyntaxKind.BarToken => "op_BitwiseOr",
136+
SyntaxKind.CaretToken => "op_ExclusiveOr",
137+
SyntaxKind.LessThanLessThanToken => "op_LeftShift",
138+
SyntaxKind.GreaterThanGreaterThanToken => "op_RightShift",
139+
SyntaxKind.EqualsEqualsToken => "op_Equality",
140+
SyntaxKind.ExclamationEqualsToken => "op_Inequality",
141+
SyntaxKind.LessThanToken => "op_LessThan",
142+
SyntaxKind.GreaterThanToken => "op_GreaterThan",
143+
SyntaxKind.LessThanEqualsToken => "op_LessThanOrEqual",
144+
SyntaxKind.GreaterThanEqualsToken => "op_GreaterThanOrEqual",
145+
SyntaxKind.PlusPlusToken => "op_Increment",
146+
SyntaxKind.MinusMinusToken => "op_Decrement",
147+
SyntaxKind.ExclamationToken => "op_LogicalNot",
148+
SyntaxKind.TildeToken => "op_OnesComplement",
149+
SyntaxKind.TrueKeyword => "op_True",
150+
SyntaxKind.FalseKeyword => "op_False",
151+
_ => "op_Unknown",// fallback; unlikely but ensures a key if docs exist
152+
};
149153

150154
private static string NormalizeType(TypeSyntax? typeSyntax)
151155
{
152156
if (typeSyntax == null)
153157
return "?";
158+
154159
// Strip trivia and normalize whitespace
155160
var text = typeSyntax.ToString().Trim();
161+
156162
// Collapse spaces
157163
while (text.Contains(" "))
158164
text = text.Replace(" ", " ");
165+
159166
return text;
160167
}
161168

@@ -165,10 +172,14 @@ private static bool IsPublic(MemberDeclarationSyntax member, string? currentType
165172
if (member is NamespaceDeclarationSyntax)
166173
return true;
167174

168-
// Enum members (EnumMemberDeclarationSyntax) are always effectively public in a public enum
175+
// For enum declarations: require 'public'
169176
if (member is EnumDeclarationSyntax enumDecl)
170177
return enumDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword));
171178

179+
// Enum members (EnumMemberDeclarationSyntax) are always effectively public in a public enum
180+
if (member is EnumMemberDeclarationSyntax enumMemberDecl)
181+
return enumMemberDecl.Parent is EnumDeclarationSyntax parentDecl && parentDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword));
182+
172183
// For type declarations: require 'public'
173184
if (member is TypeDeclarationSyntax typeDecl)
174185
return typeDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword));

utils/SkiaSharpGenerator/Properties/launchSettings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
"SkiaSharpGenerator": {
44
"commandName": "Project",
55
},
6-
"SkiaSharpGenerator (Generate SkiaSharp)": {
6+
"SkiaSharpGenerator (SkiaSharp)": {
77
"commandName": "Project",
88
"commandLineArgs": "generate --config binding/libSkiaSharp.json --root externals/skia --output binding/SkiaSharp/SkiaApi.generated.cs --verbose",
99
"workingDirectory": "$(ProjectDir)..\\.."
10+
},
11+
"SkiaSharpGenerator (HarfBuzzSharp)": {
12+
"commandName": "Project",
13+
"commandLineArgs": "generate --config binding/libHarfBuzzSharp.json --root externals/skia/third_party/externals/harfbuzz --output binding/HarfBuzzSharp/HarfBuzzApi.generated.cs --verbose",
14+
"workingDirectory": "$(ProjectDir)..\\.."
1015
}
1116
}
1217
}

0 commit comments

Comments
 (0)