├── .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 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo.WpfApp/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace F0.Talks.SourceGenerators.Demo.WpfApp;
4 |
5 | public partial class MainWindow : Window
6 | {
7 | public MainWindow()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo.WpfApp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
4 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo/AdditionalText1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1
4 | 1
5 |
6 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo/AdditionalText2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2
4 | 2
5 |
6 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo/AdditionalText3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 3
4 | 3
5 |
6 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo/F0.Talks.SourceGenerators.Demo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | enable
7 | enable
8 |
9 |
10 |
11 | true
12 | $(BaseIntermediateOutputPath)Generated
13 |
14 |
15 |
16 | $(InterceptorsPreviewNamespaces);F0.Talks.SourceGenerators.Demo.Generated
17 | $(InterceptorsNamespaces);Generated
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo/Intercepted.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace F0.Talks.SourceGenerators.Demo;
5 |
6 | [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Demo")]
7 | internal sealed class Intercepted
8 | {
9 | [Interceptable]
10 | public static string Static(string text)
11 | {
12 | return $"Ordinary Method: {text}";
13 | }
14 |
15 | [Interceptable]
16 | public string Instance(string text)
17 | {
18 | return $"Ordinary Method: {text}";
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo/JsonSerializerDemo.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json;
2 | using System.Text.Json.Serialization;
3 |
4 | namespace F0.Talks.SourceGenerators.Demo;
5 |
6 | internal static class JsonSerializerDemo
7 | {
8 | public static void Roundtrip()
9 | {
10 | Entity entity = new()
11 | {
12 | Name = "Generation",
13 | Number = 0x_F0,
14 | };
15 |
16 | string json = JsonSerializer.Serialize(entity, SerializerContext.Default.Entity);
17 | Console.WriteLine(json);
18 |
19 | Entity? roundtrip = JsonSerializer.Deserialize(json, SerializerContext.Default.Entity);
20 | Console.WriteLine(roundtrip!.ToString());
21 | }
22 | }
23 |
24 | public record class Entity
25 | {
26 | public string? Name { get; set; }
27 | public int Number { get; set; }
28 | }
29 |
30 | [JsonSerializable(typeof(Entity))]
31 | [JsonSourceGenerationOptions(WriteIndented = true)]
32 | public partial class SerializerContext : JsonSerializerContext
33 | {
34 | }
35 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo/PreviewInterceptors.g.cs:
--------------------------------------------------------------------------------
1 | //
2 | #nullable enable
3 |
4 | namespace F0.Talks.SourceGenerators.Demo.Generated
5 | {
6 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("F0.Talks.SourceGenerators.Demo", "1.0.0.0")]
7 | file static class PreviewInterceptors
8 | {
9 | private const string FilePath = @"Location\Program.cs";
10 |
11 | // [System.Runtime.CompilerServices.InterceptsLocation(FilePath, 20, 36)]
12 | internal static string Interceptor0(string text)
13 | {
14 | return $"Intercepted (static): {text}";
15 | }
16 |
17 | // [System.Runtime.CompilerServices.InterceptsLocation(FilePath, 21, 42)]
18 | internal static string Interceptor1(this F0.Talks.SourceGenerators.Demo.Intercepted instance, string text)
19 | {
20 | return $"Intercepted (instance): {text}";
21 | }
22 | }
23 | }
24 |
25 | namespace System.Runtime.CompilerServices
26 | {
27 | #pragma warning disable CS9113 // Parameter is unread.
28 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("F0.Talks.SourceGenerators.Demo", "1.0.0.0")]
29 | [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
30 | file sealed class InterceptsLocationAttribute(string filePath, int line, int character) : global::System.Attribute
31 | {
32 | }
33 | #pragma warning restore CS9113 // Parameter is unread.
34 | }
35 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Demo/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using F0.GeneratedNamespace;
3 | using F0.Talks.SourceGenerators.Demo;
4 |
5 | JsonSerializerDemo.Roundtrip();
6 | Console.WriteLine();
7 |
8 | Console.WriteLine($"ModuleInitializer: {Helper.Text}");
9 |
10 | Console.WriteLine($"Roslyn 3.8: {Helper.GetText()}");
11 | Console.WriteLine($"Roslyn 3.9: {PostInitialization.Roslyn3_9.Get()}");
12 |
13 | Console.WriteLine($"Roslyn 4.0: {new Generated1().Number}");
14 |
15 | Console.WriteLine($"Roslyn 4.3: {Helper.GetNumber()}");
16 |
17 | Console.WriteLine();
18 | Console.WriteLine("Interceptors:");
19 | Console.WriteLine($"- {Intercepted.Static("Hello, World!")}");
20 | Console.WriteLine($"- {new Intercepted().Instance("Techorama 2024")}");
21 |
22 | public static partial class Helper
23 | {
24 | public static string? Text { get; set; }
25 |
26 | [ModuleInitializer]
27 | internal static void Init()
28 | {
29 | Text = "initialized";
30 | }
31 |
32 | internal static partial string GetText();
33 |
34 | [Generated]
35 | internal static partial int GetNumber();
36 | }
37 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/F0.Talks.SourceGenerators.Presentation.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/Program.cs:
--------------------------------------------------------------------------------
1 | using Statiq.Markdown;
2 | using System.Text.RegularExpressions;
3 |
4 | return await Bootstrapper
5 | .Factory
6 | .CreateDefault(args)
7 | .BuildPipeline("Render Presentation", static builder => builder
8 | .WithInputReadFiles("*.md")
9 | .WithProcessModules(new LinkModule(), new RenderMarkdown().UseExtensions())
10 | .WithPostProcessModules(new SlideModule())
11 | .WithOutputWriteFiles(".html"))
12 | .BuildPipeline("Copy CSS", static builder => builder
13 | .WithInputReadFiles("*.css")
14 | .WithOutputWriteFiles(".css"))
15 | .RunAsync();
16 |
17 | internal sealed partial class LinkModule : ParallelModule
18 | {
19 | [GeneratedRegex(@"(\[.+]\(\.\/[^/]+\.)(md)(\))", RegexOptions.None)]
20 | private static partial Regex Regex { get; }
21 |
22 | protected override async Task> ExecuteInputAsync(IDocument input, IExecutionContext context)
23 | {
24 | MemoryStream stream = new();
25 | StreamWriter writer = new(stream);
26 |
27 | await using (Stream content = input.ContentProvider.GetStream())
28 | {
29 | using (StreamReader reader = new(content))
30 | {
31 | while (await reader.ReadLineAsync() is { } line)
32 | {
33 | line = Regex.Replace(line, "$1html$3", 1);
34 |
35 | await writer.WriteLineAsync(line);
36 | }
37 | }
38 | }
39 |
40 | await writer.FlushAsync();
41 |
42 | IContentProvider provider = context.GetContentProvider(stream, MediaTypes.Html);
43 |
44 | IEnumerable output = input
45 | .Clone(input.Source, input.Destination, context, provider)
46 | .Yield();
47 |
48 | return output;
49 | }
50 | }
51 |
52 | internal sealed class SlideModule : ParallelModule
53 | {
54 | protected override async Task> ExecuteInputAsync(IDocument input, IExecutionContext context)
55 | {
56 | MemoryStream stream = new();
57 | StreamWriter writer = new(stream);
58 |
59 | await writer.WriteLineAsync("");
60 | await writer.WriteLineAsync("");
61 | await writer.WriteLineAsync("");
62 | await writer.WriteLineAsync(@"");
63 | await writer.WriteLineAsync("");
64 | await writer.WriteLineAsync("");
65 | await writer.FlushAsync();
66 |
67 | await using (Stream content = input.ContentProvider.GetStream())
68 | {
69 | await content.CopyToAsync(stream);
70 | }
71 |
72 | await writer.WriteLineAsync("");
73 | await writer.WriteLineAsync(" ");
74 | await writer.FlushAsync();
75 |
76 | IContentProvider provider = context.GetContentProvider(stream, MediaTypes.Html);
77 |
78 | IEnumerable output = input
79 | .Clone(input.Source, input.Destination, context, provider)
80 | .Yield();
81 |
82 | return output;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Additional.md:
--------------------------------------------------------------------------------
1 | # References & Additional Resources
2 |
3 | ## Blogs
4 |
5 | - [Learn Roslyn Now](https://joshvarty.com/learn-roslyn-now/)
6 | - [The [Source Code] Generation Game (Steve Collins)](https://gist.github.com/stevetalkscode/2882e9e9443f142faa5081444e7f2d7b)
7 | - [Working with types in a Roslyn analyzer (Gérald Barré)](https://www.meziantou.net/working-with-types-in-a-roslyn-analyzer.htm)
8 | - [Series: Creating a source generator (Andrew Lock)](https://andrewlock.net/series/creating-a-source-generator/)
9 | - [Exploring .NET 6 - Source generator updates: incremental generators (Andrew Lock)](https://andrewlock.net/exploring-dotnet-6-part-9-source-generator-updates-incremental-generators/)
10 | - [Incremental Roslyn Source Generators In .NET 6 (Pawel Gerr)](https://www.thinktecture.com/en/net/roslyn-source-generators-introduction/)
11 |
12 | ## Videos
13 |
14 | - [C# Source Generators - Write Code that Writes Code (David Wengier)](https://www.youtube.com/watch?v=3YwwdoRg2F4)
15 | - [Using Source Generators for Fun and maybe profit (Jason Bock)](https://www.youtube.com/watch?v=P9Pv5IdinMU)
16 | - [C# Source Generators in Action (Andrey Dyatlov)](https://www.youtube.com/watch?v=052xutD86uI)
17 | - [Exploring Source Generators (Martin Ullrich)](https://www.youtube.com/watch?v=qFI9k-9N_js)
18 | - [Source and Incremental Generators: Under the hood (Chris Sienkiewicz)](https://youtu.be/tJldyGnWDEQ?t=6858)
19 | - [Webinar: Roslyn Source Generators in .NET 6](https://www.thinktecture.com/webinare/roslyn-source-generators-in-dot-net-6/)
20 |
21 | ---
22 | #### [TOC](./Content.md)
23 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Anatomy.md:
--------------------------------------------------------------------------------
1 | # Anatomy
2 |
3 | ```
4 |
5 |
6 | netstandard2.0
7 |
8 |
9 |
10 |
11 |
12 |
13 | ```
14 |
15 | ### ISourceGenerator (deprecated)
16 | ```
17 | [Generator]
18 | internal sealed class MyGenerator : ISourceGenerator
19 | {
20 | public void Initialize(GeneratorInitializationContext context);
21 | public void Execute(GeneratorExecutionContext context);
22 | }
23 |
24 | internal sealed class MySyntaxReceiver : ISyntaxReceiver
25 | {
26 | public void OnVisitSyntaxNode(SyntaxNode syntaxNode);
27 | }
28 | ```
29 |
30 | ### IIncrementalGenerator
31 | ```
32 | [Generator(LanguageNames.CSharp)]
33 | internal sealed class MyGenerator : IIncrementalGenerator
34 | {
35 | public void Initialize(IncrementalGeneratorInitializationContext context);
36 | }
37 | ```
38 |
39 | ---
40 | #### References
41 | - [ISourceGenerator Interface](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.isourcegenerator)
42 | - [GeneratorInitializationContext Struct](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.generatorinitializationcontext)
43 | - [ISyntaxReceiver Interface](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.isyntaxreceiver)
44 | - [ISyntaxContextReceiver Interface](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.isyntaxcontextreceiver)
45 | - [GeneratorExecutionContext Struct](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.generatorexecutioncontext)
46 | - [IIncrementalGenerator Interface](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.iincrementalgenerator)
47 | - [IncrementalGeneratorInitializationContext Struct](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.incrementalgeneratorinitializationcontext)
48 |
49 | #### [TOC](./Content.md)
50 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/BestPractices.md:
--------------------------------------------------------------------------------
1 | # Best Practices
2 |
3 | - `// `
4 | - `#nullable enable`
5 | - `global::` -> `global::System.Console.WriteLine("Hello, World!");`
6 | - `[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Tool", "Version")]`
7 | - `HintName.g.cs` or `HintName.generated.cs`
8 | - Mind the required `.NET SDK`
9 | - Mind the required `LangVersion`
10 | - Mind the performance (Benchmarking and Profiling)
11 | - Should be _deterministic_, especially _incremental generators_
12 | - Testing! (Unit Tests, Integration Tests, Code Coverage, Mutation Testing)
13 | - Use Analyzers
14 | - Set `All`
15 | - Use `Microsoft.CodeAnalysis.Analyzers`
16 | - Set `true`
17 |
18 | ---
19 | - [Source Generators Cookbook](https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md)
20 | - [Incremental Generators](https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md)
21 | - [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet)
22 | - [Microsoft.CodeAnalysis.Testing](https://github.com/dotnet/roslyn-sdk/tree/main/src/Microsoft.CodeAnalysis.Testing)
23 | - [Stryker.NET](https://github.com/stryker-mutator/stryker-net)
24 |
25 | #### [TOC](./Content.md)
26 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/CSharp.md:
--------------------------------------------------------------------------------
1 | # C# language features
2 |
3 | ## C# 2.0
4 |
5 | - partial types
6 |
7 | ## C# 3.0
8 |
9 | - partial methods
10 | - no accessibility modifiers
11 | - return `void`
12 | - no `out` parameters
13 |
14 | ## C# 9.0
15 |
16 | > "Support for code generators"
17 |
18 | - extended partial methods
19 | - allow explicit access modifier
20 | - may be non-`private`
21 | - may have a non-`void` return type
22 | - may have `out` parameters
23 | - module initializers
24 | - must be static
25 | - must be parameterless
26 | - must return void
27 | - must not be a generic method
28 | - must not be contained in a generic class
29 | - must be accessible from the containing module
30 | - `internal` or `public`
31 | - no local function
32 |
33 | ## C# 11.0
34 |
35 | > "Avoid name collisions"
36 |
37 | - file-scoped types
38 | - `file` access modifier
39 | - on top-level types
40 | - accessibility is scoped to the declaring source file
41 | - also for nested types
42 | - enables shadowing of a non-`file`-local type by a `file`-local type
43 | - cannot be used in a member signature in non-`file`-local types
44 | - may implicitly implement a `file`-scoped interface type
45 | - see implementing less-accessible interfaces
46 | - `global using static` not permitted
47 |
48 | ## C# 12.0
49 |
50 | - experimental Interceptors
51 | - `[InterceptsLocation]`
52 | ```CSharp
53 | namespace System.Runtime.CompilerServices
54 | {
55 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
56 | public sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute
57 | {
58 | }
59 | }
60 | ```
61 | - ordinary Methods only
62 | - contained in non-generic type
63 | - one or more `[InterceptsLocation]` attributes
64 | - requires matching signatures
65 | - Static Methods or Extension Methods
66 |
67 | ## C# 13.0
68 |
69 | - stable Interceptors
70 | - `[InterceptsLocation]`
71 | ```CSharp
72 | namespace System.Runtime.CompilerServices
73 | {
74 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
75 | public sealed class InterceptsLocationAttribute(int version, string data) : Attribute
76 | {
77 | }
78 | }
79 | ```
80 | - partial properties
81 | - must have a matching implementation part
82 | - partial indexers
83 | - must have a matching implementation part
84 |
85 | ---
86 | #### References
87 | - [partial member](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/partial-member)
88 | - [ModuleInitializerAttribute](https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.moduleinitializerattribute)
89 | - [file keyword](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/file)
90 | - [File-local types](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-11.0/file-local-types)
91 | - [Interceptors](https://github.com/dotnet/roslyn/blob/main/docs/features/interceptors.md)
92 |
93 | #### [TOC](./Content.md)
94 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Content.md:
--------------------------------------------------------------------------------
1 | # Table of contents
2 |
3 | 1. [Roslyn](./Roslyn.md)
4 | 1. [.NET Generators](./NET.md)
5 | 1. [C# language features](./CSharp.md)
6 | 1. [Laws of Source Generation](./SourceGeneration.md)
7 | 1. [Anatomy](./Anatomy.md)
8 | 1. [Tooling](./Tooling.md)
9 | 1. [Debugging](./Debugging.md)
10 | 1. [Nullable reference types](./NRT.md)
11 | 1. [Versioning](./Versioning.md)
12 | 1. [Performance](./Performance.md)
13 | 1. [NuGet](./NuGet.md)
14 | 1. [Testing](./Testing.md)
15 | 1. [Best Practices](./BestPractices.md)
16 | 1. [Get started](./Kickstart.md)
17 | 1. [Examples](./Examples.md)
18 | 1. [Would You Like to Know More?](./Additional.md)
19 |
20 | ---
21 | #### [Q & A](./QA.md)
22 |
23 | #### [https://github.com/Flash0ver/F0-Talks-SourceGenerators](https://github.com/Flash0ver/F0-Talks-SourceGenerators)
24 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Debugging.md:
--------------------------------------------------------------------------------
1 | # Debugging
2 |
3 | - Visual Studio 2019 [16.10](https://learn.microsoft.com/visualstudio/releases/2019/release-notes-v16.10) or greater
4 | - Rider [2023.1](https://www.jetbrains.com/rider/whatsnew/2023-1/)
5 |
6 | ```
7 |
8 | true
9 |
10 | ```
11 |
12 | ```
13 | {
14 | "profiles": {
15 | "LaunchSettings": {
16 | "commandName": "DebugRoslynComponent",
17 | "targetProject": "..\\..\\src\\ConsoleApp240\\Consoleapp240.csproj"
18 | }
19 | }
20 | }
21 | ```
22 |
23 | ```
24 |
25 |
31 |
32 | ```
33 |
34 | ---
35 | - [Debugging C# Source Generators with Visual Studio 2019 16.10](https://stevetalkscode.co.uk/debug-source-generators-with-vs2019-1610)
36 |
37 | #### [TOC](./Content.md)
38 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Examples.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | - [C# Source Generators](https://github.com/amis92/csharp-source-generators)
4 | - [Awesome Roslyn](https://github.com/ironcev/awesome-roslyn#source-generators)
5 | - [CommunityToolkit](https://github.com/CommunityToolkit/dotnet)
6 | - [Data Builder Generator](https://github.com/dasMulli/data-builder-generator)
7 | - [F0.Generators](https://github.com/Flash0ver/F0.Generators)
8 | - [F0.Compatibility](https://github.com/Flash0ver/F0.Compatibility)
9 | - [FlashOWare.Generators](https://github.com/FlashOWare/FlashOWare.Generators)
10 |
11 | ---
12 | #### [TOC](./Content.md)
13 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Exit.md:
--------------------------------------------------------------------------------
1 | # Thank you
2 |
3 | > Enough talk!
4 |
5 | (Conan, Conan the Destroyer, 1984)
6 |
7 | ---
8 | #### [Index](./)
9 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Index.md:
--------------------------------------------------------------------------------
1 | # Roslyn Source Generators
2 | # Let's Code an incremental source generator with Roslyn
3 | # Let's Build an incremental source generator with Roslyn
4 |
5 | > Never send a human to do a machine's job
6 |
7 | (Agent Smith, The Matrix, 1999)
8 |
9 | ---
10 | #### [Speaker](./Speaker.md)
11 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Kickstart.md:
--------------------------------------------------------------------------------
1 | # Get started
2 |
3 | `F0.Templates`
4 | - [https://github.com/Flash0ver/F0.Templates](https://github.com/Flash0ver/F0.Templates)
5 | - [Docs](https://github.com/Flash0ver/F0.Templates/blob/main/documentation/F0.Templates.md)
6 | - [NuGet](https://www.nuget.org/packages/F0.Templates/)
7 |
8 | `Solution Template for Roslyn Source Generator`
9 | - [Rider 2023.2](https://www.jetbrains.com/rider/whatsnew/2023-2/)
10 |
11 | ---
12 | #### [TOC](./Content.md)
13 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/NET.md:
--------------------------------------------------------------------------------
1 | # .NET Generators
2 |
3 | ## .NET 6.0
4 |
5 | - System.Text.Json | [Source](https://source.dot.net/#q=System.Text.Json.SourceGeneration.JsonSourceGenerator) | [Documentation](https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/source-generation)
6 | - Microsoft.Extensions.Logging.Abstractions | [Source](https://source.dot.net/#q=Microsoft.Extensions.Logging.Generators.LoggerMessageGenerator) | [Documentation](https://learn.microsoft.com/dotnet/core/extensions/logger-message-generator)
7 | - Blazor | [Blog](https://andrewlock.net/using-source-generators-with-blazor-in-dotnet-6/)
8 |
9 | ## .NET 7.0
10 |
11 | - System.Text.RegularExpressions | [Source](https://source.dot.net/#q=System.Text.RegularExpressions.Generator.RegexGenerator) | [Documentation](https://learn.microsoft.com/dotnet/standard/base-types/regular-expression-source-generators)
12 | - System.Runtime.InteropServices | [Source](https://source.dot.net/#q=Microsoft.Interop.LibraryImportGenerator) | [Documentation](https://learn.microsoft.com/dotnet/standard/native-interop/pinvoke-source-generation)
13 | - System.Runtime.InteropServices.JavaScript
14 | - JSImportGenerator | [Source](https://source.dot.net/#q=Microsoft.Interop.JavaScript.JSImportGenerator)
15 | - JSExportGenerator | [Source](https://source.dot.net/#q=Microsoft.Interop.JavaScript.JSExportGenerator)
16 |
17 | ## .NET 8.0
18 |
19 | - Microsoft.AspNetCore.Http.RequestDelegateGenerator | [Source](https://source.dot.net/#q=Microsoft.AspNetCore.Http.RequestDelegateGenerator.RequestDelegateGenerator)
20 | - Configuration-binding source generator | [Source](https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs)
21 | - `true`
22 | - Source-generated COM interop | [YouTube](https://www.youtube.com/watch?v=DZd1SGd7dSU)
23 |
24 | ## .NET 9.0
25 |
26 | - System.Text.RegularExpressions.GeneratedRegexAttribute
27 | - supports `partial properties` via `AttributeTargets.Property`
28 | - previously only `partial methods` via `AttributeTargets.Method`
29 |
30 | ---
31 | #### [TOC](./Content.md)
32 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/NRT.md:
--------------------------------------------------------------------------------
1 | # Nullable reference types
2 |
3 | - C# 8.0 vs .NET Standard 2.0
4 | - [C# language versioning](https://learn.microsoft.com/dotnet/csharp/language-reference/configure-language-version)
5 |
6 | ```
7 |
8 | net6.0;netstandard2.0
9 | latest
10 | enable
11 |
12 | ```
13 |
14 | ```
15 |
16 |
17 |
18 | ```
19 |
20 | ```
21 |
22 | $(NoWarn);nullable
23 |
24 | ```
25 |
26 | ---
27 | - [Nullable Reference Types](https://learn.microsoft.com/dotnet/csharp/nullable-references)
28 | - [Nullable Attributes](https://learn.microsoft.com/dotnet/csharp/language-reference/attributes/nullable-analysis)
29 | - [Package: Nullable](https://www.nuget.org/packages/Nullable/)
30 |
31 | #### [TOC](./Content.md)
32 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/NuGet.md:
--------------------------------------------------------------------------------
1 | # NuGet
2 |
3 | - .NET Standard 2.0
4 | - .NET Analyzers
5 |
6 | ```
7 |
8 | false
9 | true
10 | true
11 |
12 | ```
13 |
14 | ```
15 |
16 |
17 |
18 | ```
19 |
20 | ---
21 | #### [TOC](./Content.md)
22 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Performance.md:
--------------------------------------------------------------------------------
1 | # Performance
2 |
3 | - Cancellation via `CancellationToken`
4 | - `ThrowIfCancellationRequested()`
5 | - forward the CancellationToken parameter to methods that take one
6 | - many syntax nodes = many invocations
7 | - `ISyntaxReceiver.OnVisitSyntaxNode(SyntaxNode)`
8 | - `ISyntaxContextReceiver.OnVisitSyntaxNode(GeneratorSyntaxContext)`
9 | - large projects / solutions
10 |
11 | ---
12 | #### [TOC](./Content.md)
13 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/QA.md:
--------------------------------------------------------------------------------
1 | # Q & A
2 |
3 | ```
4 | Input: Question
5 | Output: Answer
6 | ```
7 |
8 | ### The source of truth
9 | https://github.com/Flash0ver/F0-Talks-SourceGenerators
10 |
11 | ### Channels
12 | * Twitch: [FlashOWare](https://www.twitch.tv/flashoware)
13 | * YouTube: [FlashOWare](https://www.youtube.com/@FlashOWare)
14 |
15 | ### Contact
16 | * X (Twitter): [@0x_F0](https://twitter.com/0x_F0)
17 | * Mastodon: [@0x_F0@dotnet.social](https://dotnet.social/@0x_F0)
18 | * Bluesky: [@flash0ver.bsky.social](https://bsky.app/profile/flash0ver.bsky.social)
19 | * GitHub: [Flash0ver](https://github.com/Flash0ver)
20 | * NuGet: [Flash0ver](https://www.nuget.org/profiles/Flash0ver)
21 | * Stack Overflow: [FlashOver](https://stackoverflow.com/users/10167996/flashover)
22 | * LinkedIn: [Stefan Pölz](https://www.linkedin.com/in/flashover/)
23 | * Sessionize: [FlashOver](https://sessionize.com/FlashOver)
24 | * Credly: [FlashOver](https://www.credly.com/users/flashover)
25 |
26 | ### Web
27 | [FlashOWare.net](http://flashoware.net)
28 |
29 | ---
30 | #### [Exit](./Exit.md)
31 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Roslyn.md:
--------------------------------------------------------------------------------
1 | # Roslyn
2 |
3 | The .NET Compiler Platform
4 | (_C#_ and _Visual Basic_)
5 |
6 | NuGet: [Microsoft.CodeAnalysis](https://www.nuget.org/packages/Microsoft.CodeAnalysis)
7 |
8 | GitHub: [https://github.com/dotnet/roslyn](https://github.com/dotnet/roslyn)
9 |
10 | - [DiagnosticAnalyzer](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.diagnostics.diagnosticanalyzer)
11 | - [CodeFixProvider](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.codefixes.codefixprovider)
12 | - [CodeRefactoringProvider](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.coderefactorings.coderefactoringprovider)
13 | - [DiagnosticSuppressor](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.diagnostics.diagnosticsuppressor)
14 | - **Generator**
15 | - [ISourceGenerator](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.isourcegenerator)
16 | - [IIncrementalGenerator](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.iincrementalgenerator)
17 | - **Standalone Code Analysis Tool**
18 | - [MSBuildLocator](https://learn.microsoft.com/dotnet/api/microsoft.build.locator.msbuildlocator)
19 | - [MSBuildWorkspace](https://learn.microsoft.com/dotnet/api/microsoft.codeanalysis.workspace)
20 |
21 | ---
22 | #### [TOC](./Content.md)
23 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/SourceGeneration.md:
--------------------------------------------------------------------------------
1 | # Laws of Source Generation
2 |
3 | - retrieve compilation representing user code
4 | - with syntax trees
5 | - with semantic models
6 | - new source code can be added to the compilation as additional source code
7 | - `0..n`
8 | - as strings
9 | - additive only
10 | - can produce diagnostics
11 | - may access additional files (non-C# source texts)
12 | - oblivious
13 | - no access to documents created by other source generators
14 | - are technically analyzers
15 |
16 | ## Use cases
17 | - avoid tedious boilerplate (error-prone) code written manual
18 | - avoid _Reflection_ with high-performance code
19 | - facilitate _Trimming_ and _Native AOT_
20 |
21 | ---
22 | - [Source Generators Documentation](https://learn.microsoft.com/dotnet/csharp/roslyn-sdk/source-generators-overview)
23 | - [Source Generators Design Document](https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.md)
24 | - [Source Generators Cookbook](https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md)
25 | - [Incremental Generators Design Document](https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md)
26 | - [Incremental Generators Cookbook](https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md)
27 |
28 | #### [TOC](./Content.md)
29 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Speaker.md:
--------------------------------------------------------------------------------
1 | ### Stefan Pölz
2 | * Clean C# Coder
3 | * Test-driven .NET developer
4 | * [FlashOWare.net](http://flashoware.net)
5 |
6 | #### My _Generator_ journey
7 | * Coding since 2008
8 | * C# since 2012
9 | * .NET since 2013
10 | * Roslyn since 2020
11 | * Source Generators since 2021
12 | * Lead Software Engineer @ [Tricentis](https://www.tricentis.com)
13 |
14 | #### Community
15 | * JetBrains Community Contributor (.NET)
16 | * Microsoft MVP (Developer Technologies)
17 | * Co-organizer of [DotNetDevs.at](https://www.meetup.com/dotnet-austria)
18 |
19 | #### Channels
20 | * Twitch: [FlashOWare](https://www.twitch.tv/flashoware)
21 | * YouTube: [FlashOWare](https://www.youtube.com/@FlashOWare)
22 |
23 | #### Alter egos
24 | * X (Twitter): [@0x_F0](https://twitter.com/0x_F0)
25 | * Mastodon: [@0x_F0@dotnet.social](https://dotnet.social/@0x_F0)
26 | * Bluesky: [@flash0ver.bsky.social](https://bsky.app/profile/flash0ver.bsky.social)
27 | * GitHub: [Flash0ver](https://github.com/Flash0ver)
28 | * NuGet: [Flash0ver](https://www.nuget.org/profiles/Flash0ver)
29 | * Stack Overflow: [FlashOver](https://stackoverflow.com/users/10167996/flashover)
30 | * LinkedIn: [Stefan Pölz](https://www.linkedin.com/in/flashover/)
31 | * Sessionize: [FlashOver](https://sessionize.com/FlashOver)
32 | * Credly: [FlashOver](https://www.credly.com/users/flashover)
33 |
34 | ---
35 | #### [TOC](./Content.md)
36 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Testing.md:
--------------------------------------------------------------------------------
1 | # Testing
2 |
3 | [Microsoft.CodeAnalysis.Testing](https://github.com/dotnet/roslyn-sdk/tree/main/src/Microsoft.CodeAnalysis.Testing)
4 |
5 | - MSTest (v2+)
6 | - [Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest](https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest)
7 | - [Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.MSTest](https://www.nuget.org/packages/Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.MSTest)
8 | - NUnit
9 | - [Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit](https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.NUnit)
10 | - [Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.NUnit](https://www.nuget.org/packages/Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.NUnit)
11 | - xUnit.net
12 | - [Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit](https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit)
13 | - [Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.XUnit](https://www.nuget.org/packages/Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.XUnit)
14 |
15 | ---
16 | #### [TOC](./Content.md)
17 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/Tooling.md:
--------------------------------------------------------------------------------
1 | # Tooling
2 |
3 | - _Solution Explorer_ displays Roslyn generated sources
4 | - [Visual Studio 2019 16.9](https://learn.microsoft.com/visualstudio/releases/2019/release-notes-v16.9)
5 | - [Rider 2022.2](https://www.jetbrains.com/rider/whatsnew/2022-2/)
6 | - _MSBuild_ properties: save the generated sources as files
7 | ```
8 |
9 | true
10 | $(BaseIntermediateOutputPath)Generated
11 |
12 | ```
13 | - [SharpLab (Syntax Tree)](https://sharplab.io/)
14 | - [Visual Studio: Syntax Visualizer](https://learn.microsoft.com/dotnet/csharp/roslyn-sdk/syntax-visualizer)
15 | - [.NET Compiler Platform SDK](https://learn.microsoft.com/dotnet/csharp/roslyn-sdk/)
16 | - [RoslynQuoter](https://roslynquoter.azurewebsites.net/)
17 | - [Source Browser](https://sourceroslyn.io/)
18 | - [//grep.app](https://grep.app/search?filter[repo][0]=dotnet/roslyn)
19 | - [Decompilation Differ](https://wengier.com/DecompilationDiffer/)
20 | - [MSBuild Binary and Structured Log Viewer](https://msbuildlog.com/)
21 | - [Structured Log Viewer](https://live.msbuildlog.com/)
22 | - [NuGet Package Explorer](https://nuget.info/)
23 |
24 | ---
25 | - [Saving source generator output in source control (Andrew Lock)](https://andrewlock.net/creating-a-source-generator-part-6-saving-source-generator-output-in-source-control/)
26 |
27 | #### [TOC](./Content.md)
28 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/input/styles.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: "Cascadia Code";
3 | font-size: 20px;
4 |
5 | color: #0F0F0F;
6 | background: #F0F0F0;
7 |
8 | margin: 25px 50px 25px 50px;
9 | }
10 |
11 | code {
12 | font-weight: bold;
13 |
14 | color: #512bd4;
15 | }
16 |
17 | a, u {
18 | text-decoration: none;
19 | }
20 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/output/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/code/F0.Talks.SourceGenerators.Presentation/temp/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/gen/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | default
5 | enable
6 | enable
7 | $(MSBuildThisFileDirectory)..\artifacts
8 |
9 |
10 |
11 | true
12 | All
13 | 7.0
14 | true
15 |
16 |
17 |
18 | true
19 | true
20 | $(WarningsNotAsErrors);CS0612;CS0618
21 |
22 |
23 |
24 | $(NoWarn);CA1812;CA2007;
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | <_Parameter1>false
34 | <_Parameter1_TypeName>System.Boolean
35 | <_Parameter1_IsLiteral>false
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/gen/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(NoWarn);nullable
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/gen/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.Benchmarks/F0.Gen.EqualityComparison.Benchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0;net472
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.Benchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using BenchmarkDotNet.Columns;
3 | using BenchmarkDotNet.Configs;
4 | using BenchmarkDotNet.Diagnosers;
5 | using BenchmarkDotNet.Environments;
6 | using BenchmarkDotNet.Exporters;
7 | using BenchmarkDotNet.Jobs;
8 | using BenchmarkDotNet.Running;
9 | using BenchmarkDotNet.Validators;
10 |
11 | namespace F0.Gen.EqualityComparison.Benchmarks;
12 |
13 | internal static class Program
14 | {
15 | private static void Main(string[] args)
16 | {
17 | IConfig config = Debugger.IsAttached
18 | ? CreateDebugConfiguration()
19 | : CreateBenchmarkConfiguration();
20 |
21 | _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
22 |
23 | static IConfig CreateDebugConfiguration()
24 | {
25 | return new DebugInProcessConfig();
26 | }
27 |
28 | static IConfig CreateBenchmarkConfiguration()
29 | {
30 | return DefaultConfig.Instance
31 | .AddJob(Job.InProcess.WithRuntime(ClrRuntime.Net472))
32 | .AddJob(Job.InProcess.WithRuntime(CoreRuntime.Core60))
33 | .AddColumn(StatisticColumn.Min, StatisticColumn.Max, StatisticColumn.Median)
34 | .AddDiagnoser(MemoryDiagnoser.Default)
35 | .AddExporter(DefaultExporters.AsciiDoc)
36 | .AddValidator(ExecutionValidator.FailOnError);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.Example/EqualityComparisonBenchmarks.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Roslyn.Generated;
3 |
4 | namespace F0.Gen.EqualityComparison.Example;
5 |
6 | [MemoryDiagnoser]
7 | public class EqualityComparisonBenchmarks
8 | {
9 | private Dictionary referenceDictionary = null!;
10 | private Dictionary valueDictionary = null!;
11 |
12 | private MyClass reference = null!;
13 | private MyStruct value = default!;
14 |
15 | [GlobalSetup]
16 | public void Setup()
17 | {
18 | referenceDictionary = new Dictionary();
19 | valueDictionary = new Dictionary();
20 |
21 | referenceDictionary.Add(new MyClass(1, "1"), "Hello, World!");
22 | valueDictionary.Add(new MyStruct(1, "1"), "Hello, World!");
23 |
24 | reference = new MyClass(1, "1");
25 | value = new MyStruct(1, "1");
26 | }
27 |
28 | [Benchmark]
29 | public bool ReferenceType()
30 | {
31 | return referenceDictionary.TryGetValue(reference, out _);
32 | }
33 |
34 | [Benchmark]
35 | public bool ValueType()
36 | {
37 | return valueDictionary.TryGetValue(value, out _);
38 | }
39 | }
40 |
41 | [EqualityComparer(typeof(MyClass))]
42 | internal partial class MyClassEqualityComparer
43 | {
44 | }
45 |
46 | [EqualityComparer(typeof(MyStruct))]
47 | internal partial class MyStructEqualityComparer
48 | {
49 | }
50 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.Example/F0.Gen.EqualityComparison.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0;net472
6 |
7 |
8 |
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.Example/MyClass.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.EqualityComparison.Example;
2 |
3 | internal sealed class MyClass
4 | {
5 | public MyClass(int number, string text)
6 | {
7 | Number = number;
8 | Text = text;
9 | }
10 |
11 | public int Number { get; init; }
12 | public string Text { get; init; }
13 | }
14 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.Example/MyStruct.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.EqualityComparison.Example;
2 |
3 | internal readonly struct MyStruct
4 | {
5 | public MyStruct(int number, string text)
6 | {
7 | Number = number;
8 | Text = text;
9 | }
10 |
11 | public int Number { get; init; }
12 | public string Text { get; init; }
13 | }
14 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.Example/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 |
3 | namespace F0.Gen.EqualityComparison.Example;
4 |
5 | internal static class Program
6 | {
7 | private static void Main(string[] args)
8 | {
9 | Console.WriteLine(args);
10 | Console.WriteLine(DateTime.UtcNow.ToString(DateTimeFormatInfo.InvariantInfo));
11 |
12 | #if !DEBUG
13 | _ = BenchmarkDotNet.Running.BenchmarkRunner.Run();
14 | #endif
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.IntegrationTests/EqualityComparerGeneratorIntegrationTests.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using FluentAssertions;
3 | using Roslyn.Generated;
4 | using Xunit;
5 |
6 | namespace F0.Gen.EqualityComparison.IntegrationTests;
7 |
8 | public class EqualityComparerGeneratorIntegrationTests
9 | {
10 | private readonly MyClass reference1 = new(1, "1");
11 | private readonly MyClass reference2 = new(1, "1");
12 | private readonly MyClass reference3 = new(2, "2");
13 |
14 | private readonly MyStruct value1 = new(1, "1");
15 | private readonly MyStruct value2 = new(1, "1");
16 | private readonly MyStruct value3 = new(2, "2");
17 |
18 | [Fact]
19 | public void EqualityComparer_Equals()
20 | {
21 | EqualityComparer.Default.Equals(reference1, reference2).Should().BeTrue();
22 | EqualityComparer.Default.Equals(reference1, reference3).Should().BeFalse();
23 | MyClassEqualityComparer.Instance.Equals(reference1, reference2).Should().BeTrue();
24 | MyClassEqualityComparer.Instance.Equals(reference1, reference3).Should().BeFalse();
25 |
26 | EqualityComparer.Default.Equals(value1, value2).Should().BeTrue();
27 | EqualityComparer.Default.Equals(value1, value3).Should().BeFalse();
28 | MyStructEqualityComparer.Instance.Equals(value1, value2).Should().BeTrue();
29 | MyStructEqualityComparer.Instance.Equals(value1, value3).Should().BeFalse();
30 | }
31 |
32 | [Fact]
33 | [SuppressMessage("BestPractice", "F01001:Prefer is pattern to check for null", Justification = "EqualityComparer`1")]
34 | public void EqualityComparer_Equals_Null()
35 | {
36 | (null == null).Should().BeTrue();
37 |
38 | EqualityComparer.Default.Equals(reference1, null).Should().BeFalse();
39 | EqualityComparer.Default.Equals(null, reference2).Should().BeFalse();
40 | EqualityComparer.Default.Equals(null, null).Should().BeTrue();
41 | MyClassEqualityComparer.Instance.Equals(reference1, null).Should().BeFalse();
42 | MyClassEqualityComparer.Instance.Equals(null, reference2).Should().BeFalse();
43 | MyClassEqualityComparer.Instance.Equals(null, null).Should().BeTrue();
44 | }
45 |
46 | [Fact]
47 | public void EqualityComparer_GetHashCode()
48 | {
49 | EqualityComparer.Default.GetHashCode(reference1).Should().Be(EqualityComparer.Default.GetHashCode(reference2));
50 | EqualityComparer.Default.GetHashCode(reference1).Should().NotBe(EqualityComparer.Default.GetHashCode(reference3));
51 | MyClassEqualityComparer.Instance.GetHashCode(reference1).Should().Be(MyClassEqualityComparer.Instance.GetHashCode(reference2));
52 | MyClassEqualityComparer.Instance.GetHashCode(reference1).Should().NotBe(MyClassEqualityComparer.Instance.GetHashCode(reference3));
53 |
54 | EqualityComparer.Default.GetHashCode(value1).Should().Be(EqualityComparer.Default.GetHashCode(value2));
55 | EqualityComparer.Default.GetHashCode(value1).Should().NotBe(EqualityComparer.Default.GetHashCode(value3));
56 | MyStructEqualityComparer.Instance.GetHashCode(value1).Should().Be(MyStructEqualityComparer.Instance.GetHashCode(value2));
57 | MyStructEqualityComparer.Instance.GetHashCode(value1).Should().NotBe(MyStructEqualityComparer.Instance.GetHashCode(value3));
58 | }
59 |
60 | [Fact]
61 | public void EqualityComparer_GetHashCode_Null()
62 | {
63 | EqualityComparer.Default.GetHashCode(null!).Should().Be(0);
64 | MyClassEqualityComparer.Instance.GetHashCode(null!).Should().Be(0);
65 | }
66 | }
67 |
68 | [EqualityComparer(typeof(MyClass))]
69 | internal partial class MyClassEqualityComparer
70 | {
71 | }
72 |
73 | [EqualityComparer(typeof(MyStruct))]
74 | internal partial class MyStructEqualityComparer
75 | {
76 | }
77 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.IntegrationTests/F0.Gen.EqualityComparison.IntegrationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net472
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1707
10 | true
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.IntegrationTests/MyClass.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.EqualityComparison.IntegrationTests;
2 |
3 | internal sealed record class MyClass
4 | {
5 | public MyClass(int number, string text)
6 | {
7 | Number = number;
8 | Text = text;
9 | }
10 |
11 | public int Number { get; init; }
12 | public string Text { get; init; }
13 | }
14 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.IntegrationTests/MyStruct.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.EqualityComparison.IntegrationTests;
2 |
3 | internal readonly record struct MyStruct
4 | {
5 | public MyStruct(int number, string text)
6 | {
7 | Number = number;
8 | Text = text;
9 | }
10 |
11 | public int Number { get; init; }
12 | public string Text { get; init; }
13 | }
14 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.IntegrationTests/TypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Xunit;
3 |
4 | namespace F0.Gen.EqualityComparison.IntegrationTests;
5 |
6 | public class TypeTests
7 | {
8 | [Fact]
9 | public void Type_BaseType()
10 | {
11 | typeof(MyClass).BaseType.Should().Be(typeof(object));
12 | typeof(MyClass).BaseType!.BaseType.Should().BeNull();
13 |
14 | typeof(MyStruct).BaseType.Should().Be(typeof(ValueType));
15 | typeof(MyStruct).BaseType!.BaseType.Should().Be(typeof(object));
16 | typeof(MyStruct).BaseType!.BaseType!.BaseType.Should().BeNull();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.UnitTests/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.UnitTests/Diagnostics/DebugAssertException.cs:
--------------------------------------------------------------------------------
1 | #if NETFRAMEWORK
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace F0.Gen.EqualityComparison.UnitTests.Diagnostics;
5 |
6 | [SuppressMessage("Design", "CA1032:Implement standard exception constructors", Justification = "Debug.Assert on .NET Framework")]
7 | [SuppressMessage("Design", "CA1064:Exceptions should be public", Justification = "Debug.Assert on .NET Framework")]
8 | internal sealed class DebugAssertException : Exception
9 | {
10 | public DebugAssertException(string? message)
11 | : base(message)
12 | {
13 | }
14 | }
15 | #endif
16 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.UnitTests/Diagnostics/DebugTraceListener.cs:
--------------------------------------------------------------------------------
1 | #if NETFRAMEWORK
2 | using System.Diagnostics;
3 |
4 | namespace F0.Gen.EqualityComparison.UnitTests.Diagnostics;
5 |
6 | internal sealed class DebugTraceListener : TraceListener
7 | {
8 | public DebugTraceListener()
9 | : base(nameof(Debug))
10 | {
11 | }
12 |
13 | public DebugTraceListener(string? name)
14 | : base(name)
15 | {
16 | }
17 |
18 | public override void Write(string? message)
19 | => throw new NotImplementedException($"{nameof(DebugTraceListener)}.{nameof(Write)}({nameof(String)})");
20 |
21 | public override void WriteLine(string? message)
22 | => throw new DebugAssertException(message);
23 | }
24 | #endif
25 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.UnitTests/F0.Gen.EqualityComparison.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net472
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1707
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.UnitTests/Verifiers/CSharpSourceGeneratorVerifier.Test.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Testing;
4 | using Microsoft.CodeAnalysis.Testing;
5 | using Microsoft.CodeAnalysis.Testing.Verifiers;
6 |
7 | namespace F0.Gen.EqualityComparison.UnitTests.Verifiers;
8 |
9 | internal static partial class CSharpSourceGeneratorVerifier
10 | where TSourceGenerator : IIncrementalGenerator, new()
11 | {
12 | public sealed class Test : CSharpSourceGeneratorTest
13 | {
14 | public Test()
15 | {
16 | }
17 |
18 | public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default;
19 |
20 | protected override IEnumerable GetSourceGenerators()
21 | {
22 | return new[] { new TSourceGenerator().AsSourceGenerator() };
23 | }
24 |
25 | protected override CompilationOptions CreateCompilationOptions()
26 | {
27 | CompilationOptions compilationOptions = base.CreateCompilationOptions();
28 | return compilationOptions.WithSpecificDiagnosticOptions(
29 | compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
30 | }
31 |
32 | protected override ParseOptions CreateParseOptions()
33 | {
34 | return ((CSharpParseOptions)base.CreateParseOptions()).WithLanguageVersion(LanguageVersion);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.UnitTests/Verifiers/CSharpSourceGeneratorVerifier.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.Testing;
4 | using Microsoft.CodeAnalysis.Text;
5 |
6 | namespace F0.Gen.EqualityComparison.UnitTests.Verifiers;
7 |
8 | internal static partial class CSharpSourceGeneratorVerifier
9 | where TSourceGenerator : IIncrementalGenerator, new()
10 | {
11 | internal static readonly (string filename, string content)[] EmptyGeneratedSources = Array.Empty<(string filename, string content)>();
12 |
13 | public static DiagnosticResult Diagnostic()
14 | => new DiagnosticResult();
15 |
16 | public static DiagnosticResult Diagnostic(string id, DiagnosticSeverity severity)
17 | => new DiagnosticResult(id, severity);
18 |
19 | public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
20 | => new DiagnosticResult(descriptor);
21 |
22 | public static async Task VerifyGeneratorAsync(string source, (string filename, string content) generatedSource)
23 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, new[] { generatedSource });
24 |
25 | public static async Task VerifyGeneratorAsync(string source, params (string filename, string content)[] generatedSources)
26 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, generatedSources);
27 |
28 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic)
29 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, EmptyGeneratedSources);
30 |
31 | public static async Task VerifyGeneratorAsync(string source, params DiagnosticResult[] diagnostics)
32 | => await VerifyGeneratorAsync(source, diagnostics, EmptyGeneratedSources);
33 |
34 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, (string filename, string content) generatedSource)
35 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, new[] { generatedSource });
36 |
37 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, (string filename, string content) generatedSource)
38 | => await VerifyGeneratorAsync(source, diagnostics, new[] { generatedSource });
39 |
40 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, params (string filename, string content)[] generatedSources)
41 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, generatedSources);
42 |
43 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, params (string filename, string content)[] generatedSources)
44 | {
45 | CSharpSourceGeneratorVerifier.Test test = new()
46 | {
47 | TestState =
48 | {
49 | Sources = { source },
50 | },
51 | ReferenceAssemblies = ReferenceAssemblies.Net.Net60,
52 | };
53 |
54 | foreach ((string filename, string content) in generatedSources)
55 | {
56 | test.TestState.GeneratedSources.Add((typeof(TSourceGenerator), filename, SourceText.From(content, Encoding.UTF8)));
57 | }
58 |
59 | test.ExpectedDiagnostics.AddRange(diagnostics);
60 |
61 | await test.RunAsync(CancellationToken.None);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.UnitTests/Verifiers/CSharpVerifierHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.CSharp;
4 |
5 | namespace F0.Gen.EqualityComparison.UnitTests.Verifiers;
6 |
7 | internal static class CSharpVerifierHelper
8 | {
9 | internal static ImmutableDictionary NullableWarnings { get; } = GetNullableWarningsFromCompiler();
10 |
11 | private static ImmutableDictionary GetNullableWarningsFromCompiler()
12 | {
13 | string[] args = { "/warnaserror:nullable" };
14 | CSharpCommandLineArguments commandLineArguments = CSharpCommandLineParser.Default.Parse(args, Environment.CurrentDirectory, Environment.CurrentDirectory);
15 | ImmutableDictionary nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
16 |
17 | return nullableWarnings;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32319.34
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.EqualityComparison", "F0.Gen.EqualityComparison\F0.Gen.EqualityComparison.csproj", "{9F80DF06-A9BB-4931-A667-AD8C837B44BC}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.EqualityComparison.Benchmarks", "F0.Gen.EqualityComparison.Benchmarks\F0.Gen.EqualityComparison.Benchmarks.csproj", "{A8652D7E-E8C9-4E6E-BEB2-8B60C3D98126}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.EqualityComparison.Example", "F0.Gen.EqualityComparison.Example\F0.Gen.EqualityComparison.Example.csproj", "{6EF2B28E-CC8D-42D6-BDAE-DC29FEE58E9B}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.EqualityComparison.IntegrationTests", "F0.Gen.EqualityComparison.IntegrationTests\F0.Gen.EqualityComparison.IntegrationTests.csproj", "{B98BFB10-5612-4C6D-BD60-7438ABE13486}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.EqualityComparison.UnitTests", "F0.Gen.EqualityComparison.UnitTests\F0.Gen.EqualityComparison.UnitTests.csproj", "{FA977F0F-3DBE-444B-A47F-DACD5F47B836}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F0.Gen.Extern", "F0.Gen.Extern\F0.Gen.Extern.csproj", "{D5C5683D-97D7-460D-B020-CC3A31DC886E}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Release|Any CPU = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {9F80DF06-A9BB-4931-A667-AD8C837B44BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {9F80DF06-A9BB-4931-A667-AD8C837B44BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {9F80DF06-A9BB-4931-A667-AD8C837B44BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {9F80DF06-A9BB-4931-A667-AD8C837B44BC}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {A8652D7E-E8C9-4E6E-BEB2-8B60C3D98126}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {A8652D7E-E8C9-4E6E-BEB2-8B60C3D98126}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {A8652D7E-E8C9-4E6E-BEB2-8B60C3D98126}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {A8652D7E-E8C9-4E6E-BEB2-8B60C3D98126}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {6EF2B28E-CC8D-42D6-BDAE-DC29FEE58E9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {6EF2B28E-CC8D-42D6-BDAE-DC29FEE58E9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {6EF2B28E-CC8D-42D6-BDAE-DC29FEE58E9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {6EF2B28E-CC8D-42D6-BDAE-DC29FEE58E9B}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {B98BFB10-5612-4C6D-BD60-7438ABE13486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {B98BFB10-5612-4C6D-BD60-7438ABE13486}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {B98BFB10-5612-4C6D-BD60-7438ABE13486}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {B98BFB10-5612-4C6D-BD60-7438ABE13486}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {FA977F0F-3DBE-444B-A47F-DACD5F47B836}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {FA977F0F-3DBE-444B-A47F-DACD5F47B836}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {FA977F0F-3DBE-444B-A47F-DACD5F47B836}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {FA977F0F-3DBE-444B-A47F-DACD5F47B836}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {D5C5683D-97D7-460D-B020-CC3A31DC886E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {D5C5683D-97D7-460D-B020-CC3A31DC886E}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {D5C5683D-97D7-460D-B020-CC3A31DC886E}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {D5C5683D-97D7-460D-B020-CC3A31DC886E}.Release|Any CPU.Build.0 = Release|Any CPU
48 | EndGlobalSection
49 | GlobalSection(SolutionProperties) = preSolution
50 | HideSolutionNode = FALSE
51 | EndGlobalSection
52 | GlobalSection(ExtensibilityGlobals) = postSolution
53 | SolutionGuid = {178004DC-0D1F-46A9-B866-C67CAD035CCB}
54 | EndGlobalSection
55 | EndGlobal
56 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison/EqualityComparerGenerator.Attributes.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.EqualityComparison;
2 |
3 | internal sealed partial class EqualityComparerGenerator
4 | {
5 | private static readonly string GeneratedCodeAttribute = $@"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""{typeof(EqualityComparerGenerator).Assembly.GetName().Name}"", ""{typeof(EqualityComparerGenerator).Assembly.GetName().Version}"")]";
6 |
7 | private static readonly string EqualityComparerAttribute = $@"//
8 | #nullable enable
9 |
10 | namespace Roslyn.Generated;
11 |
12 | {GeneratedCodeAttribute}
13 | [global::System.AttributeUsageAttribute(global::System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
14 | internal sealed class EqualityComparerAttribute : global::System.Attribute
15 | {{
16 | public EqualityComparerAttribute(global::System.Type type)
17 | {{
18 | Type = type;
19 | }}
20 |
21 | public global::System.Type Type {{ get; }}
22 | }}
23 | ";
24 | }
25 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison/EqualityComparerGenerator.Contexts.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 |
3 | namespace F0.Gen.EqualityComparison;
4 |
5 | internal sealed partial class EqualityComparerGenerator
6 | {
7 | private readonly record struct EqualityComparerContext(string? Namespace, string Name, CompareTypeContext CompareType);
8 | private readonly record struct CompareTypeContext(bool IsReferenceType, string QualifiedName, ImmutableArray Properties);
9 | private readonly record struct PropertyContext(string Type, string Name);
10 |
11 | private sealed class EqualityComparerContextEqualityComparer : IEqualityComparer
12 | {
13 | private EqualityComparerContextEqualityComparer() { }
14 |
15 | public static EqualityComparerContextEqualityComparer Instance { get; } = new EqualityComparerContextEqualityComparer();
16 |
17 | public bool Equals(EqualityComparerContext x, EqualityComparerContext y)
18 | {
19 | return x.Namespace == y.Namespace
20 | && x.Name == y.Name
21 | && CompareTypeContextEqualityComparer.Instance.Equals(x.CompareType, y.CompareType);
22 | }
23 |
24 | public int GetHashCode(EqualityComparerContext obj)
25 | {
26 | throw new NotImplementedException();
27 | }
28 | }
29 |
30 | private sealed class CompareTypeContextEqualityComparer : IEqualityComparer
31 | {
32 | private CompareTypeContextEqualityComparer() { }
33 |
34 | public static CompareTypeContextEqualityComparer Instance { get; } = new CompareTypeContextEqualityComparer();
35 |
36 | public bool Equals(CompareTypeContext x, CompareTypeContext y)
37 | {
38 | return x.IsReferenceType == y.IsReferenceType
39 | && x.QualifiedName == y.QualifiedName
40 | && x.Properties.SequenceEqual(y.Properties, PropertyContextEqualityComparer.Instance);
41 | }
42 |
43 | public int GetHashCode(CompareTypeContext obj)
44 | {
45 | throw new NotImplementedException();
46 | }
47 | }
48 |
49 | private sealed class PropertyContextEqualityComparer : IEqualityComparer
50 | {
51 | private PropertyContextEqualityComparer() { }
52 |
53 | public static PropertyContextEqualityComparer Instance { get; } = new PropertyContextEqualityComparer();
54 |
55 | public bool Equals(PropertyContext x, PropertyContext y)
56 | {
57 | return x.Type == y.Type
58 | && x.Name == y.Name;
59 | }
60 |
61 | public int GetHashCode(PropertyContext obj)
62 | {
63 | throw new NotImplementedException();
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison/EqualityComparerGenerator.Formats.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace F0.Gen.EqualityComparison;
4 |
5 | internal sealed partial class EqualityComparerGenerator
6 | {
7 | private static readonly SymbolDisplayFormat Format = SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes | SymbolDisplayMiscellaneousOptions.ExpandNullable | SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier);
8 | }
9 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison/EqualityComparerGenerator.Names.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.EqualityComparison;
2 |
3 | internal sealed partial class EqualityComparerGenerator
4 | {
5 | private const string EqualityComparerInterfaceName = "System.Collections.Generic.IEqualityComparer";
6 |
7 | private const string EqualityComparerAttributeName = "Roslyn.Generated.EqualityComparerAttribute";
8 | }
9 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;netstandard2.0
5 |
6 |
7 |
8 | true
9 | false
10 | true
11 | true
12 | true
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | <_Parameter1>F0.Gen.EqualityComparison.Benchmarks
27 |
28 |
29 | <_Parameter1>F0.Gen.EqualityComparison.UnitTests
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison/NamedTypeSymbolExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace F0.Gen.EqualityComparison;
4 |
5 | internal static class NamedTypeSymbolExtensions
6 | {
7 | public static IEnumerable GetThisAndSubtypes(this INamedTypeSymbol? type)
8 | {
9 | INamedTypeSymbol? current = type;
10 | while (current is not null)
11 | {
12 | yield return current;
13 | current = current.BaseType;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.EqualityComparison/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "F0.Gen.EqualityComparison": {
4 | "commandName": "DebugRoslynComponent",
5 | "targetProject": "..\\F0.Gen.EqualityComparison.Example\\F0.Gen.EqualityComparison.Example.csproj"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.Extern/F0.Gen.Extern.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1044
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.Extern/GlobalType.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | [SuppressMessage("Design", "CA1050:Declare types in namespaces", Justification = "Demo")]
4 | public sealed class GlobalType
5 | {
6 | public int Number { get; init; }
7 | public string Text { get; init; }
8 |
9 | [SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "Demo")]
10 | public sealed class NestedType
11 | {
12 | public int Number { get; init; }
13 | public string Text { get; init; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.Extern/Inheritance.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.Extern;
2 |
3 | public sealed class SealedType : DerivedType
4 | {
5 | }
6 |
7 | public class DerivedType : AbstractType
8 | {
9 | public override int AbstractProperty { get; init; }
10 | public override int VirtualProperty { get; init; }
11 | }
12 |
13 | public abstract class AbstractType
14 | {
15 | public abstract int AbstractProperty { get; init; }
16 | public virtual int VirtualProperty { get; init; }
17 | }
18 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.Extern/InternalClass.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.Extern;
2 |
3 | internal class InternalClass
4 | {
5 | private string writeOnlyProperty;
6 |
7 | public InternalClass(string value)
8 | {
9 | (PublicProperty, ProtectedProperty, InternalProperty, ProtectedInternalProperty, PrivateProperty, PrivateProtectedProperty) = (value, value, value, value, value, value);
10 | writeOnlyProperty = nameof(WriteOnlyProperty);
11 | }
12 |
13 | public static string StaticProperty { get; }
14 | public string PublicProperty { get; init; }
15 | protected string ProtectedProperty { get; init; }
16 | internal string InternalProperty { get; init; }
17 | protected internal string ProtectedInternalProperty { get; init; }
18 | private string PrivateProperty { get; init; }
19 | private protected string PrivateProtectedProperty { get; init; }
20 | public string WriteOnlyProperty { init => writeOnlyProperty = value; }
21 | }
22 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.Extern/InternalStruct.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.Extern;
2 |
3 | internal readonly record struct InternalStruct
4 | {
5 | public InternalStruct(int number, string text)
6 | {
7 | Number = number;
8 | Text = text;
9 | }
10 |
11 | public int Number { get; init; }
12 | public string Text { get; init; }
13 | }
14 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.Extern/PublicClass.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.Extern;
2 |
3 | public class PublicClass
4 | {
5 | private string writeOnlyProperty;
6 |
7 | public PublicClass(string value)
8 | {
9 | (PublicProperty, ProtectedProperty, InternalProperty, ProtectedInternalProperty, PrivateProperty, PrivateProtectedProperty) = (value, value, value, value, value, value);
10 | writeOnlyProperty = nameof(WriteOnlyProperty);
11 | }
12 |
13 | public static string StaticProperty { get; }
14 | public string PublicProperty { get; init; }
15 | protected string ProtectedProperty { get; init; }
16 | internal string InternalProperty { get; init; }
17 | protected internal string ProtectedInternalProperty { get; init; }
18 | private string PrivateProperty { get; init; }
19 | private protected string PrivateProtectedProperty { get; init; }
20 | public string WriteOnlyProperty { init => writeOnlyProperty = value; }
21 | }
22 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.Extern/PublicStruct.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.Extern;
2 |
3 | public readonly record struct PublicStruct
4 | {
5 | public PublicStruct(int number, string text)
6 | {
7 | Number = number;
8 | Text = text;
9 | }
10 |
11 | public int Number { get; init; }
12 | public string Text { get; init; }
13 | }
14 |
--------------------------------------------------------------------------------
/gen/F0.Gen.EqualityComparison/F0.Gen.Extern/TopLevelType.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | namespace F0.Gen.Extern;
4 |
5 | public sealed class TopLevelType
6 | {
7 | public int Number { get; init; }
8 | public string Text { get; init; }
9 |
10 | [SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "Demo")]
11 | public sealed class NestedType
12 | {
13 | public int Number { get; init; }
14 | public string Text { get; init; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.Benchmarks/F0.Gen.GetNameOfEnum.Benchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0;net472
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.Benchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using BenchmarkDotNet.Columns;
3 | using BenchmarkDotNet.Configs;
4 | using BenchmarkDotNet.Diagnosers;
5 | using BenchmarkDotNet.Environments;
6 | using BenchmarkDotNet.Exporters;
7 | using BenchmarkDotNet.Jobs;
8 | using BenchmarkDotNet.Running;
9 | using BenchmarkDotNet.Validators;
10 |
11 | namespace F0.Gen.GetNameOfEnum.Benchmarks;
12 |
13 | internal static class Program
14 | {
15 | private static void Main(string[] args)
16 | {
17 | IConfig config = Debugger.IsAttached
18 | ? CreateDebugConfiguration()
19 | : CreateBenchmarkConfiguration();
20 |
21 | _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
22 |
23 | static IConfig CreateDebugConfiguration()
24 | {
25 | return new DebugInProcessConfig();
26 | }
27 |
28 | static IConfig CreateBenchmarkConfiguration()
29 | {
30 | return DefaultConfig.Instance
31 | .AddJob(Job.InProcess.WithRuntime(ClrRuntime.Net472))
32 | .AddJob(Job.InProcess.WithRuntime(CoreRuntime.Core60))
33 | .AddColumn(StatisticColumn.Min, StatisticColumn.Max, StatisticColumn.Median)
34 | .AddDiagnoser(MemoryDiagnoser.Default)
35 | .AddExporter(DefaultExporters.AsciiDoc)
36 | .AddValidator(ExecutionValidator.FailOnError);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.Example/EnumInfo.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Roslyn.Generated;
3 |
4 | namespace F0.Gen.GetNameOfEnum.Example;
5 |
6 | internal static partial class EnumInfo
7 | {
8 | [GetNameOfEnum]
9 | public static partial string? GetName(LogLevel hello);
10 | }
11 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.Example/F0.Gen.GetNameOfEnum.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0;net472
6 |
7 |
8 |
9 | true
10 | $(BaseIntermediateOutputPath)generated
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.Example/GetNameOfEnumBenchmarks.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using BenchmarkDotNet.Attributes;
3 | using Microsoft.Extensions.Logging;
4 |
5 | namespace F0.Gen.GetNameOfEnum.Example;
6 |
7 | [MemoryDiagnoser]
8 | [SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Benchmarks")]
9 | [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "BenchmarkDotNet")]
10 | public class GetNameOfEnumBenchmarks
11 | {
12 | private const LogLevel logLevel = LogLevel.None;
13 |
14 | [Benchmark(Baseline = true)]
15 | public string Enum_ToString()
16 | => logLevel.ToString();
17 |
18 | [Benchmark]
19 | public string? Enum_GetName()
20 | #if NETFRAMEWORK
21 | => Enum.GetName(typeof(LogLevel), logLevel);
22 | #else
23 | => Enum.GetName(logLevel);
24 | #endif
25 |
26 | [Benchmark]
27 | public string? Generated_GetName()
28 | => EnumInfo.GetName(logLevel);
29 | }
30 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.Example/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace F0.Gen.GetNameOfEnum.Example;
4 |
5 | internal static class Program
6 | {
7 | private static void Main(string[] args)
8 | {
9 | string? name = EnumInfo.GetName(LogLevel.None);
10 | Console.WriteLine(name);
11 |
12 | #if !DEBUG
13 | _ = BenchmarkDotNet.Running.BenchmarkRunner.Run();
14 | #endif
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.IntegrationTests/EnumInfo.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Roslyn.Generated;
3 |
4 | namespace F0.Gen.GetNameOfEnum.IntegrationTests;
5 |
6 | internal partial class EnumInfo
7 | {
8 | public static string? GetName_HandRolled(LogLevel value)
9 | {
10 | return value switch
11 | {
12 | LogLevel.Trace => nameof(LogLevel.Trace),
13 | LogLevel.Debug => nameof(LogLevel.Debug),
14 | LogLevel.Information => nameof(LogLevel.Information),
15 | LogLevel.Warning => nameof(LogLevel.Warning),
16 | LogLevel.Error => nameof(LogLevel.Error),
17 | LogLevel.Critical => nameof(LogLevel.Critical),
18 | LogLevel.None => nameof(LogLevel.None),
19 | _ => null,
20 | };
21 | }
22 |
23 | [GetNameOfEnum]
24 | public static partial string? GetName_Generated(LogLevel value);
25 | }
26 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.IntegrationTests/F0.Gen.GetNameOfEnum.IntegrationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net472
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1707
10 |
11 |
12 |
13 | true
14 | $(BaseIntermediateOutputPath)generated
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.IntegrationTests/GetNameOfEnumGeneratorIntegrationTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.Extensions.Logging;
3 | using Xunit;
4 |
5 | namespace F0.Gen.GetNameOfEnum.IntegrationTests;
6 |
7 | public class GetNameOfEnumGeneratorIntegrationTests
8 | {
9 | [Theory]
10 | [InlineData(LogLevel.Trace, nameof(LogLevel.Trace))]
11 | [InlineData(LogLevel.Debug, nameof(LogLevel.Debug))]
12 | [InlineData(LogLevel.Information, nameof(LogLevel.Information))]
13 | [InlineData(LogLevel.Warning, nameof(LogLevel.Warning))]
14 | [InlineData(LogLevel.Error, nameof(LogLevel.Error))]
15 | [InlineData(LogLevel.Critical, nameof(LogLevel.Critical))]
16 | [InlineData(LogLevel.None, nameof(LogLevel.None))]
17 | public void Generated_Enum_GetName(LogLevel logLevel, string? expected)
18 | {
19 | logLevel.ToString().Should().Be(expected);
20 |
21 | #if NETFRAMEWORK
22 | Enum.GetName(typeof(LogLevel), logLevel).Should().Be(expected);
23 | #else
24 | Enum.GetName(logLevel).Should().Be(expected);
25 | #endif
26 |
27 | EnumInfo.GetName_HandRolled(logLevel).Should().Be(expected);
28 | EnumInfo.GetName_Generated(logLevel).Should().Be(expected);
29 | }
30 |
31 | [Theory]
32 | [InlineData((LogLevel)7, null, "7")]
33 | public void Generated_Enum_GetName_Null(LogLevel logLevel, string? getName, string toString)
34 | {
35 | logLevel.ToString().Should().Be(toString);
36 |
37 | #if NETFRAMEWORK
38 | Enum.GetName(typeof(LogLevel), logLevel).Should().Be(getName);
39 | #else
40 | Enum.GetName(logLevel).Should().Be(getName);
41 | #endif
42 |
43 | EnumInfo.GetName_HandRolled(logLevel).Should().Be(getName);
44 | EnumInfo.GetName_Generated(logLevel).Should().Be(getName);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.UnitTests/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.UnitTests/Diagnostics/DebugAssertException.cs:
--------------------------------------------------------------------------------
1 | #if NETFRAMEWORK
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace F0.Gen.GetNameOfEnum.UnitTests.Diagnostics
5 | {
6 | [SuppressMessage("Design", "CA1032:Implement standard exception constructors", Justification = "Debug.Assert on .NET Framework")]
7 | [SuppressMessage("Design", "CA1064:Exceptions should be public", Justification = "Debug.Assert on .NET Framework")]
8 | internal sealed class DebugAssertException : Exception
9 | {
10 | public DebugAssertException(string? message)
11 | : base(message)
12 | {
13 | }
14 | }
15 | }
16 | #endif
17 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.UnitTests/Diagnostics/DebugTraceListener.cs:
--------------------------------------------------------------------------------
1 | #if NETFRAMEWORK
2 | using System.Diagnostics;
3 |
4 | namespace F0.Gen.GetNameOfEnum.UnitTests.Diagnostics
5 | {
6 | internal sealed class DebugTraceListener : TraceListener
7 | {
8 | public DebugTraceListener()
9 | : base(nameof(Debug))
10 | {
11 | }
12 |
13 | public DebugTraceListener(string? name)
14 | : base(name)
15 | {
16 | }
17 |
18 | public override void Write(string? message)
19 | => throw new NotImplementedException($"{nameof(DebugTraceListener)}.{nameof(Write)}({nameof(String)})");
20 |
21 | public override void WriteLine(string? message)
22 | => throw new DebugAssertException(message);
23 | }
24 | }
25 | #endif
26 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.UnitTests/F0.Gen.GetNameOfEnum.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net472
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1707
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.UnitTests/Verifiers/CSharpSourceGeneratorVerifier.Test.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Testing;
4 | using Microsoft.CodeAnalysis.Testing;
5 | using Microsoft.CodeAnalysis.Testing.Verifiers;
6 |
7 | namespace F0.Gen.GetNameOfEnum.UnitTests.Verifiers
8 | {
9 | internal static partial class CSharpSourceGeneratorVerifier
10 | where TSourceGenerator : IIncrementalGenerator, new()
11 | {
12 | public sealed class Test : CSharpSourceGeneratorTest
13 | {
14 | public Test()
15 | {
16 | }
17 |
18 | public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default;
19 |
20 | protected override IEnumerable GetSourceGenerators()
21 | {
22 | return new[] { new TSourceGenerator().AsSourceGenerator() };
23 | }
24 |
25 | protected override CompilationOptions CreateCompilationOptions()
26 | {
27 | CompilationOptions compilationOptions = base.CreateCompilationOptions();
28 | return compilationOptions.WithSpecificDiagnosticOptions(
29 | compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
30 | }
31 |
32 | protected override ParseOptions CreateParseOptions()
33 | {
34 | return ((CSharpParseOptions)base.CreateParseOptions()).WithLanguageVersion(LanguageVersion);
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.UnitTests/Verifiers/CSharpSourceGeneratorVerifier.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.Testing;
4 | using Microsoft.CodeAnalysis.Text;
5 |
6 | namespace F0.Gen.GetNameOfEnum.UnitTests.Verifiers
7 | {
8 | internal static partial class CSharpSourceGeneratorVerifier
9 | where TSourceGenerator : IIncrementalGenerator, new()
10 | {
11 | internal static readonly (string filename, string content)[] EmptyGeneratedSources = Array.Empty<(string filename, string content)>();
12 |
13 | public static DiagnosticResult Diagnostic()
14 | => new DiagnosticResult();
15 |
16 | public static DiagnosticResult Diagnostic(string id, DiagnosticSeverity severity)
17 | => new DiagnosticResult(id, severity);
18 |
19 | public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
20 | => new DiagnosticResult(descriptor);
21 |
22 | public static async Task VerifyGeneratorAsync(string source, (string filename, string content) generatedSource)
23 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, new[] { generatedSource });
24 |
25 | public static async Task VerifyGeneratorAsync(string source, params (string filename, string content)[] generatedSources)
26 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, generatedSources);
27 |
28 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic)
29 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, EmptyGeneratedSources);
30 |
31 | public static async Task VerifyGeneratorAsync(string source, params DiagnosticResult[] diagnostics)
32 | => await VerifyGeneratorAsync(source, diagnostics, EmptyGeneratedSources);
33 |
34 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, (string filename, string content) generatedSource)
35 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, new[] { generatedSource });
36 |
37 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, (string filename, string content) generatedSource)
38 | => await VerifyGeneratorAsync(source, diagnostics, new[] { generatedSource });
39 |
40 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, params (string filename, string content)[] generatedSources)
41 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, generatedSources);
42 |
43 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, params (string filename, string content)[] generatedSources)
44 | {
45 | CSharpSourceGeneratorVerifier.Test test = new()
46 | {
47 | TestState =
48 | {
49 | Sources = { source },
50 | },
51 | };
52 |
53 | foreach ((string filename, string content) generatedSource in generatedSources)
54 | {
55 | test.TestState.GeneratedSources.Add((typeof(TSourceGenerator), generatedSource.filename, SourceText.From(generatedSource.content, Encoding.UTF8)));
56 | }
57 |
58 | test.ExpectedDiagnostics.AddRange(diagnostics);
59 |
60 | await test.RunAsync(CancellationToken.None);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.UnitTests/Verifiers/CSharpVerifierHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.CSharp;
4 |
5 | namespace F0.Gen.GetNameOfEnum.UnitTests.Verifiers
6 | {
7 | internal static class CSharpVerifierHelper
8 | {
9 | internal static ImmutableDictionary NullableWarnings { get; } = GetNullableWarningsFromCompiler();
10 |
11 | private static ImmutableDictionary GetNullableWarningsFromCompiler()
12 | {
13 | string[] args = { "/warnaserror:nullable" };
14 | CSharpCommandLineArguments commandLineArguments = CSharpCommandLineParser.Default.Parse(args, Environment.CurrentDirectory, Environment.CurrentDirectory);
15 | ImmutableDictionary nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
16 |
17 | return nullableWarnings;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32319.34
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.GetNameOfEnum", "F0.Gen.GetNameOfEnum\F0.Gen.GetNameOfEnum.csproj", "{D7B0786F-3FF5-4468-BD69-F321CDF7E96D}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.GetNameOfEnum.Benchmarks", "F0.Gen.GetNameOfEnum.Benchmarks\F0.Gen.GetNameOfEnum.Benchmarks.csproj", "{F51B73A4-5DA2-4FFD-86C8-DEDF154AC919}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.GetNameOfEnum.Example", "F0.Gen.GetNameOfEnum.Example\F0.Gen.GetNameOfEnum.Example.csproj", "{E5129027-8298-4EDF-BA0E-7680563ACEE6}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.GetNameOfEnum.IntegrationTests", "F0.Gen.GetNameOfEnum.IntegrationTests\F0.Gen.GetNameOfEnum.IntegrationTests.csproj", "{EC688739-B324-477B-8E27-ED6BC325143D}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "F0.Gen.GetNameOfEnum.UnitTests", "F0.Gen.GetNameOfEnum.UnitTests\F0.Gen.GetNameOfEnum.UnitTests.csproj", "{15CD220B-F18F-4E46-B3B0-205DC9E114D2}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {D7B0786F-3FF5-4468-BD69-F321CDF7E96D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {D7B0786F-3FF5-4468-BD69-F321CDF7E96D}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {D7B0786F-3FF5-4468-BD69-F321CDF7E96D}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {D7B0786F-3FF5-4468-BD69-F321CDF7E96D}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {F51B73A4-5DA2-4FFD-86C8-DEDF154AC919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {F51B73A4-5DA2-4FFD-86C8-DEDF154AC919}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {F51B73A4-5DA2-4FFD-86C8-DEDF154AC919}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {F51B73A4-5DA2-4FFD-86C8-DEDF154AC919}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {E5129027-8298-4EDF-BA0E-7680563ACEE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {E5129027-8298-4EDF-BA0E-7680563ACEE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {E5129027-8298-4EDF-BA0E-7680563ACEE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {E5129027-8298-4EDF-BA0E-7680563ACEE6}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {EC688739-B324-477B-8E27-ED6BC325143D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {EC688739-B324-477B-8E27-ED6BC325143D}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {EC688739-B324-477B-8E27-ED6BC325143D}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {EC688739-B324-477B-8E27-ED6BC325143D}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {15CD220B-F18F-4E46-B3B0-205DC9E114D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {15CD220B-F18F-4E46-B3B0-205DC9E114D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {15CD220B-F18F-4E46-B3B0-205DC9E114D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {15CD220B-F18F-4E46-B3B0-205DC9E114D2}.Release|Any CPU.Build.0 = Release|Any CPU
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | GlobalSection(ExtensibilityGlobals) = postSolution
47 | SolutionGuid = {72070B80-1F47-442D-BA2D-B99B5CF13ACA}
48 | EndGlobalSection
49 | EndGlobal
50 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;netstandard2.0
5 |
6 |
7 |
8 | true
9 | false
10 | true
11 | true
12 | true
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | <_Parameter1>F0.Gen.GetNameOfEnum.Benchmarks
27 |
28 |
29 | <_Parameter1>F0.Gen.GetNameOfEnum.UnitTests
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum/GetNameOfEnumGenerator.Attribute.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.CSharp.Syntax;
4 |
5 | namespace F0.Gen.GetNameOfEnum;
6 |
7 | internal partial class GetNameOfEnumGenerator
8 | {
9 | private const string GetNameOfEnumAttributeName = "Roslyn.Generated.GetNameOfEnumAttribute";
10 |
11 | private static readonly AssemblyName assemblyName = typeof(GetNameOfEnumGenerator).Assembly.GetName();
12 | private static readonly string generatedCodeAttribute = $@"global::System.CodeDom.Compiler.GeneratedCodeAttribute(""{assemblyName.Name}"", ""{assemblyName.Version}"")";
13 |
14 | private static readonly string GetNameOfEnumAttribute = $@"//
15 | #nullable enable
16 |
17 | namespace Roslyn.Generated;
18 |
19 | [{generatedCodeAttribute}]
20 | [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false)]
21 | internal sealed class GetNameOfEnumAttribute : global::System.Attribute
22 | {{
23 | }}
24 | ";
25 |
26 | private static bool HasAttribute(MethodDeclarationSyntax candidate, string attributeName, SemanticModel semanticModel, CancellationToken cancellationToken)
27 | {
28 | foreach (AttributeListSyntax attributeList in candidate.AttributeLists)
29 | {
30 | foreach (AttributeSyntax attribute in attributeList.Attributes)
31 | {
32 | SymbolInfo info = semanticModel.GetSymbolInfo(attribute, cancellationToken);
33 | ISymbol? symbol = info.Symbol;
34 |
35 | if (symbol is IMethodSymbol method
36 | && method.ContainingType.ToDisplayString().Equals(attributeName, StringComparison.Ordinal))
37 | {
38 | return true;
39 | }
40 | }
41 | }
42 |
43 | return false;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum/GetNameOfEnumGenerator.Comparer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 |
3 | namespace F0.Gen.GetNameOfEnum;
4 |
5 | internal partial class GetNameOfEnumGenerator
6 | {
7 | private sealed class MyEqualityComparer : IEqualityComparer<(string methodName, string modifiers, string enumType, string paramName, string keyword, bool isNullable, ImmutableArray constants, string typeName, string nameSpace, bool isGlobal)>
8 | {
9 | public static MyEqualityComparer Instance { get; } = new MyEqualityComparer();
10 |
11 | private MyEqualityComparer() { }
12 |
13 | public bool Equals((string methodName, string modifiers, string enumType, string paramName, string keyword, bool isNullable, ImmutableArray constants, string typeName, string nameSpace, bool isGlobal) x, (string methodName, string modifiers, string enumType, string paramName, string keyword, bool isNullable, ImmutableArray constants, string typeName, string nameSpace, bool isGlobal) y)
14 | {
15 | return x.Item1 == y.Item1 && x.Item2 == y.Item2 && x.Item3 == y.Item3 && x.Item4 == y.Item4 && x.Item5 == y.Item5 && x.Item6 == y.Item6 && x.Item7.SequenceEqual(y.Item7) && x.Rest.Equals(y.Rest);
16 | }
17 |
18 | public int GetHashCode((string methodName, string modifiers, string enumType, string paramName, string keyword, bool isNullable, ImmutableArray constants, string typeName, string nameSpace, bool isGlobal) obj)
19 | {
20 | return HashCode.Combine(obj.Item1, obj.Item2, obj.Item3, obj.Item4, obj.Item5, obj.Item6, obj.Item7, obj.Rest);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum/GetNameOfEnumGenerator.Formats.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace F0.Gen.GetNameOfEnum;
4 |
5 | internal partial class GetNameOfEnumGenerator
6 | {
7 | private static class Formats
8 | {
9 | internal static readonly SymbolDisplayFormat GlobalAlias = SymbolDisplayFormat.FullyQualifiedFormat
10 | .WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes | SymbolDisplayMiscellaneousOptions.ExpandNullable | SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier)
11 | .WithMemberOptions(SymbolDisplayMemberOptions.IncludeContainingType);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum/IndentedTextWriterExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.CodeDom.Compiler;
2 |
3 | namespace F0.Gen.GetNameOfEnum;
4 |
5 | internal static class IndentedTextWriterExtensions
6 | {
7 | public static void OpenBlock(this IndentedTextWriter writer)
8 | {
9 | writer.WriteLine("{");
10 | writer.Indent++;
11 | }
12 |
13 | public static void CloseBlock(this IndentedTextWriter writer)
14 | {
15 | writer.Indent--;
16 | writer.WriteLine("}");
17 | }
18 |
19 | public static void CloseBlockSemicolon(this IndentedTextWriter writer)
20 | {
21 | writer.Indent--;
22 | writer.WriteLine("};");
23 | }
24 |
25 | public static void WriteLineNoTabs(this IndentedTextWriter writer)
26 | {
27 | writer.WriteLineNoTabs(null);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/gen/F0.Gen.GetNameOfEnum/F0.Gen.GetNameOfEnum/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "F0.Gen.GetNameOfEnum": {
4 | "commandName": "DebugRoslynComponent",
5 | "targetProject": "..\\F0.Gen.GetNameOfEnum.Example\\F0.Gen.GetNameOfEnum.Example.csproj"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.Example/F0.Gen.IsEnumDefined.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0;net472
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.Example/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Roslyn.Generated;
3 |
4 | namespace F0.Gen.IsEnumDefined.Example;
5 |
6 | internal static class Program
7 | {
8 | private static void Main(string[] args)
9 | {
10 | var level = ((LogLevel)(-1));
11 |
12 | bool isDefined = EnumInfo.IsDefined(level);
13 |
14 | Console.WriteLine(isDefined);
15 | }
16 | }
17 |
18 | [IsEnumDefined]
19 | [IsEnumDefined]
20 | internal static partial class EnumInfo
21 | {
22 | }
23 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.IntegrationBenchmarks/F0.Gen.IsEnumDefined.IntegrationBenchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0;net472
6 |
7 |
8 |
9 | $(NoWarn);CA1822
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.IntegrationBenchmarks/IsEnumDefinedGeneratorIntegrationBenchmarks.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using Microsoft.Extensions.Logging;
3 | using Roslyn.Generated;
4 |
5 | namespace F0.Gen.IsEnumDefined.IntegrationBenchmarks;
6 |
7 | public class IsEnumDefinedGeneratorIntegrationBenchmarks
8 | {
9 | private const LogLevel _logLevel = LogLevel.Trace;
10 |
11 | [Benchmark(Baseline = true)]
12 | public bool Bcl()
13 | {
14 | #if NET472
15 | return Enum.IsDefined(typeof(LogLevel), _logLevel);
16 | #else
17 | return Enum.IsDefined(_logLevel);
18 | #endif
19 | }
20 |
21 | [Benchmark]
22 | public bool HandRolled()
23 | {
24 | return IsDefined(_logLevel);
25 |
26 | static bool IsDefined(LogLevel value)
27 | {
28 | return value is
29 | LogLevel.Trace or
30 | LogLevel.Debug or
31 | LogLevel.Information or
32 | LogLevel.Warning or
33 | LogLevel.Error or
34 | LogLevel.Critical or
35 | LogLevel.None;
36 | }
37 | }
38 |
39 | [Benchmark]
40 | public bool Generated()
41 | {
42 | return EnumInfo.IsDefined(_logLevel);
43 | }
44 | }
45 |
46 | [IsEnumDefined]
47 | internal static partial class EnumInfo
48 | {
49 | }
50 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.IntegrationBenchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using BenchmarkDotNet.Columns;
3 | using BenchmarkDotNet.Configs;
4 | using BenchmarkDotNet.Diagnosers;
5 | using BenchmarkDotNet.Environments;
6 | using BenchmarkDotNet.Exporters;
7 | using BenchmarkDotNet.Jobs;
8 | using BenchmarkDotNet.Running;
9 | using BenchmarkDotNet.Validators;
10 |
11 | namespace F0.Gen.IsEnumDefined.IntegrationBenchmarks;
12 |
13 | internal static class Program
14 | {
15 | private static void Main(string[] args)
16 | {
17 | IConfig config = Debugger.IsAttached
18 | ? CreateDebugConfiguration()
19 | : CreateBenchmarkConfiguration();
20 |
21 | _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
22 |
23 | static IConfig CreateDebugConfiguration()
24 | {
25 | return new DebugInProcessConfig();
26 | }
27 |
28 | static IConfig CreateBenchmarkConfiguration()
29 | {
30 | return DefaultConfig.Instance
31 | .AddJob(Job.InProcess.WithRuntime(ClrRuntime.Net472))
32 | .AddJob(Job.InProcess.WithRuntime(CoreRuntime.Core70))
33 | .AddColumn(StatisticColumn.Min, StatisticColumn.Max, StatisticColumn.Median)
34 | .AddDiagnoser(MemoryDiagnoser.Default)
35 | .AddExporter(DefaultExporters.AsciiDoc)
36 | .AddValidator(ExecutionValidator.FailOnError);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.IntegrationTests/F0.Gen.IsEnumDefined.IntegrationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0;net472
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1707
10 | true
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.IntegrationTests/IsEnumDefinedGeneratorIntegrationTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.Extensions.Logging;
3 | using Roslyn.Generated;
4 | using Xunit;
5 |
6 | namespace F0.Gen.IsEnumDefined.IntegrationTests;
7 |
8 | public class IsEnumDefinedGeneratorIntegrationTests
9 | {
10 | [Theory]
11 | [InlineData(-1, false)]
12 | [InlineData(0, true)]
13 | [InlineData(1, true)]
14 | [InlineData(2, true)]
15 | [InlineData(3, true)]
16 | [InlineData(4, true)]
17 | [InlineData(5, true)]
18 | [InlineData(6, true)]
19 | [InlineData(7, false)]
20 | public void Generated_Enum_IsDefined(int underlying, bool expected)
21 | {
22 | var logLevel = (LogLevel)underlying;
23 |
24 | bool bcl = Bcl(logLevel);
25 | bool generated = EnumInfo.IsDefined(logLevel);
26 |
27 | bcl.Should().Be(expected);
28 | generated.Should().Be(expected);
29 |
30 | static bool Bcl(LogLevel logLevel)
31 | {
32 | #if NET472
33 | return Enum.IsDefined(typeof(LogLevel), logLevel);
34 | #else
35 | return Enum.IsDefined(logLevel);
36 | #endif
37 | }
38 | }
39 |
40 | [Fact]
41 | public void Are_All_Values_Defined()
42 | {
43 | foreach (LogLevel value in GetValues())
44 | {
45 | var actual = EnumInfo.IsDefined(value);
46 |
47 | actual.Should().BeTrue();
48 | }
49 |
50 | static Array GetValues()
51 | {
52 | #if NET472
53 | return Enum.GetValues(typeof(LogLevel));
54 | #else
55 | return Enum.GetValues();
56 | #endif
57 | }
58 | }
59 | }
60 |
61 | [IsEnumDefined]
62 | internal static partial class EnumInfo
63 | {
64 | }
65 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitBenchmarks/F0.Gen.IsEnumDefined.UnitBenchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0;net472
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitBenchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using BenchmarkDotNet.Columns;
3 | using BenchmarkDotNet.Configs;
4 | using BenchmarkDotNet.Diagnosers;
5 | using BenchmarkDotNet.Environments;
6 | using BenchmarkDotNet.Exporters;
7 | using BenchmarkDotNet.Jobs;
8 | using BenchmarkDotNet.Running;
9 | using BenchmarkDotNet.Validators;
10 |
11 | namespace F0.Gen.IsEnumDefined.UnitBenchmarks;
12 |
13 | internal static class Program
14 | {
15 | private static void Main(string[] args)
16 | {
17 | IConfig config = Debugger.IsAttached
18 | ? CreateDebugConfiguration()
19 | : CreateBenchmarkConfiguration();
20 |
21 | _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
22 |
23 | static IConfig CreateDebugConfiguration()
24 | {
25 | return new DebugInProcessConfig();
26 | }
27 |
28 | static IConfig CreateBenchmarkConfiguration()
29 | {
30 | return DefaultConfig.Instance
31 | .AddJob(Job.InProcess.WithRuntime(ClrRuntime.Net472))
32 | .AddJob(Job.InProcess.WithRuntime(CoreRuntime.Core70))
33 | .AddColumn(StatisticColumn.Min, StatisticColumn.Max, StatisticColumn.Median)
34 | .AddDiagnoser(MemoryDiagnoser.Default)
35 | .AddExporter(DefaultExporters.AsciiDoc)
36 | .AddValidator(ExecutionValidator.FailOnError);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitTests/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitTests/Diagnostics/DebugAssertException.cs:
--------------------------------------------------------------------------------
1 | #if NETFRAMEWORK
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace F0.Gen.IsEnumDefined.UnitTests.Diagnostics;
5 |
6 | [SuppressMessage("Design", "CA1032:Implement standard exception constructors", Justification = "Debug.Assert on .NET Framework")]
7 | [SuppressMessage("Design", "CA1064:Exceptions should be public", Justification = "Debug.Assert on .NET Framework")]
8 | internal sealed class DebugAssertException : Exception
9 | {
10 | public DebugAssertException(string? message)
11 | : base(message)
12 | {
13 | }
14 | }
15 | #endif
16 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitTests/Diagnostics/DebugTraceListener.cs:
--------------------------------------------------------------------------------
1 | #if NETFRAMEWORK
2 | using System.Diagnostics;
3 |
4 | namespace F0.Gen.IsEnumDefined.UnitTests.Diagnostics;
5 |
6 | internal sealed class DebugTraceListener : TraceListener
7 | {
8 | public DebugTraceListener()
9 | : base(nameof(Debug))
10 | {
11 | }
12 |
13 | public DebugTraceListener(string? name)
14 | : base(name)
15 | {
16 | }
17 |
18 | public override void Write(string? message)
19 | => throw new NotImplementedException($"{nameof(DebugTraceListener)}.{nameof(Write)}({nameof(String)})");
20 |
21 | public override void WriteLine(string? message)
22 | => throw new DebugAssertException(message);
23 | }
24 | #endif
25 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitTests/F0.Gen.IsEnumDefined.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0;net472
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1707
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitTests/Verifiers/CSharpSourceGeneratorVerifier.Test.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Testing;
4 | using Microsoft.CodeAnalysis.Testing;
5 | using Microsoft.CodeAnalysis.Testing.Verifiers;
6 |
7 | namespace F0.Gen.IsEnumDefined.UnitTests.Verifiers;
8 |
9 | internal static partial class CSharpSourceGeneratorVerifier
10 | where TSourceGenerator : IIncrementalGenerator, new()
11 | {
12 | public sealed class Test : CSharpSourceGeneratorTest
13 | {
14 | public Test()
15 | {
16 | }
17 |
18 | public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default;
19 |
20 | protected override IEnumerable GetSourceGenerators()
21 | {
22 | return new[] { new TSourceGenerator().AsSourceGenerator() };
23 | }
24 |
25 | protected override CompilationOptions CreateCompilationOptions()
26 | {
27 | CompilationOptions compilationOptions = base.CreateCompilationOptions();
28 | return compilationOptions.WithSpecificDiagnosticOptions(
29 | compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
30 | }
31 |
32 | protected override ParseOptions CreateParseOptions()
33 | {
34 | return ((CSharpParseOptions)base.CreateParseOptions()).WithLanguageVersion(LanguageVersion);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitTests/Verifiers/CSharpSourceGeneratorVerifier.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.CSharp;
4 | using Microsoft.CodeAnalysis.Testing;
5 | using Microsoft.CodeAnalysis.Text;
6 |
7 | namespace F0.Gen.IsEnumDefined.UnitTests.Verifiers;
8 |
9 | internal static partial class CSharpSourceGeneratorVerifier
10 | where TSourceGenerator : IIncrementalGenerator, new()
11 | {
12 | internal static readonly (string filename, string content)[] EmptyGeneratedSources = Array.Empty<(string filename, string content)>();
13 |
14 | public static DiagnosticResult Diagnostic()
15 | => new DiagnosticResult();
16 |
17 | public static DiagnosticResult Diagnostic(string id, DiagnosticSeverity severity)
18 | => new DiagnosticResult(id, severity);
19 |
20 | public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
21 | => new DiagnosticResult(descriptor);
22 |
23 | public static async Task VerifyGeneratorAsync(string source, (string filename, string content) generatedSource)
24 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, new[] { generatedSource });
25 |
26 | public static async Task VerifyGeneratorAsync(string source, params (string filename, string content)[] generatedSources)
27 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, generatedSources);
28 |
29 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic)
30 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, EmptyGeneratedSources);
31 |
32 | public static async Task VerifyGeneratorAsync(string source, params DiagnosticResult[] diagnostics)
33 | => await VerifyGeneratorAsync(source, diagnostics, EmptyGeneratedSources);
34 |
35 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, (string filename, string content) generatedSource)
36 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, new[] { generatedSource });
37 |
38 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, (string filename, string content) generatedSource)
39 | => await VerifyGeneratorAsync(source, diagnostics, new[] { generatedSource });
40 |
41 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, params (string filename, string content)[] generatedSources)
42 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, generatedSources);
43 |
44 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, params (string filename, string content)[] generatedSources)
45 | {
46 | CSharpSourceGeneratorVerifier.Test test = new()
47 | {
48 | TestState =
49 | {
50 | Sources = { source },
51 | },
52 | LanguageVersion = LanguageVersion.Preview,
53 | };
54 |
55 | foreach ((string filename, string content) generatedSource in generatedSources)
56 | {
57 | test.TestState.GeneratedSources.Add((typeof(TSourceGenerator), generatedSource.filename, SourceText.From(generatedSource.content, Encoding.UTF8)));
58 | }
59 |
60 | test.ExpectedDiagnostics.AddRange(diagnostics);
61 |
62 | await test.RunAsync(CancellationToken.None);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.UnitTests/Verifiers/CSharpVerifierHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.CSharp;
4 |
5 | namespace F0.Gen.IsEnumDefined.UnitTests.Verifiers;
6 |
7 | internal static class CSharpVerifierHelper
8 | {
9 | internal static ImmutableDictionary NullableWarnings { get; } = GetNullableWarningsFromCompiler();
10 |
11 | private static ImmutableDictionary GetNullableWarningsFromCompiler()
12 | {
13 | string[] args = { "/warnaserror:nullable" };
14 | CSharpCommandLineArguments commandLineArguments = CSharpCommandLineParser.Default.Parse(args, Environment.CurrentDirectory, Environment.CurrentDirectory);
15 | ImmutableDictionary nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
16 |
17 | return nullableWarnings;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0;netstandard2.0
5 |
6 |
7 |
8 | true
9 | false
10 | true
11 | true
12 | true
13 |
14 |
15 |
16 | true
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | <_Parameter1>F0.Gen.IsEnumDefined.UnitBenchmarks
31 |
32 |
33 | <_Parameter1>F0.Gen.IsEnumDefined.UnitTests
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined/IsEnumDefinedGenerator.Attribute.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace F0.Gen.IsEnumDefined;
4 |
5 | internal sealed partial class IsEnumDefinedGenerator
6 | {
7 | private static readonly AssemblyName _assemblyName = typeof(IsEnumDefinedGenerator).Assembly.GetName();
8 | private static readonly string _generatedCodeAttribute = $"""global::System.CodeDom.Compiler.GeneratedCodeAttribute("{_assemblyName.Name}", "{_assemblyName.Version}")""";
9 |
10 | private static readonly string _isEnumDefinedAttribute = $$"""
11 | //
12 | #nullable enable
13 |
14 | namespace Roslyn.Generated;
15 |
16 | [{{_generatedCodeAttribute}}]
17 | [global::System.AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = true)]
18 | internal sealed class IsEnumDefinedAttribute : global::System.Attribute
19 | where TEnum : struct, global::System.Enum
20 | {
21 | }
22 |
23 | """;
24 | }
25 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined/IsEnumDefinedGenerator.Comparer.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace F0.Gen.IsEnumDefined;
4 |
5 | internal sealed partial class IsEnumDefinedGenerator
6 | {
7 | private static readonly IsEnumDefinedTypeEqualityComparer _comparer = IsEnumDefinedTypeEqualityComparer.Instance;
8 |
9 | private sealed class IsEnumDefinedTypeEqualityComparer : IEqualityComparer
10 | {
11 | private IsEnumDefinedTypeEqualityComparer() { }
12 |
13 | public static IsEnumDefinedTypeEqualityComparer Instance { get; } = new();
14 |
15 | public bool Equals(IsEnumDefinedType x, IsEnumDefinedType y)
16 | {
17 | return x.IsGlobalNamespace == y.IsGlobalNamespace
18 | && x.Namespace == y.Namespace
19 | && x.Name == y.Name
20 | && x.Methods.SequenceEqual(y.Methods, IsEnumDefinedMethodEqualityComparer.Instance);
21 | }
22 |
23 | public int GetHashCode(IsEnumDefinedType obj)
24 | {
25 | throw new UnreachableException();
26 | }
27 | }
28 |
29 | private sealed class IsEnumDefinedMethodEqualityComparer : IEqualityComparer
30 | {
31 | private IsEnumDefinedMethodEqualityComparer() { }
32 |
33 | public static IsEnumDefinedMethodEqualityComparer Instance { get; } = new();
34 |
35 | public bool Equals(IsEnumDefinedMethod x, IsEnumDefinedMethod y)
36 | {
37 | return x.EnumName == y.EnumName
38 | && x.EnumConstants.SequenceEqual(y.EnumConstants);
39 | }
40 |
41 | public int GetHashCode(IsEnumDefinedMethod obj)
42 | {
43 | throw new UnreachableException();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined/IsEnumDefinedGenerator.Formats.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 |
3 | namespace F0.Gen.IsEnumDefined;
4 |
5 | internal sealed partial class IsEnumDefinedGenerator
6 | {
7 | private static readonly SymbolDisplayFormat _format = SymbolDisplayFormat.FullyQualifiedFormat
8 | .WithMemberOptions(SymbolDisplayMemberOptions.IncludeContainingType);
9 | }
10 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined/IsEnumDefinedGenerator.Info.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 |
3 | namespace F0.Gen.IsEnumDefined;
4 |
5 | internal sealed partial class IsEnumDefinedGenerator
6 | {
7 | private readonly record struct IsEnumDefinedType(
8 | bool IsGlobalNamespace,
9 | string Namespace,
10 | string Name,
11 | ImmutableArray Methods)
12 | {
13 | public string GetFullName()
14 | {
15 | if (IsGlobalNamespace)
16 | {
17 | return Name;
18 | }
19 | else
20 | {
21 | return $"{Namespace}.{Name}";
22 | }
23 | }
24 | }
25 |
26 | private readonly record struct IsEnumDefinedMethod(
27 | string EnumName,
28 | ImmutableArray EnumConstants);
29 | }
30 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined/IsEnumDefinedGenerator.Source.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 | using System.Collections.Immutable;
4 |
5 | namespace F0.Gen.IsEnumDefined;
6 |
7 | internal sealed partial class IsEnumDefinedGenerator
8 | {
9 | private readonly record struct IsEnumDefinedSource(
10 | ClassDeclarationSyntax Node,
11 | INamedTypeSymbol Symbol,
12 | ImmutableArray Attributes)
13 | {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined/Polyfilling/System.Diagnostics.UnreachableException.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 |
3 | #if NETSTANDARD2_0
4 | // ReSharper disable once CheckNamespace
5 | namespace System.Diagnostics;
6 |
7 | [SuppressMessage("Design", "CA1064:Exceptions should be public")]
8 | internal sealed class UnreachableException : Exception
9 | {
10 | public UnreachableException()
11 | : base("The program executed an instruction that was thought to be unreachable.")
12 | {
13 | }
14 |
15 | public UnreachableException(string? message)
16 | : base(message)
17 | {
18 | }
19 |
20 | public UnreachableException(string? message, Exception? innerException)
21 | : base(message, innerException)
22 | {
23 | }
24 | }
25 | #endif
26 |
--------------------------------------------------------------------------------
/gen/F0.Gen.IsEnumDefined/F0.Gen.IsEnumDefined/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "F0.Gen.IsEnumDefined": {
4 | "commandName": "DebugRoslynComponent",
5 | "targetProject": "..\\F0.Gen.IsEnumDefined.Example\\F0.Gen.IsEnumDefined.Example.csproj"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.Example/F0.Gen.ValueTypeEquality.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0;net472
6 |
7 |
8 |
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.Example/Program.cs:
--------------------------------------------------------------------------------
1 | namespace F0.Gen.ValueTypeEquality.Example;
2 |
3 | internal static class Program
4 | {
5 | private static void Main(string[] args)
6 | {
7 | HashSet set = new();
8 |
9 | MyStruct value1 = new(2022, "2022");
10 | MyStruct value2 = new(2022, "2022");
11 |
12 | set.Add(value1);
13 | set.Add(value2);
14 |
15 | Console.WriteLine($"{nameof(set.Count)}: {set.Count}");
16 | }
17 | }
18 |
19 | internal readonly struct MyStruct
20 | {
21 | public MyStruct(int number, string text)
22 | {
23 | Number = number;
24 | Text = text;
25 | }
26 |
27 | public int Number { get; init; }
28 | public string Text { get; init; }
29 | }
30 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.IntegrationBenchmarks/F0.Gen.ValueTypeEquality.IntegrationBenchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0;net472
6 |
7 |
8 |
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.IntegrationBenchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Running;
2 | using F0.Gen.ValueTypeEquality.IntegrationBenchmarks;
3 |
4 | _ = BenchmarkRunner.Run();
5 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.IntegrationBenchmarks/ValueTypeBenchmarks.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace F0.Gen.ValueTypeEquality.IntegrationBenchmarks;
4 |
5 | ///
6 | /// How to define value equality for a class or struct (C# Programming Guide)
7 | /// Performance implications of default struct equality in C#
8 | ///
9 | [MemoryDiagnoser]
10 | public class ValueTypeBenchmarks
11 | {
12 | private HashSet defaultEqualitySet = null!;
13 | private HashSet recordEqualitySet = null!;
14 |
15 | private MyStruct defaultEqualityValue;
16 | private MyRecordStruct recordEqualityValue;
17 |
18 | [GlobalSetup]
19 | public void Setup()
20 | {
21 | defaultEqualitySet = new HashSet();
22 | recordEqualitySet = new HashSet();
23 |
24 | defaultEqualitySet.Add(new MyStruct(1, "1"));
25 | recordEqualitySet.Add(new MyRecordStruct(1, "1"));
26 |
27 | defaultEqualityValue = new MyStruct(1, "2");
28 | recordEqualityValue = new MyRecordStruct(1, "2");
29 | }
30 |
31 | [Benchmark]
32 | public bool Implicit()
33 | {
34 | return defaultEqualitySet.Contains(defaultEqualityValue);
35 | }
36 |
37 | [Benchmark]
38 | public bool Explicit()
39 | {
40 | return recordEqualitySet.Contains(recordEqualityValue);
41 | }
42 | }
43 |
44 | internal readonly struct MyStruct
45 | {
46 | public MyStruct(int number, string text)
47 | {
48 | Number = number;
49 | Text = text;
50 | }
51 |
52 | public int Number { get; init; }
53 | public string Text { get; init; }
54 | }
55 |
56 | internal readonly record struct MyRecordStruct(int Number, string Text);
57 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.IntegrationTests/F0.Gen.ValueTypeEquality.IntegrationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net472
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1707
10 | true
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.IntegrationTests/ValueTypeTests.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using FluentAssertions;
3 | using Xunit;
4 |
5 | namespace F0.Gen.ValueTypeEquality.IntegrationTests;
6 |
7 | ///
8 | /// How to define value equality for a class or struct (C# Programming Guide)
9 | /// Performance implications of default struct equality in C#
10 | ///
11 | public class ValueTypeTests
12 | {
13 | [Fact]
14 | public void StructureTypes_ImplicitlyInheritFrom_SystemValueType()
15 | {
16 | typeof(MyStruct).BaseType.Should().Be(typeof(ValueType));
17 | typeof(MyStruct).BaseType!.BaseType.Should().Be(typeof(object));
18 | typeof(MyStruct).BaseType!.BaseType!.BaseType.Should().BeNull();
19 | }
20 |
21 | [Fact]
22 | public void ValueEquality_UsesReflection()
23 | {
24 | MyStruct value1 = new(1, "1");
25 | MyStruct value2 = new(1, "2");
26 |
27 | value1.Equals(value2).Should().BeFalse();
28 | }
29 |
30 | [Fact]
31 | public void GetHashCode_HashCodeOfFirstNonStaticField()
32 | {
33 | MyStruct value1 = new(1, "1");
34 | MyStruct value2 = new(1, "2");
35 |
36 | int hashCode1 = value1.GetHashCode();
37 | int hashCode2 = value2.GetHashCode();
38 |
39 | hashCode1.Should().NotBe(hashCode2);
40 | }
41 |
42 | [Fact]
43 | public void GetHashCode_HashCollision()
44 | {
45 | MyStruct value1 = new(1, "1");
46 | MyStruct value2 = new(1, "2");
47 |
48 | HashSet set = new();
49 |
50 | set.Add(value1).Should().BeTrue();
51 | set.Add(value2).Should().BeTrue();
52 |
53 | set.Should().HaveCount(2);
54 | }
55 |
56 | [Fact]
57 | public void SizeOf()
58 | {
59 | Marshal.SizeOf().Should().Be(16);
60 | }
61 | }
62 |
63 | internal readonly struct MyStruct
64 | {
65 | public MyStruct(int number, string text)
66 | {
67 | Number = number;
68 | Text = text;
69 | }
70 |
71 | public int Number { get; init; }
72 | public string Text { get; init; }
73 | }
74 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitBenchmarks/F0.Gen.ValueTypeEquality.UnitBenchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0;net472
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitBenchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Running;
2 | using F0.Gen.ValueTypeEquality.UnitBenchmarks;
3 |
4 | _ = BenchmarkRunner.Run();
5 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/Diagnostics/DebugAssertException.cs:
--------------------------------------------------------------------------------
1 | #if NETFRAMEWORK
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace F0.Gen.ValueTypeEquality.UnitTests.Diagnostics;
5 |
6 | [SuppressMessage("Design", "CA1032:Implement standard exception constructors", Justification = "Debug.Assert on .NET Framework")]
7 | [SuppressMessage("Design", "CA1064:Exceptions should be public", Justification = "Debug.Assert on .NET Framework")]
8 | internal sealed class DebugAssertException : Exception
9 | {
10 | public DebugAssertException(string? message)
11 | : base(message)
12 | {
13 | }
14 | }
15 | #endif
16 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/Diagnostics/DebugTraceListener.cs:
--------------------------------------------------------------------------------
1 | #if NETFRAMEWORK
2 | using System.Diagnostics;
3 |
4 | namespace F0.Gen.ValueTypeEquality.UnitTests.Diagnostics;
5 |
6 | internal sealed class DebugTraceListener : TraceListener
7 | {
8 | public DebugTraceListener()
9 | : base(nameof(Debug))
10 | {
11 | }
12 |
13 | public DebugTraceListener(string? name)
14 | : base(name)
15 | {
16 | }
17 |
18 | public override void Write(string? message)
19 | => throw new NotImplementedException($"{nameof(DebugTraceListener)}.{nameof(Write)}({nameof(String)})");
20 |
21 | public override void WriteLine(string? message)
22 | => throw new DebugAssertException(message);
23 | }
24 | #endif
25 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/F0.Gen.ValueTypeEquality.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net472
5 |
6 |
7 |
8 | false
9 | $(NoWarn);CA1707
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/Verifiers/CSharpIncrementalGeneratorVerifier.Test.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Testing;
4 | using Microsoft.CodeAnalysis.Testing;
5 | using Microsoft.CodeAnalysis.Testing.Verifiers;
6 |
7 | namespace F0.Gen.ValueTypeEquality.UnitTests.Verifiers;
8 |
9 | internal static partial class CSharpIncrementalGeneratorVerifier
10 | where TIncrementalGenerator : IIncrementalGenerator, new()
11 | {
12 | public sealed class Test : CSharpSourceGeneratorTest
13 | {
14 | public Test()
15 | {
16 | }
17 |
18 | public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default;
19 |
20 | protected override IEnumerable GetSourceGenerators()
21 | {
22 | return new[] { new TIncrementalGenerator().AsSourceGenerator() };
23 | }
24 |
25 | protected override CompilationOptions CreateCompilationOptions()
26 | {
27 | CompilationOptions compilationOptions = base.CreateCompilationOptions();
28 | return compilationOptions.WithSpecificDiagnosticOptions(
29 | compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
30 | }
31 |
32 | protected override ParseOptions CreateParseOptions()
33 | {
34 | return ((CSharpParseOptions)base.CreateParseOptions()).WithLanguageVersion(LanguageVersion);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/Verifiers/CSharpIncrementalGeneratorVerifier.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.Testing;
4 | using Microsoft.CodeAnalysis.Text;
5 |
6 | namespace F0.Gen.ValueTypeEquality.UnitTests.Verifiers;
7 |
8 | internal static partial class CSharpIncrementalGeneratorVerifier
9 | where TIncrementalGenerator : IIncrementalGenerator, new()
10 | {
11 | internal static readonly (string filename, string content)[] EmptyGeneratedSources = Array.Empty<(string filename, string content)>();
12 |
13 | public static DiagnosticResult Diagnostic()
14 | => new DiagnosticResult();
15 |
16 | public static DiagnosticResult Diagnostic(string id, DiagnosticSeverity severity)
17 | => new DiagnosticResult(id, severity);
18 |
19 | public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
20 | => new DiagnosticResult(descriptor);
21 |
22 | public static async Task VerifyGeneratorAsync(string source, (string filename, string content) generatedSource)
23 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, new[] { generatedSource });
24 |
25 | public static async Task VerifyGeneratorAsync(string source, params (string filename, string content)[] generatedSources)
26 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, generatedSources);
27 |
28 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic)
29 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, EmptyGeneratedSources);
30 |
31 | public static async Task VerifyGeneratorAsync(string source, params DiagnosticResult[] diagnostics)
32 | => await VerifyGeneratorAsync(source, diagnostics, EmptyGeneratedSources);
33 |
34 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, (string filename, string content) generatedSource)
35 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, new[] { generatedSource });
36 |
37 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, (string filename, string content) generatedSource)
38 | => await VerifyGeneratorAsync(source, diagnostics, new[] { generatedSource });
39 |
40 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, params (string filename, string content)[] generatedSources)
41 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, generatedSources);
42 |
43 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, params (string filename, string content)[] generatedSources)
44 | {
45 | CSharpIncrementalGeneratorVerifier.Test test = new()
46 | {
47 | TestState =
48 | {
49 | Sources = { source },
50 | },
51 | ReferenceAssemblies = ReferenceAssemblies.Net.Net60,
52 | };
53 |
54 | foreach ((string filename, string content) generatedSource in generatedSources)
55 | {
56 | test.TestState.GeneratedSources.Add((typeof(TIncrementalGenerator), generatedSource.filename, SourceText.From(generatedSource.content, Encoding.UTF8)));
57 | }
58 |
59 | test.ExpectedDiagnostics.AddRange(diagnostics);
60 |
61 | await test.RunAsync(CancellationToken.None);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/Verifiers/CSharpSourceGeneratorVerifier.Test.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp;
3 | using Microsoft.CodeAnalysis.CSharp.Testing;
4 | using Microsoft.CodeAnalysis.Testing.Verifiers;
5 |
6 | namespace F0.Gen.ValueTypeEquality.UnitTests.Verifiers;
7 |
8 | internal static partial class CSharpSourceGeneratorVerifier
9 | where TSourceGenerator : ISourceGenerator, new()
10 | {
11 | public sealed class Test : CSharpSourceGeneratorTest
12 | {
13 | public Test()
14 | {
15 | }
16 |
17 | public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default;
18 |
19 | protected override CompilationOptions CreateCompilationOptions()
20 | {
21 | CompilationOptions compilationOptions = base.CreateCompilationOptions();
22 | return compilationOptions.WithSpecificDiagnosticOptions(
23 | compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings));
24 | }
25 |
26 | protected override ParseOptions CreateParseOptions()
27 | {
28 | return ((CSharpParseOptions)base.CreateParseOptions()).WithLanguageVersion(LanguageVersion);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/Verifiers/CSharpSourceGeneratorVerifier.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.Testing;
4 | using Microsoft.CodeAnalysis.Text;
5 |
6 | namespace F0.Gen.ValueTypeEquality.UnitTests.Verifiers;
7 |
8 | internal static partial class CSharpSourceGeneratorVerifier
9 | where TSourceGenerator : ISourceGenerator, new()
10 | {
11 | internal static readonly (string filename, string content)[] EmptyGeneratedSources = Array.Empty<(string filename, string content)>();
12 |
13 | public static DiagnosticResult Diagnostic()
14 | => new DiagnosticResult();
15 |
16 | public static DiagnosticResult Diagnostic(string id, DiagnosticSeverity severity)
17 | => new DiagnosticResult(id, severity);
18 |
19 | public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
20 | => new DiagnosticResult(descriptor);
21 |
22 | public static async Task VerifyGeneratorAsync(string source, (string filename, string content) generatedSource)
23 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, new[] { generatedSource });
24 |
25 | public static async Task VerifyGeneratorAsync(string source, params (string filename, string content)[] generatedSources)
26 | => await VerifyGeneratorAsync(source, DiagnosticResult.EmptyDiagnosticResults, generatedSources);
27 |
28 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic)
29 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, EmptyGeneratedSources);
30 |
31 | public static async Task VerifyGeneratorAsync(string source, params DiagnosticResult[] diagnostics)
32 | => await VerifyGeneratorAsync(source, diagnostics, EmptyGeneratedSources);
33 |
34 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, (string filename, string content) generatedSource)
35 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, new[] { generatedSource });
36 |
37 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, (string filename, string content) generatedSource)
38 | => await VerifyGeneratorAsync(source, diagnostics, new[] { generatedSource });
39 |
40 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult diagnostic, params (string filename, string content)[] generatedSources)
41 | => await VerifyGeneratorAsync(source, new[] { diagnostic }, generatedSources);
42 |
43 | public static async Task VerifyGeneratorAsync(string source, DiagnosticResult[] diagnostics, params (string filename, string content)[] generatedSources)
44 | {
45 | CSharpSourceGeneratorVerifier.Test test = new()
46 | {
47 | TestState =
48 | {
49 | Sources = { source },
50 | },
51 | ReferenceAssemblies = ReferenceAssemblies.Net.Net60,
52 | };
53 |
54 | foreach ((string filename, string content) generatedSource in generatedSources)
55 | {
56 | test.TestState.GeneratedSources.Add((typeof(TSourceGenerator), generatedSource.filename, SourceText.From(generatedSource.content, Encoding.UTF8)));
57 | }
58 |
59 | test.ExpectedDiagnostics.AddRange(diagnostics);
60 |
61 | await test.RunAsync(CancellationToken.None);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.UnitTests/Verifiers/CSharpVerifierHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using Microsoft.CodeAnalysis;
3 | using Microsoft.CodeAnalysis.CSharp;
4 |
5 | namespace F0.Gen.ValueTypeEquality.UnitTests.Verifiers;
6 |
7 | internal static class CSharpVerifierHelper
8 | {
9 | internal static ImmutableDictionary NullableWarnings { get; } = GetNullableWarningsFromCompiler();
10 |
11 | private static ImmutableDictionary GetNullableWarningsFromCompiler()
12 | {
13 | string[] args = { "/warnaserror:nullable" };
14 | CSharpCommandLineArguments commandLineArguments = CSharpCommandLineParser.Default.Parse(args, Environment.CurrentDirectory, Environment.CurrentDirectory);
15 | ImmutableDictionary nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
16 |
17 | return nullableWarnings;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;netstandard2.0
5 |
6 |
7 |
8 | true
9 | false
10 | true
11 | true
12 | true
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | <_Parameter1>F0.Gen.ValueTypeEquality.UnitBenchmarks
27 |
28 |
29 | <_Parameter1>F0.Gen.ValueTypeEquality.UnitTests
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/gen/F0.Gen.ValueTypeEquality/F0.Gen.ValueTypeEquality/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "F0.Gen.ValueTypeEquality": {
4 | "commandName": "DebugRoslynComponent",
5 | "targetProject": "..\\F0.Gen.ValueTypeEquality.Example\\F0.Gen.ValueTypeEquality.Example.csproj"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------