mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-04 00:56:31 +02:00
Add XML doc comments for generated classes, constructors, and properties
This commit is contained in:
@@ -141,16 +141,22 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator
|
|||||||
|
|
||||||
// All properties ever assigned by any ctor, deduplicated by name.
|
// All properties ever assigned by any ctor, deduplicated by name.
|
||||||
// We need a get-only property for each of them.
|
// We need a get-only property for each of them.
|
||||||
List<(string PropName, ITypeSymbol PropType)> ctorProps = ctors
|
var ctorProps = ctors
|
||||||
.SelectMany(c => c.Parameters)
|
.SelectMany(c => c.Parameters)
|
||||||
.Select(p => (
|
.Select(p => {
|
||||||
PropName: ResolvePropertyName(attributeSymbol, p),
|
string propName = ResolvePropertyName(attributeSymbol, p);
|
||||||
PropType: p.Type))
|
IPropertySymbol? propSymbol = attributeSymbol
|
||||||
|
.GetMembers()
|
||||||
|
.OfType<IPropertySymbol>()
|
||||||
|
.FirstOrDefault(sym => string.Equals(sym.Name, propName, StringComparison.OrdinalIgnoreCase));
|
||||||
|
return (PropName: propName, PropType: p.Type, PropSymbol: propSymbol);
|
||||||
|
})
|
||||||
.GroupBy(x => x.PropName, StringComparer.OrdinalIgnoreCase)
|
.GroupBy(x => x.PropName, StringComparer.OrdinalIgnoreCase)
|
||||||
.Select(g => g.First())
|
.Select(g => g.First())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// ---- class declaration ----
|
// ---- class declaration ----
|
||||||
|
_ = sb.Append(GetFormattedComment(attributeSymbol, attributeSymbol, className, $"Information about the {className} class.", ""));
|
||||||
_ = sb.AppendLine($"public sealed class {className}");
|
_ = sb.AppendLine($"public sealed class {className}");
|
||||||
_ = sb.AppendLine("{");
|
_ = sb.AppendLine("{");
|
||||||
|
|
||||||
@@ -159,6 +165,7 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator
|
|||||||
{
|
{
|
||||||
if (ctor.Parameters.Length == 0)
|
if (ctor.Parameters.Length == 0)
|
||||||
{
|
{
|
||||||
|
_ = sb.Append(GetFormattedComment(ctor, attributeSymbol, className, $"Initializes a new instance of the <see cref=\"{className}\"/> class.", " "));
|
||||||
_ = sb.AppendLine($" public {className}() {{ }}");
|
_ = sb.AppendLine($" public {className}() {{ }}");
|
||||||
_ = sb.AppendLine();
|
_ = sb.AppendLine();
|
||||||
continue;
|
continue;
|
||||||
@@ -167,6 +174,7 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator
|
|||||||
string ctorParams = string.Join(", ",
|
string ctorParams = string.Join(", ",
|
||||||
ctor.Parameters.Select(p => $"{GlobalType(p.Type)} {p.Name}"));
|
ctor.Parameters.Select(p => $"{GlobalType(p.Type)} {p.Name}"));
|
||||||
|
|
||||||
|
_ = sb.Append(GetFormattedComment(ctor, attributeSymbol, className, $"Initializes a new instance of the <see cref=\"{className}\"/> class.", " "));
|
||||||
_ = sb.AppendLine($" public {className}({ctorParams})");
|
_ = sb.AppendLine($" public {className}({ctorParams})");
|
||||||
_ = sb.AppendLine(" {");
|
_ = sb.AppendLine(" {");
|
||||||
|
|
||||||
@@ -181,15 +189,26 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- get-only properties sourced from ctor parameters ----
|
// ---- get-only properties sourced from ctor parameters ----
|
||||||
foreach ((string propName, ITypeSymbol propType) in ctorProps)
|
foreach (var ctorProp in ctorProps)
|
||||||
{
|
{
|
||||||
_ = sb.AppendLine($" public {GlobalType(propType)} {propName} {{ get; }}");
|
if (ctorProp.PropSymbol is not null)
|
||||||
|
{
|
||||||
|
_ = sb.Append(GetFormattedComment(ctorProp.PropSymbol, attributeSymbol, className, $"Gets the {ctorProp.PropName} property.", " "));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ = sb.AppendLine(" /// <summary>");
|
||||||
|
_ = sb.AppendLine($" /// Gets the {ctorProp.PropName} property.");
|
||||||
|
_ = sb.AppendLine(" /// </summary>");
|
||||||
|
}
|
||||||
|
_ = sb.AppendLine($" public {GlobalType(ctorProp.PropType)} {ctorProp.PropName} {{ get; }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- settable properties (named-argument style) ----
|
// ---- settable properties (named-argument style) ----
|
||||||
foreach (IPropertySymbol prop in settableProps)
|
foreach (IPropertySymbol prop in settableProps)
|
||||||
{
|
{
|
||||||
string defaultClause = GetDefaultClause(prop, compilation);
|
string defaultClause = GetDefaultClause(prop, compilation);
|
||||||
|
_ = sb.Append(GetFormattedComment(prop, attributeSymbol, className, $"Gets or sets the {prop.Name} property.", " "));
|
||||||
_ = sb.AppendLine($" public {GlobalType(prop.Type)} {prop.Name} {{ get; init; }}{defaultClause}");
|
_ = sb.AppendLine($" public {GlobalType(prop.Type)} {prop.Name} {{ get; init; }}{defaultClause}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +216,65 @@ public sealed class StatementRegistryGenerator : IIncrementalGenerator
|
|||||||
_ = sb.AppendLine();
|
_ = sb.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetFormattedComment(
|
||||||
|
ISymbol symbol,
|
||||||
|
INamedTypeSymbol attributeSymbol,
|
||||||
|
string className,
|
||||||
|
string fallbackSummary,
|
||||||
|
string indent = " ")
|
||||||
|
{
|
||||||
|
string? xml = symbol.GetDocumentationCommentXml();
|
||||||
|
if (!string.IsNullOrEmpty(xml))
|
||||||
|
{
|
||||||
|
xml = xml!.Replace(attributeSymbol.Name, className);
|
||||||
|
}
|
||||||
|
|
||||||
|
string formatted = FormatXmlComment(xml, indent);
|
||||||
|
if (!string.IsNullOrWhiteSpace(formatted))
|
||||||
|
{
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
_ = sb.AppendLine($"{indent}/// <summary>");
|
||||||
|
_ = sb.AppendLine($"{indent}/// {fallbackSummary}");
|
||||||
|
_ = sb.AppendLine($"{indent}/// </summary>");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatXmlComment(string? xml, string indent)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(xml))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var element = System.Xml.Linq.XElement.Parse(xml!);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var child in element.Elements())
|
||||||
|
{
|
||||||
|
string nodeXml = child.ToString();
|
||||||
|
string[] lines = nodeXml.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
string trimmedLine = line.Trim();
|
||||||
|
if (trimmedLine.Length > 0)
|
||||||
|
{
|
||||||
|
_ = sb.AppendLine($"{indent}/// {trimmedLine}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Finds the attribute property that corresponds to a constructor parameter.
|
// Finds the attribute property that corresponds to a constructor parameter.
|
||||||
private static string ResolvePropertyName(INamedTypeSymbol attributeSymbol, IParameterSymbol parameter)
|
private static string ResolvePropertyName(INamedTypeSymbol attributeSymbol, IParameterSymbol parameter)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user