Skip to content

Commit

Permalink
Fixing comments for generic types
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov committed Jul 20, 2024
1 parent 0d5e51e commit b1ffa17
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 127 deletions.
198 changes: 102 additions & 96 deletions src/Pure.DI.Core/Core/Code/ClassCommenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,120 +24,126 @@ public void AddComments(CompositionCode composition, Unit unit)
}

code.AppendLine("/// <summary>");
if (classComments.Count > 0)
try
{
foreach (var comment in comments.Format(classComments, true))
if (classComments.Count > 0)
{
code.AppendLine(comment);
foreach (var comment in comments.Format(classComments, true))
{
code.AppendLine(comment);
}
}
}

var orderedRoots = composition.Roots
.OrderByDescending(root => root.IsPublic)
.ThenBy(root => root.DisplayName)
.ThenBy(root => root.Node.Binding)
.ToArray();

if (orderedRoots.Length > 0)
{
var rootComments = comments.FormatList(
"<b>Composition roots:</b>",
orderedRoots.Select(root => (CreateRootTerms(root), CreateRootDescriptions(root))),
false);
var orderedRoots = composition.Roots
.OrderByDescending(root => root.IsPublic)
.ThenBy(root => root.DisplayName)
.ThenBy(root => root.Node.Binding)
.ToArray();

foreach (var rootComment in rootComments)
if (orderedRoots.Length > 0)
{
code.AppendLine(rootComment);
}
var rootComments = comments.FormatList(
"<b>Composition roots:</b>",
orderedRoots.Select(root => (CreateRootTerms(root), CreateRootDescriptions(root))),
false);

IReadOnlyCollection<string> CreateRootTerms(Root root)
{
var term = new StringBuilder();
if (root.IsPublic)
{
term.Append(formatter.FormatRef(composition.Source.Source, root.Injection.Type));
term.Append(' ');
term.Append(formatter.FormatRef(root));
}
else
{
term.Append("Private composition root of type ");
term.Append(formatter.FormatRef(composition.Source.Source, root.Injection.Type));
term.Append('.');
}

if (!hints.IsResolveEnabled)
foreach (var rootComment in rootComments)
{
return [term.ToString()];
code.AppendLine(rootComment);
}

var resolvers = resolversBuilder.Build(new RootContext(composition.Source.Source, ImmutableArray.Create(root)));
if (!resolvers.Any())

IReadOnlyCollection<string> CreateRootTerms(Root root)
{
var term = new StringBuilder();
if (root.IsPublic)
{
term.Append(formatter.FormatRef(composition.Source.Source, root.Injection.Type));
term.Append(' ');
term.Append(formatter.FormatRef(root));
}
else
{
term.Append("Private composition root of type ");
term.Append(formatter.FormatRef(composition.Source.Source, root.Injection.Type));
term.Append('.');
}

if (!hints.IsResolveEnabled)
{
return [term.ToString()];
}

var resolvers = resolversBuilder.Build(new RootContext(composition.Source.Source, ImmutableArray.Create(root)));
if (!resolvers.Any())
{
return [term.ToString()];
}

if (root.IsPublic)
{
term.Append("<br/>or using ");
}
else
{
term.Append(" It can be resolved by ");
}

if (root.Injection.Tag is null)
{
term.Append(formatter.FormatRef($"{hints.ResolveMethodName}{{T}}()"));
term.Append(" method: <c>");
term.Append(hints.ResolveMethodName);
term.Append("&lt;");
}
else
{
term.Append(formatter.FormatRef($"{hints.ResolveByTagMethodName}{{T}}(object)"));
term.Append(" method: <c>");
term.Append(hints.ResolveByTagMethodName);
term.Append("&lt;");
}

term.Append(comments.Escape(root.TypeDescription.Name));
term.Append("&gt;(");
term.Append(root.Injection.Tag != null ? root.Injection.Tag.ValueToString() : "");
term.Append(")</c>");
return [term.ToString()];
}

if (root.IsPublic)
{
term.Append("<br/>or using ");
}
else
{
term.Append(" It can be resolved by ");
}

if (root.Injection.Tag is null)
{
term.Append(formatter.FormatRef($"{hints.ResolveMethodName}{{T}}()"));
term.Append(" method: <c>");
term.Append(hints.ResolveMethodName);
term.Append("&lt;");
}
else
{
term.Append(formatter.FormatRef($"{hints.ResolveByTagMethodName}{{T}}(object)"));
term.Append(" method: <c>");
term.Append(hints.ResolveByTagMethodName);
term.Append("&lt;");
}
IReadOnlyCollection<string> CreateRootDescriptions(Root root) =>
root.Source.Comments.Count > 0
? root.Source.Comments.Select(comments.Escape).ToList()
: [$"Provides a composition root of type {formatter.FormatRef(composition.Source.Source, root.Node.Type)}."];
}

term.Append(comments.Escape(root.TypeDescription.Name));
term.Append("&gt;(");
term.Append(root.Injection.Tag != null ? root.Injection.Tag.ValueToString() : "");
term.Append(")</c>");
return [term.ToString()];
var root = orderedRoots.FirstOrDefault(i => i.IsPublic);
if (root is not null)
{
code.AppendLine("/// <example>");
code.AppendLine($"/// This example shows how to get an instance of type {formatter.FormatRef(composition.Source.Source, root.Node.Type)} using the composition root {formatter.FormatRef(root)}:");
code.AppendLine("/// <code>");
code.AppendLine($"/// {(composition.TotalDisposablesCount == 0 ? "" : "using ")}var composition = new {composition.Source.Source.Name.ClassName}({string.Join(", ", composition.Args.Where(i => i.Node.Arg?.Source.Kind == ArgKind.Class).Select(arg => arg.VariableDeclarationName))});");
code.AppendLine($"/// var instance = composition.{formatter.Format(root)};");
code.AppendLine("/// </code>");
code.AppendLine("/// See also:");
code.AppendLine("/// <br/><see cref=\"Pure.DI.DI.Setup\"/>");
code.AppendLine("/// <br/><see cref=\"Pure.DI.IConfiguration.Bind(object[])\"/>");
code.AppendLine("/// <br/><see cref=\"Pure.DI.IConfiguration.Bind{T}(object[])\"/>");
code.AppendLine("/// </example>");
}

IReadOnlyCollection<string> CreateRootDescriptions(Root root) =>
root.Source.Comments.Count > 0
? root.Source.Comments.Select(comments.Escape).ToList()
: [ $"Provides a composition root of type {formatter.FormatRef(composition.Source.Source, root.Node.Type)}." ];
}

var root = orderedRoots.FirstOrDefault(i => i.IsPublic);
if (root is not null)
{
code.AppendLine("/// <example>");
code.AppendLine($"/// This example shows how to get an instance of type {formatter.FormatRef(composition.Source.Source, root.Node.Type)} using the composition root {formatter.FormatRef(root)}:");
code.AppendLine("/// <code>");
code.AppendLine($"/// {(composition.TotalDisposablesCount == 0 ? "" : "using ")}var composition = new {composition.Source.Source.Name.ClassName}({string.Join(", ", composition.Args.Where(i => i.Node.Arg?.Source.Kind == ArgKind.Class).Select(arg => arg.VariableDeclarationName))});");
code.AppendLine($"/// var instance = composition.{formatter.Format(root)};");
code.AppendLine("/// </code>");
code.AppendLine("/// See also:");
code.AppendLine("/// <br/><see cref=\"Pure.DI.DI.Setup\"/>");
code.AppendLine("/// <br/><see cref=\"Pure.DI.IConfiguration.Bind(object[])\"/>");
code.AppendLine("/// <br/><see cref=\"Pure.DI.IConfiguration.Bind{T}(object[])\"/>");
code.AppendLine("/// </example>");
}
code.AppendLine("/// <br/>");
if (!composition.Diagram.IsEmpty)
{
var diagramUrl = mermaidUrlBuilder.Build(composition.Diagram.Select(i => i.Text));
code.AppendLine($"/// <br/><a href=\"{diagramUrl}\">Class diagram</a><br/>");
}

code.AppendLine("/// <br/>");
if (!composition.Diagram.IsEmpty)
code.AppendLine("/// <br/>This class was created by <a href=\"https://github.com/DevTeam/Pure.DI\">Pure.DI</a> source code generator.");
}
finally
{
var diagramUrl = mermaidUrlBuilder.Build(composition.Diagram.Select(i => i.Text));
code.AppendLine($"/// <br/><a href=\"{diagramUrl}\">Class diagram</a><br/>");
code.AppendLine("/// </summary>");
}

code.AppendLine("/// <br/>This class was created by <a href=\"https://github.com/DevTeam/Pure.DI\">Pure.DI</a> source code generator.");
code.AppendLine("/// </summary>");
}
}
2 changes: 1 addition & 1 deletion src/Pure.DI.Core/Core/Code/DisposeMethodBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public CompositionCode Build(CompositionCode composition)
code.AppendLine();
code.AppendLine("/// <summary>");
code.AppendLine("/// Implement this partial method to handle the exception on async disposing.");
code.AppendLine("/// <summary>");
code.AppendLine("/// </summary>");
code.AppendLine("/// <param name=\"asyncDisposableInstance\">The disposable instance.</param>");
code.AppendLine("/// <param name=\"exception\">Exception occurring during disposal.</param>");
code.AppendLine("/// <typeparam name=\"T\">The actual type of instance being disposed of.</typeparam>");
Expand Down
29 changes: 20 additions & 9 deletions src/Pure.DI.Core/Core/Code/Formatter.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
// ReSharper disable ClassNeverInstantiated.Global
namespace Pure.DI.Core.Code;

internal class Formatter(
ITypeResolver typeResolver,
IComments comments)
internal class Formatter(IComments comments)
: IFormatter
{
private static readonly SymbolDisplayFormat RefFormat = new(
genericsOptions:
SymbolDisplayGenericsOptions.IncludeTypeParameters,
typeQualificationStyle:
SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
memberOptions:
SymbolDisplayMemberOptions.IncludeType |
SymbolDisplayMemberOptions.IncludeContainingType,
miscellaneousOptions:
SymbolDisplayMiscellaneousOptions.ExpandValueTuple |
SymbolDisplayMiscellaneousOptions.UseSpecialTypes |
SymbolDisplayMiscellaneousOptions.ExpandNullable
);

public string Format(Root root)
{
var sb = new StringBuilder();
Expand Down Expand Up @@ -55,10 +67,9 @@ public string FormatRef(Root root)
public string FormatRef(string text) =>
$"<see cref=\"{text}\"/>";

public string FormatRef(MdSetup setup, ITypeSymbol type) =>
FormatRef(
comments.Escape(
typeResolver.Resolve(setup, type).Name
.Replace('<', '{')
.Replace('>', '}')));
public string FormatRef(MdSetup setup, ITypeSymbol type)
{
var originalDefinitionTypeName = type.OriginalDefinition.ToDisplayString(NullableFlowState.None, RefFormat);
return FormatRef(comments.Escape(originalDefinitionTypeName.Replace('<', '{').Replace('>', '}')));
}
}
54 changes: 33 additions & 21 deletions src/Pure.DI.Core/Core/Code/RootMethodsCommenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,44 @@ public void AddComments(CompositionCode composition, Root root)
var rootComments = root.Source.Comments;
var code = composition.Code;
code.AppendLine("/// <summary>");
code.AppendLine("/// <para>");
if (rootComments.Count > 0)
try
{
foreach (var comment in comments.Format(rootComments, true))
code.AppendLine("/// <para>");
try
{
code.AppendLine(comment);
if (rootComments.Count > 0)
{
foreach (var comment in comments.Format(rootComments, true))
{
code.AppendLine(comment);
}
}
else
{
code.AppendLine($"/// Provides a composition root of type {formatter.FormatRef(composition.Source.Source, root.Node.Type)}.");
}
}
finally
{
code.AppendLine("/// </para>");
}

if (!root.IsPublic)
{
return;
}

code.AppendLine("/// <example>");
code.AppendLine($"/// This example shows how to get an instance of type {formatter.FormatRef(composition.Source.Source, root.Node.Type)}:");
code.AppendLine("/// <code>");
code.AppendLine($"/// {(composition.TotalDisposablesCount == 0 ? "" : "using ")}var composition = new {composition.Source.Source.Name.ClassName}({string.Join(", ", composition.Args.Where(i => i.Node.Arg?.Source.Kind == ArgKind.Class).Select(arg => arg.VariableDeclarationName))});");
code.AppendLine($"/// var instance = composition.{formatter.Format(root)};");
code.AppendLine("/// </code>");
code.AppendLine("/// </example>");
}
else
{
code.AppendLine($"/// Provides a composition root of type {formatter.FormatRef(composition.Source.Source, root.Node.Type)}.");
}

code.AppendLine("/// </para>");
if (!root.IsPublic)
finally
{
return;
code.AppendLine("/// </summary>");
}

code.AppendLine("/// <example>");
code.AppendLine($"/// This example shows how to get an instance of type {formatter.FormatRef(composition.Source.Source, root.Node.Type)}:");
code.AppendLine("/// <code>");
code.AppendLine($"/// {(composition.TotalDisposablesCount == 0 ? "" : "using ")}var composition = new {composition.Source.Source.Name.ClassName}({string.Join(", ", composition.Args.Where(i => i.Node.Arg?.Source.Kind == ArgKind.Class).Select(arg => arg.VariableDeclarationName))});");
code.AppendLine($"/// var instance = composition.{formatter.Format(root)};");
code.AppendLine("/// </code>");
code.AppendLine("/// </example>");
code.AppendLine("/// </summary>");
}
}
2 changes: 2 additions & 0 deletions tests/Pure.DI.UsageTests/Pure.DI.UsageTests.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>../../.logs</CompilerGeneratedFilesOutputPath>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down

0 comments on commit b1ffa17

Please sign in to comment.