Skip to content

Commit

Permalink
Merge pull request #12 from almostchristian/develop
Browse files Browse the repository at this point in the history
Refactored Generator to be more generic.
  • Loading branch information
almostchristian authored Sep 19, 2023
2 parents 44fecea + edd3e6f commit 553021f
Show file tree
Hide file tree
Showing 30 changed files with 523 additions and 140 deletions.
28 changes: 14 additions & 14 deletions ConfigurationProcessor.DependencyInjection.sln
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleOutboxApi", "sample\S
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Components", "sample\Sample.Components\Sample.Components.csproj", "{53B667D5-FB51-4C83-A040-31724EC96F30}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.DependencyInjection.Generator", "src\ConfigurationProcessor.DependencyInjection.Generator\ConfigurationProcessor.DependencyInjection.Generator.csproj", "{AD8581E7-B99F-42D8-BBA9-39D631F1F496}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWebApiGenerator", "sample\TestWebApiGenerator\TestWebApiGenerator.csproj", "{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.DependencyInjection.SourceGeneration", "src\ConfigurationProcessor.DependencyInjection.SourceGeneration\ConfigurationProcessor.DependencyInjection.SourceGeneration.csproj", "{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.SourceGeneration.UnitTests", "tests\ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests\ConfigurationProcessor.SourceGeneration.UnitTests.csproj", "{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.SourceGeneration", "src\ConfigurationProcessor.SourceGeneration\ConfigurationProcessor.SourceGeneration.csproj", "{D3FF19EC-056F-4A54-81C2-6399877A6258}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests", "tests\ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests\ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests.csproj", "{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.Generator", "src\ConfigurationProcessor.Generator\ConfigurationProcessor.Generator.csproj", "{BC10F1A0-C2BE-4D0D-B874-6A79B709CCDF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -87,22 +87,22 @@ Global
{53B667D5-FB51-4C83-A040-31724EC96F30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53B667D5-FB51-4C83-A040-31724EC96F30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53B667D5-FB51-4C83-A040-31724EC96F30}.Release|Any CPU.Build.0 = Release|Any CPU
{AD8581E7-B99F-42D8-BBA9-39D631F1F496}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD8581E7-B99F-42D8-BBA9-39D631F1F496}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD8581E7-B99F-42D8-BBA9-39D631F1F496}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD8581E7-B99F-42D8-BBA9-39D631F1F496}.Release|Any CPU.Build.0 = Release|Any CPU
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}.Release|Any CPU.Build.0 = Release|Any CPU
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}.Release|Any CPU.Build.0 = Release|Any CPU
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}.Release|Any CPU.Build.0 = Release|Any CPU
{D3FF19EC-056F-4A54-81C2-6399877A6258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D3FF19EC-056F-4A54-81C2-6399877A6258}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D3FF19EC-056F-4A54-81C2-6399877A6258}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D3FF19EC-056F-4A54-81C2-6399877A6258}.Release|Any CPU.Build.0 = Release|Any CPU
{BC10F1A0-C2BE-4D0D-B874-6A79B709CCDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC10F1A0-C2BE-4D0D-B874-6A79B709CCDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC10F1A0-C2BE-4D0D-B874-6A79B709CCDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC10F1A0-C2BE-4D0D-B874-6A79B709CCDF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -117,10 +117,10 @@ Global
{81216638-2D84-40AB-8AAA-5CA8065079F7} = {14052F2C-4DA2-45FC-8F05-33B7AC728494}
{E6D3E9E4-983D-4193-90FC-98E3F7C8B530} = {645ABE25-B876-4372-8712-C66AA34020FC}
{53B667D5-FB51-4C83-A040-31724EC96F30} = {645ABE25-B876-4372-8712-C66AA34020FC}
{AD8581E7-B99F-42D8-BBA9-39D631F1F496} = {60E2AA27-F390-4152-9039-A05388E2D3D8}
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1} = {645ABE25-B876-4372-8712-C66AA34020FC}
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC} = {60E2AA27-F390-4152-9039-A05388E2D3D8}
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553} = {14052F2C-4DA2-45FC-8F05-33B7AC728494}
{D3FF19EC-056F-4A54-81C2-6399877A6258} = {60E2AA27-F390-4152-9039-A05388E2D3D8}
{BC10F1A0-C2BE-4D0D-B874-6A79B709CCDF} = {60E2AA27-F390-4152-9039-A05388E2D3D8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2358CB49-45E6-4E83-85C1-F995C676A43F}
Expand Down
4 changes: 2 additions & 2 deletions sample/TestWebApiGenerator/ServiceRegistrationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using ConfigurationProcessor.DependencyInjection;
using ConfigurationProcessor;
using OpenTelemetry.Trace;

namespace TestWebApiGenerator;

internal static partial class ServiceRegistrationExtensions
{
[GenerateServiceRegistration("Services", ExcludedSections = new[] { "Hsts" })]
[GenerateServiceRegistration("Services", ExcludedSections = new[] { "Hsts" }, ImplicitSuffixes = new[] { "Instrumentation", "Exporter" })]
public static partial void AddServicesFromConfiguration(this WebApplicationBuilder builder);

// [GenerateServiceRegistration("Services")]
Expand Down
4 changes: 2 additions & 2 deletions sample/TestWebApiGenerator/TestWebApiGenerator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ConfigurationProcessor.DependencyInjection.Generator\ConfigurationProcessor.DependencyInjection.Generator.csproj" />
<ProjectReference Include="..\..\src\ConfigurationProcessor.DependencyInjection.SourceGeneration\ConfigurationProcessor.DependencyInjection.SourceGeneration.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\ConfigurationProcessor.Generator\ConfigurationProcessor.Generator.csproj" />
<ProjectReference Include="..\..\src\ConfigurationProcessor.SourceGeneration\ConfigurationProcessor.SourceGeneration.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
8 changes: 4 additions & 4 deletions sample/TestWebApiGenerator/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
"EndpointsApiExplorer": true,
"SwaggerGen": true,
"OpenTelemetryTracing": {
"AspNetCoreInstrumentation": true,
"HttpClientInstrumentation": true,
"SqlClientInstrumentation": true,
"JaegerExporter": true
"AspNetCore": true,
"HttpClient": true,
"SqlClient": true,
"Jaeger": true
}
}
}
28 changes: 23 additions & 5 deletions src/ConfigurationProcessor.Core/Implementation/CommonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,22 @@ public static List<MethodInfo> FindConfigurationExtensionMethods(
IEnumerable<string>? candidateNames,
MethodFilter? filter)
{
static bool IsDefined(MethodInfo method, Type attributeType)
{
#if Generator
try
{
return method.CustomAttributes.Any(x => x.AttributeType.FullName == attributeType.FullName);
}
catch (InvalidOperationException)
{
return false;
}
#else
return method.IsDefined(attributeType, false);
#endif
}

IReadOnlyCollection<Assembly> configurationAssemblies = resolutionContext.ConfigurationAssemblies;
var interfaces = configType.GetInterfaces();
var scannedTypes = configurationAssemblies
Expand All @@ -125,11 +141,13 @@ public static List<MethodInfo> FindConfigurationExtensionMethods(
.Concat(interfaces.Select(t => t.GetTypeInfo()))
.SelectMany(t => candidateNames != null ? candidateNames.SelectMany(n => t.GetDeclaredMethods(n)) : t.DeclaredMethods)
.Where(m => filter == null || filter(m, key))
#if Generator
.Where(m => m.IsPublic && (m.IsStatic || IsTypeCompatible(configType, m.DeclaringType) || interfaces.Contains(m.DeclaringType)))
#else
.Where(m => !m.IsDefined(typeof(CompilerGeneratedAttribute), false) && m.IsPublic && ((m.IsStatic && m.IsDefined(typeof(ExtensionAttribute), false)) || IsTypeCompatible(configType, m.DeclaringType) || interfaces.Contains(m.DeclaringType)))
#endif
.Where(m =>
!IsDefined(m, typeof(CompilerGeneratedAttribute)) && // method must not be compiler generated and
m.IsPublic && // method must be public and
(
(m.IsStatic && IsDefined(m, typeof(ExtensionAttribute))) || // method is an extension method
IsTypeCompatible(configType, m.DeclaringType) || // method is declared in the target object type
interfaces.Contains(m.DeclaringType))) // the method is declared in one of the implemented interfaces
.Where(m => !m.IsStatic || configType.IsTypeCompatible(SafeGetParameters(m).ElementAtOrDefault(0)?.ParameterType)) // If static method, checks that the first parameter is same as the extension type
.ToList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public StringArgumentValue(IConfigurationSection section, string providedValue,

if (methodCandidate != null)
{
if (typeof(MethodInfo) == toType)
if (typeof(MethodInfo) == toType || typeof(Delegate) == toType)
{
return methodCandidate;
}
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ConfigurationProcessor.DependencyInjection.SourceGeneration\ConfigurationProcessor.DependencyInjection.SourceGeneration.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" PackAsAnalyzer="true" />
<ProjectReference Include="..\ConfigurationProcessor.SourceGeneration\ConfigurationProcessor.SourceGeneration.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" PackAsAnalyzer="true" />

<PackageReference Include="Microsoft.Extensions.Primitives" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace ConfigurationProcessor.DependencyInjection;
namespace ConfigurationProcessor;

/// <summary>
/// Attribute for generating service registration.
Expand Down Expand Up @@ -33,6 +29,16 @@ public GenerateServiceRegistrationAttribute(string configurationSection)
/// </summary>
public string[] ExcludedSections { get; set; } = Array.Empty<string>();

/// <summary>
/// Subsections that are treated separately.
/// </summary>
public string[] ExpandableSections { get; set; } = Array.Empty<string>();

/// <summary>
/// Suffixes that can be ommitted.
/// </summary>
public string[] ImplicitSuffixes { get; set; } = Array.Empty<string>();

/// <summary>
/// Gets the configuration section.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.2.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,21 @@ namespace ConfigurationProcessor.Core.Implementation;

internal static class CoreCompatExtensions
{
public static IConfigurationArgumentValue GetArgumentValue(this IConfigurationSection value, ResolutionContext resolutionContext)
=> BlankConfigurationArgValue.Instance;
public static IConfigurationArgumentValue GetArgumentValue(this IConfigurationSection argumentSection, ResolutionContext resolutionContext)
{
IConfigurationArgumentValue argumentValue;

if (argumentSection.Value != null)
{
argumentValue = new StringArgumentValue(argumentSection, argumentSection.Value, argumentSection.Key);
}
else
{
argumentValue = new ObjectArgumentValue(argumentSection);
}

return argumentValue;
}

internal static Dictionary<string, (IConfigurationArgumentValue Value, IConfigurationSection Section)> Blank(this IConfigurationSection section)
=> new()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Reflection;
using ConfigurationProcessor.DependencyInjection.SourceGeneration.Utility;
using ConfigurationProcessor.SourceGeneration.Utility;
using Microsoft.Extensions.Configuration;

namespace ConfigurationProcessor.Core.Implementation;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
using System.Reflection;
using ConfigurationProcessor.DependencyInjection.SourceGeneration.Parsing;
using ConfigurationProcessor.DependencyInjection.SourceGeneration.Utility;
using ConfigurationProcessor.SourceGeneration.Parsing;
using ConfigurationProcessor.SourceGeneration.Utility;
using Microsoft.Extensions.Configuration;

namespace ConfigurationProcessor.DependencyInjection.SourceGeneration;
namespace ConfigurationProcessor.SourceGeneration;

internal class Emitter
/// <summary>
/// Generates code.
/// </summary>
public static class Emitter
{
/// <summary>
/// The version string.
/// </summary>
public static readonly string VersionString = typeof(Emitter).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;

public string Emit(IReadOnlyList<ServiceRegistrationClass> generateConfigurationClasses, List<Assembly> references, CancellationToken cancellationToken)
/// <summary>
/// Generates code from service class registrations.
/// </summary>
/// <param name="generateConfigurationClasses"></param>
/// <param name="references"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static string Emit(IReadOnlyList<ServiceRegistrationClass> generateConfigurationClasses, List<Assembly> references, CancellationToken cancellationToken)
{
var emitContext = new EmitContext(generateConfigurationClasses.First().Namespace, references);

Expand All @@ -31,12 +44,13 @@ static partial class {{configClass.Name}}
emitContext.IncreaseIndent();
foreach (var configMethod in configClass.Methods)
{
emitContext.ImplicitSuffixes = configMethod.ImplicitSuffixes;
var sectionName = configMethod.ConfigurationSectionName;

string configSectionVariableName = "servicesSection";

emitContext.Write($$"""
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationProcessor.DependencyInjection.Generator", "{{VersionString}}")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("ConfigurationProcessor.Generator", "{{VersionString}}")]
{{configMethod.Modifiers}} void {{configMethod.Name}}({{configMethod.Arguments}})
{
var {{configSectionVariableName}} = {{configMethod.ConfigurationField}}.GetSection("{{sectionName}}");
Expand All @@ -47,7 +61,7 @@ static partial class {{configClass.Name}}
""");

emitContext.IncreaseIndent();
BuildMethods(emitContext, configMethod.ConfigurationValues, sectionName, configMethod.ServiceCollectionField!, configSectionVariableName);
BuildMethods(emitContext, configMethod.ConfigurationValues, sectionName, configMethod.TargetField!, configSectionVariableName);
emitContext.DecreaseIndent();
emitContext.Write("}");
}
Expand All @@ -63,7 +77,7 @@ static partial class {{configClass.Name}}
return emitContext.ToString();
}

private void BuildMethods(EmitContext emitContext, IEnumerable<KeyValuePair<string, string?>> configurationValues, string sectionName, string targetExpression, string configSectionVariableName)
private static void BuildMethods(EmitContext emitContext, IEnumerable<KeyValuePair<string, string?>> configurationValues, string sectionName, string targetExpression, string configSectionVariableName)
{
var configBuilder = new ConfigurationBuilder();
configBuilder.AddInMemoryCollection(configurationValues);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

using System.Reflection;
using System.Text;
using ConfigurationProcessor.DependencyInjection.SourceGeneration;
using ConfigurationProcessor.DependencyInjection.SourceGeneration.Parsing;
using ConfigurationProcessor.SourceGeneration;
using ConfigurationProcessor.SourceGeneration.Parsing;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
Expand All @@ -16,7 +16,7 @@ namespace ConfigurationProcessor;
/// Generates method for registration based on an appsetting.json file.
/// </summary>
[Generator]
public class RegistrationGenerator : ISourceGenerator
public class Generator : ISourceGenerator
{
/// <inheritdoc/>
public void Initialize(GeneratorInitializationContext context)
Expand All @@ -33,6 +33,10 @@ public void Execute(GeneratorExecutionContext context)
return;
}

#if DEBUG
System.Diagnostics.Debugger.Launch();
#endif

var p = new Parser(context, context.ReportDiagnostic, context.CancellationToken);
IReadOnlyList<ServiceRegistrationClass> registrationClasses = p.GetServiceRegistrationClasses(receiver.ClassDeclarations);
if (registrationClasses.Count > 0)
Expand All @@ -42,10 +46,9 @@ public void Execute(GeneratorExecutionContext context)
var mlc = new MetadataLoadContext(resolver);
var references = context.Compilation.ExternalReferences.Select(x => mlc.LoadFromAssemblyPath(x.Display!)).ToList();

var e = new Emitter();
string result = e.Emit(registrationClasses, references, context.CancellationToken);
string result = Emitter.Emit(registrationClasses, references, context.CancellationToken);

context.AddSource("RegisterServices.g.cs", SourceText.From(result, Encoding.UTF8));
context.AddSource($"{registrationClasses.First().Name}.g.cs", SourceText.From(result, Encoding.UTF8));
}
}

Expand Down
Loading

0 comments on commit 553021f

Please sign in to comment.