From b58a21d023913d10474fccfd4dbb14216f3637ad Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 5 Nov 2024 21:36:06 +0000 Subject: [PATCH 1/5] Add Diagnostics To Reactive Generator --- src/Directory.build.props | 2 +- .../ReactiveUI.CodeFixes.csproj | 4 +- .../Reactive/ReactiveGenerator.Execute.cs | 39 +++++++++++++++++-- .../Reactive/ReactiveGenerator.cs | 13 ++++++- .../ReactiveUI.SourceGenerators.csproj | 4 +- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/Directory.build.props b/src/Directory.build.props index d6a248a..31dd74b 100644 --- a/src/Directory.build.props +++ b/src/Directory.build.props @@ -17,7 +17,7 @@ https://github.com/reactiveui/ReactiveUI.SourceGenerators/releases https://github.com/reactiveui/reactiveui.sourcegenerators git - $(NoWarn);IDE0060;IDE1006;IDE0130;VSSpell001;RS2007 + $(NoWarn);IDE0060;IDE1006;IDE0130;VSSpell001;RS2007;NU5128 true diff --git a/src/ReactiveUI.SourceGenerators.CodeFixers/ReactiveUI.CodeFixes.csproj b/src/ReactiveUI.SourceGenerators.CodeFixers/ReactiveUI.CodeFixes.csproj index b6fc69c..fd37c00 100644 --- a/src/ReactiveUI.SourceGenerators.CodeFixers/ReactiveUI.CodeFixes.csproj +++ b/src/ReactiveUI.SourceGenerators.CodeFixers/ReactiveUI.CodeFixes.csproj @@ -3,14 +3,14 @@ netstandard2.0 enable + latest true true - latest true true false + A MVVM framework that integrates with the Reactive Extensions for .NET to create elegant, testable User Interfaces that run on any mobile or desktop platform. This is the Source Generators package for ReactiveUI - diff --git a/src/ReactiveUI.SourceGenerators/Reactive/ReactiveGenerator.Execute.cs b/src/ReactiveUI.SourceGenerators/Reactive/ReactiveGenerator.Execute.cs index 837af44..cc95503 100644 --- a/src/ReactiveUI.SourceGenerators/Reactive/ReactiveGenerator.Execute.cs +++ b/src/ReactiveUI.SourceGenerators/Reactive/ReactiveGenerator.Execute.cs @@ -14,6 +14,7 @@ using ReactiveUI.SourceGenerators.Helpers; using ReactiveUI.SourceGenerators.Models; using ReactiveUI.SourceGenerators.Reactive.Models; +using static ReactiveUI.SourceGenerators.Diagnostics.DiagnosticDescriptors; namespace ReactiveUI.SourceGenerators; @@ -31,9 +32,12 @@ public sealed partial class ReactiveGenerator /// /// The context. /// The token. - /// The value. - private static PropertyInfo? GetVariableInfo(in GeneratorAttributeSyntaxContext context, CancellationToken token) + /// + /// The value. + /// + private static Result? GetVariableInfo(in GeneratorAttributeSyntaxContext context, CancellationToken token) { + using var builder = ImmutableArrayBuilder.Rent(); var symbol = context.TargetSymbol; if (!symbol.TryGetAttributeWithFullyQualifiedMetadataName(AttributeDefinitions.ReactiveAttributeType, out var attributeData)) @@ -48,7 +52,12 @@ public sealed partial class ReactiveGenerator if (!IsTargetTypeValid(fieldSymbol)) { - return default; + builder.Add( + InvalidReactiveError, + fieldSymbol, + fieldSymbol.ContainingType, + fieldSymbol.Name); + return new(default, builder.ToImmutable()); } token.ThrowIfCancellationRequested(); @@ -73,6 +82,16 @@ public sealed partial class ReactiveGenerator var fieldName = fieldSymbol.Name; var propertyName = fieldSymbol.GetGeneratedPropertyName(); + if (fieldName == propertyName) + { + builder.Add( + ReactivePropertyNameCollisionError, + fieldSymbol, + fieldSymbol.ContainingType, + fieldSymbol.Name); + return new(default, builder.ToImmutable()); + } + token.ThrowIfCancellationRequested(); // Get the nullability info for the property @@ -147,6 +166,11 @@ public sealed partial class ReactiveGenerator // lack of IntelliSense when constructing attributes over the field, but this is the best we can do from this end anyway. if (!context.SemanticModel.GetSymbolInfo(attribute, token).TryGetAttributeTypeSymbol(out var attributeTypeSymbol)) { + builder.Add( + InvalidPropertyTargetedAttributeOnReactiveField, + attribute, + fieldSymbol, + attribute.Name); continue; } @@ -155,6 +179,11 @@ public sealed partial class ReactiveGenerator // Try to extract the forwarded attribute if (!AttributeInfo.TryCreate(attributeTypeSymbol, context.SemanticModel, attributeArguments, token, out var attributeInfo)) { + builder.Add( + InvalidPropertyTargetedAttributeExpressionOnReactiveField, + attribute, + fieldSymbol, + attribute.Name); continue; } @@ -171,6 +200,7 @@ public sealed partial class ReactiveGenerator token.ThrowIfCancellationRequested(); return new( + new( targetInfo.FileHintName, targetInfo.TargetName, targetInfo.TargetNamespace, @@ -184,7 +214,8 @@ public sealed partial class ReactiveGenerator isReferenceTypeOrUnconstraindTypeParameter, includeMemberNotNullOnSetAccessor, forwardedAttributesString, - accessModifier); + accessModifier), + builder.ToImmutable()); } /// diff --git a/src/ReactiveUI.SourceGenerators/Reactive/ReactiveGenerator.cs b/src/ReactiveUI.SourceGenerators/Reactive/ReactiveGenerator.cs index ce39222..07cb237 100644 --- a/src/ReactiveUI.SourceGenerators/Reactive/ReactiveGenerator.cs +++ b/src/ReactiveUI.SourceGenerators/Reactive/ReactiveGenerator.cs @@ -11,6 +11,8 @@ using Microsoft.CodeAnalysis.Text; using ReactiveUI.SourceGenerators.Extensions; using ReactiveUI.SourceGenerators.Helpers; +using ReactiveUI.SourceGenerators.Models; +using ReactiveUI.SourceGenerators.Reactive.Models; namespace ReactiveUI.SourceGenerators; @@ -46,7 +48,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Generate the requested properties context.RegisterSourceOutput(propertyInfo, static (context, input) => { - var groupedPropertyInfo = input.GroupBy( + foreach (var diagnostic in input.SelectMany(static x => x.Errors)) + { + // Output the diagnostics + context.ReportDiagnostic(diagnostic.ToDiagnostic()); + } + + // Gather all the properties that are valid and group them by the target information. + var groupedPropertyInfo = input + .Where(static x => x.Value != null) + .Select(static x => x.Value!).GroupBy( static info => (info.FileHintName, info.TargetName, info.TargetNamespace, info.TargetVisibility, info.TargetType), static info => info) .ToImmutableArray(); diff --git a/src/ReactiveUI.SourceGenerators/ReactiveUI.SourceGenerators.csproj b/src/ReactiveUI.SourceGenerators/ReactiveUI.SourceGenerators.csproj index bd89f71..d1654e0 100644 --- a/src/ReactiveUI.SourceGenerators/ReactiveUI.SourceGenerators.csproj +++ b/src/ReactiveUI.SourceGenerators/ReactiveUI.SourceGenerators.csproj @@ -3,16 +3,16 @@ netstandard2.0 enable + latest true - Generated true - latest true true false A MVVM framework that integrates with the Reactive Extensions for .NET to create elegant, testable User Interfaces that run on any mobile or desktop platform. This is the Source Generators package for ReactiveUI + Generated diff --git a/src/ReactiveUI.SourceGenerators.sln b/src/ReactiveUI.SourceGenerators.sln index eb7af8c..4ed07cd 100644 --- a/src/ReactiveUI.SourceGenerators.sln +++ b/src/ReactiveUI.SourceGenerators.sln @@ -24,7 +24,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.SourceGenerators EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestLibs", "TestLibs", "{B86ED9C1-AFFB-4854-AD80-F4B4050CAD0A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.CodeFixes", "ReactiveUI.SourceGenerators.CodeFixers\ReactiveUI.CodeFixes.csproj", "{C89EE66E-E1DC-4A31-9322-20D95CB0D74D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.SourceGenerators.Analyzers.CodeFixes", "ReactiveUI.SourceGenerators.CodeFixers\ReactiveUI.SourceGenerators.Analyzers.CodeFixes.csproj", "{C89EE66E-E1DC-4A31-9322-20D95CB0D74D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/ReactiveUI.SourceGenerators/ReactiveUI.SourceGenerators.csproj b/src/ReactiveUI.SourceGenerators/ReactiveUI.SourceGenerators.csproj index d1654e0..6950971 100644 --- a/src/ReactiveUI.SourceGenerators/ReactiveUI.SourceGenerators.csproj +++ b/src/ReactiveUI.SourceGenerators/ReactiveUI.SourceGenerators.csproj @@ -9,6 +9,7 @@ true true false + true A MVVM framework that integrates with the Reactive Extensions for .NET to create elegant, testable User Interfaces that run on any mobile or desktop platform. This is the Source Generators package for ReactiveUI @@ -44,7 +45,7 @@ - + From 89007ffa275034337c6e0d02aa3bcf8d54d2d58b Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Wed, 6 Nov 2024 01:09:45 +0000 Subject: [PATCH 5/5] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 333e9b9..5cd6605 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # ReactiveUI.SourceGenerators Use source generators to generate ReactiveUI objects. +The minimum C# version is 12.0 and the minimum Visual Studio version is 17.8.0. These Source Generators were designed to work in full with ReactiveUI V19.5.31 and newer supporting all features, currently: - [Reactive] @@ -15,6 +16,8 @@ These Source Generators were designed to work in full with ReactiveUI V19.5.31 a Versions older than V19.5.31 to this: - [ReactiveCommand] all options supported except Cancellation Token asnyc methods. +For dot net framework 4.8 and older versions please add Polyfill or PolySharp package to your project to gain the IsExternalInit class and set the LangVersion to 12.0 or latest in your project file. + [analyzer codes](https://github.com/reactiveui/ReactiveUI.SourceGenerators/blob/main/src/ReactiveUI.SourceGenerators/AnalyzerReleases.Shipped.md) # Historical ways