From f9b1b61da4bef96359433baa3e29c2c91586f525 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 23 Dec 2025 01:26:03 +0000 Subject: [PATCH 1/6] Add IReactiveObject source generator and tests Introduces the [IReactiveObject] attribute and a new source generator to implement IReactiveObject for classes that cannot inherit from ReactiveObject. Updates documentation, adds generator logic, supporting models, and unit tests to verify generated code. Also updates helper and project files to support the new generator. --- README.md | 14 ++ ...ors.IReactiveObjectAttribute.g.verified.cs | 19 +++ ...estNs.TestVM.IReactiveObject.g.verified.cs | 68 +++++++++ .../ReactiveUI.SourceGenerators.Tests.csproj | 1 + .../TestHelper.cs | 1 + .../UnitTests/ReactiveObjectGeneratorTests.cs | 41 ++++++ .../Person.cs | 6 +- .../AttributeDefinitions.cs | 6 +- .../BindableDerivedListGenerator.cs | 2 - .../Core/Extensions/FieldSyntaxExtensions.cs | 7 +- .../IViewFor/IViewForGenerator.Execute.cs | 4 +- .../Models/ReactiveObjectInfo.cs | 13 ++ .../ReactiveObjectGenerator.Execute.cs | 136 ++++++++++++++++++ .../ReactiveObject/ReactiveObjectGenerator.cs | 61 ++++++++ 14 files changed, 366 insertions(+), 13 deletions(-) create mode 100644 src/ReactiveUI.SourceGenerator.Tests/REACTIVEOBJ/ReactiveObjectGeneratorTests.FromReactiveObject#ReactiveUI.SourceGenerators.IReactiveObjectAttribute.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/REACTIVEOBJ/ReactiveObjectGeneratorTests.FromReactiveObject#TestNs.TestVM.IReactiveObject.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs create mode 100644 src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs create mode 100644 src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.Execute.cs create mode 100644 src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.cs diff --git a/README.md b/README.md index 4d9ecdb..6d5a239 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ ReactiveUI Source Generators automatically generate ReactiveUI objects to stream - `[ViewModelControlHost("YourNameSpace.CustomControl")]` - `[BindableDerivedList]` Generates a derived list from a ReadOnlyObservableCollection backing field - `[ReactiveCollection]` Generates property changed notifications on add, remove, new actions on a ObservableCollection backing field +- `[IReactiveObject]` Generates IReactiveObject implementation for classes not able to inherit from ReactiveObject #### IViewFor Registration generator @@ -684,6 +685,19 @@ public partial class MyReactiveClass : ReactiveObject } ``` +### ReactiveObject implementation for classes not able to inherit from ReactiveObject +```csharp +using ReactiveUI; +using ReactiveUI.SourceGenerators; + +[IReactiveObject] +public partial class MyReactiveClass +{ + [Reactive] + private string _myProperty; +} +``` + ### TODO: - Add ObservableAsProperty to generate from a IObservable method with parameters. diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVEOBJ/ReactiveObjectGeneratorTests.FromReactiveObject#ReactiveUI.SourceGenerators.IReactiveObjectAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVEOBJ/ReactiveObjectGeneratorTests.FromReactiveObject#ReactiveUI.SourceGenerators.IReactiveObjectAttribute.g.verified.cs new file mode 100644 index 0000000..3a7be2f --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVEOBJ/ReactiveObjectGeneratorTests.FromReactiveObject#ReactiveUI.SourceGenerators.IReactiveObjectAttribute.g.verified.cs @@ -0,0 +1,19 @@ +//HintName: ReactiveUI.SourceGenerators.IReactiveObjectAttribute.g.cs +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +// +#pragma warning disable +#nullable enable +namespace ReactiveUI.SourceGenerators; + +/// +/// IReactiveObject Attribute. +/// +/// +[global::System.AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +internal sealed class IReactiveObjectAttribute : global::System.Attribute; +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVEOBJ/ReactiveObjectGeneratorTests.FromReactiveObject#TestNs.TestVM.IReactiveObject.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVEOBJ/ReactiveObjectGeneratorTests.FromReactiveObject#TestNs.TestVM.IReactiveObject.g.verified.cs new file mode 100644 index 0000000..cb482d4 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVEOBJ/ReactiveObjectGeneratorTests.FromReactiveObject#TestNs.TestVM.IReactiveObject.g.verified.cs @@ -0,0 +1,68 @@ +//HintName: TestNs.TestVM.IReactiveObject.g.cs +// +#pragma warning disable +#nullable enable +using System; +using System.Diagnostics.CodeAnalysis; +using System.ComponentModel; +using ReactiveUI; + +namespace TestNs +{ + /// + /// Partial class for the TestVM which contains ReactiveUI IReactiveObject initialization. + /// + public partial class TestVM : IReactiveObject + { + private bool _propertyChangingEventsSubscribed; + private bool _propertyChangedEventsSubscribed; + + /// + public event PropertyChangingEventHandler? PropertyChanging + { + add + { + if (!_propertyChangingEventsSubscribed) + { + this.SubscribePropertyChangingEvents(); + _propertyChangingEventsSubscribed = true; + } + + PropertyChangingHandler += value; + } + remove => PropertyChangingHandler -= value; + } + + /// + public event PropertyChangedEventHandler? PropertyChanged + { + add + { + if (!_propertyChangedEventsSubscribed) + { + this.SubscribePropertyChangedEvents(); + _propertyChangedEventsSubscribed = true; + } + + PropertyChangedHandler += value; + } + remove => PropertyChangedHandler -= value; + } + + [SuppressMessage("Roslynator", "RCS1159:Use EventHandler", Justification = "Long term design.")] + private event PropertyChangingEventHandler? PropertyChangingHandler; + + [SuppressMessage("Roslynator", "RCS1159:Use EventHandler", Justification = "Long term design.")] + private event PropertyChangedEventHandler? PropertyChangedHandler; + + /// + void IReactiveObject.RaisePropertyChanging(PropertyChangingEventArgs args) => + PropertyChangingHandler?.Invoke(this, args); + + /// + void IReactiveObject.RaisePropertyChanged(PropertyChangedEventArgs args) => + PropertyChangedHandler?.Invoke(this, args); + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj b/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj index 8630fcf..f89d767 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj +++ b/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj @@ -40,6 +40,7 @@ + diff --git a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs index 8309201..6f471a3 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs @@ -87,6 +87,7 @@ public string VerifiedFilePath() nameof(ViewModelControlHostGenerator) => "CONTROLHOST", nameof(BindableDerivedListGenerator) => "DERIVEDLIST", nameof(ReactiveCollectionGenerator) => "REACTIVECOLL", + nameof(ReactiveObjectGenerator) => "REACTIVEOBJ", _ => name, }; } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs new file mode 100644 index 0000000..bcee58d --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs @@ -0,0 +1,41 @@ +// Copyright (c) 2025 ReactiveUI and contributors. All rights reserved. +// Licensed to the ReactiveUI and contributors under one or more agreements. +// The ReactiveUI and contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using ReactiveUI.SourceGenerators; + +namespace ReactiveUI.SourceGenerator.Tests; + +/// +/// Unit tests for the Reactive generator. +/// +[TestFixture] +public class ReactiveObjectGeneratorTests : TestBase +{ + /// + /// Froms the reactive object. + /// + /// A task to monitor the async. + [Test] + public Task FromReactiveObject() + { + // Arrange: Setup the source code that matches the generator input expectations. + const string sourceCode = """ + using System; + using ReactiveUI.SourceGenerators; + using System.Reactive.Linq; + namespace TestNs; + + [IReactiveObject] + public partial class TestVM + { + [Reactive] + private int _test1 = 10; + } + """; + + // Act: Initialize the helper and run the generator. Assert: Verify the generated code. + return TestHelper.TestPass(sourceCode); + } +} diff --git a/src/ReactiveUI.SourceGenerators.Execute/Person.cs b/src/ReactiveUI.SourceGenerators.Execute/Person.cs index 2c05550..1958f51 100644 --- a/src/ReactiveUI.SourceGenerators.Execute/Person.cs +++ b/src/ReactiveUI.SourceGenerators.Execute/Person.cs @@ -4,7 +4,6 @@ // See the LICENSE file in the project root for full license information. using System.Diagnostics.CodeAnalysis; -using ReactiveUI; using ReactiveUI.SourceGenerators; namespace SGReactiveUI.SourceGenerators.Test; @@ -14,7 +13,8 @@ namespace SGReactiveUI.SourceGenerators.Test; /// /// [ExcludeFromCodeCoverage] -public partial class Person : ReactiveObject +[IReactiveObject] +public partial class Person { /// /// Gets or sets a value indicating whether this is deleted. @@ -23,5 +23,5 @@ public partial class Person : ReactiveObject /// true if deleted; otherwise, false. /// [Reactive] - public bool Deleted { get; set; } + public partial bool Deleted { get; set; } } diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs b/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs index ccecb84..0e9b876 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs @@ -77,6 +77,8 @@ internal enum SplatRegistrationType #pragma warning restore """; + public const string ReactiveObjectAttributeType = "ReactiveUI.SourceGenerators.IReactiveObjectAttribute"; + public static string ReactiveObjectAttribute => $$""" // Copyright (c) {{DateTime.Now.Year}} .NET Foundation and Contributors. All rights reserved. // Licensed to the .NET Foundation under one or more agreements. @@ -89,12 +91,12 @@ internal enum SplatRegistrationType namespace ReactiveUI.SourceGenerators; /// -/// ReactiveObjectAttribute. +/// IReactiveObject Attribute. /// /// [global::System.CodeDom.Compiler.GeneratedCode("ReactiveUI.SourceGenerators.ReactiveObjectGenerator", "{{ReactiveGenerator.GeneratorVersion}}")] [global::System.AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)] -internal sealed class ReactiveObjectAttribute : global::System.Attribute; +internal sealed class IReactiveObjectAttribute : global::System.Attribute; #nullable restore #pragma warning restore """; diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/BindableDerivedList/BindableDerivedListGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/BindableDerivedList/BindableDerivedListGenerator.cs index fdf8b79..51f9e2f 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/BindableDerivedList/BindableDerivedListGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/BindableDerivedList/BindableDerivedListGenerator.cs @@ -3,8 +3,6 @@ // The ReactiveUI and contributors licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Text; diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/FieldSyntaxExtensions.cs b/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/FieldSyntaxExtensions.cs index fb62a63..067883a 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/FieldSyntaxExtensions.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/FieldSyntaxExtensions.cs @@ -5,6 +5,7 @@ using System.Globalization; using Microsoft.CodeAnalysis; +using ReactiveUI.SourceGenerators.Helpers; namespace ReactiveUI.SourceGenerators.Extensions; @@ -124,7 +125,7 @@ internal static bool IsTargetTypeValid(this IFieldSymbol fieldSymbol) { var isObservableObject = fieldSymbol.ContainingType.InheritsFromFullyQualifiedMetadataName("ReactiveUI.ReactiveObject"); var isIObservableObject = fieldSymbol.ContainingType.ImplementsFullyQualifiedMetadataName("ReactiveUI.IReactiveObject"); - var hasObservableObjectAttribute = fieldSymbol.ContainingType.HasOrInheritsAttributeWithFullyQualifiedMetadataName("ReactiveUI.SourceGenerators.ReactiveObjectAttribute"); + var hasObservableObjectAttribute = fieldSymbol.ContainingType.HasOrInheritsAttributeWithFullyQualifiedMetadataName(AttributeDefinitions.ReactiveObjectAttributeType); return isIObservableObject || isObservableObject || hasObservableObjectAttribute; } @@ -138,7 +139,7 @@ internal static bool IsTargetTypeValid(this IPropertySymbol propertySymbol) { var isObservableObject = propertySymbol.ContainingType.InheritsFromFullyQualifiedMetadataName("ReactiveUI.ReactiveObject"); var isIObservableObject = propertySymbol.ContainingType.ImplementsFullyQualifiedMetadataName("ReactiveUI.IReactiveObject"); - var hasObservableObjectAttribute = propertySymbol.ContainingType.HasOrInheritsAttributeWithFullyQualifiedMetadataName("ReactiveUI.SourceGenerators.ReactiveObjectAttribute"); + var hasObservableObjectAttribute = propertySymbol.ContainingType.HasOrInheritsAttributeWithFullyQualifiedMetadataName(AttributeDefinitions.ReactiveObjectAttributeType); return isIObservableObject || isObservableObject || hasObservableObjectAttribute; } @@ -152,7 +153,7 @@ internal static bool IsTargetTypeValid(this IMethodSymbol methodSymbol) { var isObservableObject = methodSymbol.ContainingType.InheritsFromFullyQualifiedMetadataName("ReactiveUI.ReactiveObject"); var isIObservableObject = methodSymbol.ContainingType.ImplementsFullyQualifiedMetadataName("ReactiveUI.IReactiveObject"); - var hasObservableObjectAttribute = methodSymbol.ContainingType.HasOrInheritsAttributeWithFullyQualifiedMetadataName("ReactiveUI.SourceGenerators.ReactiveObjectAttribute"); + var hasObservableObjectAttribute = methodSymbol.ContainingType.HasOrInheritsAttributeWithFullyQualifiedMetadataName(AttributeDefinitions.ReactiveObjectAttributeType); return isIObservableObject || isObservableObject || hasObservableObjectAttribute; } diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.Execute.cs b/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.Execute.cs index 700bfef..d55ee07 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.Execute.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.Execute.cs @@ -26,8 +26,6 @@ public partial class IViewForGenerator internal static readonly string GeneratorName = typeof(IViewForGenerator).FullName!; internal static readonly string GeneratorVersion = typeof(IViewForGenerator).Assembly.GetName().Version.ToString(); - private static readonly string[] excludeFromCodeCoverage = ["[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]"]; - private static IViewForInfo? GetClassInfo(in GenericGeneratorAttributeSyntaxContext context, CancellationToken token) { if (!(context.TargetNode is ClassDeclarationSyntax declaredClass && declaredClass.Modifiers.Any(SyntaxKind.PartialKeyword))) @@ -126,7 +124,7 @@ public partial class IViewForGenerator private static string GenerateSource(string containingTypeName, string containingNamespace, string containingClassVisibility, string containingType, IViewForInfo iviewForInfo) { // Prepare any forwarded property attributes - var forwardedAttributesString = string.Join("\n ", excludeFromCodeCoverage); + var forwardedAttributesString = string.Join("\n ", AttributeDefinitions.ExcludeFromCodeCoverage); switch (iviewForInfo.BaseType) { diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs new file mode 100644 index 0000000..a00ba6e --- /dev/null +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2025 ReactiveUI and contributors. All rights reserved. +// Licensed to the ReactiveUI and contributors under one or more agreements. +// The ReactiveUI and contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace ReactiveUI.SourceGenerators.Models; + +/// +/// A model with gathered info on a given command method. +/// +internal sealed record ReactiveObjectInfo( + TargetInfo TargetInfo, + string ViewModelTypeName); diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.Execute.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.Execute.cs new file mode 100644 index 0000000..1276e53 --- /dev/null +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.Execute.cs @@ -0,0 +1,136 @@ +// Copyright (c) 2025 ReactiveUI and contributors. All rights reserved. +// Licensed to the ReactiveUI and contributors under one or more agreements. +// The ReactiveUI and contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using ReactiveUI.SourceGenerators.Extensions; +using ReactiveUI.SourceGenerators.Helpers; +using ReactiveUI.SourceGenerators.Models; + +namespace ReactiveUI.SourceGenerators; + +/// +/// A source generator for generating reactiveObject properties. +/// +public partial class ReactiveObjectGenerator +{ + internal static readonly string GeneratorName = typeof(ReactiveObjectGenerator).FullName!; + internal static readonly string GeneratorVersion = typeof(ReactiveObjectGenerator).Assembly.GetName().Version.ToString(); + + private static ReactiveObjectInfo? GetClassInfo(in GenericGeneratorAttributeSyntaxContext context, CancellationToken token) + { + if (!(context.TargetNode is ClassDeclarationSyntax declaredClass && declaredClass.Modifiers.Any(SyntaxKind.PartialKeyword))) + { + return default; + } + + var symbol = context.TargetSymbol; + token.ThrowIfCancellationRequested(); + + if (!symbol.TryGetAttributeWithFullyQualifiedMetadataName(AttributeDefinitions.ReactiveObjectAttributeType, out var attributeData)) + { + return default; + } + + token.ThrowIfCancellationRequested(); + if (symbol is not INamedTypeSymbol classSymbol) + { + return default; + } + + var constructorArgument = attributeData.GetConstructorArguments().FirstOrDefault(); + var genericArgument = attributeData.GetGenericType(); + token.ThrowIfCancellationRequested(); + var viewModelTypeName = string.IsNullOrWhiteSpace(constructorArgument) ? genericArgument : constructorArgument; + if (string.IsNullOrWhiteSpace(viewModelTypeName)) + { + return default; + } + + token.ThrowIfCancellationRequested(); + + // Get the containing type info + var targetInfo = TargetInfo.From(classSymbol); + + token.ThrowIfCancellationRequested(); + return new( + targetInfo, + viewModelTypeName!); + } + + private static string GenerateSource(string containingTypeName, string containingNamespace, string containingClassVisibility, string containingType, ReactiveObjectInfo reactiveObjectInfo) => + $$""" +// +#pragma warning disable +#nullable enable +using System; +using System.Diagnostics.CodeAnalysis; +using System.ComponentModel; +using ReactiveUI; + +namespace {{containingNamespace}} +{ + /// + /// Partial class for the {{containingTypeName}} which contains ReactiveUI IReactiveObject initialization. + /// + {{containingClassVisibility}} partial {{containingType}} {{containingTypeName}} : IReactiveObject + { + private bool _propertyChangingEventsSubscribed; + private bool _propertyChangedEventsSubscribed; + + /// + public event PropertyChangingEventHandler? PropertyChanging + { + add + { + if (!_propertyChangingEventsSubscribed) + { + this.SubscribePropertyChangingEvents(); + _propertyChangingEventsSubscribed = true; + } + + PropertyChangingHandler += value; + } + remove => PropertyChangingHandler -= value; + } + + /// + public event PropertyChangedEventHandler? PropertyChanged + { + add + { + if (!_propertyChangedEventsSubscribed) + { + this.SubscribePropertyChangedEvents(); + _propertyChangedEventsSubscribed = true; + } + + PropertyChangedHandler += value; + } + remove => PropertyChangedHandler -= value; + } + + [SuppressMessage("Roslynator", "RCS1159:Use EventHandler", Justification = "Long term design.")] + private event PropertyChangingEventHandler? PropertyChangingHandler; + + [SuppressMessage("Roslynator", "RCS1159:Use EventHandler", Justification = "Long term design.")] + private event PropertyChangedEventHandler? PropertyChangedHandler; + + /// + void IReactiveObject.RaisePropertyChanging(PropertyChangingEventArgs args) => + PropertyChangingHandler?.Invoke(this, args); + + /// + void IReactiveObject.RaisePropertyChanged(PropertyChangedEventArgs args) => + PropertyChangedHandler?.Invoke(this, args); + } +} +#nullable restore +#pragma warning restore +"""; +} diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.cs new file mode 100644 index 0000000..83ab0cf --- /dev/null +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2025 ReactiveUI and contributors. All rights reserved. +// Licensed to the ReactiveUI and contributors under one or more agreements. +// The ReactiveUI and contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; +using ReactiveUI.SourceGenerators.Helpers; + +namespace ReactiveUI.SourceGenerators; + +/// +/// A source generator for generating reative properties. +/// +[Generator(LanguageNames.CSharp)] +public sealed partial class ReactiveObjectGenerator : IIncrementalGenerator +{ + /// + public void Initialize(IncrementalGeneratorInitializationContext context) + { + context.RegisterPostInitializationOutput(ctx => + ctx.AddSource(AttributeDefinitions.ReactiveObjectAttributeType + ".g.cs", SourceText.From(AttributeDefinitions.ReactiveObjectAttribute, Encoding.UTF8))); + + // Gather info for all annotated IViewFor Classes + var reactiveObjectInfo = + context.SyntaxProvider + .ForAttributeWithMetadataNameWithGenerics( + AttributeDefinitions.ReactiveObjectAttributeType, + static (node, _) => node is ClassDeclarationSyntax { AttributeLists.Count: > 0 }, + static (context, token) => GetClassInfo(context, token)) + .Where(x => x != null) + .Select((x, _) => x!) + .Collect(); + + // Generate the requested properties and methods for IViewFor + context.RegisterSourceOutput(reactiveObjectInfo, static (context, input) => + { + var groupedPropertyInfo = input.GroupBy( + static info => (info.TargetInfo.FileHintName, info.TargetInfo.TargetName, info.TargetInfo.TargetNamespace, info.TargetInfo.TargetVisibility, info.TargetInfo.TargetType), + static info => info) + .ToImmutableArray(); + + foreach (var grouping in groupedPropertyInfo) + { + var items = grouping.ToImmutableArray(); + + if (items.Length == 0) + { + continue; + } + + var source = GenerateSource(grouping.Key.TargetName, grouping.Key.TargetNamespace, grouping.Key.TargetVisibility, grouping.Key.TargetType, grouping.FirstOrDefault()); + context.AddSource(grouping.Key.FileHintName + ".IReactiveObject.g.cs", source); + } + }); + } +} From 57af3f31c4bad993067fb9b80f381de0c0b27c16 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 23 Dec 2025 01:42:25 +0000 Subject: [PATCH 2/6] Remove ViewModelTypeName from ReactiveObjectInfo Eliminated the ViewModelTypeName property from the ReactiveObjectInfo record and updated the generator logic to reflect this change. This simplifies the model and generator by removing unused or unnecessary data. --- .../Models/ReactiveObjectInfo.cs | 3 +-- .../ReactiveObjectGenerator.Execute.cs | 19 +------------------ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs index a00ba6e..97e3ac3 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs @@ -9,5 +9,4 @@ namespace ReactiveUI.SourceGenerators.Models; /// A model with gathered info on a given command method. /// internal sealed record ReactiveObjectInfo( - TargetInfo TargetInfo, - string ViewModelTypeName); + TargetInfo TargetInfo); diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.Execute.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.Execute.cs index 1276e53..65d076d 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.Execute.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.Execute.cs @@ -32,35 +32,18 @@ public partial class ReactiveObjectGenerator var symbol = context.TargetSymbol; token.ThrowIfCancellationRequested(); - if (!symbol.TryGetAttributeWithFullyQualifiedMetadataName(AttributeDefinitions.ReactiveObjectAttributeType, out var attributeData)) - { - return default; - } - - token.ThrowIfCancellationRequested(); if (symbol is not INamedTypeSymbol classSymbol) { return default; } - var constructorArgument = attributeData.GetConstructorArguments().FirstOrDefault(); - var genericArgument = attributeData.GetGenericType(); - token.ThrowIfCancellationRequested(); - var viewModelTypeName = string.IsNullOrWhiteSpace(constructorArgument) ? genericArgument : constructorArgument; - if (string.IsNullOrWhiteSpace(viewModelTypeName)) - { - return default; - } - token.ThrowIfCancellationRequested(); // Get the containing type info var targetInfo = TargetInfo.From(classSymbol); token.ThrowIfCancellationRequested(); - return new( - targetInfo, - viewModelTypeName!); + return new(targetInfo); } private static string GenerateSource(string containingTypeName, string containingNamespace, string containingClassVisibility, string containingType, ReactiveObjectInfo reactiveObjectInfo) => From 1de168b5fa2634f70620796559df9aa2999e1d6d Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 23 Dec 2025 01:48:17 +0000 Subject: [PATCH 3/6] Fix typos in documentation and comments Corrected 'reative' to 'reactive' in XML documentation and comments across multiple source generator files. Also fixed a typo in the summary for ReactiveCommandAttribute and clarified some comments in ReactiveObjectGenerator. --- .../AttributeDefinitions.cs | 2 +- .../IViewFor/IViewForGenerator.cs | 2 +- .../ObservableAsPropertyGenerator{FromField}.cs | 2 +- .../ObservableAsPropertyGenerator{FromObservable}.cs | 2 +- .../Reactive/ReactiveGenerator.cs | 2 +- .../ReactiveCollection/ReactiveCollectionGenerator.cs | 2 +- .../ReactiveCommand/ReactiveCommandGenerator.cs | 2 +- .../ReactiveObject/ReactiveObjectGenerator.cs | 6 +++--- .../RoutedControlHost/RoutedControlHostGenerator.cs | 2 +- .../ViewModelControlHost/ViewModelControlHostGenerator.cs | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs b/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs index 0e9b876..2cdfdd8 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs @@ -121,7 +121,7 @@ internal sealed class IReactiveObjectAttribute : global::System.Attribute; namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.CodeDom.Compiler.GeneratedCode("ReactiveUI.SourceGenerators.ReactiveCommandGenerator", "{{ReactiveGenerator.GeneratorVersion}}")] diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.cs index fef7d26..1bb994e 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// [Generator(LanguageNames.CSharp)] public sealed partial class IViewForGenerator : IIncrementalGenerator diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromField}.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromField}.cs index ed6ee33..838816d 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromField}.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromField}.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// public sealed partial class ObservableAsPropertyGenerator { diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromObservable}.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromObservable}.cs index 038b534..3f100d8 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromObservable}.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromObservable}.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// public sealed partial class ObservableAsPropertyGenerator { diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.cs index c9f7fa5..f4469c4 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// [Generator(LanguageNames.CSharp)] public sealed partial class ReactiveGenerator : IIncrementalGenerator diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCollection/ReactiveCollectionGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCollection/ReactiveCollectionGenerator.cs index 5114905..6d717ac 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCollection/ReactiveCollectionGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCollection/ReactiveCollectionGenerator.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// [Generator(LanguageNames.CSharp)] public sealed partial class ReactiveCollectionGenerator : IIncrementalGenerator diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.cs index e40aef2..e2f3822 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// [Generator(LanguageNames.CSharp)] public sealed partial class ReactiveCommandGenerator : IIncrementalGenerator diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.cs index 83ab0cf..afba4e5 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/ReactiveObjectGenerator.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// [Generator(LanguageNames.CSharp)] public sealed partial class ReactiveObjectGenerator : IIncrementalGenerator @@ -25,7 +25,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterPostInitializationOutput(ctx => ctx.AddSource(AttributeDefinitions.ReactiveObjectAttributeType + ".g.cs", SourceText.From(AttributeDefinitions.ReactiveObjectAttribute, Encoding.UTF8))); - // Gather info for all annotated IViewFor Classes + // Gather info for all annotated IReactiveObject Classes var reactiveObjectInfo = context.SyntaxProvider .ForAttributeWithMetadataNameWithGenerics( @@ -36,7 +36,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Select((x, _) => x!) .Collect(); - // Generate the requested properties and methods for IViewFor + // Generate the requested properties and methods for IReactiveObject context.RegisterSourceOutput(reactiveObjectInfo, static (context, input) => { var groupedPropertyInfo = input.GroupBy( diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/RoutedControlHost/RoutedControlHostGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/RoutedControlHost/RoutedControlHostGenerator.cs index 5fe349e..9ea0bf6 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/RoutedControlHost/RoutedControlHostGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/RoutedControlHost/RoutedControlHostGenerator.cs @@ -15,7 +15,7 @@ namespace ReactiveUI.SourceGenerators.WinForms; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// [Generator(LanguageNames.CSharp)] public sealed partial class RoutedControlHostGenerator : IIncrementalGenerator diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ViewModelControlHost/ViewModelControlHostGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ViewModelControlHost/ViewModelControlHostGenerator.cs index 3984534..d0922b4 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ViewModelControlHost/ViewModelControlHostGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ViewModelControlHost/ViewModelControlHostGenerator.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerators.WinForms; /// -/// A source generator for generating reative properties. +/// A source generator for generating reactive properties. /// [Generator(LanguageNames.CSharp)] public sealed partial class ViewModelControlHostGenerator : IIncrementalGenerator From 1effa5604e4a3075e2ff785b4b282bb954d14d5d Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 23 Dec 2025 01:51:04 +0000 Subject: [PATCH 4/6] Update XML doc for ReactiveObject generator test Clarified the summary comment for the test method to specify it tests the ReactiveObject generator with IReactiveObjectAttribute. --- .../UnitTests/ReactiveObjectGeneratorTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs index bcee58d..fde4731 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs @@ -14,7 +14,7 @@ namespace ReactiveUI.SourceGenerator.Tests; public class ReactiveObjectGeneratorTests : TestBase { /// - /// Froms the reactive object. + /// Tests the ReactiveObject generator with IReactiveObjectAttribute. /// /// A task to monitor the async. [Test] From ce56bbc8dbc36312da8a18b7584013d15f7c55f7 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 23 Dec 2025 01:52:19 +0000 Subject: [PATCH 5/6] Update summary for ReactiveObjectInfo model Revised the XML summary comment for ReactiveObjectInfo to clarify that it represents information about a generated ReactiveObject (view model), improving documentation accuracy. --- .../ReactiveObject/Models/ReactiveObjectInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs index 97e3ac3..8181866 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveObject/Models/ReactiveObjectInfo.cs @@ -6,7 +6,7 @@ namespace ReactiveUI.SourceGenerators.Models; /// -/// A model with gathered info on a given command method. +/// A model with gathered information about a generated ReactiveObject (view model). /// internal sealed record ReactiveObjectInfo( TargetInfo TargetInfo); From 826db8d2db040e2c909eae47d5d67268b322e0b0 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Tue, 23 Dec 2025 02:00:41 +0000 Subject: [PATCH 6/6] Fix typo in ReactiveCommand attribute summary Corrected 'ReativeCommandAttribute' to 'ReactiveCommand Attribute' in the summary comments of multiple generated test files for improved clarity and accuracy. --- ...veUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs | 2 +- ...veUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs | 2 +- ...veUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs | 2 +- ...veUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs | 2 +- ...veUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs | 2 +- ...veUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs | 2 +- ...veUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs | 2 +- ...veUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveAsyncCommand#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveAsyncCommand#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs index 1462b40..bcdbe60 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveAsyncCommand#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveAsyncCommand#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveAsyncCommandWithParameter#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveAsyncCommandWithParameter#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs index 1462b40..bcdbe60 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveAsyncCommandWithParameter#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveAsyncCommandWithParameter#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommand#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommand#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs index 1462b40..bcdbe60 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommand#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommand#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithAccessModifier#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithAccessModifier#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs index 1462b40..bcdbe60 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithAccessModifier#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithAccessModifier#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithNestedClasses#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithNestedClasses#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs index 1462b40..bcdbe60 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithNestedClasses#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithNestedClasses#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithNullableTypeAndNullableReturnType#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithNullableTypeAndNullableReturnType#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs index 1462b40..bcdbe60 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithNullableTypeAndNullableReturnType#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithNullableTypeAndNullableReturnType#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithOutputScheduler#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithOutputScheduler#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs index 1462b40..bcdbe60 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithOutputScheduler#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithOutputScheduler#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithParameter#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithParameter#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs index 1462b40..bcdbe60 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithParameter#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.FromReactiveCommandWithParameter#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -10,7 +10,7 @@ namespace ReactiveUI.SourceGenerators; /// -/// ReativeCommandAttribute. +/// ReactiveCommand Attribute. /// /// [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)]