Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ csharp_preserve_single_line_statements = true
##########################################

# Always have accessibility keyword
dotnet_style_require_accessibility_modifiers = always:warning
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning

# Use file scoped namespaces
csharp_style_namespace_declarations = file_scoped:warning
6 changes: 3 additions & 3 deletions src/AutoCtor.Shared/AttributeSourceGenerator/Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ public static SourceText GenerateSource()
using (source.StartBlock())
{
source.AppendLine("public AutoConstructAttribute(GuardSetting guard = GuardSetting.Default)");
source.OpenBlock().CloseBlock();
source.StartBlock().Dispose();
}

source.AddCompilerGeneratedAttribute().AddGeneratedCodeAttribute();
source.AppendLine("[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)]");
source.AppendLine("internal sealed class AutoPostConstructAttribute : global::System.Attribute");
source.OpenBlock().CloseBlock();
source.StartBlock().Dispose();

source.AddCompilerGeneratedAttribute().AddGeneratedCodeAttribute();
source.AppendLine("[global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)]");
source.AppendLine("internal sealed class AutoConstructIgnoreAttribute : global::System.Attribute");
source.OpenBlock().CloseBlock();
source.StartBlock().Dispose();
}
source.AppendLine("#endif");

Expand Down
6 changes: 3 additions & 3 deletions src/AutoCtor.Shared/AutoConstructSourceGenerator/Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ private static (SourceText?, ParameterList?) GenerateSource(
.AddDebuggerNonUserCodeAttribute();

source.AppendIndent()
.Append($"public {type.Name}({parameters})")
.Append(parameters.HasBaseParameters, $" : base({parameters:B})")
.Append($"public {type.Name}({parameters.ParameterDeclarations:commaindent})")
.Append(parameters.HasBaseParameters, $" : base({parameters.BaseParameters:commaindent})")
.AppendLine();

using (source.StartBlock())
Expand All @@ -138,7 +138,7 @@ private static (SourceText?, ParameterList?) GenerateSource(
}
if (postCtorMethod.HasValue)
{
source.AppendLine($"{postCtorMethod.Value.Name}({parameters:P});");
source.AppendLine($"{postCtorMethod.Value.Name}({parameters.Parameters:commaindent});");
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/AutoCtor.Shared/AutoCtor.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@
<Compile Include="$(MSBuildThisFileDirectory)AutoConstructSourceGenerator\Tracking.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AutoConstructSourceGenerator\Diagnostics.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AutoConstructSourceGenerator\Emitter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\CodeBuilder.Block.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\CodeBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\CodeBuilder.InterpolatedStringHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\CodeBuilder.PartialType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\CodeBuilder.Templates.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\EquatableList.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\EquatableTypeSymbol.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\Extensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\GeneratorUtilities.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\IsExternalInit.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\Polyfill.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\AttributeNames.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\IPartialTypeModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\MemberModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\ParameterModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\ParameterList.cs" />
Expand All @@ -30,4 +35,4 @@
<AdditionalFiles Include="$(MSBuildThisFileDirectory)AnalyzerReleases.Shipped.md" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)AnalyzerReleases.Unshipped.md" />
</ItemGroup>
</Project>
</Project>
27 changes: 27 additions & 0 deletions src/AutoCtor.Shared/Helpers/CodeBuilder.Block.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
internal partial class CodeBuilder
{
public IDisposable StartBlock() => StartIndent("{", "}");
public IDisposable StartBlock(string line)
{
AppendLine(line);
return StartIndent("{", "}");
}

public IDisposable StartIndent(string? startLine = null, string? endLine = null)
{
if (!string.IsNullOrEmpty(startLine))
AppendLine(startLine!);
IncreaseIndent();
return new DetentDisposable(this, endLine);
}

private readonly struct DetentDisposable(CodeBuilder codeBuilder, string? endLine) : IDisposable
{
public void Dispose()
{
codeBuilder.DecreaseIndent();
if (!string.IsNullOrEmpty(endLine))
codeBuilder.AppendLine(endLine!);
}
}
}
127 changes: 127 additions & 0 deletions src/AutoCtor.Shared/Helpers/CodeBuilder.InterpolatedStringHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System.Runtime.CompilerServices;

#pragma warning disable CS9113 // Parameter is unread.
#pragma warning disable IDE0060 // Remove unused parameter

internal partial class CodeBuilder
{
public CodeBuilder Append(
[InterpolatedStringHandlerArgument("")]
ref CodeBuilderInterpolatedStringHandler builder) => this;

public CodeBuilder Append(bool enabled,
[InterpolatedStringHandlerArgument("", nameof(enabled))]
ref ConditionalCodeBuilderInterpolatedStringHandler builder) => this;

public CodeBuilder AppendLineRaw(
[InterpolatedStringHandlerArgument("")]
ref CodeBuilderInterpolatedStringHandler builder) => AppendLine();

public CodeBuilder AppendLineRaw(bool enabled,
[InterpolatedStringHandlerArgument("", nameof(enabled))]
ref ConditionalCodeBuilderInterpolatedStringHandler builder) => enabled ? AppendLine() : this;

public CodeBuilder AppendLine(
[InterpolatedStringHandlerArgument("")]
IndentedCodeBuilderInterpolatedStringHandler builder) => AppendLine();

public CodeBuilder AppendLine(bool enabled,
[InterpolatedStringHandlerArgument("", nameof(enabled))]
ConditionalIndentedCodeBuilderInterpolatedStringHandler builder) => enabled ? AppendLine() : this;

private void AppendFormatted(IEnumerable<string> items, string? format)
{
if (format == "comma")
AppendCommaSeparated(items);

if (format == "commaindent")
AppendCommaIndented(items);
}

private void AppendCommaSeparated(IEnumerable<string> items)
{
var comma = false;
foreach (var item in items)
{
if (comma)
Append(", ");
comma = true;
Append(item);
}
}

private void AppendCommaIndented(IEnumerable<string> items)
{
var count = items.Count();

if (count < 3)
{
AppendCommaSeparated(items);
return;
}

AppendLine();
IncreaseIndent();
var comma = false;
foreach (var item in items)
{
if (comma)
Append(",").AppendLine();
comma = true;
AppendIndent().Append(item);
}
AppendLine();
DecreaseIndent();
AppendIndent();
}

[InterpolatedStringHandler]
internal readonly struct CodeBuilderInterpolatedStringHandler(
int literalLength, int formattedCount, CodeBuilder codeBuilder)
{
public readonly void AppendLiteral(string s) => codeBuilder.Append(s);
public readonly void AppendFormatted(string s) => codeBuilder.Append(s);
public readonly void AppendFormatted(IEnumerable<string> items, string? format)
=> codeBuilder.AppendFormatted(items, format);
}

[InterpolatedStringHandler]
internal readonly struct ConditionalCodeBuilderInterpolatedStringHandler(
int literalLength, int formattedCount, CodeBuilder codeBuilder, bool enabled)
{
public readonly bool AppendLiteral(string s) { if (enabled) codeBuilder.Append(s); return enabled; }
public readonly bool AppendFormatted(string s) { if (enabled) codeBuilder.Append(s); return enabled; }
public readonly bool AppendFormatted(IEnumerable<string> items, string? format)
{ if (enabled) codeBuilder.AppendFormatted(items, format); return enabled; }
}

[InterpolatedStringHandler]
internal class IndentedCodeBuilderInterpolatedStringHandler(
int literalLength, int formattedCount, CodeBuilder codeBuilder)
{
private bool _hasIndented;

private void EnsureIndent()
{
if (_hasIndented) return;
codeBuilder.AppendIndent();
_hasIndented = true;
}

public void AppendLiteral(string s) { EnsureIndent(); codeBuilder.Append(s); }
public void AppendFormatted(string s) { EnsureIndent(); codeBuilder.Append(s); }
public void AppendFormatted(IEnumerable<string> items, string? format)
{ EnsureIndent(); codeBuilder.AppendFormatted(items, format); }
}

[InterpolatedStringHandler]
internal class ConditionalIndentedCodeBuilderInterpolatedStringHandler(
int literalLength, int formattedCount, CodeBuilder codeBuilder, bool enabled)
: IndentedCodeBuilderInterpolatedStringHandler(literalLength, formattedCount, codeBuilder)
{
public new bool AppendLiteral(string s) { if (enabled) base.AppendLiteral(s); return enabled; }
public new bool AppendFormatted(string s) { if (enabled) base.AppendFormatted(s); return enabled; }
public new bool AppendFormatted(IEnumerable<string> items, string? format)
{ if (enabled) base.AppendFormatted(items, format); return enabled; }
}
}
33 changes: 33 additions & 0 deletions src/AutoCtor.Shared/Helpers/CodeBuilder.PartialType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
internal partial class CodeBuilder
{
public IDisposable StartPartialType(IPartialTypeModel typeModel)
{
if (!string.IsNullOrEmpty(typeModel.Namespace))
{
AppendLine($"namespace {typeModel.Namespace!}");
AppendLine("{");
IncreaseIndent();
}

for (var i = 0; i < typeModel.TypeDeclarations.Count; i++)
{
AppendLine(typeModel.TypeDeclarations[i]);
AppendLine("{");
IncreaseIndent();
}

return new CloseBlockDisposable(this, typeModel.TypeDeclarations.Count + (typeModel.Namespace != null ? 1 : 0));
}

private readonly struct CloseBlockDisposable(CodeBuilder codeBuilder, int count) : IDisposable
{
public void Dispose()
{
for (var i = 0; i < count; i++)
{
codeBuilder.DecreaseIndent();
codeBuilder.AppendLine("}");
}
}
}
}
40 changes: 40 additions & 0 deletions src/AutoCtor.Shared/Helpers/CodeBuilder.Templates.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Reflection;

internal partial class CodeBuilder
{
private static readonly string s_assemblyName;
private static readonly string s_version;
private static readonly string? s_packageProjectUrl;
private static readonly string? s_gitSha;

static CodeBuilder()
{
var assembly = Assembly.GetAssembly(typeof(CodeBuilder));
s_assemblyName = assembly?.GetCustomAttribute<AssemblyTitleAttribute>()?.Title ?? "Untitled";
s_version = assembly?.GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "0.0.0.0";
var metadata = assembly?.GetCustomAttributes<AssemblyMetadataAttribute>()?.ToDictionary(m => m.Key, m => m.Value);
if (metadata != null)
{
metadata.TryGetValue("PackageProjectUrl", out s_packageProjectUrl);
metadata.TryGetValue("GitSha", out s_gitSha);
}
}

public CodeBuilder AddCompilerGeneratedAttribute()
=> AppendLine("[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]");

public CodeBuilder AddDebuggerNonUserCodeAttribute()
=> AppendLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute]");

public CodeBuilder AddGeneratedCodeAttribute()
=> AppendLine($"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"{s_assemblyName}\", \"{s_version}\")]");

public CodeBuilder AppendHeader() =>
AppendLine($"//------------------------------------------------------------------------------")
.AppendLine($"// <auto-generated>")
.AppendLine(!string.IsNullOrEmpty(s_packageProjectUrl), $"// This code was generated by {s_packageProjectUrl!}")
.AppendLine($"// Version: {s_version}")
.AppendLine(!string.IsNullOrEmpty(s_gitSha), $"// SHA: {s_gitSha!}")
.AppendLine($"// </auto-generated>")
.AppendLine($"//------------------------------------------------------------------------------");
}
Loading