Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: format code with dotnet-format #15

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
24 changes: 12 additions & 12 deletions src/CompileTimeComputation/Tests/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ public static class Constants
"""
namespace Foo;

public partial class Bar
{
public static readonly MD5 MD5 = global::System.Security.Cryptography.MD5.Create();
public const string UriString = "https://dgmjr.io/codegeneration/compiletimecomputation/samples";
[method: CompileTimeComputation("GuidString")]
public static string MakeGuidString() => MD5.ComputeHash(UriString.ToUTF8Bytes()).ToHexString();
}
public partial class Bar
{
public static readonly MD5 MD5 = global::System.Security.Cryptography.MD5.Create();

public const string UriString = "https://dgmjr.io/codegeneration/compiletimecomputation/samples";

[method: CompileTimeComputation("GuidString")]
public static string MakeGuidString() => MD5.ComputeHash(UriString.ToUTF8Bytes()).ToHexString();
}
""";

public const string Bar = nameof(Bar);
public const string Foo = nameof(Foo);
public const string GuidString = nameof(GuidString);
public const string Bar = nameof(Bar);
public const string Foo = nameof(Foo);
public const string GuidString = nameof(GuidString);
}
64 changes: 32 additions & 32 deletions src/CompileTimeComputation/Tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,36 @@ namespace Dgmjr.CodeGeneration.CompileTimeComputation.Tests;

public class Tests(ITestOutputHelper output) : BaseTest<CompileTimeComputationGenerator>(output)
{
public override CompileTimeComputationGenerator UnitUnderTest { get; } = new CompileTimeComputationGenerator();
[Fact]
public void Can_Produce_Compile_Time_Computation()
{
Logger.LogSourceToBeCompiled(Constants.Source);
var (inputCompilation, outputCompilation, _) = UnitUnderTest.RunGenerators(Constants.Source);
var inputErrors = inputCompilation.GetDiagnostics().Errors();
var outputErrors = outputCompilation.GetDiagnostics().Errors();
// errors.Any().Should().BeFalse("there were errors during compilation");
Logger.LogInformation("Input Errors:");
if (inputErrors.Any())
{
foreach (var error in inputErrors)
{
Logger.LogDiagnosticError(error.Location, error.Id, error.Descriptor);
}
}
Logger.LogInformation("Output Errors:");
if (outputErrors.Any())
{
foreach (var error in outputErrors)
{
Logger.LogDiagnosticError(error);
}
}
var compiledType = outputCompilation.GetTypeByMetadataName($"{Constants.Foo}.{Constants.Bar}");
compiledType.Should().NotBeNull();
var guidStringField = compiledType.GetMembers(Constants.GuidString).FirstOrDefault() as IFieldSymbol;
guidStringField.Should().NotBeNull();
Logger.LogInformation($"guidStringField.ConstantValue: {guidStringField.ConstantValue}");
}
public override CompileTimeComputationGenerator UnitUnderTest { get; } = new CompileTimeComputationGenerator();

[Fact]
public void Can_Produce_Compile_Time_Computation()
{
Logger.LogSourceToBeCompiled(Constants.Source);
var (inputCompilation, outputCompilation, _) = UnitUnderTest.RunGenerators(Constants.Source);
var inputErrors = inputCompilation.GetDiagnostics().Errors();
var outputErrors = outputCompilation.GetDiagnostics().Errors();
// errors.Any().Should().BeFalse("there were errors during compilation");
Logger.LogInformation("Input Errors:");
if (inputErrors.Any())
{
foreach (var error in inputErrors)
{
Logger.LogDiagnosticError(error.Location, error.Id, error.Descriptor);
}
}
Logger.LogInformation("Output Errors:");
if (outputErrors.Any())
{
foreach (var error in outputErrors)
{
Logger.LogDiagnosticError(error);
}
}
var compiledType = outputCompilation.GetTypeByMetadataName($"{Constants.Foo}.{Constants.Bar}");
compiledType.Should().NotBeNull();
var guidStringField = compiledType.GetMembers(Constants.GuidString).FirstOrDefault() as IFieldSymbol;
guidStringField.Should().NotBeNull();
Logger.LogInformation($"guidStringField.ConstantValue: {guidStringField.ConstantValue}");
}
}
47 changes: 28 additions & 19 deletions src/CompileTimeComputation/src/CompileTimeComputationGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,29 +61,38 @@ public static void Execute(SourceProductionContext context, (ImmutableArray<Fiel
var constDeclaration =
HeaderTemplate.Render(new { Filename = filename }) +
$$$"""
namespace {{{fieldSymbol.ContainingType.ContainingNamespace.ToDisplayString()}}};

{{{fieldSymbol.ContainingType.DeclaredAccessibility.ToString().ToLower().Replace("or", " ").Replace("and", " ")}}} {{{(fieldSymbol.ContainingType.IsStatic ? "static" : "")}}} partial {{{(fieldSymbol.ContainingType.IsRecord ? "record" : "")}}} {{{(fieldSymbol.ContainingType.TypeKind == TypeKind.Class ? "class" : fieldSymbol.ContainingType.TypeKind == TypeKind.Struct ? "struct" : $"#error Wrong data structure type: {fieldSymbol.ContainingType.TypeKind}")}}} {{{fieldSymbol.ContainingType.Name}}}
{
public const {{{fieldSymbol.ToDisplayString()}}} {{{name}}} = {{{(fieldType.Name.Equals(nameof(String), InvariantCultureIgnoreCase) ? "\"" : "")}}}{{{funcResult}}}{{{(fieldSymbol.Name.Equals(nameof(String), InvariantCultureIgnoreCase) ? "\"" : "")}}};
namespace {{{fieldSymbol.ContainingType.ContainingNamespace.ToDisplayString() }
}};

{ { { fieldSymbol.ContainingType.DeclaredAccessibility.ToString().ToLower().Replace("or", " ").Replace("and", " ")} } }
{ { { (fieldSymbol.ContainingType.IsStatic ? "static" : "")} } }
partial
{ { { (fieldSymbol.ContainingType.IsRecord ? "record" : "")} } }
{ { { (fieldSymbol.ContainingType.TypeKind == TypeKind.Class ? "class" : fieldSymbol.ContainingType.TypeKind == TypeKind.Struct ? "struct" : $"#error Wrong data structure type: {fieldSymbol.ContainingType.TypeKind}")} } }
{ { { fieldSymbol.ContainingType.Name} } }
{
public const { { { fieldSymbol.ToDisplayString()} } }
{ { { name} } } = { { { (fieldType.Name.Equals(nameof(String), InvariantCultureIgnoreCase) ? "\"" : "")} } }
{ { { funcResult} } }
{ { { (fieldSymbol.Name.Equals(nameof(String), InvariantCultureIgnoreCase) ? "\"" : "")} } };
}
""";

// Add the class and const variable declarations to the compilation
context.AddSource(filename, constDeclaration);
}
catch (TargetInvocationException tiex)
{
throw tiex.InnerException ?? tiex;

// Add the class and const variable declarations to the compilation
context.AddSource(filename, constDeclaration);
}
catch (TargetInvocationException tiex)
{
throw tiex.InnerException ?? tiex;
}
}
else
{
context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor("CTCG002", "Error generatimg compile-time computed constant: must be const-able",
Format(CTCG002ErrorMessage, fieldSymbolDisplay),
"CTCG002: Field must be const-able", DiagnosticSeverity.Error, true),
fieldSymbol.Locations.FirstOrDefault()));
}
else
{
context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor("CTCG002", "Error generatimg compile-time computed constant: must be const-able",
Format(CTCG002ErrorMessage, fieldSymbolDisplay),
"CTCG002: Field must be const-able", DiagnosticSeverity.Error, true),
fieldSymbol.Locations.FirstOrDefault()));
}
}
}
}
23 changes: 13 additions & 10 deletions src/CompileTimeComputation/src/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,19 @@ public static class Constants

public const string CompileTimeComputationClassDeclaration =
$$$"""
{{{GeneratedCodeAttributes}}}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
internal sealed class {{{CompileTimeComputation}}} : Attribute
{
public {{{CompileTimeComputation}}}(string name)
{
Name = name;
}

public string Name { get; }
{{{GeneratedCodeAttributes
}
}}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
internal sealed class {{ { CompileTimeComputation} }} : Attribute
{
public
{ { { CompileTimeComputation} } } (string name)
{
Name = name;
}

public string Name { get; }
}
""";
}
80 changes: 41 additions & 39 deletions src/Extensions/MemberSymbolExtensions/MemberSymbolExtenisons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,52 +35,54 @@ public static object InvokeStaticMethod(this IMethodSymbol methodSymbol, Compila
$$"""
using System;

public static class {{programClassName}}
{
public static object Run() => {{methodSymbol.ContainingType.ToDisplayString()}}.{{methodSymbol.Name}}({{Join(", ", arguments.Select(arg => $"{(arg is string ? "\"" : "")}{arg}{(arg is string ? "\"" : "")}"))}});
}
""";
public static class {{programClassName
}
}
{
public static object Run() => { { methodSymbol.ContainingType.ToDisplayString()} }.{ { methodSymbol.Name} } ({ { Join(", ", arguments.Select(arg => $"{(arg is string ? "\"" : "")}{arg}{(arg is string ? "\"" : "")}"))} });
}
""";
return AddToCompilatonAndCallRun(compilation, program, programClassName);
}

public static object GetStaticPropertyValue(this IPropertySymbol propertySymbol, Compilation compilation)
{
if (!propertySymbol.IsStatic || propertySymbol.DeclaredAccessibility != Accessibility.Public)
{
throw new InvalidOperationException($"The property {propertySymbol.ToDisplayString()} must be public and static.");
}
var programClassName = $"Program_{guid.NewGuid().ToByteArray().ToHexString()}";
var program =
public static object GetStaticPropertyValue(this IPropertySymbol propertySymbol, Compilation compilation)
{
if (!propertySymbol.IsStatic || propertySymbol.DeclaredAccessibility != Accessibility.Public)
{
throw new InvalidOperationException($"The property {propertySymbol.ToDisplayString()} must be public and static.");
}
var programClassName = $"Program_{guid.NewGuid().ToByteArray().ToHexString()}";
var program =
$$"""
using System;

public static class {{programClassName}}
{
public static object Run() => {{propertySymbol.ContainingType.ToDisplayString()}}.{{propertySymbol.Name}};
}
""";
public static class {{ programClassName}}
{
public static object Run() => { { propertySymbol.ContainingType.ToDisplayString()} }.{ { propertySymbol.Name} };
}
""";
return AddToCompilatonAndCallRun(compilation, program, programClassName);
}

private static object AddToCompilatonAndCallRun(Compilation compilation, string cSharpCode, string programClassName)
{
compilation = compilation.AddSyntaxTrees(SyntaxFactory.ParseSyntaxTree(cSharpCode, compilation.SyntaxTrees.First().Options));
return EmitAndCallRun(compilation, programClassName, cSharpCode);
}
private static object EmitAndCallRun(Compilation compilation, string programClassName, string? extraInfo = "")
{
using var asmStream = new MemoryStream();
var emitResult = compilation.Emit(asmStream, options: new EmitOptions(false, debugInformationFormat: DebugInformationFormat.Embedded));
if (!emitResult.Success)
{
var errorDiagnostic = emitResult.Diagnostics.FirstOrDefault(diag => diag.Severity == DiagnosticSeverity.Error);
throw new CompilationException($"{programClassName}: {errorDiagnostic?.GetMessage()}{(!IsNullOrEmpty(extraInfo) ? ", *" : "")}{extraInfo?.Replace("\n", " ").Replace("\r", " ")}{(!IsNullOrEmpty(extraInfo) ? "*" : "")}");
}
asmStream.Flush();
var asm = Assembly.Load(asmStream.GetBuffer());
var programClass = Find(asm.GetExportedTypes(), t => t.Name == programClassName);
var runMethod = programClass.GetMethod("Run");
return runMethod.Invoke(null, null);
}
private static object AddToCompilatonAndCallRun(Compilation compilation, string cSharpCode, string programClassName)
{
compilation = compilation.AddSyntaxTrees(SyntaxFactory.ParseSyntaxTree(cSharpCode, compilation.SyntaxTrees.First().Options));
return EmitAndCallRun(compilation, programClassName, cSharpCode);
}

private static object EmitAndCallRun(Compilation compilation, string programClassName, string? extraInfo = "")
{
using var asmStream = new MemoryStream();
var emitResult = compilation.Emit(asmStream, options: new EmitOptions(false, debugInformationFormat: DebugInformationFormat.Embedded));
if (!emitResult.Success)
{
var errorDiagnostic = emitResult.Diagnostics.FirstOrDefault(diag => diag.Severity == DiagnosticSeverity.Error);
throw new CompilationException($"{programClassName}: {errorDiagnostic?.GetMessage()}{(!IsNullOrEmpty(extraInfo) ? ", *" : "")}{extraInfo?.Replace("\n", " ").Replace("\r", " ")}{(!IsNullOrEmpty(extraInfo) ? "*" : "")}");
}
asmStream.Flush();
var asm = Assembly.Load(asmStream.GetBuffer());
var programClass = Find(asm.GetExportedTypes(), t => t.Name == programClassName);
var runMethod = programClass.GetMethod("Run");
return runMethod.Invoke(null, null);
}
}