diff --git a/src/Riok.Mapperly/AnalyzerReleases.Shipped.md b/src/Riok.Mapperly/AnalyzerReleases.Shipped.md index a3902060f4..8c66ba596a 100644 --- a/src/Riok.Mapperly/AnalyzerReleases.Shipped.md +++ b/src/Riok.Mapperly/AnalyzerReleases.Shipped.md @@ -102,3 +102,4 @@ RMG040 | Mapper | Error | A target enum member value does not match the ta RMG041 | Mapper | Error | A source enum member value does not match the source enum type RMG042 | Mapper | Error | The type of the enum fallback value does not match the target enum type RMG043 | Mapper | Warning | Enum fallback values are only supported for the ByName and ByValueCheckDefined strategies, but not for the ByValue strategy +RMG044 | Mapper | Error | This C# language version is not supported by Mapperly diff --git a/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs b/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs index 7f9f21a9a5..3c0f484b34 100644 --- a/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs +++ b/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs @@ -383,4 +383,13 @@ internal static class DiagnosticDescriptors DiagnosticSeverity.Warning, true ); + + public static readonly DiagnosticDescriptor LanguageVersionNotSupported = new DiagnosticDescriptor( + "RMG044", + "This C# language version is not supported by Mapperly", + "Mapperly does not support the C# language version {0} but requires at C# least version {1}", + DiagnosticCategories.Mapper, + DiagnosticSeverity.Error, + true + ); } diff --git a/src/Riok.Mapperly/MapperGenerator.cs b/src/Riok.Mapperly/MapperGenerator.cs index 71ccc4e7a7..1ee195ea45 100644 --- a/src/Riok.Mapperly/MapperGenerator.cs +++ b/src/Riok.Mapperly/MapperGenerator.cs @@ -1,10 +1,12 @@ using System.Collections.Immutable; using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using Riok.Mapperly.Abstractions; using Riok.Mapperly.Descriptors; +using Riok.Mapperly.Diagnostics; using Riok.Mapperly.Emit; using Riok.Mapperly.Helpers; @@ -23,6 +25,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { var mapperClassDeclarations = SyntaxProvider.GetClassDeclarations(context); + context.ReportDiagnostics(context.CompilationProvider.Select(static (compilation, ct) => BuildCompilationDiagnostics(compilation))); + var compilationAndMappers = context.CompilationProvider.Combine(mapperClassDeclarations.Collect()); var mappersWithDiagnostics = compilationAndMappers.Select( static (x, cancellationToken) => BuildDescriptors(x.Left, x.Right, cancellationToken) @@ -89,4 +93,20 @@ CancellationToken cancellationToken cancellationToken.ThrowIfCancellationRequested(); return new MapperResults(members.ToImmutableEquatableArray(), diagnostics.ToImmutableEquatableArray()); } + + private static ImmutableEquatableArray BuildCompilationDiagnostics(Compilation compilation) + { + if (compilation is CSharpCompilation { LanguageVersion: < LanguageVersion.CSharp9 } cSharpCompilation) + { + var diagnostic = Diagnostic.Create( + DiagnosticDescriptors.LanguageVersionNotSupported, + null, + cSharpCompilation.LanguageVersion.ToDisplayString(), + LanguageVersion.CSharp9.ToDisplayString() + ); + return ImmutableEquatableArray.Create(diagnostic); + } + + return ImmutableEquatableArray.Empty(); + } } diff --git a/test/Riok.Mapperly.Tests/Generator/IncrementalGeneratorTest.cs b/test/Riok.Mapperly.Tests/Generator/IncrementalGeneratorTest.cs index 9da967a7e5..f65afe98cc 100644 --- a/test/Riok.Mapperly.Tests/Generator/IncrementalGeneratorTest.cs +++ b/test/Riok.Mapperly.Tests/Generator/IncrementalGeneratorTest.cs @@ -35,17 +35,17 @@ public void AddingNewMapperDoesNotRegenerateOriginal() var secondary = TestSourceBuilder.SyntaxTree( """ - using Riok.Mapperly.Abstractions; + using Riok.Mapperly.Abstractions; - namespace Test.B + namespace Test.B + { + [Mapper] + internal partial class BarFooMapper { - [Mapper] - internal partial class BarFooMapper - { - internal partial string BarToFoo(string value); - } + internal partial string BarToFoo(string value); } - """ + } + """ ); var syntaxTree = CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default); diff --git a/test/Riok.Mapperly.Tests/Mapping/MapperTest.cs b/test/Riok.Mapperly.Tests/Mapping/MapperTest.cs index 9cc6e621a5..339931fcae 100644 --- a/test/Riok.Mapperly.Tests/Mapping/MapperTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/MapperTest.cs @@ -1,3 +1,6 @@ +using Microsoft.CodeAnalysis.CSharp; +using Riok.Mapperly.Diagnostics; + namespace Riok.Mapperly.Tests.Mapping; [UsesVerify] @@ -108,4 +111,18 @@ public partial class CarMapper return TestHelper.VerifyGenerator(source); } + + [Fact] + public void LanguageLevelLower9ShouldDiagnostic() + { + var source = TestSourceBuilder.Mapping("string", "int"); + TestHelper + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics with { LanguageVersion = LanguageVersion.CSharp8 }) + .Should() + .HaveDiagnostic( + DiagnosticDescriptors.LanguageVersionNotSupported, + "Mapperly does not support the C# language version 8.0 but requires at C# least version 9.0" + ) + .HaveAssertedAllDiagnostics(); + } }