├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── code ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.props ├── F0.Talks.SourceGenerators.Demo.Benchmarks │ ├── EnumGetNameBenchmarks.cs │ ├── EnumIsDefinedBenchmarks.cs │ ├── F0.Talks.SourceGenerators.Demo.Benchmarks.csproj │ ├── LoggingBenchmarks.cs │ ├── Program.cs │ └── RegexBenchmarks.cs ├── F0.Talks.SourceGenerators.Demo.Roslyn3_8 │ ├── F0.Talks.SourceGenerators.Demo.Roslyn3_8.csproj │ ├── Properties │ │ └── launchSettings.json │ └── Roslyn3_8Generator.cs ├── F0.Talks.SourceGenerators.Demo.Roslyn3_9 │ ├── F0.Talks.SourceGenerators.Demo.Roslyn3_9.csproj │ ├── Properties │ │ └── launchSettings.json │ └── Roslyn3_9Generator.cs ├── F0.Talks.SourceGenerators.Demo.Roslyn4_0 │ ├── F0.Talks.SourceGenerators.Demo.Roslyn4_0.csproj │ ├── Properties │ │ └── launchSettings.json │ └── Roslyn4_0Generator.cs ├── F0.Talks.SourceGenerators.Demo.Roslyn4_10 │ ├── F0.Talks.SourceGenerators.Demo.Roslyn4_10.csproj │ ├── InterceptorMethodAnalyzer.cs │ └── Properties │ │ └── launchSettings.json ├── F0.Talks.SourceGenerators.Demo.Roslyn4_11 │ ├── F0.Talks.SourceGenerators.Demo.Roslyn4_11.csproj │ ├── InterceptorMethodGenerator.cs │ └── Properties │ │ └── launchSettings.json ├── F0.Talks.SourceGenerators.Demo.Roslyn4_2 │ ├── F0.Talks.SourceGenerators.Demo.Roslyn4_2.csproj │ ├── Properties │ │ └── launchSettings.json │ └── Roslyn4_2Generator.cs ├── F0.Talks.SourceGenerators.Demo.Roslyn4_3 │ ├── F0.Talks.SourceGenerators.Demo.Roslyn4_3.csproj │ ├── Properties │ │ └── launchSettings.json │ └── Roslyn4_3Generator.cs ├── F0.Talks.SourceGenerators.Demo.Tests │ ├── F0.Talks.SourceGenerators.Demo.Tests.csproj │ └── RegexTests.cs ├── F0.Talks.SourceGenerators.Demo.WebApi │ ├── F0.Talks.SourceGenerators.Demo.WebApi.csproj │ ├── F0.Talks.SourceGenerators.Demo.WebApi.http │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── appsettings.Development.json │ └── appsettings.json ├── F0.Talks.SourceGenerators.Demo.WpfApp │ ├── App.xaml │ ├── App.xaml.cs │ ├── F0.Talks.SourceGenerators.Demo.WpfApp.csproj │ ├── MainViewModel.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ └── Properties │ │ └── AssemblyInfo.cs ├── F0.Talks.SourceGenerators.Demo │ ├── AdditionalText1.xml │ ├── AdditionalText2.xml │ ├── AdditionalText3.xml │ ├── F0.Talks.SourceGenerators.Demo.csproj │ ├── Intercepted.cs │ ├── JsonSerializerDemo.cs │ ├── PreviewInterceptors.g.cs │ └── Program.cs ├── F0.Talks.SourceGenerators.Presentation │ ├── F0.Talks.SourceGenerators.Presentation.csproj │ ├── Program.cs │ ├── cache │ │ └── .gitignore │ ├── input │ │ ├── Additional.md │ │ ├── Anatomy.md │ │ ├── BestPractices.md │ │ ├── CSharp.md │ │ ├── Content.md │ │ ├── Debugging.md │ │ ├── Examples.md │ │ ├── Exit.md │ │ ├── Index.md │ │ ├── Kickstart.md │ │ ├── NET.md │ │ ├── NRT.md │ │ ├── NuGet.md │ │ ├── Performance.md │ │ ├── QA.md │ │ ├── Roslyn.md │ │ ├── SourceGeneration.md │ │ ├── Speaker.md │ │ ├── Testing.md │ │ ├── Tooling.md │ │ ├── Versioning.md │ │ └── styles.css │ ├── output │ │ └── .gitignore │ └── temp │ │ └── .gitignore └── F0.Talks.SourceGenerators.sln ├── gen ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.props ├── F0.Gen.EqualityComparison │ ├── F0.Gen.EqualityComparison.Benchmarks │ │ ├── EqualityComparerGeneratorBenchmarks.cs │ │ ├── F0.Gen.EqualityComparison.Benchmarks.csproj │ │ └── Program.cs │ ├── F0.Gen.EqualityComparison.Example │ │ ├── EqualityComparisonBenchmarks.cs │ │ ├── F0.Gen.EqualityComparison.Example.csproj │ │ ├── MyClass.cs │ │ ├── MyStruct.cs │ │ └── Program.cs │ ├── F0.Gen.EqualityComparison.IntegrationTests │ │ ├── EqualityComparerGeneratorIntegrationTests.cs │ │ ├── F0.Gen.EqualityComparison.IntegrationTests.csproj │ │ ├── MyClass.cs │ │ ├── MyStruct.cs │ │ └── TypeTests.cs │ ├── F0.Gen.EqualityComparison.UnitTests │ │ ├── App.config │ │ ├── Diagnostics │ │ │ ├── DebugAssertException.cs │ │ │ └── DebugTraceListener.cs │ │ ├── EqualityComparerGeneratorUnitTests.cs │ │ ├── F0.Gen.EqualityComparison.UnitTests.csproj │ │ └── Verifiers │ │ │ ├── CSharpSourceGeneratorVerifier.Test.cs │ │ │ ├── CSharpSourceGeneratorVerifier.cs │ │ │ └── CSharpVerifierHelper.cs │ ├── F0.Gen.EqualityComparison.sln │ ├── F0.Gen.EqualityComparison │ │ ├── EqualityComparerGenerator.Attributes.cs │ │ ├── EqualityComparerGenerator.Contexts.cs │ │ ├── EqualityComparerGenerator.Formats.cs │ │ ├── EqualityComparerGenerator.Names.cs │ │ ├── EqualityComparerGenerator.cs │ │ ├── F0.Gen.EqualityComparison.csproj │ │ ├── NamedTypeSymbolExtensions.cs │ │ └── Properties │ │ │ └── launchSettings.json │ └── F0.Gen.Extern │ │ ├── F0.Gen.Extern.csproj │ │ ├── GlobalType.cs │ │ ├── Inheritance.cs │ │ ├── InternalClass.cs │ │ ├── InternalStruct.cs │ │ ├── PublicClass.cs │ │ ├── PublicStruct.cs │ │ └── TopLevelType.cs ├── F0.Gen.GetNameOfEnum │ ├── F0.Gen.GetNameOfEnum.Benchmarks │ │ ├── F0.Gen.GetNameOfEnum.Benchmarks.csproj │ │ ├── GetNameOfEnumGeneratorBenchmarks.cs │ │ └── Program.cs │ ├── F0.Gen.GetNameOfEnum.Example │ │ ├── EnumInfo.cs │ │ ├── F0.Gen.GetNameOfEnum.Example.csproj │ │ ├── GetNameOfEnumBenchmarks.cs │ │ └── Program.cs │ ├── F0.Gen.GetNameOfEnum.IntegrationTests │ │ ├── EnumInfo.cs │ │ ├── F0.Gen.GetNameOfEnum.IntegrationTests.csproj │ │ └── GetNameOfEnumGeneratorIntegrationTests.cs │ ├── F0.Gen.GetNameOfEnum.UnitTests │ │ ├── App.config │ │ ├── Diagnostics │ │ │ ├── DebugAssertException.cs │ │ │ └── DebugTraceListener.cs │ │ ├── F0.Gen.GetNameOfEnum.UnitTests.csproj │ │ ├── GetNameOfEnumGeneratorUnitTests.cs │ │ └── Verifiers │ │ │ ├── CSharpSourceGeneratorVerifier.Test.cs │ │ │ ├── CSharpSourceGeneratorVerifier.cs │ │ │ └── CSharpVerifierHelper.cs │ ├── F0.Gen.GetNameOfEnum.sln │ └── F0.Gen.GetNameOfEnum │ │ ├── F0.Gen.GetNameOfEnum.csproj │ │ ├── GetNameOfEnumGenerator.Attribute.cs │ │ ├── GetNameOfEnumGenerator.Comparer.cs │ │ ├── GetNameOfEnumGenerator.Formats.cs │ │ ├── GetNameOfEnumGenerator.cs │ │ ├── IndentedTextWriterExtensions.cs │ │ └── Properties │ │ └── launchSettings.json ├── F0.Gen.IsEnumDefined │ ├── F0.Gen.IsEnumDefined.Example │ │ ├── F0.Gen.IsEnumDefined.Example.csproj │ │ └── Program.cs │ ├── F0.Gen.IsEnumDefined.IntegrationBenchmarks │ │ ├── F0.Gen.IsEnumDefined.IntegrationBenchmarks.csproj │ │ ├── IsEnumDefinedGeneratorIntegrationBenchmarks.cs │ │ └── Program.cs │ ├── F0.Gen.IsEnumDefined.IntegrationTests │ │ ├── F0.Gen.IsEnumDefined.IntegrationTests.csproj │ │ └── IsEnumDefinedGeneratorIntegrationTests.cs │ ├── F0.Gen.IsEnumDefined.UnitBenchmarks │ │ ├── F0.Gen.IsEnumDefined.UnitBenchmarks.csproj │ │ ├── IsEnumDefinedGeneratorUnitBenchmarks.cs │ │ └── Program.cs │ ├── F0.Gen.IsEnumDefined.UnitTests │ │ ├── App.config │ │ ├── Diagnostics │ │ │ ├── DebugAssertException.cs │ │ │ └── DebugTraceListener.cs │ │ ├── F0.Gen.IsEnumDefined.UnitTests.csproj │ │ ├── IsEnumDefinedGeneratorUnitTests.cs │ │ └── Verifiers │ │ │ ├── CSharpSourceGeneratorVerifier.Test.cs │ │ │ ├── CSharpSourceGeneratorVerifier.cs │ │ │ └── CSharpVerifierHelper.cs │ ├── F0.Gen.IsEnumDefined.sln │ └── F0.Gen.IsEnumDefined │ │ ├── F0.Gen.IsEnumDefined.csproj │ │ ├── IsEnumDefinedGenerator.Attribute.cs │ │ ├── IsEnumDefinedGenerator.Comparer.cs │ │ ├── IsEnumDefinedGenerator.Formats.cs │ │ ├── IsEnumDefinedGenerator.Info.cs │ │ ├── IsEnumDefinedGenerator.Source.cs │ │ ├── IsEnumDefinedGenerator.cs │ │ ├── Polyfilling │ │ └── System.Diagnostics.UnreachableException.cs │ │ └── Properties │ │ └── launchSettings.json └── F0.Gen.ValueTypeEquality │ ├── F0.Gen.ValueTypeEquality.Example │ ├── F0.Gen.ValueTypeEquality.Example.csproj │ └── Program.cs │ ├── F0.Gen.ValueTypeEquality.IntegrationBenchmarks │ ├── F0.Gen.ValueTypeEquality.IntegrationBenchmarks.csproj │ ├── Program.cs │ └── ValueTypeBenchmarks.cs │ ├── F0.Gen.ValueTypeEquality.IntegrationTests │ ├── F0.Gen.ValueTypeEquality.IntegrationTests.csproj │ └── ValueTypeTests.cs │ ├── F0.Gen.ValueTypeEquality.UnitBenchmarks │ ├── F0.Gen.ValueTypeEquality.UnitBenchmarks.csproj │ ├── Program.cs │ └── ValueTypeEqualityGeneratorUnitBenchmarks.cs │ ├── F0.Gen.ValueTypeEquality.UnitTests │ ├── App.config │ ├── Diagnostics │ │ ├── DebugAssertException.cs │ │ └── DebugTraceListener.cs │ ├── F0.Gen.ValueTypeEquality.UnitTests.csproj │ ├── ValueTypeEqualityGeneratorUnitTests.cs │ └── Verifiers │ │ ├── CSharpIncrementalGeneratorVerifier.Test.cs │ │ ├── CSharpIncrementalGeneratorVerifier.cs │ │ ├── CSharpSourceGeneratorVerifier.Test.cs │ │ ├── CSharpSourceGeneratorVerifier.cs │ │ └── CSharpVerifierHelper.cs │ ├── F0.Gen.ValueTypeEquality.sln │ └── F0.Gen.ValueTypeEquality │ ├── F0.Gen.ValueTypeEquality.csproj │ ├── IncrementalValueTypeEqualityGenerator.cs │ ├── Properties │ └── launchSettings.json │ └── ValueTypeEqualityGenerator.cs └── nuget.config /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.config text 4 | *.cs text diff=csharp 5 | *.cshtml text 6 | *.csproj text 7 | *.css text diff=css 8 | *.editorconfig text 9 | *.globalconfig text 10 | *.htm text diff=html 11 | *.html text diff=html 12 | *.json text 13 | *.md text diff=markdown 14 | *.props text 15 | *.ps1 text 16 | *.razor text 17 | *.resx text 18 | *.runsettings text 19 | *.sln text 20 | *.slnf text 21 | *.targets text 22 | *.txt text 23 | *.vb text 24 | *.vbproj text 25 | *.vsixmanifest text 26 | *.xaml text 27 | *.xml text 28 | *.yaml text 29 | *.yml text 30 | 31 | *.png binary 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Flash0ver 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)..\artifacts 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /code/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /code/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Benchmarks/EnumGetNameBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | namespace F0.Talks.SourceGenerators.Demo.Benchmarks; 4 | 5 | [ShortRunJob] 6 | [MemoryDiagnoser(false)] 7 | public class EnumGetNameBenchmarks 8 | { 9 | private StringComparison value; 10 | 11 | [GlobalSetup] 12 | public void Setup() 13 | { 14 | value = StringComparison.OrdinalIgnoreCase; 15 | } 16 | 17 | [Benchmark] 18 | public string? Enum_GetName_Bcl() 19 | { 20 | return SystemEnum.GetName(value); 21 | } 22 | 23 | [Benchmark] 24 | public string? Enum_GetName_Generated() 25 | { 26 | return InterceptedEnum.GetName(value); 27 | } 28 | 29 | private static class SystemEnum 30 | { 31 | internal static string? GetName(TEnum value) where TEnum : struct, Enum 32 | { 33 | return Enum.GetName(value); 34 | } 35 | } 36 | 37 | private static class InterceptedEnum 38 | { 39 | internal static string? GetName(StringComparison value) 40 | { 41 | return Enum.GetName(value); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Benchmarks/EnumIsDefinedBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | namespace F0.Talks.SourceGenerators.Demo.Benchmarks; 4 | 5 | [ShortRunJob] 6 | [MemoryDiagnoser(false)] 7 | public class EnumIsDefinedBenchmarks 8 | { 9 | private StringComparison value; 10 | 11 | [GlobalSetup] 12 | public void Setup() 13 | { 14 | value = StringComparison.OrdinalIgnoreCase; 15 | } 16 | 17 | [Benchmark] 18 | public bool Enum_IsDefined_Bcl() 19 | { 20 | return SystemEnum.IsDefined(value); 21 | } 22 | 23 | [Benchmark] 24 | public bool Enum_IsDefined_Generated() 25 | { 26 | return InterceptedEnum.IsDefined(value); 27 | } 28 | 29 | private static class SystemEnum 30 | { 31 | internal static bool IsDefined(TEnum value) where TEnum : struct, Enum 32 | { 33 | return Enum.IsDefined(value); 34 | } 35 | } 36 | 37 | private static class InterceptedEnum 38 | { 39 | internal static bool IsDefined(StringComparison value) 40 | { 41 | return Enum.IsDefined(value); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Benchmarks/F0.Talks.SourceGenerators.Demo.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Benchmarks/LoggingBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using F0.Primitives; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace F0.Talks.SourceGenerators.Demo.Benchmarks; 6 | 7 | /// 8 | /// Compile-time logging source generation 9 | /// High-performance logging in .NET 10 | /// High-performance logging with LoggerMessage in ASP.NET Core 11 | /// 12 | [ShortRunJob] 13 | [MemoryDiagnoser(false)] 14 | public class LoggingBenchmarks 15 | { 16 | private readonly string name = "Techorama"; 17 | private readonly int number = 2024; 18 | 19 | [ParamsSource(nameof(Loggers))] 20 | public ILogger Logger { get; set; } = null!; 21 | 22 | public static IEnumerable Loggers() 23 | { 24 | return 25 | [ 26 | new MyLogger(LogLevel.Information), 27 | new MyLogger(LogLevel.Warning), 28 | ]; 29 | } 30 | 31 | [Benchmark(Baseline = true)] 32 | public void LoggerExtensions() 33 | { 34 | Logger.LogInformation(240, "Hello, {name} {number}!", name, number); 35 | } 36 | 37 | [Benchmark] 38 | public void LoggerExtensions_IsEnabled() 39 | { 40 | if (Logger.IsEnabled(LogLevel.Information)) 41 | { 42 | Logger.LogInformation(240, "Hello, {name} {number}!", name, number); 43 | } 44 | } 45 | 46 | [Benchmark] 47 | public void LoggerMessage_Generator() 48 | { 49 | Logger.Hello(name, number); 50 | } 51 | } 52 | 53 | public static partial class Log 54 | { 55 | [LoggerMessage(240, LogLevel.Information, "Hello, {name} {number}!")] 56 | public static partial void Hello(this ILogger logger, string name, int number); 57 | } 58 | 59 | internal sealed class MyLogger : ILogger 60 | { 61 | private readonly LogLevel minLevel; 62 | 63 | public MyLogger(LogLevel minLevel) 64 | { 65 | this.minLevel = minLevel; 66 | } 67 | 68 | public IDisposable BeginScope(TState state) where TState : notnull 69 | { 70 | return NullDisposable.Instance; 71 | } 72 | 73 | public bool IsEnabled(LogLevel logLevel) 74 | { 75 | return logLevel != LogLevel.None 76 | && logLevel >= minLevel; 77 | } 78 | 79 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) 80 | { 81 | // no-op 82 | } 83 | 84 | public override string ToString() 85 | { 86 | return $"Min: {Enum.GetName(minLevel)}"; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); 4 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Benchmarks/RegexBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Text.RegularExpressions; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace F0.Talks.SourceGenerators.Demo.Benchmarks; 6 | 7 | /// 8 | /// .NET regular expression source generators 9 | /// 10 | [ShortRunJob] 11 | [MemoryDiagnoser(false)] 12 | [SuppressMessage("Performance", "SYSLIB1045:Convert to 'GeneratedRegexAttribute'.", Justification = "Demo")] 13 | public partial class RegexBenchmarks 14 | { 15 | // lang=regex 16 | private const string Pattern = @".+\.(cs|vb)"; 17 | 18 | private static readonly Regex s_regex = new(Pattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled); 19 | 20 | private string _text = null!; 21 | 22 | [GlobalSetup] 23 | public void Setup() 24 | { 25 | _text = "Document.generated.cs"; 26 | } 27 | 28 | [Benchmark] 29 | public bool Interpreted_New() 30 | { 31 | Regex regex = new(Pattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); 32 | return regex.IsMatch(_text); 33 | } 34 | 35 | [Benchmark] 36 | public bool Compiled_New() 37 | { 38 | Regex regex = new(Pattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled); 39 | return regex.IsMatch(_text); 40 | } 41 | 42 | [Benchmark] 43 | public bool Compiled_Cached() 44 | { 45 | return s_regex.IsMatch(_text); 46 | } 47 | 48 | [Benchmark] 49 | public bool Generated() 50 | { 51 | return GeneratedRegex.IsMatch(_text); 52 | } 53 | 54 | [GeneratedRegex(Pattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture)] 55 | private static partial Regex GeneratedRegex { get; } 56 | } 57 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn3_8/F0.Talks.SourceGenerators.Demo.Roslyn3_8.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0;netstandard2.0 5 | latest 6 | enable 7 | enable 8 | 9 | 10 | 11 | true 12 | true 13 | 14 | 15 | 16 | $(NoWarn);nullable 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn3_8/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "F0.Talks.SourceGenerators.Demo.Roslyn3_8": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "..\\F0.Talks.SourceGenerators.Demo\\F0.Talks.SourceGenerators.Demo.csproj" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn3_8/Roslyn3_8Generator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using System.CodeDom.Compiler; 5 | using System.Diagnostics; 6 | using System.Globalization; 7 | using System.Runtime.CompilerServices; 8 | 9 | namespace F0.Talks.SourceGenerators.Demo.Roslyn3_8; 10 | 11 | [Generator] 12 | internal sealed class Roslyn3_8Generator : ISourceGenerator 13 | { 14 | public void Initialize(GeneratorInitializationContext context) 15 | { 16 | context.RegisterForSyntaxNotifications(static () => new SyntaxReceiver()); 17 | } 18 | 19 | public void Execute(GeneratorExecutionContext context) 20 | { 21 | Debug.Assert(context.SyntaxReceiver is SyntaxReceiver); 22 | var receiver = Unsafe.As(context.SyntaxReceiver); 23 | 24 | foreach (MethodDeclarationSyntax candidate in receiver.Candidates) 25 | { 26 | SemanticModel semanticModel = context.Compilation.GetSemanticModel(candidate.SyntaxTree); 27 | 28 | IMethodSymbol? method = semanticModel.GetDeclaredSymbol(candidate); 29 | Debug.Assert(method is not null); 30 | INamedTypeSymbol type = method.ContainingType; 31 | 32 | using StringWriter writer = new(CultureInfo.InvariantCulture); 33 | using IndentedTextWriter source = new(writer); 34 | 35 | source.WriteLine($"static partial class {type.Name}"); 36 | source.WriteLine("{"); 37 | source.Indent++; 38 | source.WriteLine($"{SyntaxFacts.GetText(method.DeclaredAccessibility)} static partial string {method.Name}()"); 39 | source.WriteLine("{"); 40 | source.Indent++; 41 | source.WriteLine(@"return ""From Generator"";"); 42 | source.Indent--; 43 | source.WriteLine("}"); 44 | source.Indent--; 45 | source.WriteLine("}"); 46 | 47 | Debug.Assert(source.Indent == 0); 48 | context.AddSource("HintName.g.cs", writer.ToString()); 49 | } 50 | } 51 | } 52 | 53 | internal sealed class SyntaxReceiver : ISyntaxReceiver 54 | { 55 | public List Candidates { get; } = new(); 56 | 57 | public void OnVisitSyntaxNode(SyntaxNode syntaxNode) 58 | { 59 | if (syntaxNode is MethodDeclarationSyntax method 60 | && method.Modifiers.Any(SyntaxKind.StaticKeyword) 61 | && method.Modifiers.Any(SyntaxKind.PartialKeyword) 62 | && method.ReturnType is PredefinedTypeSyntax predefined && predefined.Keyword.IsKind(SyntaxKind.StringKeyword)) 63 | { 64 | Candidates.Add(method); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn3_9/F0.Talks.SourceGenerators.Demo.Roslyn3_9.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0;netstandard2.0 5 | latest 6 | enable 7 | enable 8 | 9 | 10 | 11 | true 12 | true 13 | 14 | 15 | 16 | $(NoWarn);nullable 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn3_9/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "F0.Talks.SourceGenerators.Demo.Roslyn3_9": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "..\\F0.Talks.SourceGenerators.Demo\\F0.Talks.SourceGenerators.Demo.csproj" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn3_9/Roslyn3_9Generator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using System.Diagnostics; 3 | using System.Runtime.CompilerServices; 4 | using System.Text; 5 | 6 | namespace F0.Talks.SourceGenerators.Demo.Roslyn3_9; 7 | 8 | [Generator(LanguageNames.CSharp)] 9 | internal sealed class Roslyn3_9Generator : ISourceGenerator 10 | { 11 | public void Initialize(GeneratorInitializationContext context) 12 | { 13 | context.RegisterForPostInitialization(PostInitialization); 14 | context.RegisterForSyntaxNotifications(static () => new SyntaxContextReceiver()); 15 | } 16 | 17 | public void Execute(GeneratorExecutionContext context) 18 | { 19 | Debug.Assert(context.SyntaxReceiver is null); 20 | Debug.Assert(context.SyntaxContextReceiver is SyntaxContextReceiver); 21 | var receiver = Unsafe.As(context.SyntaxContextReceiver); 22 | 23 | INamedTypeSymbol? type = context.Compilation.GetTypeByMetadataName("PostInitialization.Roslyn3_9"); 24 | bool hasPostInitialization = type is not null; 25 | 26 | StringBuilder source = new(); 27 | source.AppendLine($"// PostInitialization found: {hasPostInitialization}"); 28 | source.AppendLine($"// {nameof(receiver.NodesVisited)}: {receiver.NodesVisited}"); 29 | source.AppendLine($"// Generated on {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}"); 30 | source.AppendLine(); 31 | 32 | context.AddSource("Generated.g.cs", source.ToString()); 33 | } 34 | 35 | private static void PostInitialization(GeneratorPostInitializationContext context) 36 | { 37 | //language=c# 38 | const string source = """ 39 | namespace PostInitialization; 40 | 41 | internal static class Roslyn3_9 42 | { 43 | internal static string Get() 44 | { 45 | return "PostInitialization"; 46 | } 47 | } 48 | 49 | """; 50 | 51 | context.AddSource("PostInitialization.g.cs", source); 52 | } 53 | } 54 | 55 | internal sealed class SyntaxContextReceiver : ISyntaxContextReceiver 56 | { 57 | public int NodesVisited { get; private set; } 58 | 59 | public void OnVisitSyntaxNode(GeneratorSyntaxContext context) 60 | { 61 | NodesVisited++; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_0/F0.Talks.SourceGenerators.Demo.Roslyn4_0.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0;netstandard2.0 5 | latest 6 | enable 7 | enable 8 | 9 | 10 | 11 | true 12 | true 13 | 14 | 15 | 16 | $(NoWarn);nullable 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_0/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "F0.Talks.SourceGenerators.Demo.Roslyn4_0": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "..\\F0.Talks.SourceGenerators.Demo\\F0.Talks.SourceGenerators.Demo.csproj" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_0/Roslyn4_0Generator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.Text; 3 | using System.CodeDom.Compiler; 4 | using System.Globalization; 5 | using System.Text; 6 | using System.Xml.Linq; 7 | 8 | namespace F0.Talks.SourceGenerators.Demo.Roslyn4_0; 9 | 10 | [Generator(LanguageNames.CSharp)] 11 | internal sealed class Roslyn4_0Generator : IIncrementalGenerator 12 | { 13 | public void Initialize(IncrementalGeneratorInitializationContext context) 14 | { 15 | IncrementalValuesProvider xmlFiles = 16 | context.AdditionalTextsProvider.Where(static (AdditionalText text) => text.Path.EndsWith(".xml")); 17 | 18 | IncrementalValuesProvider source = 19 | xmlFiles.Select(GetDocument) 20 | .Where(static (XDocument? document) => document is not null)!; 21 | 22 | context.RegisterSourceOutput(source, Execute); 23 | } 24 | 25 | private static XDocument? GetDocument(AdditionalText additionalText, CancellationToken cancellationToken) 26 | { 27 | SourceText? text = additionalText.GetText(cancellationToken); 28 | if (text is null) 29 | { 30 | return null; 31 | } 32 | 33 | var document = XDocument.Parse(text.ToString()); 34 | return document; 35 | } 36 | 37 | private static void Execute(SourceProductionContext context, XDocument source) 38 | { 39 | StringBuilder builder = new(); 40 | using StringWriter writer = new(builder, CultureInfo.InvariantCulture); 41 | using IndentedTextWriter text = new(writer); 42 | 43 | string name = source.Root!.Name.ToString(); 44 | 45 | text.WriteLine("// "); 46 | text.WriteLine("#nullable enable"); 47 | text.WriteLine(); 48 | text.WriteLine($@"[global::System.CodeDom.Compiler.GeneratedCode(""Roslyn4_0"", ""{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}"")]"); 49 | text.WriteLine($"internal sealed class {name}"); 50 | text.WriteLine("{"); 51 | text.Indent++; 52 | 53 | foreach (XElement descendant in source.Root.Descendants()) 54 | { 55 | string property = descendant.FirstAttribute switch 56 | { 57 | { Name.LocalName: "type", Value: "int" } => $"public int {descendant.Name} {{ get; }} = {descendant.Value};", 58 | { Name.LocalName: "type", Value: "string" } => $@"public string {descendant.Name} {{ get; }} = ""{descendant.Value}"";", 59 | _ => throw new NotImplementedException(descendant.ToString()), 60 | }; 61 | 62 | text.WriteLine(property); 63 | } 64 | 65 | text.Indent--; 66 | text.WriteLine("}"); 67 | 68 | context.AddSource($"{name}.g.cs", writer.ToString()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_10/F0.Talks.SourceGenerators.Demo.Roslyn4_10.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0;netstandard2.0 5 | latest 6 | enable 7 | enable 8 | 9 | 10 | 11 | true 12 | true 13 | 14 | 15 | 16 | $(NoWarn);nullable 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_10/InterceptorMethodAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using System.Collections.Immutable; 6 | using System.Diagnostics; 7 | using System.Diagnostics.CodeAnalysis; 8 | using System.Runtime.CompilerServices; 9 | 10 | namespace F0.Talks.SourceGenerators.Demo.Roslyn4_10; 11 | 12 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 13 | internal sealed class InterceptorMethodAnalyzer : DiagnosticAnalyzer 14 | { 15 | [SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking", Justification = "Demo")] 16 | private static readonly DiagnosticDescriptor Rule = new( 17 | "DEMO0001", 18 | "Interceptor-Method", 19 | "Invocation '{0}' is intercepted by Method '{1}'", 20 | "Demo", 21 | DiagnosticSeverity.Warning, 22 | true, 23 | ".NET 9.0.200 Interceptor found.", 24 | "https://github.com/Flash0ver/F0-Talks-SourceGenerators" 25 | ); 26 | 27 | public override ImmutableArray SupportedDiagnostics => [Rule]; 28 | 29 | public override void Initialize(AnalysisContext context) 30 | { 31 | context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); 32 | context.EnableConcurrentExecution(); 33 | 34 | context.RegisterSyntaxNodeAction(AnalyzeInvocationExpression, SyntaxKind.InvocationExpression); 35 | } 36 | 37 | private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context) 38 | { 39 | Debug.Assert(context.Node is InvocationExpressionSyntax); 40 | 41 | var node = Unsafe.As(context.Node); 42 | 43 | #pragma warning disable RSEXPERIMENTAL002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. 44 | IMethodSymbol? symbol = context.SemanticModel.GetInterceptorMethod(node, context.CancellationToken); 45 | #pragma warning restore RSEXPERIMENTAL002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. 46 | 47 | if (symbol is null) 48 | { 49 | return; 50 | } 51 | 52 | SymbolInfo info = context.SemanticModel.GetSymbolInfo(node, context.CancellationToken); 53 | 54 | Location location = symbol.Locations[0]; 55 | var diagnostic = Diagnostic.Create(Rule, location, info.Symbol?.Name, symbol.Name); 56 | context.ReportDiagnostic(diagnostic); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_10/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "F0.Talks.SourceGenerators.Demo.Roslyn4_10": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "..\\F0.Talks.SourceGenerators.Demo\\F0.Talks.SourceGenerators.Demo.csproj" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_11/F0.Talks.SourceGenerators.Demo.Roslyn4_11.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0;netstandard2.0 5 | latest 6 | enable 7 | enable 8 | 9 | 10 | 11 | true 12 | true 13 | 14 | 15 | 16 | $(NoWarn);nullable 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_11/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "F0.Talks.SourceGenerators.Demo.Roslyn4_11": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "..\\F0.Talks.SourceGenerators.Demo\\F0.Talks.SourceGenerators.Demo.csproj" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_2/F0.Talks.SourceGenerators.Demo.Roslyn4_2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0;netstandard2.0 5 | latest 6 | enable 7 | enable 8 | 9 | 10 | 11 | true 12 | true 13 | 14 | 15 | 16 | $(NoWarn);nullable 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_2/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "F0.Talks.SourceGenerators.Demo.Roslyn4_2": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "..\\F0.Talks.SourceGenerators.Demo\\F0.Talks.SourceGenerators.Demo.csproj" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_2/Roslyn4_2Generator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using System.CodeDom.Compiler; 3 | using System.Collections.Immutable; 4 | using System.Globalization; 5 | using System.Text; 6 | 7 | namespace F0.Talks.SourceGenerators.Demo.Roslyn4_2; 8 | 9 | [Generator(LanguageNames.CSharp)] 10 | internal sealed class Roslyn4_2Generator : IIncrementalGenerator 11 | { 12 | public void Initialize(IncrementalGeneratorInitializationContext context) 13 | { 14 | IncrementalValuesProvider provider = 15 | context.MetadataReferencesProvider; 16 | 17 | var source = provider.Collect(); 18 | 19 | context.RegisterSourceOutput(source, Execute); 20 | } 21 | 22 | private static void Execute(SourceProductionContext context, ImmutableArray source) 23 | { 24 | StringBuilder builder = new(); 25 | using StringWriter writer = new(builder, CultureInfo.InvariantCulture); 26 | using IndentedTextWriter text = new(writer); 27 | 28 | text.WriteLine("// "); 29 | text.WriteLine("#nullable enable"); 30 | text.WriteLine(); 31 | 32 | foreach (MetadataReference metadataReference in source) 33 | { 34 | string line = $"// {metadataReference.Display} ({metadataReference.Properties.Kind})"; 35 | text.WriteLine(line); 36 | } 37 | 38 | context.AddSource("MetadataReferences.g.cs", writer.ToString()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_3/F0.Talks.SourceGenerators.Demo.Roslyn4_3.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0;netstandard2.0 5 | latest 6 | enable 7 | enable 8 | 9 | 10 | 11 | true 12 | true 13 | 14 | 15 | 16 | $(NoWarn);nullable 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_3/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "F0.Talks.SourceGenerators.Demo.Roslyn4_3": { 5 | "commandName": "DebugRoslynComponent", 6 | "targetProject": "..\\F0.Talks.SourceGenerators.Demo\\F0.Talks.SourceGenerators.Demo.csproj" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Roslyn4_3/Roslyn4_3Generator.cs: -------------------------------------------------------------------------------- 1 | using System.CodeDom.Compiler; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.Runtime.CompilerServices; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.CSharp; 7 | using Microsoft.CodeAnalysis.CSharp.Syntax; 8 | 9 | namespace F0.Talks.SourceGenerators.Demo.Roslyn4_3; 10 | 11 | [Generator(LanguageNames.CSharp)] 12 | internal sealed class Roslyn4_3Generator : IIncrementalGenerator 13 | { 14 | private static readonly string generatedCodeAttribute = $@"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""{typeof(Roslyn4_3Generator).Assembly.GetName().Name}"", ""{typeof(Roslyn4_3Generator).Assembly.GetName().Version}"")]"; 15 | 16 | public void Initialize(IncrementalGeneratorInitializationContext context) 17 | { 18 | context.RegisterPostInitializationOutput(static void (IncrementalGeneratorPostInitializationContext context) => 19 | { 20 | const string hintName = "F0.GeneratedNamespace.GeneratedAttribute.g.cs"; 21 | //language=c# 22 | string source = $$""" 23 | namespace F0.GeneratedNamespace; 24 | 25 | {{generatedCodeAttribute}} 26 | [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 27 | internal sealed class GeneratedAttribute : global::System.Attribute 28 | { 29 | } 30 | 31 | """; 32 | 33 | context.AddSource(hintName, source); 34 | }); 35 | 36 | IncrementalValuesProvider<(string TypeName, Accessibility MethodAccessibility, string MethodName)> provider = 37 | context.SyntaxProvider.ForAttributeWithMetadataName("F0.GeneratedNamespace.GeneratedAttribute", 38 | static bool (SyntaxNode node, CancellationToken cancellationToken) => 39 | { 40 | return node is MethodDeclarationSyntax method 41 | && method.Modifiers.Any(SyntaxKind.StaticKeyword) 42 | && method.Modifiers.Any(SyntaxKind.PartialKeyword) 43 | && method.ReturnType is PredefinedTypeSyntax predefined 44 | && predefined.Keyword.IsKind(SyntaxKind.IntKeyword); 45 | }, 46 | static (string TypeName, Accessibility MethodAccessibility, string MethodName) (GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken) => 47 | { 48 | Debug.Assert(context.TargetNode is MethodDeclarationSyntax); 49 | Debug.Assert(context.TargetSymbol is IMethodSymbol); 50 | Debug.Assert(!context.Attributes.IsEmpty); 51 | 52 | var symbol = Unsafe.As(context.TargetSymbol); 53 | 54 | return (symbol.ContainingType.Name, symbol.DeclaredAccessibility, symbol.Name); 55 | }); 56 | 57 | context.RegisterSourceOutput(provider, static void (SourceProductionContext context, (string TypeName, Accessibility MethodAccessibility, string MethodName) info) => 58 | { 59 | using StringWriter writer = new(CultureInfo.InvariantCulture); 60 | using IndentedTextWriter source = new(writer); 61 | 62 | source.WriteLine($"static partial class {info.TypeName}"); 63 | source.WriteLine("{"); 64 | source.Indent++; 65 | source.WriteLine($"{SyntaxFacts.GetText(info.MethodAccessibility)} static partial int {info.MethodName}()"); 66 | source.WriteLine("{"); 67 | source.Indent++; 68 | source.WriteLine("return 0x_F0;"); 69 | source.Indent--; 70 | source.WriteLine("}"); 71 | source.Indent--; 72 | source.WriteLine("}"); 73 | 74 | Debug.Assert(source.Indent == 0); 75 | context.AddSource($"{info.TypeName}.g.cs", writer.ToString()); 76 | }); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Tests/F0.Talks.SourceGenerators.Demo.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.Tests/RegexTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace F0.Talks.SourceGenerators.Demo.Tests; 6 | 7 | /// 8 | /// .NET regular expression source generators 9 | /// 10 | [SuppressMessage("GeneratedRegex", "SYSLIB1045:Convert to 'GeneratedRegexAttribute'.", Justification = "Demo")] 11 | public partial class RegexTests 12 | { 13 | private static readonly Regex _regex = new("Flash(Over|0ver|OWare)", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled); 14 | 15 | [GeneratedRegex("Flash(Over|0ver|OWare)", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture, "en-US")] 16 | private static partial Regex GeneratedRegex { get; } 17 | 18 | [Theory] 19 | [InlineData("FlashOver")] 20 | [InlineData("flashover")] 21 | [InlineData("Flash0ver")] 22 | [InlineData("flash0ver")] 23 | [InlineData("FlashOWare")] 24 | [InlineData("flashoware")] 25 | public void IsMatch_Match_ReturnTrue(string text) 26 | { 27 | _regex.IsMatch(text).Should().BeTrue(); 28 | GeneratedRegex.IsMatch(text).Should().BeTrue(); 29 | } 30 | 31 | [Theory] 32 | [InlineData("0x_F0")] 33 | [InlineData("Backdraft")] 34 | [InlineData("Techorama 2024")] 35 | public void IsMatch_Mismatch_ReturnFalse(string text) 36 | { 37 | _regex.IsMatch(text).Should().BeFalse(); 38 | GeneratedRegex.IsMatch(text).Should().BeFalse(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WebApi/F0.Talks.SourceGenerators.Demo.WebApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | true 8 | true 9 | 10 | 11 | 12 | true 13 | true 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WebApi/F0.Talks.SourceGenerators.Demo.WebApi.http: -------------------------------------------------------------------------------- 1 | @F0.Talks.SourceGenerators.Demo.WebApi_HostAddress = http://localhost:5261 2 | 3 | GET {{F0.Talks.SourceGenerators.Demo.WebApi_HostAddress}}/todos/ 4 | Accept: application/json 5 | 6 | ### 7 | 8 | GET {{F0.Talks.SourceGenerators.Demo.WebApi_HostAddress}}/todos/1 9 | Accept: application/json 10 | 11 | ### 12 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WebApi/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | var builder = WebApplication.CreateSlimBuilder(args); 4 | 5 | builder.Services.ConfigureHttpJsonOptions(options => 6 | { 7 | options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); 8 | }); 9 | 10 | var app = builder.Build(); 11 | 12 | var sampleTodos = new Todo[] { 13 | new(1, "Walk the dog"), 14 | new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)), 15 | new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))), 16 | new(4, "Clean the bathroom"), 17 | new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2))) 18 | }; 19 | 20 | var todosApi = app.MapGroup("/todos"); 21 | todosApi.MapGet("/", () => sampleTodos); 22 | todosApi.MapGet("/{id}", (int id) => 23 | sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo 24 | ? Results.Ok(todo) 25 | : Results.NotFound()); 26 | 27 | app.Run(); 28 | 29 | public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false); 30 | 31 | [JsonSerializable(typeof(Todo[]))] 32 | internal partial class AppJsonSerializerContext : JsonSerializerContext 33 | { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WebApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "http": { 5 | "commandName": "Project", 6 | "dotnetRunMessages": true, 7 | "launchBrowser": true, 8 | "launchUrl": "todos", 9 | "applicationUrl": "http://localhost:5261", 10 | "environmentVariables": { 11 | "ASPNETCORE_ENVIRONMENT": "Development" 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WebApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WebApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WpfApp/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WpfApp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace F0.Talks.SourceGenerators.Demo.WpfApp; 4 | 5 | public partial class App : Application 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WpfApp/F0.Talks.SourceGenerators.Demo.WpfApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net9.0-windows 6 | enable 7 | enable 8 | true 9 | 10 | 11 | 12 | preview 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WpfApp/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Input; 3 | using System.Diagnostics.CodeAnalysis; 4 | 5 | namespace F0.Talks.SourceGenerators.Demo.WpfApp; 6 | 7 | [INotifyPropertyChanged] 8 | [SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "MVVMTK0032:Inherit from ObservableObject instead of using [INotifyPropertyChanged]", Justification = "Demo")] 9 | internal sealed partial class MainViewModel 10 | { 11 | [ObservableProperty] 12 | public partial int Number { get; set; } = 0x_F0; 13 | 14 | [RelayCommand] 15 | void Increment() 16 | { 17 | Number++; 18 | } 19 | 20 | [RelayCommand] 21 | void Decrement() 22 | { 23 | Number--; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/F0.Talks.SourceGenerators.Demo.WpfApp/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |