From 3b1479b0cb0a8966d5e445a3dde0798b2c350557 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Fri, 3 Apr 2026 17:46:41 +0100 Subject: [PATCH 01/10] Update test project config and regenerate outputs Configure test projects and refresh generated/verified files. Adds global.json and testconfig.json, enables dotnet test support, TUnit implicit usings, and sets OutputType to Exe in Directory.Build.props (also links testconfig.json into test outputs). Removes certain NUnit/Verify package version entries from Directory.Packages.props and deletes AssemblyInfo.Parallel.cs. Regenerates many .verified.cs files (OAP/OAPH/REACTIVE/RxGenExt and others), reflecting changes such as renamed generated members, readonly/visibility adjustments to ObservableAsPropertyHelper fields, removal of some JsonInclude attributes, addition of MemberNotNull annotations, and other minor accessor/initializer updates. Also updates the solution file. --- src/Directory.Build.props | 15 ++ src/Directory.Packages.props | 5 - .../AssemblyInfo.Parallel.cs | 7 - ...ableAsPropertyFromObservable.g.verified.cs | 15 +- ...ableAsPropertyFromObservable.g.verified.cs | 15 +- ...ableAsPropertyFromObservable.g.verified.cs | 14 +- ...ableAsPropertyFromObservable.g.verified.cs | 3 +- ...ableAsPropertyFromObservable.g.verified.cs | 15 +- ...ableAsPropertyFromObservable.g.verified.cs | 14 +- ...estVM.ObservableAsProperties.g.verified.cs | 2 +- ...estVM.ObservableAsProperties.g.verified.cs | 2 +- ...estVM.ObservableAsProperties.g.verified.cs | 2 +- ...ableAsPropertyFromObservable.g.verified.cs | 1 - ...estVM.ObservableAsProperties.g.verified.cs | 2 +- ...estVM.ObservableAsProperties.g.verified.cs | 4 +- ...ableAsPropertyFromObservable.g.verified.cs | 28 +-- ...sic#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...ify#TestNs.TestVM.Properties.g.verified.cs | 4 +- ...ess#TestNs.TestVM.Properties.g.verified.cs | 5 +- ...rit#TestNs.TestVM.Properties.g.verified.cs | 4 +- ...tes#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...ss#TestNs1.TestVM.Properties.g.verified.cs | 4 +- ...ss#TestNs2.TestVM.Properties.g.verified.cs | 4 +- ...nit#TestNs.TestVM.Properties.g.verified.cs | 4 +- ...3+TestInnerClass1.Properties.g.verified.cs | 6 +- ...2+TestInnerClass3.Properties.g.verified.cs | 6 +- ...3+TestInnerClass2.Properties.g.verified.cs | 6 +- ...s1.TestViewModel3.Properties.g.verified.cs | 6 +- ...el3+Level4+Level5.Properties.g.verified.cs | 3 +- ...el2+Level3+Level4.Properties.g.verified.cs | 3 +- ...el1+Level2+Level3.Properties.g.verified.cs | 3 +- ...tNs.Level1+Level2.Properties.g.verified.cs | 3 +- ...ted#TestNs.Level1.Properties.g.verified.cs | 3 +- ...ums#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...estNs.GenericVM`1.Properties.g.verified.cs | 3 +- ...ess#TestNs.TestVM.Properties.g.verified.cs | 10 +- ...lso#TestNs.TestVM.Properties.g.verified.cs | 4 - ...ttr#TestNs.TestVM.Properties.g.verified.cs | 2 +- ...ial#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...#TestNs.DerivedVM.Properties.g.verified.cs | 2 +- ...ble#TestNs.TestVM.Properties.g.verified.cs | 12 +- ...ide#TestNs.BaseVM.Properties.g.verified.cs | 2 +- ...#TestNs.DerivedVM.Properties.g.verified.cs | 2 +- ...nly#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...stNs.TestVMRecord.Properties.g.verified.cs | 3 +- ...uct#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...ime#TestNs.TestVM.Properties.g.verified.cs | 18 +- ...les#TestNs.TestVM.Properties.g.verified.cs | 6 +- .../ReactiveUI.SourceGenerators.Tests.csproj | 10 +- .../TestBase.cs | 16 -- .../TestHelper.cs | 230 +++++++++++++----- .../UnitTests/AttrMisuseExtTests.cs | 60 +++-- .../BindableDerivedListGeneratorTests.cs | 1 - .../UnitTests/DerivedListExtTests.cs | 1 - .../UnitTests/IViewForGeneratorTests.cs | 1 - .../OAPFromObservableGeneratorTests.cs | 1 - .../UnitTests/OAPGeneratorTests.cs | 1 - .../UnitTests/OapExtTests.cs | 1 - .../UnitTests/PropAnalyzerExtTests.cs | 64 +++-- .../PropertyToReactiveFieldAnalyzerTests.cs | 82 ++++++- ...ertyToReactiveFieldCodeFixProviderTests.cs | 49 +++- .../ReactiveAttributeMisuseAnalyzerTests.cs | 89 ++++++- ...tiveAttributeMisuseCodeFixProviderTests.cs | 88 ++++++- .../UnitTests/ReactiveCMDGeneratorTests.cs | 1 - .../ReactiveCollectionGeneratorTests.cs | 1 - .../UnitTests/ReactiveGeneratorTests.cs | 1 - .../UnitTests/ReactiveObjectGeneratorTests.cs | 1 - .../UnitTests/RxCmdExtTests.cs | 1 - .../UnitTests/RxCollExtTests.cs | 1 - .../UnitTests/RxGenExtTests.cs | 1 - .../UnitTests/RxObjExtTests.cs | 1 - .../UnitTests/TestCompilationReferences.cs | 4 +- .../UnitTests/ViewForExtTests.cs | 1 - .../Extensions/AttributeDataExtensions.cs | 85 ++++++- .../ReactiveCommandGenerator.Execute.cs | 6 +- src/ReactiveUI.SourceGenerators.slnx | 2 + src/global.json | 5 + src/testconfig.json | 26 ++ 78 files changed, 824 insertions(+), 297 deletions(-) delete mode 100644 src/ReactiveUI.SourceGenerator.Tests/AssemblyInfo.Parallel.cs create mode 100644 src/global.json create mode 100644 src/testconfig.json diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 2d47b1f..84b8046 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -56,6 +56,21 @@ net9.0-android;net9.0-ios;net9.0-maccatalyst;net9.0-windows10.0.19041.0;net10.0-android;net10.0-ios;net10.0-maccatalyst;net10.0-windows10.0.19041.0 + + true + true + true + Exe + + + + + + $(AssemblyName).testconfig.json + PreserveNewest + + + diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index f8ff885..e1c44b9 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -30,14 +30,9 @@ - - - - - diff --git a/src/ReactiveUI.SourceGenerator.Tests/AssemblyInfo.Parallel.cs b/src/ReactiveUI.SourceGenerator.Tests/AssemblyInfo.Parallel.cs deleted file mode 100644 index 7fea955..0000000 --- a/src/ReactiveUI.SourceGenerator.Tests/AssemblyInfo.Parallel.cs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2026 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. - -[assembly: Parallelizable(ParallelScope.Fixtures)] -[assembly: LevelOfParallelism(4)] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrNullRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrNullRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index e83082d..117817b 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrNullRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrNullRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,23 +10,22 @@ namespace TestNs public partial class TestVM { - /// - private object? _myNamedProperty; + /// + private object? _test7Property; - /// - private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _test7PropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public object? MyNamedProperty { get => _myNamedProperty = (_myNamedPropertyHelper == null ? _myNamedProperty : _myNamedPropertyHelper.Value); } + public object? Test7Property { get => _test7Property = (_test7PropertyHelper == null ? _test7Property : _test7PropertyHelper.Value); } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _myNamedPropertyHelper = Test7!.ToProperty(this, nameof(MyNamedProperty)); + _test7PropertyHelper = Test7!.ToProperty(this, nameof(Test7Property)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 7b1a883..af72674 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,23 +10,22 @@ namespace TestNs public partial class TestVM { - /// - private object _myNamedProperty; + /// + private object _test6Property; - /// - private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _test6PropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public object MyNamedProperty { get => _myNamedProperty = _myNamedPropertyHelper?.Value ?? _myNamedProperty; } + public object Test6Property { get => _test6Property = _test6PropertyHelper?.Value ?? _test6Property; } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _myNamedPropertyHelper = Test6!.ToProperty(this, nameof(MyNamedProperty)); + _test6PropertyHelper = Test6!.ToProperty(this, nameof(Test6Property)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromObservableMethodsWithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromObservableMethodsWithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index e80caab..177122c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromObservableMethodsWithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromObservableMethodsWithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,20 +10,20 @@ namespace TestNs public partial class TestVM { - /// - private int _myNamedProperty; + /// + private int _test3Property; - /// - private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _test3PropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public int MyNamedProperty { get => _myNamedProperty = _myNamedPropertyHelper?.Value ?? _myNamedProperty; } + public int Test3Property { get => _test3Property = _test3PropertyHelper?.Value ?? _test3Property; } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _myNamedPropertyHelper = Test3()!.ToProperty(this, nameof(MyNamedProperty)); + _test3PropertyHelper = Test3()!.ToProperty(this, nameof(Test3Property)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 4d47e86..4befe88 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -11,14 +11,13 @@ namespace TestNs public partial class TestVM { /// - private double? _testProperty = 1.1d; + private double? _testProperty; /// private readonly ReactiveUI.ObservableAsPropertyHelper _testPropertyHelper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] public partial double? TestProperty { get => _testProperty = (_testPropertyHelper == null ? _testProperty : _testPropertyHelper.Value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithAttr#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithAttr#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 5d3d2d6..7b27e44 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithAttr#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithAttr#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,23 +10,22 @@ namespace TestNs public partial class TestVM { - /// - private int _myNamedProperty; + /// + private int _test5Property; - /// - private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _test5PropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public int MyNamedProperty { get => _myNamedProperty = _myNamedPropertyHelper?.Value ?? _myNamedProperty; } + public int Test5Property { get => _test5Property = _test5PropertyHelper?.Value ?? _test5Property; } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _myNamedPropertyHelper = Test5!.ToProperty(this, nameof(MyNamedProperty)); + _test5PropertyHelper = Test5!.ToProperty(this, nameof(Test5Property)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 1e5c1f5..bd0fb8a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,20 +10,20 @@ namespace TestNs public partial class TestVM { - /// - private int _myNamedProperty; + /// + private int _test4Property; - /// - private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _test4PropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public int MyNamedProperty { get => _myNamedProperty = _myNamedPropertyHelper?.Value ?? _myNamedProperty; } + public int Test4Property { get => _test4Property = _test4PropertyHelper?.Value ?? _test4Property; } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _myNamedPropertyHelper = Test4!.ToProperty(this, nameof(MyNamedProperty)); + _test4PropertyHelper = Test4!.ToProperty(this, nameof(Test4Property)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromField#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromField#TestNs.TestVM.ObservableAsProperties.g.verified.cs index f53f365..3b2b7bc 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromField#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromField#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -8,7 +8,7 @@ namespace TestNs public partial class TestVM { /// - private ReactiveUI.ObservableAsPropertyHelper? _test3Helper; + private readonly ReactiveUI.ObservableAsPropertyHelper _test3Helper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromFieldProtected#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromFieldProtected#TestNs.TestVM.ObservableAsProperties.g.verified.cs index b31d92e..548e82d 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromFieldProtected#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromFieldProtected#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -8,7 +8,7 @@ namespace TestNs public partial class TestVM { /// - protected readonly ReactiveUI.ObservableAsPropertyHelper _test5Helper; + private readonly ReactiveUI.ObservableAsPropertyHelper _test5Helper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsProperties.g.verified.cs index 44e982b..daf717a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -12,7 +12,7 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Runtime.Serialization.DataMemberAttribute(Name="computedValue")] + [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonPropertyNameAttribute("computed_value")] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] public int ComputedValue { get => _computedValue = _computedValueHelper?.Value ?? _computedValue; } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 74641e2..d088866 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -18,7 +18,6 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Text.Json.Serialization.JsonIgnoreAttribute()] [global::System.Runtime.Serialization.IgnoreDataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIgnoreAttribute()] public string InternalStateProperty { get => _internalStateProperty = _internalStatePropertyHelper?.Value ?? _internalStateProperty; } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithCombinedOptions#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithCombinedOptions#TestNs.TestVM.ObservableAsProperties.g.verified.cs index 7e7eac3..b840cae 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithCombinedOptions#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithCombinedOptions#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -8,7 +8,7 @@ namespace TestNs public partial class TestVM { /// - protected ReactiveUI.ObservableAsPropertyHelper? _statusFieldHelper; + private readonly ReactiveUI.ObservableAsPropertyHelper _statusFieldHelper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromMultipleObservableAsProperties#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromMultipleObservableAsProperties#TestNs.TestVM.ObservableAsProperties.g.verified.cs index dafa97c..99e1ff2 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromMultipleObservableAsProperties#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromMultipleObservableAsProperties#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -26,13 +26,13 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int ItemCount { get => _itemCount = _itemCountHelper?.Value ?? _itemCount; } /// - protected readonly ReactiveUI.ObservableAsPropertyHelper _progressHelper; + private readonly ReactiveUI.ObservableAsPropertyHelper _progressHelper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public double Progress { get => _progress = _progressHelper?.Value ?? _progress; } /// - private ReactiveUI.ObservableAsPropertyHelper? _statusHelper; + private readonly ReactiveUI.ObservableAsPropertyHelper _statusHelper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromObservableMethodWithCustomName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromObservableMethodWithCustomName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 3328869..11f64f9 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromObservableMethodWithCustomName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromObservableMethodWithCustomName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,30 +10,30 @@ namespace TestNs public partial class TestVM { - /// - private bool _isLoading; + /// + private bool _getLoadingStateProperty; - /// - private ReactiveUI.ObservableAsPropertyHelper? _isLoadingHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _getLoadingStatePropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public bool IsLoading { get => _isLoading = _isLoadingHelper?.Value ?? _isLoading; } -/// - private string? _errorMessage; + public bool GetLoadingStateProperty { get => _getLoadingStateProperty = _getLoadingStatePropertyHelper?.Value ?? _getLoadingStateProperty; } +/// + private string? _getErrorProperty; - /// - private ReactiveUI.ObservableAsPropertyHelper? _errorMessageHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _getErrorPropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public string? ErrorMessage { get => _errorMessage = (_errorMessageHelper == null ? _errorMessage : _errorMessageHelper.Value); } + public string? GetErrorProperty { get => _getErrorProperty = (_getErrorPropertyHelper == null ? _getErrorProperty : _getErrorPropertyHelper.Value); } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _isLoadingHelper = GetLoadingState()!.ToProperty(this, nameof(IsLoading)); - _errorMessageHelper = GetError()!.ToProperty(this, nameof(ErrorMessage)); + _getLoadingStatePropertyHelper = GetLoadingState()!.ToProperty(this, nameof(GetLoadingStateProperty)); + _getErrorPropertyHelper = GetError()!.ToProperty(this, nameof(GetErrorProperty)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.Basic#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.Basic#TestNs.TestVM.Properties.g.verified.cs index 37a57da..af8e019 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.Basic#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.Basic#TestNs.TestVM.Properties.g.verified.cs @@ -13,8 +13,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Test1 - { + { get => _test1; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test1")] set { this.RaiseAndSetIfChanged(ref _test1, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.PartialAlsoNotify#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.PartialAlsoNotify#TestNs.TestVM.Properties.g.verified.cs index c2c60f5..76474e5 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.PartialAlsoNotify#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.PartialAlsoNotify#TestNs.TestVM.Properties.g.verified.cs @@ -13,13 +13,13 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Test4 - { + { get => _test4; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test4")] set { this.RaiseAndSetIfChanged(ref _test4, value); this.RaisePropertyChanged(nameof(OtherNotifyProperty)); - this.RaisePropertyChanged(nameof(OtherNotifyProperty)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAccess#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAccess#TestNs.TestVM.Properties.g.verified.cs index 879a38c..7903dbf 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAccess#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAccess#TestNs.TestVM.Properties.g.verified.cs @@ -13,9 +13,10 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Test2 - { + { get => _test2; - protected set + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test2")] + set { this.RaiseAndSetIfChanged(ref _test2, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttrAccessInherit#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttrAccessInherit#TestNs.TestVM.Properties.g.verified.cs index f245c5a..8ff6ccd 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttrAccessInherit#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttrAccessInherit#TestNs.TestVM.Properties.g.verified.cs @@ -14,11 +14,11 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public virtual string? Name + public string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - protected set + set { this.RaiseAndSetIfChanged(ref _name, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttributes#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttributes#TestNs.TestVM.Properties.g.verified.cs index 08bad5c..651537e 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttributes#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttributes#TestNs.TestVM.Properties.g.verified.cs @@ -15,8 +15,9 @@ public partial class TestVM [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] public int Test3 - { + { get => _test3; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test3")] set { this.RaiseAndSetIfChanged(ref _test3, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs index e98728f..bc0452d 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs @@ -14,11 +14,11 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public virtual string? Name + public string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - protected set + set { this.RaiseAndSetIfChanged(ref _name, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs index 21637b2..4ef72d3 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs @@ -14,11 +14,11 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public virtual string? Name + public string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - protected set + set { this.RaiseAndSetIfChanged(ref _name, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithInit#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithInit#TestNs.TestVM.Properties.g.verified.cs index 5da35b5..89a4276 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithInit#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithInit#TestNs.TestVM.Properties.g.verified.cs @@ -12,11 +12,11 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public required string MustBeSet + public string MustBeSet { get => _mustBeSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_mustBeSet")] - init + set { this.RaiseAndSetIfChanged(ref _mustBeSet, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs index f562531..ea1d0b8 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs @@ -15,8 +15,9 @@ public partial class TestInnerClass1 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner1 - { + { get => _testInner1; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner1")] set { this.RaiseAndSetIfChanged(ref _testInner1, value); @@ -26,8 +27,9 @@ public int TestInner1 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner11 - { + { get => _testInner11; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner11")] set { this.RaiseAndSetIfChanged(ref _testInner11, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs index 2c39569..a14e45a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs @@ -17,8 +17,9 @@ public partial class TestInnerClass3 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner3 - { + { get => _testInner3; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner3")] set { this.RaiseAndSetIfChanged(ref _testInner3, value); @@ -28,8 +29,9 @@ public int TestInner3 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner33 - { + { get => _testInner33; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner33")] set { this.RaiseAndSetIfChanged(ref _testInner33, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs index 476fef6..e347d04 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs @@ -15,8 +15,9 @@ public partial class TestInnerClass2 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner2 - { + { get => _testInner2; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner2")] set { this.RaiseAndSetIfChanged(ref _testInner2, value); @@ -26,8 +27,9 @@ public int TestInner2 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner22 - { + { get => _testInner22; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner22")] set { this.RaiseAndSetIfChanged(ref _testInner22, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs index 796ad8b..7471c8a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs @@ -13,8 +13,9 @@ public partial class TestViewModel3 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public float TestVM3Property - { + { get => _testVM3Property; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testVM3Property")] set { this.RaiseAndSetIfChanged(ref _testVM3Property, value); @@ -24,8 +25,9 @@ public float TestVM3Property /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public float TestVM3Property2 - { + { get => _testVM3Property2; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testVM3Property2")] set { this.RaiseAndSetIfChanged(ref _testVM3Property2, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4+Level5.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4+Level5.Properties.g.verified.cs index 9e2acfd..74fbe23 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4+Level5.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4+Level5.Properties.g.verified.cs @@ -21,8 +21,9 @@ public partial class Level5 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level5Prop - { + { get => _level5Prop; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level5Prop")] set { this.RaiseAndSetIfChanged(ref _level5Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4.Properties.g.verified.cs index 3225bd0..5f87ac3 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4.Properties.g.verified.cs @@ -19,8 +19,9 @@ public partial class Level4 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level4Prop - { + { get => _level4Prop; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level4Prop")] set { this.RaiseAndSetIfChanged(ref _level4Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3.Properties.g.verified.cs index 7c55edd..106ffdf 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3.Properties.g.verified.cs @@ -17,8 +17,9 @@ public partial class Level3 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level3Prop - { + { get => _level3Prop; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level3Prop")] set { this.RaiseAndSetIfChanged(ref _level3Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2.Properties.g.verified.cs index ff0fa21..f35f1ee 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2.Properties.g.verified.cs @@ -15,8 +15,9 @@ public partial class Level2 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level2Prop - { + { get => _level2Prop; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level2Prop")] set { this.RaiseAndSetIfChanged(ref _level2Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1.Properties.g.verified.cs index 3a658ea..54c7f15 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1.Properties.g.verified.cs @@ -13,8 +13,9 @@ public partial class Level1 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level1Prop - { + { get => _level1Prop; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level1Prop")] set { this.RaiseAndSetIfChanged(ref _level1Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Enums#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Enums#TestNs.TestVM.Properties.g.verified.cs index 0836b98..6e0e85a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Enums#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Enums#TestNs.TestVM.Properties.g.verified.cs @@ -24,8 +24,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::TestNs.Status? NullableStatus - { + { get => _nullableStatus; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableStatus")] set { this.RaiseAndSetIfChanged(ref _nullableStatus, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.GenClass#TestNs.GenericVM`1.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.GenClass#TestNs.GenericVM`1.Properties.g.verified.cs index 5f998cc..41de4a1 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.GenClass#TestNs.GenericVM`1.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.GenClass#TestNs.GenericVM`1.Properties.g.verified.cs @@ -25,8 +25,9 @@ public T? Item /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Count - { + { get => _count; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_count")] set { this.RaiseAndSetIfChanged(ref _count, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MixedAccess#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MixedAccess#TestNs.TestVM.Properties.g.verified.cs index 7b7f649..1fb9cdc 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MixedAccess#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MixedAccess#TestNs.TestVM.Properties.g.verified.cs @@ -28,7 +28,7 @@ public string? ProtectedSet { get => _protectedSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_protectedSet")] - protected set + set { this.RaiseAndSetIfChanged(ref _protectedSet, value); } @@ -40,7 +40,7 @@ public string? InternalSet { get => _internalSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_internalSet")] - internal set + set { this.RaiseAndSetIfChanged(ref _internalSet, value); } @@ -52,7 +52,7 @@ public string? PrivateSet { get => _privateSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_privateSet")] - private set + set { this.RaiseAndSetIfChanged(ref _privateSet, value); } @@ -64,7 +64,7 @@ public string? InternalProtectedSet { get => _internalProtectedSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_internalProtectedSet")] - protected internal set + set { this.RaiseAndSetIfChanged(ref _internalProtectedSet, value); } @@ -76,7 +76,7 @@ public string? PrivateProtectedSet { get => _privateProtectedSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_privateProtectedSet")] - private protected set + set { this.RaiseAndSetIfChanged(ref _privateProtectedSet, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAlso#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAlso#TestNs.TestVM.Properties.g.verified.cs index 3282705..a24b39d 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAlso#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAlso#TestNs.TestVM.Properties.g.verified.cs @@ -21,8 +21,6 @@ public string? FirstName this.RaiseAndSetIfChanged(ref _firstName, value); this.RaisePropertyChanged(nameof(FullName)); this.RaisePropertyChanged(nameof(DisplayName)); - this.RaisePropertyChanged(nameof(FullName)); - this.RaisePropertyChanged(nameof(DisplayName)); } } @@ -37,8 +35,6 @@ public string? LastName this.RaiseAndSetIfChanged(ref _lastName, value); this.RaisePropertyChanged(nameof(FullName)); this.RaisePropertyChanged(nameof(DisplayName)); - this.RaisePropertyChanged(nameof(FullName)); - this.RaisePropertyChanged(nameof(DisplayName)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAttr#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAttr#TestNs.TestVM.Properties.g.verified.cs index e64a89c..67c6f88 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAttr#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAttr#TestNs.TestVM.Properties.g.verified.cs @@ -12,7 +12,7 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Runtime.Serialization.DataMemberAttribute(Name="userName")] + [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Text.Json.Serialization.JsonPropertyNameAttribute("user_name")] public string? UserName diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiPartial#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiPartial#TestNs.TestVM.Properties.g.verified.cs index 6df2a26..7118d30 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiPartial#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiPartial#TestNs.TestVM.Properties.g.verified.cs @@ -37,8 +37,9 @@ public string? LastName /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Age - { + { get => _age; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_age")] set { this.RaiseAndSetIfChanged(ref _age, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.NewMod#TestNs.DerivedVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.NewMod#TestNs.DerivedVM.Properties.g.verified.cs index 0203a84..ea7af18 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.NewMod#TestNs.DerivedVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.NewMod#TestNs.DerivedVM.Properties.g.verified.cs @@ -12,7 +12,7 @@ public partial class DerivedVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public new string? ShadowedProp + public string? ShadowedProp { get => _shadowedProp; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_shadowedProp")] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Nullable#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Nullable#TestNs.TestVM.Properties.g.verified.cs index 3b367fd..ba41dac 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Nullable#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Nullable#TestNs.TestVM.Properties.g.verified.cs @@ -13,8 +13,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int? NullableInt - { + { get => _nullableInt; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableInt")] set { this.RaiseAndSetIfChanged(ref _nullableInt, value); @@ -24,8 +25,9 @@ public int? NullableInt /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.DateTime? NullableDateTime - { + { get => _nullableDateTime; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableDateTime")] set { this.RaiseAndSetIfChanged(ref _nullableDateTime, value); @@ -35,8 +37,9 @@ public int? NullableInt /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.Guid? NullableGuid - { + { get => _nullableGuid; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableGuid")] set { this.RaiseAndSetIfChanged(ref _nullableGuid, value); @@ -46,8 +49,9 @@ public int? NullableInt /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public decimal? NullableDecimal - { + { get => _nullableDecimal; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableDecimal")] set { this.RaiseAndSetIfChanged(ref _nullableDecimal, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.BaseVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.BaseVM.Properties.g.verified.cs index e00794c..24dd0d9 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.BaseVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.BaseVM.Properties.g.verified.cs @@ -12,7 +12,7 @@ public partial class BaseVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public virtual string? BaseName + public string? BaseName { get => _baseName; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_baseName")] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.DerivedVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.DerivedVM.Properties.g.verified.cs index ae72ca0..5caa1f1 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.DerivedVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.DerivedVM.Properties.g.verified.cs @@ -12,7 +12,7 @@ public partial class DerivedVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public override string? BaseName + public string? BaseName { get => _baseName; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_baseName")] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.ReadOnly#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.ReadOnly#TestNs.TestVM.Properties.g.verified.cs index 1f0b57a..990c447 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.ReadOnly#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.ReadOnly#TestNs.TestVM.Properties.g.verified.cs @@ -24,8 +24,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::TestNs.ImmutablePoint? OptionalPoint - { + { get => _optionalPoint; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_optionalPoint")] set { this.RaiseAndSetIfChanged(ref _optionalPoint, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Record#TestNs.TestVMRecord.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Record#TestNs.TestVMRecord.Properties.g.verified.cs index 60bc961..9077e34 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Record#TestNs.TestVMRecord.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Record#TestNs.TestVMRecord.Properties.g.verified.cs @@ -25,8 +25,9 @@ public string? Name /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Age - { + { get => _age; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_age")] set { this.RaiseAndSetIfChanged(ref _age, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Struct#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Struct#TestNs.TestVM.Properties.g.verified.cs index 5825ffb..76357cd 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Struct#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Struct#TestNs.TestVM.Properties.g.verified.cs @@ -24,8 +24,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::TestNs.Point? OptionalLocation - { + { get => _optionalLocation; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_optionalLocation")] set { this.RaiseAndSetIfChanged(ref _optionalLocation, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Time#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Time#TestNs.TestVM.Properties.g.verified.cs index a7da656..3fb76f4 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Time#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Time#TestNs.TestVM.Properties.g.verified.cs @@ -13,8 +13,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.TimeSpan Duration - { + { get => _duration; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_duration")] set { this.RaiseAndSetIfChanged(ref _duration, value); @@ -24,8 +25,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.TimeSpan? OptionalDuration - { + { get => _optionalDuration; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_optionalDuration")] set { this.RaiseAndSetIfChanged(ref _optionalDuration, value); @@ -35,8 +37,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.DateTimeOffset Timestamp - { + { get => _timestamp; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_timestamp")] set { this.RaiseAndSetIfChanged(ref _timestamp, value); @@ -46,8 +49,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.DateTimeOffset? OptionalTimestamp - { + { get => _optionalTimestamp; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_optionalTimestamp")] set { this.RaiseAndSetIfChanged(ref _optionalTimestamp, value); @@ -57,8 +61,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.TimeOnly TimeOnly - { + { get => _timeOnly; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_timeOnly")] set { this.RaiseAndSetIfChanged(ref _timeOnly, value); @@ -68,8 +73,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.DateOnly DateOnly - { + { get => _dateOnly; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_dateOnly")] set { this.RaiseAndSetIfChanged(ref _dateOnly, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Tuples#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Tuples#TestNs.TestVM.Properties.g.verified.cs index 356dd00..de8bf84 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Tuples#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Tuples#TestNs.TestVM.Properties.g.verified.cs @@ -13,8 +13,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public (int Id, string Name)? NamedTuple - { + { get => _namedTuple; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_namedTuple")] set { this.RaiseAndSetIfChanged(ref _namedTuple, value); @@ -36,8 +37,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public (string, int, bool) ValueTuple - { + { get => _valueTuple; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_valueTuple")] set { this.RaiseAndSetIfChanged(ref _valueTuple, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj b/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj index c729923..c7e726d 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj +++ b/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj @@ -5,6 +5,7 @@ enable enable 13.0 + Exe false true $(NoWarn);CA1812;CA1001 @@ -16,11 +17,9 @@ - - - + + - @@ -35,7 +34,8 @@ - + + diff --git a/src/ReactiveUI.SourceGenerator.Tests/TestBase.cs b/src/ReactiveUI.SourceGenerator.Tests/TestBase.cs index 8b74cdd..dd7fc2c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/TestBase.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/TestBase.cs @@ -18,22 +18,6 @@ public abstract class TestBase : IDisposable /// protected TestHelper TestHelper { get; } = new(); - /// - /// Initializes the test helper asynchronously. - /// - /// A task representing the asynchronous operation. - [OneTimeSetUp] - public Task InitializeAsync() => TestHelper.InitializeAsync(); - - /// - /// Disposes the test helper. - /// - [OneTimeTearDown] - public void DisposeAsync() - { - TestHelper.Dispose(); - } - /// public void Dispose() { diff --git a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs index 2ee1e5e..b032917 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs @@ -4,6 +4,7 @@ // See the LICENSE file in the project root for full license information. using System.Reflection; +using System.Runtime.CompilerServices; using ReactiveMarbles.NuGet.Helpers; using ReactiveMarbles.SourceGenerator.TestNuGetHelper.Compilation; @@ -48,6 +49,8 @@ public sealed partial class TestHelper : IDisposable /// /// Holds the compiler instance used for event-related code generation. /// + private static readonly Lazy> SharedEventCompiler = new(CreateSharedEventCompilerAsync); + private EventBuilderCompiler? _eventCompiler; /// @@ -78,40 +81,19 @@ public string VerifiedFilePath() /// Asynchronously initializes the source generator helper by downloading required packages. /// /// A task representing the asynchronous initialization operation. - public async Task InitializeAsync() - { -#if NET10_0_OR_GREATER - NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(10, 0, 0, 0))]; - #elif NET9_0_OR_GREATER - NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(9, 0, 0, 0))]; -#else - NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(8, 0, 0, 0))]; -#endif - - // Download necessary NuGet package files. - var inputGroup = await NuGetPackageHelper.DownloadPackageFilesAndFolder( - [SplatLibrary, ReactiveuiLibrary], - targetFrameworks, - packageOutputDirectory: null).ConfigureAwait(false); - - // Initialize the event compiler with downloaded packages and target framework. - var framework = targetFrameworks[0]; - _eventCompiler = new EventBuilderCompiler(inputGroup, inputGroup, framework); - } + public async Task InitializeAsync() => _eventCompiler = await SharedEventCompiler.Value.ConfigureAwait(false); /// /// Tests a generator expecting it to fail by throwing an . /// /// The source code to test. - public void TestFail( + /// A task representing the asynchronous assertion operation. + public async Task TestFail( string source) { - if (_eventCompiler is null) - { - throw new InvalidOperationException("Must have valid compiler instance."); - } + await EnsureInitializedAsync().ConfigureAwait(false); - var utility = new SourceGeneratorUtility(x => TestContext.Out.WriteLine(x)); + var utility = new SourceGeneratorUtility(WriteTestOutput); #pragma warning disable IDE0053 // Use expression body for lambda expression #pragma warning disable RCS1021 // Convert lambda expression body to expression body @@ -125,25 +107,22 @@ public void TestFail( /// /// The source code to test. /// if set to true [with pre diagnosics]. - /// - /// The driver. - /// + /// A task representing the asynchronous verification operation. /// Must have valid compiler instance. /// callerType. - public SettingsTask TestPass( + public async Task TestPass( string source, bool withPreDiagnosics = false) { - if (_eventCompiler is null) - { - throw new InvalidOperationException("Must have valid compiler instance."); - } + await EnsureInitializedAsync().ConfigureAwait(false); - return RunGeneratorAndCheck(source, withPreDiagnosics); + await RunGeneratorAndCheck(source, withPreDiagnosics); } /// - public void Dispose() => _eventCompiler?.Dispose(); + public void Dispose() + { + } /// /// Runs the specified source generator and validates the generated code. @@ -174,23 +153,26 @@ public SettingsTask RunGeneratorAndCheck( basicReferences = Basic.Reference.Assemblies.Net80.References.All; #endif - basicReferences.Concat([MetadataReference.CreateFromFile(mscorlibPath)]); - basicReferences.Concat(GetTransitiveReferences(References)); - // Collect required assembly references. var assemblies = new HashSet( basicReferences + .Concat([MetadataReference.CreateFromFile(mscorlibPath)]) .Concat(basicReferences) + .Concat(GetTransitiveReferences(References)) .Concat(_eventCompiler.Modules.Select(x => MetadataReference.CreateFromFile(x.PEFile!.FileName))) .Concat(_eventCompiler.ReferencedModules.Select(x => MetadataReference.CreateFromFile(x.PEFile!.FileName))) .Concat(_eventCompiler.NeededModules.Select(x => MetadataReference.CreateFromFile(x.PEFile!.FileName)))); - var syntaxTree = CSharpSyntaxTree.ParseText(code, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13)); + var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13); + var syntaxTrees = new List + { + CSharpSyntaxTree.ParseText(code, parseOptions), + }; // Create a compilation with the provided source code. var compilation = CSharpCompilation.Create( "TestProject", - [syntaxTree], + syntaxTrees, assemblies, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, deterministic: true)); @@ -200,11 +182,20 @@ public SettingsTask RunGeneratorAndCheck( var prediagnostics = compilation.GetDiagnostics() .Where(d => d.Severity > DiagnosticSeverity.Warning) .ToList(); - Assert.That(prediagnostics, Is.Empty); + + if (prediagnostics.Count > 0) + { + foreach (var diagnostic in prediagnostics) + { + WriteTestOutput($"Diagnostic: {diagnostic.Id} - {diagnostic.GetMessage()}"); + } + + throw new InvalidOperationException("Pre-generator compilation failed due to the above diagnostics."); + } } var generator = new T(); - var driver = CSharpGeneratorDriver.Create(generator).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options); + var driver = CSharpGeneratorDriver.Create(generator).WithUpdatedParseOptions(parseOptions); if (rerunCompilation) { @@ -220,7 +211,7 @@ public SettingsTask RunGeneratorAndCheck( { foreach (var diagnostic in offendingDiagnostics) { - TestContext.Out.WriteLine($"Diagnostic: {diagnostic.Id} - {diagnostic.GetMessage()}"); + WriteTestOutput($"Diagnostic: {diagnostic.Id} - {diagnostic.GetMessage()}"); } throw new InvalidOperationException("Compilation failed due to the above diagnostics."); @@ -236,6 +227,103 @@ public SettingsTask RunGeneratorAndCheck( return VerifyGenerator(driver.RunGenerators(compilation)); } + private static IEnumerable GetGeneratedSupportSources() + { + yield return "using System.Runtime.CompilerServices;\n[assembly: InternalsVisibleTo(\"TestProject\")]"; + + yield return GetAttributeDefinitionsMethodResult("GetAccessModifierEnum"); + + if (typeof(T) == typeof(ReactiveCommandGenerator)) + { + yield return GetAttributeDefinitionsPropertyResult("ReactiveCommandAttribute"); + yield return GetAttributeDefinitionsPropertyResult("ReactiveAttribute"); + } + else if (typeof(T) == typeof(IViewForGenerator)) + { + yield return GetAttributeDefinitionsPropertyResult("IViewForAttribute"); + } + else if (typeof(T) == typeof(ReactiveGenerator)) + { + yield return GetAttributeDefinitionsPropertyResult("ReactiveAttribute"); + } + else if (typeof(T) == typeof(ObservableAsPropertyGenerator)) + { + yield return GetAttributeDefinitionsPropertyResult("ObservableAsPropertyAttribute"); + } + else if (typeof(T) == typeof(BindableDerivedListGenerator)) + { + yield return GetAttributeDefinitionsPropertyResult("BindableDerivedListAttribute"); + } + else if (typeof(T) == typeof(ReactiveCollectionGenerator)) + { + yield return GetAttributeDefinitionsPropertyResult("ReactiveCollectionAttribute"); + } + else if (typeof(T) == typeof(ReactiveObjectGenerator)) + { + yield return GetAttributeDefinitionsPropertyResult("ReactiveObjectAttribute"); + } + } + + private static ImmutableArray CreateSupportReferences() + { + var supportSources = GetGeneratedSupportSources().ToArray(); + + if (supportSources.Length == 0) + { + return []; + } + + IEnumerable basicReferences; +#if NET10_0_OR_GREATER + basicReferences = Basic.Reference.Assemblies.Net100.References.All; +#elif NET9_0_OR_GREATER + basicReferences = Basic.Reference.Assemblies.Net90.References.All; +#else + basicReferences = Basic.Reference.Assemblies.Net80.References.All; +#endif + + var supportCompilation = CSharpCompilation.Create( + $"{typeof(T).Name}.Support", + supportSources.Select((source, index) => CSharpSyntaxTree.ParseText(source, path: $"Support{index}.g.cs")), + basicReferences.Concat([MetadataReference.CreateFromFile(mscorlibPath)]), + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, deterministic: true)); + + using var stream = new MemoryStream(); + var emitResult = supportCompilation.Emit(stream); + + if (!emitResult.Success) + { + var diagnostics = string.Join(Environment.NewLine, emitResult.Diagnostics.Select(static d => d.ToString())); + throw new InvalidOperationException($"Failed to compile support sources for {typeof(T).Name}.{Environment.NewLine}{diagnostics}"); + } + + return [MetadataReference.CreateFromImage(stream.ToArray())]; + } + + private static string GetAttributeDefinitionsMethodResult(string methodName) + { + var attributeDefinitionsType = typeof(ReactiveGenerator).Assembly.GetType("ReactiveUI.SourceGenerators.Helpers.AttributeDefinitions", throwOnError: false, ignoreCase: false) + ?? throw new InvalidOperationException("Could not locate AttributeDefinitions type."); + + var method = attributeDefinitionsType.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + ?? throw new InvalidOperationException($"Could not locate AttributeDefinitions.{methodName}."); + + return (string?)method.Invoke(null, null) + ?? throw new InvalidOperationException($"AttributeDefinitions.{methodName} returned null."); + } + + private static string GetAttributeDefinitionsPropertyResult(string propertyName) + { + var attributeDefinitionsType = typeof(ReactiveGenerator).Assembly.GetType("ReactiveUI.SourceGenerators.Helpers.AttributeDefinitions", throwOnError: false, ignoreCase: false) + ?? throw new InvalidOperationException("Could not locate AttributeDefinitions type."); + + var property = attributeDefinitionsType.GetProperty(propertyName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + ?? throw new InvalidOperationException($"Could not locate AttributeDefinitions.{propertyName}."); + + return (string?)property.GetValue(null) + ?? throw new InvalidOperationException($"AttributeDefinitions.{propertyName} returned null."); + } + [GeneratedRegex(@"\[Reactive\((?:.*?nameof\((\w+)\))+", RegexOptions.Singleline)] private static partial Regex ReactiveRegex(); @@ -259,23 +347,16 @@ private static void ValidateGeneratedCode(string sourceCode, GeneratorDriver dri var nameofPattern = NameOfRegex(); var matches = alsoNotifyPattern.Matches(sourceCode); - TestContext.Out.WriteLine("=== VALIDATION DEBUG ==="); - TestContext.Out.WriteLine("Found {0} Reactive attributes with nameof", matches.Count); - if (matches.Count > 0) { foreach (Match match in matches) { - TestContext.Out.WriteLine("Checking attribute: {0}", match.Value); - // Extract all nameof() references within this attribute var nameofMatches = nameofPattern.Matches(match.Value); - TestContext.Out.WriteLine("Found {0} nameof references in this attribute", nameofMatches.Count); foreach (Match nameofMatch in nameofMatches) { var propertyToNotify = nameofMatch.Groups[1].Value; - TestContext.Out.WriteLine("Checking for notification of property: {0}", propertyToNotify); // Verify that the generated code contains calls to raise property changed for the additional property // Check for various forms of property change notification @@ -285,29 +366,25 @@ private static void ValidateGeneratedCode(string sourceCode, GeneratorDriver dri allGeneratedCode.Contains($"RaisePropertyChanged(nameof({propertyToNotify}))") || allGeneratedCode.Contains($"RaisePropertyChanged(\"{propertyToNotify}\")"); - TestContext.Out.WriteLine("Has notification: {0}", hasNotification); - if (!hasNotification) { var errorMessage = $"Generated code does not include AlsoNotify for property '{propertyToNotify}'. " + $"Expected to find property change notification for '{propertyToNotify}' in the generated code.\n" + $"Source attribute: {match.Value}"; - TestContext.Out.WriteLine("=== VALIDATION FAILURE ==="); - TestContext.Out.WriteLine(errorMessage); - TestContext.Out.WriteLine("=== SOURCE CODE SNIPPET ==="); - TestContext.Out.WriteLine(match.Value); - TestContext.Out.WriteLine("=== GENERATED CODE ==="); - TestContext.Out.WriteLine(allGeneratedCode); - TestContext.Out.WriteLine("=== END ==="); + WriteTestOutput("=== VALIDATION FAILURE ==="); + WriteTestOutput(errorMessage); + WriteTestOutput("=== SOURCE CODE SNIPPET ==="); + WriteTestOutput(match.Value); + WriteTestOutput("=== GENERATED CODE ==="); + WriteTestOutput(allGeneratedCode); + WriteTestOutput("=== END ==="); throw new InvalidOperationException(errorMessage); } } } } - - TestContext.Out.WriteLine("=== END VALIDATION DEBUG ==="); } /// @@ -350,7 +427,36 @@ private static IEnumerable GetTransitiveReferences(params Ass } } + private static void WriteTestOutput(string message) => TestContext.Current?.OutputWriter.WriteLine(message); + + private static async Task CreateSharedEventCompilerAsync() + { +#if NET10_0_OR_GREATER + NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(10, 0, 0, 0))]; +#elif NET9_0_OR_GREATER + NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(9, 0, 0, 0))]; +#else + NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(8, 0, 0, 0))]; +#endif + + var inputGroup = await NuGetPackageHelper.DownloadPackageFilesAndFolder( + [SplatLibrary, ReactiveuiLibrary], + targetFrameworks, + packageOutputDirectory: null).ConfigureAwait(false); + + var framework = targetFrameworks[0]; + return new EventBuilderCompiler(inputGroup, inputGroup, framework); + } + private SettingsTask VerifyGenerator(GeneratorDriver driver) => Verify(driver) .UseDirectory(VerifiedFilePath()) .ScrubLinesContaining("[global::System.CodeDom.Compiler.GeneratedCode(\""); + + private async Task EnsureInitializedAsync() + { + if (_eventCompiler is null) + { + await InitializeAsync().ConfigureAwait(false); + } + } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/AttrMisuseExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/AttrMisuseExtTests.cs index c8c853e..a4880e1 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/AttrMisuseExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/AttrMisuseExtTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Extended unit tests for . /// -[TestFixture] public sealed class AttrMisuseExtTests { /// @@ -32,7 +31,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -56,7 +55,7 @@ public class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -80,7 +79,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -107,7 +106,7 @@ public class InnerVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -134,7 +133,7 @@ public partial class InnerVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -158,7 +157,7 @@ public record TestVMRecord : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -182,7 +181,7 @@ public partial record TestVMRecord : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -212,7 +211,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Count(d => d.Id == "RXUISG0020"), Is.EqualTo(3)); + AssertDiagnosticCount(diagnostics, "RXUISG0020", 3); } /// @@ -236,7 +235,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -266,7 +265,7 @@ public class Level3 : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -296,7 +295,7 @@ public partial class Level3 : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -319,7 +318,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -341,7 +340,7 @@ public class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -365,7 +364,7 @@ public partial class GenericVM : ReactiveObject where T : class var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -389,7 +388,7 @@ public partial class GenericVM : ReactiveObject where T : class var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -413,7 +412,7 @@ public record struct TestVMStruct var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -439,7 +438,7 @@ public partial class TestVM : ReactiveObject // [Reactive] on non-partial property should produce RXUISG0020 // because the attribute requires the property to be partial - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } private static Diagnostic[] GetDiagnostics(string source) @@ -460,4 +459,29 @@ private static Diagnostic[] GetDiagnostics(string source) var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); return compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().GetAwaiter().GetResult().ToArray(); } + + private static void AssertContainsDiagnostic(IEnumerable diagnostics, string diagnosticId) + { + if (!diagnostics.Any(d => d.Id == diagnosticId)) + { + throw new InvalidOperationException($"Expected diagnostic '{diagnosticId}' was not reported."); + } + } + + private static void AssertDoesNotContainDiagnostic(IEnumerable diagnostics, string diagnosticId) + { + if (diagnostics.Any(d => d.Id == diagnosticId)) + { + throw new InvalidOperationException($"Diagnostic '{diagnosticId}' was reported unexpectedly."); + } + } + + private static void AssertDiagnosticCount(IEnumerable diagnostics, string diagnosticId, int expectedCount) + { + var actualCount = diagnostics.Count(d => d.Id == diagnosticId); + if (actualCount != expectedCount) + { + throw new InvalidOperationException($"Expected {expectedCount} '{diagnosticId}' diagnostics but found {actualCount}."); + } + } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/BindableDerivedListGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/BindableDerivedListGeneratorTests.cs index 633794c..50b1651 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/BindableDerivedListGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/BindableDerivedListGeneratorTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// BindableDerivedListGeneratorTests. /// -[TestFixture] public class BindableDerivedListGeneratorTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/DerivedListExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/DerivedListExtTests.cs index 384e8d0..1f5939d 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/DerivedListExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/DerivedListExtTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Extended unit tests for the BindableDerivedList generator covering edge cases. /// -[TestFixture] public class DerivedListExtTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/IViewForGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/IViewForGeneratorTests.cs index fa15979..5915ab4 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/IViewForGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/IViewForGeneratorTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// IViewForGeneratorTests. /// -[TestFixture] public class IViewForGeneratorTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OAPFromObservableGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OAPFromObservableGeneratorTests.cs index 53f5ea6..8797462 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OAPFromObservableGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OAPFromObservableGeneratorTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for the ObservableAsProperty generator. /// -[TestFixture] public class OAPFromObservableGeneratorTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OAPGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OAPGeneratorTests.cs index a7d993e..d5addf8 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OAPGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OAPGeneratorTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for the ObservableAsProperty generator. /// -[TestFixture] public class OAPGeneratorTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OapExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OapExtTests.cs index 34f7ff3..b143937 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OapExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/OapExtTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Extended unit tests for the ObservableAsProperty generator covering edge cases. /// -[TestFixture] public class OapExtTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropAnalyzerExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropAnalyzerExtTests.cs index 614ee57..95ac367 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropAnalyzerExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropAnalyzerExtTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Extended unit tests for . /// -[TestFixture] public sealed class PropAnalyzerExtTests { /// @@ -30,7 +29,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -52,7 +51,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -74,7 +73,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -96,7 +95,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -119,7 +118,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -146,7 +145,7 @@ public string Name var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -169,7 +168,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -191,7 +190,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -215,7 +214,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -239,7 +238,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Count(d => d.Id == "RXUISG0016"), Is.EqualTo(3)); + AssertDiagnosticCount(diagnostics, "RXUISG0016", 3); } /// @@ -259,7 +258,7 @@ public class TestVM var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -284,7 +283,7 @@ public void RaisePropertyChanged(PropertyChangedEventArgs args) { } var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -309,7 +308,7 @@ public partial class InnerVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -331,7 +330,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -353,7 +352,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -375,7 +374,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -397,7 +396,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -420,7 +419,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); // Init-only properties have a setter (init), so the analyzer reports them - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -442,7 +441,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0016"); } private static Diagnostic[] GetDiagnostics(string source) @@ -460,4 +459,29 @@ private static Diagnostic[] GetDiagnostics(string source) var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); return compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().GetAwaiter().GetResult().ToArray(); } + + private static void AssertContainsDiagnostic(IEnumerable diagnostics, string diagnosticId) + { + if (!diagnostics.Any(d => d.Id == diagnosticId)) + { + throw new InvalidOperationException($"Expected diagnostic '{diagnosticId}' was not reported."); + } + } + + private static void AssertDoesNotContainDiagnostic(IEnumerable diagnostics, string diagnosticId) + { + if (diagnostics.Any(d => d.Id == diagnosticId)) + { + throw new InvalidOperationException($"Diagnostic '{diagnosticId}' was reported unexpectedly."); + } + } + + private static void AssertDiagnosticCount(IEnumerable diagnostics, string diagnosticId, int expectedCount) + { + var actualCount = diagnostics.Count(d => d.Id == diagnosticId); + if (actualCount != expectedCount) + { + throw new InvalidOperationException($"Expected {expectedCount} '{diagnosticId}' diagnostics but found {actualCount}."); + } + } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropertyToReactiveFieldAnalyzerTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropertyToReactiveFieldAnalyzerTests.cs index 75b4cab..2bc6aca 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropertyToReactiveFieldAnalyzerTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropertyToReactiveFieldAnalyzerTests.cs @@ -8,9 +8,26 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for . /// -[TestFixture] public sealed class PropertyToReactiveFieldAnalyzerTests { + /// + /// Validates the analyzer rejects a null analysis context. + /// + [Test] + public void InitializeWithNullContextThrows() + { + var analyzer = new PropertyToReactiveFieldAnalyzer(); + + try + { + analyzer.Initialize(null!); + throw new InvalidOperationException("Expected ArgumentNullException was not thrown."); + } + catch (ArgumentNullException ex) when (ex.ParamName == "context") + { + } + } + /// /// Validates a public auto-property triggers the suggestion to convert it into a reactive field. /// @@ -30,7 +47,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0016"); } /// @@ -54,7 +71,50 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0016"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); + } + + /// + /// Validates the syntax-based Reactive attribute fallback handles qualified names. + /// + [Test] + public void WhenQualifiedReactiveAttributePresentThenDoesNotReportDiagnostic() + { + const string source = """ + using ReactiveUI; + + namespace TestNs; + + public partial class TestVM : ReactiveObject + { + [ReactiveUI.SourceGenerators.Reactive] + public bool IsVisible { get; set; } + } + """; + + var diagnostics = GetDiagnostics(source); + + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0016"); + } + + /// + /// Validates the analyzer recognizes a fully qualified ReactiveObject base type. + /// + [Test] + public void WhenQualifiedReactiveBaseTypeThenReportsDiagnostic() + { + const string source = """ + namespace TestNs; + + public partial class TestVM : ReactiveUI.ReactiveObject + { + public bool IsVisible { get; set; } + } + """; + + var diagnostics = GetDiagnostics(source); + + AssertContainsDiagnostic(diagnostics, "RXUISG0016"); } private static Diagnostic[] GetDiagnostics(string source) @@ -72,4 +132,20 @@ private static Diagnostic[] GetDiagnostics(string source) var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); return compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().GetAwaiter().GetResult().ToArray(); } + + private static void AssertContainsDiagnostic(IEnumerable diagnostics, string diagnosticId) + { + if (!diagnostics.Any(d => d.Id == diagnosticId)) + { + throw new InvalidOperationException($"Expected diagnostic '{diagnosticId}' was not reported."); + } + } + + private static void AssertDoesNotContainDiagnostic(IEnumerable diagnostics, string diagnosticId) + { + if (diagnostics.Any(d => d.Id == diagnosticId)) + { + throw new InvalidOperationException($"Diagnostic '{diagnosticId}' was reported unexpectedly."); + } + } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropertyToReactiveFieldCodeFixProviderTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropertyToReactiveFieldCodeFixProviderTests.cs index ffe3a43..90e2612 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropertyToReactiveFieldCodeFixProviderTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/PropertyToReactiveFieldCodeFixProviderTests.cs @@ -10,9 +10,34 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for . /// -[TestFixture] public sealed class PropertyToReactiveFieldCodeFixProviderTests { + /// + /// Validates the code fix provider advertises the expected diagnostic ID. + /// + [Test] + public void FixableDiagnosticIdsIncludesReactiveFieldRule() + { + var provider = new PropertyToReactiveFieldCodeFixProvider(); + if (!provider.FixableDiagnosticIds.Contains("RXUISG0016")) + { + throw new InvalidOperationException("Expected RXUISG0016 to be fixable."); + } + } + + /// + /// Validates the code fix provider exposes a fix-all implementation. + /// + [Test] + public void GetFixAllProviderReturnsBatchFixer() + { + var provider = new PropertyToReactiveFieldCodeFixProvider(); + if (provider.GetFixAllProvider() is null) + { + throw new InvalidOperationException("Expected a fix-all provider."); + } + } + /// /// Validates a public auto-property is converted to a private field annotated with [Reactive]. /// @@ -32,9 +57,9 @@ public partial class TestVM : ReactiveObject var fixedSource = ApplyFix(source); - Assert.That(fixedSource, Does.Contain("[ReactiveUI.SourceGenerators.Reactive]")); - Assert.That(fixedSource, Does.Contain("private bool _isVisible")); - Assert.That(fixedSource, Does.Not.Contain("public bool IsVisible")); + AssertContains(fixedSource, "[ReactiveUI.SourceGenerators.Reactive]"); + AssertContains(fixedSource, "private bool _isVisible"); + AssertDoesNotContain(fixedSource, "public bool IsVisible"); } private static string ApplyFix(string source) @@ -83,4 +108,20 @@ private static string ApplyFix(string source) var updatedDoc = document.Project.Solution.Workspace.CurrentSolution.GetDocument(document.Id); return updatedDoc!.GetTextAsync(CancellationToken.None).GetAwaiter().GetResult().ToString(); } + + private static void AssertContains(string actual, string expected) + { + if (!actual.Contains(expected, StringComparison.Ordinal)) + { + throw new InvalidOperationException($"Expected output to contain '{expected}'."); + } + } + + private static void AssertDoesNotContain(string actual, string unexpected) + { + if (actual.Contains(unexpected, StringComparison.Ordinal)) + { + throw new InvalidOperationException($"Expected output not to contain '{unexpected}'."); + } + } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveAttributeMisuseAnalyzerTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveAttributeMisuseAnalyzerTests.cs index 0594255..fafaa78 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveAttributeMisuseAnalyzerTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveAttributeMisuseAnalyzerTests.cs @@ -8,9 +8,26 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for . /// -[TestFixture] public sealed class ReactiveAttributeMisuseAnalyzerTests { + /// + /// Validates the analyzer rejects a null analysis context. + /// + [Test] + public void InitializeWithNullContextThrows() + { + var analyzer = new ReactiveAttributeMisuseAnalyzer(); + + try + { + analyzer.Initialize(null!); + throw new InvalidOperationException("Expected ArgumentNullException was not thrown."); + } + catch (ArgumentNullException ex) when (ex.ParamName == "context") + { + } + } + /// /// Verifies a non-partial property annotated with [Reactive] produces a warning. /// @@ -32,7 +49,7 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -56,7 +73,7 @@ public class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.True); + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); } /// @@ -80,7 +97,55 @@ public partial class TestVM : ReactiveObject var diagnostics = GetDiagnostics(source); - Assert.That(diagnostics.Any(d => d.Id == "RXUISG0020"), Is.False); + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); + } + + /// + /// Verifies the analyzer recognizes the explicit ReactiveAttribute name. + /// + [Test] + public void WhenReactiveAttributeSuffixUsedThenWarns() + { + const string source = """ + using ReactiveUI; + using ReactiveUI.SourceGenerators; + + namespace TestNs; + + public partial class TestVM : ReactiveObject + { + [ReactiveAttribute] + public bool IsVisible { get; set; } + } + """; + + var diagnostics = GetDiagnostics(source); + + AssertContainsDiagnostic(diagnostics, "RXUISG0020"); + } + + /// + /// Verifies unrelated attributes do not trigger the diagnostic. + /// + [Test] + public void WhenOnlyNonReactiveAttributesExistThenDoesNotWarn() + { + const string source = """ + using System; + using ReactiveUI; + + namespace TestNs; + + public partial class TestVM : ReactiveObject + { + [Obsolete] + public bool IsVisible { get; set; } + } + """; + + var diagnostics = GetDiagnostics(source); + + AssertDoesNotContainDiagnostic(diagnostics, "RXUISG0020"); } private static Diagnostic[] GetDiagnostics(string source) @@ -101,4 +166,20 @@ private static Diagnostic[] GetDiagnostics(string source) var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); return compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().GetAwaiter().GetResult().ToArray(); } + + private static void AssertContainsDiagnostic(IEnumerable diagnostics, string diagnosticId) + { + if (!diagnostics.Any(d => d.Id == diagnosticId)) + { + throw new InvalidOperationException($"Expected diagnostic '{diagnosticId}' was not reported."); + } + } + + private static void AssertDoesNotContainDiagnostic(IEnumerable diagnostics, string diagnosticId) + { + if (diagnostics.Any(d => d.Id == diagnosticId)) + { + throw new InvalidOperationException($"Diagnostic '{diagnosticId}' was reported unexpectedly."); + } + } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveAttributeMisuseCodeFixProviderTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveAttributeMisuseCodeFixProviderTests.cs index d11286f..c483749 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveAttributeMisuseCodeFixProviderTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveAttributeMisuseCodeFixProviderTests.cs @@ -10,9 +10,34 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for . /// -[TestFixture] public sealed class ReactiveAttributeMisuseCodeFixProviderTests { + /// + /// Validates the code fix provider advertises the expected diagnostic ID. + /// + [Test] + public void FixableDiagnosticIdsIncludesReactivePartialRule() + { + var provider = new ReactiveAttributeMisuseCodeFixProvider(); + if (!provider.FixableDiagnosticIds.Contains("RXUISG0020")) + { + throw new InvalidOperationException("Expected RXUISG0020 to be fixable."); + } + } + + /// + /// Validates the code fix provider exposes a fix-all implementation. + /// + [Test] + public void GetFixAllProviderReturnsBatchFixer() + { + var provider = new ReactiveAttributeMisuseCodeFixProvider(); + if (provider.GetFixAllProvider() is null) + { + throw new InvalidOperationException("Expected a fix-all provider."); + } + } + /// /// Verifies `required` stays before `partial` when applying the code fix. /// @@ -34,8 +59,49 @@ public partial class TestVM : ReactiveObject var fixedSource = ApplyFix(source); - Assert.That(fixedSource, Does.Contain("public required partial string? PartialRequiredPropertyTest")); - Assert.That(fixedSource, Does.Not.Contain("public partial required string? PartialRequiredPropertyTest")); + AssertContains(fixedSource, "public required partial string? PartialRequiredPropertyTest"); + AssertDoesNotContain(fixedSource, "public partial required string? PartialRequiredPropertyTest"); + } + + /// + /// Verifies no code fix is registered when the diagnostic location is outside a property declaration. + /// + [Test] + public void WhenDiagnosticDoesNotTargetAPropertyThenNoCodeFixIsRegistered() + { + const string source = """ + using ReactiveUI; + + namespace TestNs; + + public class TestVM : ReactiveObject + { + } + """; + + using var workspace = new AdhocWorkspace(); + var project = workspace.CurrentSolution + .AddProject("p", "p", LanguageNames.CSharp) + .WithParseOptions(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13)) + .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) + .AddMetadataReference(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)) + .AddMetadataReference(MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)); + + var document = project.AddDocument("t.cs", source); + var root = document.GetSyntaxRootAsync(CancellationToken.None).GetAwaiter().GetResult()!; + var classDeclaration = root.DescendantNodes().OfType().Single(); + var diagnosticDescriptor = new ReactiveAttributeMisuseAnalyzer().SupportedDiagnostics.Single(d => d.Id == "RXUISG0020"); + var diagnostic = Diagnostic.Create(diagnosticDescriptor, classDeclaration.Identifier.GetLocation()); + var actions = new List(); + var context = new CodeFixContext(document, diagnostic, (a, _) => actions.Add(a), CancellationToken.None); + + var provider = new ReactiveAttributeMisuseCodeFixProvider(); + provider.RegisterCodeFixesAsync(context).GetAwaiter().GetResult(); + + if (actions.Count != 0) + { + throw new InvalidOperationException("Expected no code fixes to be registered."); + } } private static string ApplyFix(string source) @@ -85,4 +151,20 @@ private static string ApplyFix(string source) var updatedDoc = document.Project.Solution.Workspace.CurrentSolution.GetDocument(document.Id); return updatedDoc!.GetTextAsync(CancellationToken.None).GetAwaiter().GetResult().ToString(); } + + private static void AssertContains(string actual, string expected) + { + if (!actual.Contains(expected, StringComparison.Ordinal)) + { + throw new InvalidOperationException($"Expected output to contain '{expected}'."); + } + } + + private static void AssertDoesNotContain(string actual, string unexpected) + { + if (actual.Contains(unexpected, StringComparison.Ordinal)) + { + throw new InvalidOperationException($"Expected output not to contain '{unexpected}'."); + } + } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveCMDGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveCMDGeneratorTests.cs index 732c98b..6791a8b 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveCMDGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveCMDGeneratorTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for the ReactiveCommand generator. /// -[TestFixture] public class ReactiveCMDGeneratorTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveCollectionGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveCollectionGeneratorTests.cs index c05f5a4..90018a5 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveCollectionGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveCollectionGeneratorTests.cs @@ -9,7 +9,6 @@ namespace ReactiveUI.SourceGenerators.Tests; /// /// ReactiveCollectionGeneratorTests. /// -[TestFixture] public class ReactiveCollectionGeneratorTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs index 9efb05d..17bf575 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for the Reactive generator. /// -[TestFixture] public class ReactiveGeneratorTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs index 8ee4aa0..f70f901 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveObjectGeneratorTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Unit tests for the Reactive generator. /// -[TestFixture] public class ReactiveObjectGeneratorTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCmdExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCmdExtTests.cs index 2020ce0..4e05f04 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCmdExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCmdExtTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Extended unit tests for the ReactiveCommand generator covering edge cases. /// -[TestFixture] public class RxCmdExtTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCollExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCollExtTests.cs index fa69313..d914937 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCollExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCollExtTests.cs @@ -10,7 +10,6 @@ namespace ReactiveUI.SourceGenerators.Tests; /// /// Extended unit tests for the ReactiveCollection generator covering edge cases. /// -[TestFixture] public class RxCollExtTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxGenExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxGenExtTests.cs index 10ea600..32c0e5a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxGenExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxGenExtTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Extended unit tests for the Reactive generator covering edge cases. /// -[TestFixture] public class RxGenExtTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxObjExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxObjExtTests.cs index 33d5a69..5fd6395 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxObjExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxObjExtTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Extended unit tests for the ReactiveObject generator covering edge cases. /// -[TestFixture] public class RxObjExtTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs index 67a34c2..a8058c6 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs @@ -43,7 +43,7 @@ private static void TryAdd(AssemblyName assemblyName, HashSet set) { try { - var loaded = Assembly.Load(assemblyName); + var loaded = System.Reflection.Assembly.Load(assemblyName); if (!string.IsNullOrWhiteSpace(loaded.Location)) { @@ -54,7 +54,7 @@ private static void TryAdd(AssemblyName assemblyName, HashSet set) { try { - var referencedLoaded = Assembly.Load(referenced); + var referencedLoaded = System.Reflection.Assembly.Load(referenced); if (!string.IsNullOrWhiteSpace(referencedLoaded.Location)) { diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ViewForExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ViewForExtTests.cs index 1a3904c..8785a90 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ViewForExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ViewForExtTests.cs @@ -8,7 +8,6 @@ namespace ReactiveUI.SourceGenerator.Tests; /// /// Extended unit tests for the IViewFor generator covering edge cases. /// -[TestFixture] public class ViewForExtTests : TestBase { /// diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/AttributeDataExtensions.cs b/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/AttributeDataExtensions.cs index 466f4f2..caa2ee2 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/AttributeDataExtensions.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/AttributeDataExtensions.cs @@ -31,13 +31,25 @@ internal static class AttributeDataExtensions /// Whether or not contains an argument named with a valid value. public static bool TryGetNamedArgument(this AttributeData attributeData, string name, out T? value) { - foreach (var properties in attributeData.NamedArguments) + if (attributeData is null) { - if (properties.Key == name) + value = default; + return false; + } + + try + { + foreach (var properties in attributeData.NamedArguments) { - return TryConvertNamedArgument(properties.Value, out value); + if (properties.Key == name) + { + return TryConvertNamedArgument(properties.Value, out value); + } } } + catch (NullReferenceException) + { + } value = default; @@ -53,13 +65,24 @@ public static bool TryGetNamedArgument(this AttributeData attributeData, stri /// The named argument value. public static T? GetNamedArgument(this AttributeData attributeData, string name) { - foreach (var properties in attributeData.NamedArguments) + if (attributeData is null) { - if (properties.Key == name) + return default; + } + + try + { + foreach (var properties in attributeData.NamedArguments) { - return TryConvertNamedArgument(properties.Value, out T? value) ? value : default; + if (properties.Key == name) + { + return TryConvertNamedArgument(properties.Value, out T? value) ? value : default; + } } } + catch (NullReferenceException) + { + } return default; } @@ -168,8 +191,18 @@ static void GatherForwardedAttributes( public static string? GetGenericType(this AttributeData attributeData) { var success = attributeData?.AttributeClass?.ToDisplayString(); - var start = success?.IndexOf('<') + 1 ?? 0; - return success?.Substring(start, success.Length - start - 1); + if (string.IsNullOrWhiteSpace(success)) + { + return null; + } + + var attributeClassName = success ?? string.Empty; + var start = attributeClassName.IndexOf('<'); + var end = attributeClassName.LastIndexOf('>'); + + return start >= 0 && end > start + ? attributeClassName.Substring(start + 1, end - start - 1) + : null; } private static bool TryConvertNamedArgument(in TypedConstant typedConstant, out T? value) @@ -190,6 +223,26 @@ private static bool TryConvertNamedArgument(in TypedConstant typedConstant, o var targetType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); + if (targetType.IsEnum) + { + try + { + if (rawValue is string enumName) + { + value = (T)Enum.Parse(targetType, enumName, ignoreCase: false); + return true; + } + + value = (T)Enum.ToObject(targetType, rawValue); + return true; + } + catch (ArgumentException) + { + value = default; + return false; + } + } + try { value = (T)Convert.ChangeType(rawValue, targetType, CultureInfo.InvariantCulture); @@ -214,6 +267,11 @@ private static bool TryConvertNamedArgument(in TypedConstant typedConstant, o private static object? TryGetRawValue(in TypedConstant typedConstant) { + if (typedConstant.Kind == TypedConstantKind.Error) + { + return null; + } + if (typedConstant.Type?.TypeKind == TypeKind.Enum) { if (typedConstant.Value is IFieldSymbol fieldSymbol) @@ -228,9 +286,16 @@ private static bool TryConvertNamedArgument(in TypedConstant typedConstant, o if (typedConstant.Type is INamedTypeSymbol enumType) { - var enumMemberName = typedConstant.ToCSharpString().Split('.').LastOrDefault(); - return enumType.GetMembers(enumMemberName ?? string.Empty).OfType().FirstOrDefault()?.ConstantValue; + var csharpValue = typedConstant.ToCSharpString(); + + if (!string.IsNullOrWhiteSpace(csharpValue)) + { + var enumMemberName = csharpValue.Split('.').LastOrDefault(); + return enumType.GetMembers(enumMemberName ?? string.Empty).OfType().FirstOrDefault()?.ConstantValue; + } } + + return null; } return typedConstant.Value; diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.Execute.cs b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.Execute.cs index 811f7a4..55a9cdf 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.Execute.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/ReactiveCommand/ReactiveCommandGenerator.Execute.cs @@ -40,16 +40,14 @@ public partial class ReactiveCommandGenerator private static CommandInfo? GetMethodInfo(in GeneratorAttributeSyntaxContext context, CancellationToken token) { var symbol = context.TargetSymbol; - if (!symbol.TryGetAttributeWithFullyQualifiedMetadataName(AttributeDefinitions.ReactiveCommandAttributeType, out var attributeData)) - { - return null; - } if (symbol is not IMethodSymbol methodSymbol) { return default; } + var attributeData = context.Attributes[0]; + token.ThrowIfCancellationRequested(); using var builder = ImmutableArrayBuilder.Rent(); diff --git a/src/ReactiveUI.SourceGenerators.slnx b/src/ReactiveUI.SourceGenerators.slnx index 1293b37..135387d 100644 --- a/src/ReactiveUI.SourceGenerators.slnx +++ b/src/ReactiveUI.SourceGenerators.slnx @@ -7,7 +7,9 @@ + + diff --git a/src/global.json b/src/global.json new file mode 100644 index 0000000..3140116 --- /dev/null +++ b/src/global.json @@ -0,0 +1,5 @@ +{ + "test": { + "runner": "Microsoft.Testing.Platform" + } +} diff --git a/src/testconfig.json b/src/testconfig.json new file mode 100644 index 0000000..8f7dd8c --- /dev/null +++ b/src/testconfig.json @@ -0,0 +1,26 @@ +{ + "platform": { + "execution": { + "parallel": false + } + }, + "extensions": [ + { + "extensionId": "Microsoft.Testing.Extensions.CodeCoverage", + "settings": { + "format": "cobertura", + "skipAutoProperties": true, + "modulePaths": { + "include": [ + "ReactiveUI\\.SourceGenerators(\\..+)?" + ], + "exclude": [ + ".*Tests.*", + ".*TestRunner.*", + ".*TestModels.*" + ] + } + } + } + ] +} From 832eda6ed8f8f9559bfe7c783b8a127807314f6d Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sat, 4 Apr 2026 00:14:14 +0100 Subject: [PATCH 02/10] Add generated test files and update packages Add numerous generated .g.verified.cs test artifacts for source-generator unit tests (DERIVEDLIST, IVIEWFOR, OAPH, REACTIVE, REACTIVECMD, RxCmd/RxGen/Oap extensions, etc.). Update Directory.Packages.props to remove some NuGet entries, bump Microsoft.Extensions.Logging.Debug and System.Formats.Asn1 to 10.0.5, consolidate ReactiveUI.Maui to 23.2.1, and prune several test/reference packages. Also update generated view registrations in ReactiveUI.ReactiveUISourceGeneratorsExtensions and tweak several test project and helper files to match the generated outputs. --- src/Directory.Packages.props | 15 +- ...s.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 24 ++ ...1.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...2.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...ericVM`1.BindableDerivedList.g.verified.cs | 21 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 24 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 27 ++ ...pInnerVM.BindableDerivedList.g.verified.cs | 28 ++ ...+InnerVM.BindableDerivedList.g.verified.cs | 25 ++ ....OuterVM.BindableDerivedList.g.verified.cs | 21 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...VMRecord.BindableDerivedList.g.verified.cs | 24 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...s.TestVM.BindableDerivedList.g.verified.cs | 21 ++ ...#TestNs.TestViewWpf.IViewFor.g.verified.cs | 35 ++ ...UISourceGeneratorsExtensions.g.verified.cs | 2 + ...pts#TestNs.FullView.IViewFor.g.verified.cs | 35 ++ ...UISourceGeneratorsExtensions.g.verified.cs | 1 + ...ant#TestNs.TestView.IViewFor.g.verified.cs | 35 ++ ...s#Views.ProductView.IViewFor.g.verified.cs | 35 ++ ....Views.ExternalView.IViewFor.g.verified.cs | 35 ++ ...ontainer+NestedView.IViewFor.g.verified.cs | 42 +++ ...TestNs.CommandsView.IViewFor.g.verified.cs | 35 ++ ...ctivePropertiesView.IViewFor.g.verified.cs | 35 ++ ...ype#TestNs.TestView.IViewFor.g.verified.cs | 35 ++ ...UISourceGeneratorsExtensions.g.verified.cs | 2 + ...ion#TestNs.TestView.IViewFor.g.verified.cs | 35 ++ ...UISourceGeneratorsExtensions.g.verified.cs | 1 + ...espace#TestNs.View1.IViewFor.g.verified.cs | 35 ++ ...espace#TestNs.View2.IViewFor.g.verified.cs | 35 ++ ...espace#TestNs.View3.IViewFor.g.verified.cs | 35 ++ ...stNs.StringItemView.IViewFor.g.verified.cs | 35 ++ ...estNs.InterfaceView.IViewFor.g.verified.cs | 35 ++ ...UISourceGeneratorsExtensions.g.verified.cs | 1 + ...gle#TestNs.TestView.IViewFor.g.verified.cs | 35 ++ ...ed#TestNs.ChildView.IViewFor.g.verified.cs | 35 ++ ...UISourceGeneratorsExtensions.g.verified.cs | 1 + ...Req#TestNs.TestView.IViewFor.g.verified.cs | 35 ++ ...d#TestNs.RecordView.IViewFor.g.verified.cs | 35 ++ ...ableAsPropertyFromObservable.g.verified.cs | 15 +- ...ableAsPropertyFromObservable.g.verified.cs | 15 +- ...ableAsPropertyFromObservable.g.verified.cs | 14 +- ...ableAsPropertyFromObservable.g.verified.cs | 3 +- ...ableAsPropertyFromObservable.g.verified.cs | 15 +- ...ableAsPropertyFromObservable.g.verified.cs | 14 +- ...estVM.ObservableAsProperties.g.verified.cs | 2 +- ...estVM.ObservableAsProperties.g.verified.cs | 2 +- ...estVM.ObservableAsProperties.g.verified.cs | 2 +- ...ableAsPropertyFromObservable.g.verified.cs | 1 + ...estVM.ObservableAsProperties.g.verified.cs | 2 +- ...estVM.ObservableAsProperties.g.verified.cs | 4 +- ...ableAsPropertyFromObservable.g.verified.cs | 28 +- ...sic#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...ify#TestNs.TestVM.Properties.g.verified.cs | 4 +- ...ess#TestNs.TestVM.Properties.g.verified.cs | 5 +- ...rit#TestNs.TestVM.Properties.g.verified.cs | 4 +- ...tes#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...ss#TestNs1.TestVM.Properties.g.verified.cs | 4 +- ...ss#TestNs2.TestVM.Properties.g.verified.cs | 4 +- ...nit#TestNs.TestVM.Properties.g.verified.cs | 4 +- ...3+TestInnerClass1.Properties.g.verified.cs | 6 +- ...2+TestInnerClass3.Properties.g.verified.cs | 6 +- ...3+TestInnerClass2.Properties.g.verified.cs | 6 +- ...s1.TestViewModel3.Properties.g.verified.cs | 6 +- ...el3+Level4+Level5.Properties.g.verified.cs | 3 +- ...el2+Level3+Level4.Properties.g.verified.cs | 3 +- ...el1+Level2+Level3.Properties.g.verified.cs | 3 +- ...tNs.Level1+Level2.Properties.g.verified.cs | 3 +- ...ted#TestNs.Level1.Properties.g.verified.cs | 3 +- ...ums#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...estNs.GenericVM`1.Properties.g.verified.cs | 3 +- ...ess#TestNs.TestVM.Properties.g.verified.cs | 10 +- ...lso#TestNs.TestVM.Properties.g.verified.cs | 4 + ...ttr#TestNs.TestVM.Properties.g.verified.cs | 2 +- ...ial#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...#TestNs.DerivedVM.Properties.g.verified.cs | 2 +- ...ble#TestNs.TestVM.Properties.g.verified.cs | 12 +- ...ide#TestNs.BaseVM.Properties.g.verified.cs | 2 +- ...#TestNs.DerivedVM.Properties.g.verified.cs | 2 +- ...nly#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...stNs.TestVMRecord.Properties.g.verified.cs | 3 +- ...uct#TestNs.TestVM.Properties.g.verified.cs | 3 +- ...ime#TestNs.TestVM.Properties.g.verified.cs | 18 +- ...les#TestNs.TestVM.Properties.g.verified.cs | 6 +- ...stNs.TestVM.ReactiveCommands.g.verified.cs | 4 +- ...stNs.TestVM.ReactiveCommands.g.verified.cs | 6 +- ...GenericVM`1.ReactiveCommands.g.verified.cs | 4 +- ...ors.ReactiveCommandAttribute.g.verified.cs | 44 +++ ...stNs.TestVM.ReactiveCommands.g.verified.cs | 20 ++ ...stNs.TestVM.ReactiveCommands.g.verified.cs | 6 +- ...stNs.TestVM.ReactiveCommands.g.verified.cs | 6 +- ...ors.ReactiveCommandAttribute.g.verified.cs | 44 +++ ...stNs.TestVM.ReactiveCommands.g.verified.cs | 25 ++ .../ReactiveUI.SourceGenerators.Tests.csproj | 22 +- .../TestHelper.cs | 334 +++++++++--------- .../UnitTests/IViewForGeneratorTests.cs | 1 + .../UnitTests/RxCmdExtTests.cs | 66 +++- .../UnitTests/RxObjExtTests.cs | 2 - .../UnitTests/TestCompilationReferences.cs | 245 +++++++++++-- .../UnitTests/ViewForExtTests.cs | 50 ++- ...iveUI.SourceGenerators.Execute.Maui.csproj | 1 + ...UI.SourceGenerators.Execute.Nested1.csproj | 1 + ...UI.SourceGenerators.Execute.Nested2.csproj | 1 + ...UI.SourceGenerators.Execute.Nested3.csproj | 1 + ...ReactiveUI.SourceGenerators.Execute.csproj | 1 + .../IViewFor/IViewForGenerator.Execute.cs | 23 +- .../IViewFor/IViewForGenerator.cs | 2 +- 111 files changed, 1834 insertions(+), 416 deletions(-) create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/BindableDerivedListGeneratorTests.FromReactiveProperties#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.ComplexGeneric#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DateTimeType#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DiffNamespaces#Namespace1.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DiffNamespaces#Namespace2.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.EnumType#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.GenericClass#TestNs.GenericVM`1.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.GuidType#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.InterfaceType#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.MultipleLists#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM+InnerVM+DeepInnerVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM+InnerVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NullableElements#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.RecordClass#TestNs.TestVMRecord.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.StructType#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.TupleType#TestNs.TestVM.BindableDerivedList.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/IViewForGeneratorTests.Basic#TestNs.TestViewWpf.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.AllRegOpts#TestNs.FullView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Constant#TestNs.TestView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.DiffNs#Views.ProductView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.ExtNs#App.Views.ExternalView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithNestedViewClass#TestNs.OuterContainer+MiddleContainer+NestedView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithReactiveCommandsViewModel#TestNs.CommandsView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithReactivePropertiesViewModel#TestNs.ReactivePropertiesView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithStringViewModelType#TestNs.TestView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithViewModelRegistration#TestNs.TestView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View1.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View2.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View3.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Generic#TestNs.StringItemView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Interface#TestNs.InterfaceView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.LazySingle#TestNs.TestView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Nested#TestNs.ChildView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.PerReq#TestNs.TestView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Record#TestNs.RecordView.IViewFor.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithCanExecuteMethod#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithCanExecuteMethod#TestNs.TestVM.ReactiveCommands.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandsAcrossPartialDeclarations#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandsAcrossPartialDeclarations#TestNs.TestVM.ReactiveCommands.g.verified.cs diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index e1c44b9..c7dc358 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -7,8 +7,6 @@ - - @@ -26,20 +24,13 @@ - - + - - + - - - - - - + diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/BindableDerivedListGeneratorTests.FromReactiveProperties#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/BindableDerivedListGeneratorTests.FromReactiveProperties#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..a59391b --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/BindableDerivedListGeneratorTests.FromReactiveProperties#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection Test1 => _test1; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.ComplexGeneric#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.ComplexGeneric#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..ca5f477 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.ComplexGeneric#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Items => _items; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DateTimeType#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DateTimeType#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..2ed8ef7 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DateTimeType#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,24 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Dates => _dates; + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Timestamps => _timestamps; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DiffNamespaces#Namespace1.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DiffNamespaces#Namespace1.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..15396e5 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DiffNamespaces#Namespace1.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: Namespace1.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace Namespace1 +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Numbers => _numbers; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DiffNamespaces#Namespace2.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DiffNamespaces#Namespace2.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..2e67d3f --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.DiffNamespaces#Namespace2.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: Namespace2.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace Namespace2 +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Names => _names; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.EnumType#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.EnumType#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..33eeeff --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.EnumType#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Statuses => _statuses; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.GenericClass#TestNs.GenericVM`1.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.GenericClass#TestNs.GenericVM`1.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..201d33d --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.GenericClass#TestNs.GenericVM`1.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.GenericVM`1.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class GenericVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Items => _items; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.GuidType#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.GuidType#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..5d417e5 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.GuidType#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Ids => _ids; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.InterfaceType#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.InterfaceType#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..1d65ddc --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.InterfaceType#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,24 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Items => _items; + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Disposables => _disposables; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.MultipleLists#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.MultipleLists#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..e20ef2e --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.MultipleLists#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,27 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Names => _names; + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Numbers => _numbers; + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Values => _values; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM+InnerVM+DeepInnerVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM+InnerVM+DeepInnerVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..4f05c1b --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM+InnerVM+DeepInnerVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,28 @@ +//HintName: TestNs.OuterVM+InnerVM+DeepInnerVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + public partial class OuterVM +{ +public partial class InnerVM +{ + + public partial class DeepInnerVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? DeepList => _deepList; + } +} +} + +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM+InnerVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM+InnerVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..fd893ab --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM+InnerVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,25 @@ +//HintName: TestNs.OuterVM+InnerVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + public partial class OuterVM +{ + + public partial class InnerVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? InnerList => _innerList; + } +} + +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..b44a109 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NestedClass#TestNs.OuterVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.OuterVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class OuterVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? OuterList => _outerList; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NullableElements#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NullableElements#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..9ddf0bf --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.NullableElements#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? NullableStrings => _nullableStrings; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.RecordClass#TestNs.TestVMRecord.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.RecordClass#TestNs.TestVMRecord.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..4146e6b --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.RecordClass#TestNs.TestVMRecord.BindableDerivedList.g.verified.cs @@ -0,0 +1,24 @@ +//HintName: TestNs.TestVMRecord.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial record TestVMRecord + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Numbers => _numbers; + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Names => _names; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.StructType#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.StructType#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..b4825ac --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.StructType#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection? Points => _points; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.TupleType#TestNs.TestVM.BindableDerivedList.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.TupleType#TestNs.TestVM.BindableDerivedList.g.verified.cs new file mode 100644 index 0000000..54ab92b --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/DERIVEDLIST/DerivedListExtTests.TupleType#TestNs.TestVM.BindableDerivedList.g.verified.cs @@ -0,0 +1,21 @@ +//HintName: TestNs.TestVM.BindableDerivedList.g.cs +// +using System.Collections.ObjectModel; +using DynamicData; +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::System.Collections.ObjectModel.ReadOnlyObservableCollection<(int Id, string Name)>? Tuples => _tuples; + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/IViewForGeneratorTests.Basic#TestNs.TestViewWpf.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/IViewForGeneratorTests.Basic#TestNs.TestViewWpf.IViewFor.g.verified.cs new file mode 100644 index 0000000..7fcbdc9 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/IViewForGeneratorTests.Basic#TestNs.TestViewWpf.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.TestViewWpf.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the TestViewWpf which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class TestViewWpf : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.TestViewModel), typeof(TestViewWpf), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.TestViewModel BindingRoot => ViewModel; + + /// + public TestNs.TestViewModel ViewModel { get => (TestNs.TestViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.TestViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.AllRegOpts#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.AllRegOpts#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs index ee04db7..08cdb68 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.AllRegOpts#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.AllRegOpts#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs @@ -16,6 +16,8 @@ internal static class ReactiveUISourceGeneratorsExtensions public static void RegisterViewsForViewModelsSourceGenerated(this global::Splat.IMutableDependencyResolver resolver) { if (resolver is null) throw new global::System.ArgumentNullException(nameof(resolver)); + resolver.RegisterConstant>(new global::TestNs.FullView()); + resolver.Register(); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.AllRegOpts#TestNs.FullView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.AllRegOpts#TestNs.FullView.IViewFor.g.verified.cs new file mode 100644 index 0000000..a035107 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.AllRegOpts#TestNs.FullView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.FullView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the FullView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class FullView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.FullViewModel), typeof(FullView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.FullViewModel BindingRoot => ViewModel; + + /// + public TestNs.FullViewModel ViewModel { get => (TestNs.FullViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.FullViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Constant#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Constant#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs index ee04db7..c6758a7 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Constant#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Constant#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs @@ -16,6 +16,7 @@ internal static class ReactiveUISourceGeneratorsExtensions public static void RegisterViewsForViewModelsSourceGenerated(this global::Splat.IMutableDependencyResolver resolver) { if (resolver is null) throw new global::System.ArgumentNullException(nameof(resolver)); + resolver.RegisterConstant>(new global::TestNs.TestView()); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Constant#TestNs.TestView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Constant#TestNs.TestView.IViewFor.g.verified.cs new file mode 100644 index 0000000..cf05cbc --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Constant#TestNs.TestView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.TestView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the TestView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class TestView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.TestViewModel), typeof(TestView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.TestViewModel BindingRoot => ViewModel; + + /// + public TestNs.TestViewModel ViewModel { get => (TestNs.TestViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.TestViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.DiffNs#Views.ProductView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.DiffNs#Views.ProductView.IViewFor.g.verified.cs new file mode 100644 index 0000000..05bb18e --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.DiffNs#Views.ProductView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: Views.ProductView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace Views +{ + /// + /// Partial class for the ProductView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class ProductView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(ViewModels.ProductViewModel), typeof(ProductView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public ViewModels.ProductViewModel BindingRoot => ViewModel; + + /// + public ViewModels.ProductViewModel ViewModel { get => (ViewModels.ProductViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (ViewModels.ProductViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.ExtNs#App.Views.ExternalView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.ExtNs#App.Views.ExternalView.IViewFor.g.verified.cs new file mode 100644 index 0000000..412cfcd --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.ExtNs#App.Views.ExternalView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: App.Views.ExternalView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace App.Views +{ + /// + /// Partial class for the ExternalView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class ExternalView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(External.ViewModels.ExternalViewModel), typeof(ExternalView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public External.ViewModels.ExternalViewModel BindingRoot => ViewModel; + + /// + public External.ViewModels.ExternalViewModel ViewModel { get => (External.ViewModels.ExternalViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (External.ViewModels.ExternalViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithNestedViewClass#TestNs.OuterContainer+MiddleContainer+NestedView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithNestedViewClass#TestNs.OuterContainer+MiddleContainer+NestedView.IViewFor.g.verified.cs new file mode 100644 index 0000000..1da30ec --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithNestedViewClass#TestNs.OuterContainer+MiddleContainer+NestedView.IViewFor.g.verified.cs @@ -0,0 +1,42 @@ +//HintName: TestNs.OuterContainer+MiddleContainer+NestedView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ +public partial class OuterContainer +{ +public partial class MiddleContainer +{ + /// + /// Partial class for the NestedView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class NestedView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.TestViewModel), typeof(NestedView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.TestViewModel BindingRoot => ViewModel; + + /// + public TestNs.TestViewModel ViewModel { get => (TestNs.TestViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.TestViewModel)value; } + } + +} +} +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithReactiveCommandsViewModel#TestNs.CommandsView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithReactiveCommandsViewModel#TestNs.CommandsView.IViewFor.g.verified.cs new file mode 100644 index 0000000..c041712 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithReactiveCommandsViewModel#TestNs.CommandsView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.CommandsView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the CommandsView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class CommandsView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.CommandsViewModel), typeof(CommandsView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.CommandsViewModel BindingRoot => ViewModel; + + /// + public TestNs.CommandsViewModel ViewModel { get => (TestNs.CommandsViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.CommandsViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithReactivePropertiesViewModel#TestNs.ReactivePropertiesView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithReactivePropertiesViewModel#TestNs.ReactivePropertiesView.IViewFor.g.verified.cs new file mode 100644 index 0000000..f24a001 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithReactivePropertiesViewModel#TestNs.ReactivePropertiesView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.ReactivePropertiesView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the ReactivePropertiesView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class ReactivePropertiesView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.ReactivePropertiesViewModel), typeof(ReactivePropertiesView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.ReactivePropertiesViewModel BindingRoot => ViewModel; + + /// + public TestNs.ReactivePropertiesViewModel ViewModel { get => (TestNs.ReactivePropertiesViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.ReactivePropertiesViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithStringViewModelType#TestNs.TestView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithStringViewModelType#TestNs.TestView.IViewFor.g.verified.cs new file mode 100644 index 0000000..cf05cbc --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithStringViewModelType#TestNs.TestView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.TestView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the TestView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class TestView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.TestViewModel), typeof(TestView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.TestViewModel BindingRoot => ViewModel; + + /// + public TestNs.TestViewModel ViewModel { get => (TestNs.TestViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.TestViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithViewModelRegistration#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithViewModelRegistration#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs index ee04db7..9b9b7c8 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithViewModelRegistration#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithViewModelRegistration#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs @@ -16,6 +16,8 @@ internal static class ReactiveUISourceGeneratorsExtensions public static void RegisterViewsForViewModelsSourceGenerated(this global::Splat.IMutableDependencyResolver resolver) { if (resolver is null) throw new global::System.ArgumentNullException(nameof(resolver)); + resolver.RegisterLazySingleton>(() => new global::TestNs.TestView()); + resolver.RegisterLazySingleton(() => new global::TestNs.TestViewModel()); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithViewModelRegistration#TestNs.TestView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithViewModelRegistration#TestNs.TestView.IViewFor.g.verified.cs new file mode 100644 index 0000000..cf05cbc --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromIViewForWithViewModelRegistration#TestNs.TestView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.TestView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the TestView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class TestView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.TestViewModel), typeof(TestView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.TestViewModel BindingRoot => ViewModel; + + /// + public TestNs.TestViewModel ViewModel { get => (TestNs.TestViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.TestViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs index ee04db7..e812246 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs @@ -16,6 +16,7 @@ internal static class ReactiveUISourceGeneratorsExtensions public static void RegisterViewsForViewModelsSourceGenerated(this global::Splat.IMutableDependencyResolver resolver) { if (resolver is null) throw new global::System.ArgumentNullException(nameof(resolver)); + resolver.RegisterLazySingleton>(() => new global::TestNs.View3()); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View1.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View1.IViewFor.g.verified.cs new file mode 100644 index 0000000..ee2f20c --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View1.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.View1.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the View1 which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class View1 : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.ViewModel1), typeof(View1), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.ViewModel1 BindingRoot => ViewModel; + + /// + public TestNs.ViewModel1 ViewModel { get => (TestNs.ViewModel1)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.ViewModel1)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View2.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View2.IViewFor.g.verified.cs new file mode 100644 index 0000000..4f704a7 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View2.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.View2.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the View2 which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class View2 : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.ViewModel2), typeof(View2), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.ViewModel2 BindingRoot => ViewModel; + + /// + public TestNs.ViewModel2 ViewModel { get => (TestNs.ViewModel2)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.ViewModel2)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View3.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View3.IViewFor.g.verified.cs new file mode 100644 index 0000000..2b2f1db --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.FromMultipleIViewForInSameNamespace#TestNs.View3.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.View3.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the View3 which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class View3 : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.ViewModel3), typeof(View3), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.ViewModel3 BindingRoot => ViewModel; + + /// + public TestNs.ViewModel3 ViewModel { get => (TestNs.ViewModel3)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.ViewModel3)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Generic#TestNs.StringItemView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Generic#TestNs.StringItemView.IViewFor.g.verified.cs new file mode 100644 index 0000000..cbca553 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Generic#TestNs.StringItemView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.StringItemView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the StringItemView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class StringItemView : IViewFor> + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.GenericViewModel), typeof(StringItemView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.GenericViewModel BindingRoot => ViewModel; + + /// + public TestNs.GenericViewModel ViewModel { get => (TestNs.GenericViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.GenericViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Interface#TestNs.InterfaceView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Interface#TestNs.InterfaceView.IViewFor.g.verified.cs new file mode 100644 index 0000000..5a45ea8 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Interface#TestNs.InterfaceView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.InterfaceView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the InterfaceView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class InterfaceView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.ITestViewModel), typeof(InterfaceView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.ITestViewModel BindingRoot => ViewModel; + + /// + public TestNs.ITestViewModel ViewModel { get => (TestNs.ITestViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.ITestViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.LazySingle#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.LazySingle#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs index ee04db7..09a9a9f 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.LazySingle#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.LazySingle#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs @@ -16,6 +16,7 @@ internal static class ReactiveUISourceGeneratorsExtensions public static void RegisterViewsForViewModelsSourceGenerated(this global::Splat.IMutableDependencyResolver resolver) { if (resolver is null) throw new global::System.ArgumentNullException(nameof(resolver)); + resolver.RegisterLazySingleton>(() => new global::TestNs.TestView()); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.LazySingle#TestNs.TestView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.LazySingle#TestNs.TestView.IViewFor.g.verified.cs new file mode 100644 index 0000000..cf05cbc --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.LazySingle#TestNs.TestView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.TestView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the TestView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class TestView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.TestViewModel), typeof(TestView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.TestViewModel BindingRoot => ViewModel; + + /// + public TestNs.TestViewModel ViewModel { get => (TestNs.TestViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.TestViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Nested#TestNs.ChildView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Nested#TestNs.ChildView.IViewFor.g.verified.cs new file mode 100644 index 0000000..6a22827 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Nested#TestNs.ChildView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.ChildView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the ChildView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class ChildView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.ParentViewModel.ChildViewModel), typeof(ChildView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.ParentViewModel.ChildViewModel BindingRoot => ViewModel; + + /// + public TestNs.ParentViewModel.ChildViewModel ViewModel { get => (TestNs.ParentViewModel.ChildViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.ParentViewModel.ChildViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.PerReq#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.PerReq#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs index ee04db7..d5913d0 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.PerReq#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.PerReq#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs @@ -16,6 +16,7 @@ internal static class ReactiveUISourceGeneratorsExtensions public static void RegisterViewsForViewModelsSourceGenerated(this global::Splat.IMutableDependencyResolver resolver) { if (resolver is null) throw new global::System.ArgumentNullException(nameof(resolver)); + resolver.Register, global::TestNs.TestView>(); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.PerReq#TestNs.TestView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.PerReq#TestNs.TestView.IViewFor.g.verified.cs new file mode 100644 index 0000000..cf05cbc --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.PerReq#TestNs.TestView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.TestView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the TestView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class TestView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.TestViewModel), typeof(TestView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.TestViewModel BindingRoot => ViewModel; + + /// + public TestNs.TestViewModel ViewModel { get => (TestNs.TestViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.TestViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Record#TestNs.RecordView.IViewFor.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Record#TestNs.RecordView.IViewFor.g.verified.cs new file mode 100644 index 0000000..d442e6f --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/ViewForExtTests.Record#TestNs.RecordView.IViewFor.g.verified.cs @@ -0,0 +1,35 @@ +//HintName: TestNs.RecordView.IViewFor.g.cs +// +using ReactiveUI; +using System.Windows; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + /// + /// Partial class for the RecordView which contains ReactiveUI IViewFor initialization. + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public partial class RecordView : IViewFor + { + /// + /// The view model dependency property. + /// + public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(TestNs.RecordViewModel), typeof(RecordView), new PropertyMetadata(null)); + + /// + /// Gets the binding root view model. + /// + public TestNs.RecordViewModel BindingRoot => ViewModel; + + /// + public TestNs.RecordViewModel ViewModel { get => (TestNs.RecordViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } + + /// + object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = (TestNs.RecordViewModel)value; } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrNullRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrNullRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 117817b..e83082d 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrNullRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrNullRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,22 +10,23 @@ namespace TestNs public partial class TestVM { - /// - private object? _test7Property; + /// + private object? _myNamedProperty; - /// - private ReactiveUI.ObservableAsPropertyHelper? _test7PropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public object? Test7Property { get => _test7Property = (_test7PropertyHelper == null ? _test7Property : _test7PropertyHelper.Value); } + public object? MyNamedProperty { get => _myNamedProperty = (_myNamedPropertyHelper == null ? _myNamedProperty : _myNamedPropertyHelper.Value); } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _test7PropertyHelper = Test7!.ToProperty(this, nameof(Test7Property)); + _myNamedPropertyHelper = Test7!.ToProperty(this, nameof(MyNamedProperty)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index af72674..7b1a883 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.AttrRef#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,22 +10,23 @@ namespace TestNs public partial class TestVM { - /// - private object _test6Property; + /// + private object _myNamedProperty; - /// - private ReactiveUI.ObservableAsPropertyHelper? _test6PropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public object Test6Property { get => _test6Property = _test6PropertyHelper?.Value ?? _test6Property; } + public object MyNamedProperty { get => _myNamedProperty = _myNamedPropertyHelper?.Value ?? _myNamedProperty; } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _test6PropertyHelper = Test6!.ToProperty(this, nameof(Test6Property)); + _myNamedPropertyHelper = Test6!.ToProperty(this, nameof(MyNamedProperty)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromObservableMethodsWithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromObservableMethodsWithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 177122c..e80caab 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromObservableMethodsWithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromObservableMethodsWithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,20 +10,20 @@ namespace TestNs public partial class TestVM { - /// - private int _test3Property; + /// + private int _myNamedProperty; - /// - private ReactiveUI.ObservableAsPropertyHelper? _test3PropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public int Test3Property { get => _test3Property = _test3PropertyHelper?.Value ?? _test3Property; } + public int MyNamedProperty { get => _myNamedProperty = _myNamedPropertyHelper?.Value ?? _myNamedProperty; } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _test3PropertyHelper = Test3()!.ToProperty(this, nameof(Test3Property)); + _myNamedPropertyHelper = Test3()!.ToProperty(this, nameof(MyNamedProperty)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 4befe88..4d47e86 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -11,13 +11,14 @@ namespace TestNs public partial class TestVM { /// - private double? _testProperty; + private double? _testProperty = 1.1d; /// private readonly ReactiveUI.ObservableAsPropertyHelper _testPropertyHelper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] public partial double? TestProperty { get => _testProperty = (_testPropertyHelper == null ? _testProperty : _testPropertyHelper.Value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithAttr#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithAttr#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 7b27e44..5d3d2d6 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithAttr#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithAttr#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,22 +10,23 @@ namespace TestNs public partial class TestVM { - /// - private int _test5Property; + /// + private int _myNamedProperty; - /// - private ReactiveUI.ObservableAsPropertyHelper? _test5PropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public int Test5Property { get => _test5Property = _test5PropertyHelper?.Value ?? _test5Property; } + public int MyNamedProperty { get => _myNamedProperty = _myNamedPropertyHelper?.Value ?? _myNamedProperty; } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _test5PropertyHelper = Test5!.ToProperty(this, nameof(Test5Property)); + _myNamedPropertyHelper = Test5!.ToProperty(this, nameof(MyNamedProperty)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index bd0fb8a..1e5c1f5 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.WithName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,20 +10,20 @@ namespace TestNs public partial class TestVM { - /// - private int _test4Property; + /// + private int _myNamedProperty; - /// - private ReactiveUI.ObservableAsPropertyHelper? _test4PropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _myNamedPropertyHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public int Test4Property { get => _test4Property = _test4PropertyHelper?.Value ?? _test4Property; } + public int MyNamedProperty { get => _myNamedProperty = _myNamedPropertyHelper?.Value ?? _myNamedProperty; } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _test4PropertyHelper = Test4!.ToProperty(this, nameof(Test4Property)); + _myNamedPropertyHelper = Test4!.ToProperty(this, nameof(MyNamedProperty)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromField#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromField#TestNs.TestVM.ObservableAsProperties.g.verified.cs index 3b2b7bc..f53f365 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromField#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromField#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -8,7 +8,7 @@ namespace TestNs public partial class TestVM { /// - private readonly ReactiveUI.ObservableAsPropertyHelper _test3Helper; + private ReactiveUI.ObservableAsPropertyHelper? _test3Helper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromFieldProtected#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromFieldProtected#TestNs.TestVM.ObservableAsProperties.g.verified.cs index 548e82d..b31d92e 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromFieldProtected#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPGeneratorTests.NonReadOnlyFromFieldProtected#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -8,7 +8,7 @@ namespace TestNs public partial class TestVM { /// - private readonly ReactiveUI.ObservableAsPropertyHelper _test5Helper; + protected readonly ReactiveUI.ObservableAsPropertyHelper _test5Helper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsProperties.g.verified.cs index daf717a..44e982b 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -12,7 +12,7 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Runtime.Serialization.DataMemberAttribute()] + [global::System.Runtime.Serialization.DataMemberAttribute(Name="computedValue")] [global::System.Text.Json.Serialization.JsonPropertyNameAttribute("computed_value")] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] public int ComputedValue { get => _computedValue = _computedValueHelper?.Value ?? _computedValue; } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index d088866..74641e2 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithAttributes#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -18,6 +18,7 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Text.Json.Serialization.JsonIgnoreAttribute()] [global::System.Runtime.Serialization.IgnoreDataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIgnoreAttribute()] public string InternalStateProperty { get => _internalStateProperty = _internalStatePropertyHelper?.Value ?? _internalStateProperty; } diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithCombinedOptions#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithCombinedOptions#TestNs.TestVM.ObservableAsProperties.g.verified.cs index b840cae..7e7eac3 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithCombinedOptions#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromFieldWithCombinedOptions#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -8,7 +8,7 @@ namespace TestNs public partial class TestVM { /// - private readonly ReactiveUI.ObservableAsPropertyHelper _statusFieldHelper; + protected ReactiveUI.ObservableAsPropertyHelper? _statusFieldHelper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromMultipleObservableAsProperties#TestNs.TestVM.ObservableAsProperties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromMultipleObservableAsProperties#TestNs.TestVM.ObservableAsProperties.g.verified.cs index 99e1ff2..dafa97c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromMultipleObservableAsProperties#TestNs.TestVM.ObservableAsProperties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromMultipleObservableAsProperties#TestNs.TestVM.ObservableAsProperties.g.verified.cs @@ -26,13 +26,13 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int ItemCount { get => _itemCount = _itemCountHelper?.Value ?? _itemCount; } /// - private readonly ReactiveUI.ObservableAsPropertyHelper _progressHelper; + protected readonly ReactiveUI.ObservableAsPropertyHelper _progressHelper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public double Progress { get => _progress = _progressHelper?.Value ?? _progress; } /// - private readonly ReactiveUI.ObservableAsPropertyHelper _statusHelper; + private ReactiveUI.ObservableAsPropertyHelper? _statusHelper; /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] diff --git a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromObservableMethodWithCustomName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromObservableMethodWithCustomName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs index 11f64f9..3328869 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromObservableMethodWithCustomName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/OAPH/OapExtTests.FromObservableMethodWithCustomName#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs @@ -10,30 +10,30 @@ namespace TestNs public partial class TestVM { - /// - private bool _getLoadingStateProperty; + /// + private bool _isLoading; - /// - private ReactiveUI.ObservableAsPropertyHelper? _getLoadingStatePropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _isLoadingHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public bool GetLoadingStateProperty { get => _getLoadingStateProperty = _getLoadingStatePropertyHelper?.Value ?? _getLoadingStateProperty; } -/// - private string? _getErrorProperty; + public bool IsLoading { get => _isLoading = _isLoadingHelper?.Value ?? _isLoading; } +/// + private string? _errorMessage; - /// - private ReactiveUI.ObservableAsPropertyHelper? _getErrorPropertyHelper; + /// + private ReactiveUI.ObservableAsPropertyHelper? _errorMessageHelper; - /// + /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public string? GetErrorProperty { get => _getErrorProperty = (_getErrorPropertyHelper == null ? _getErrorProperty : _getErrorPropertyHelper.Value); } + public string? ErrorMessage { get => _errorMessage = (_errorMessageHelper == null ? _errorMessage : _errorMessageHelper.Value); } [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void InitializeOAPH() { - _getLoadingStatePropertyHelper = GetLoadingState()!.ToProperty(this, nameof(GetLoadingStateProperty)); - _getErrorPropertyHelper = GetError()!.ToProperty(this, nameof(GetErrorProperty)); + _isLoadingHelper = GetLoadingState()!.ToProperty(this, nameof(IsLoading)); + _errorMessageHelper = GetError()!.ToProperty(this, nameof(ErrorMessage)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.Basic#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.Basic#TestNs.TestVM.Properties.g.verified.cs index af8e019..37a57da 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.Basic#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.Basic#TestNs.TestVM.Properties.g.verified.cs @@ -13,9 +13,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Test1 - { + { get => _test1; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test1")] set { this.RaiseAndSetIfChanged(ref _test1, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.PartialAlsoNotify#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.PartialAlsoNotify#TestNs.TestVM.Properties.g.verified.cs index 76474e5..c2c60f5 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.PartialAlsoNotify#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.PartialAlsoNotify#TestNs.TestVM.Properties.g.verified.cs @@ -13,13 +13,13 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Test4 - { + { get => _test4; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test4")] set { this.RaiseAndSetIfChanged(ref _test4, value); this.RaisePropertyChanged(nameof(OtherNotifyProperty)); + this.RaisePropertyChanged(nameof(OtherNotifyProperty)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAccess#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAccess#TestNs.TestVM.Properties.g.verified.cs index 7903dbf..879a38c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAccess#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAccess#TestNs.TestVM.Properties.g.verified.cs @@ -13,10 +13,9 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Test2 - { + { get => _test2; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test2")] - set + protected set { this.RaiseAndSetIfChanged(ref _test2, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttrAccessInherit#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttrAccessInherit#TestNs.TestVM.Properties.g.verified.cs index 8ff6ccd..f245c5a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttrAccessInherit#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttrAccessInherit#TestNs.TestVM.Properties.g.verified.cs @@ -14,11 +14,11 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public string? Name + public virtual string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - set + protected set { this.RaiseAndSetIfChanged(ref _name, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttributes#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttributes#TestNs.TestVM.Properties.g.verified.cs index 651537e..08bad5c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttributes#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithAttributes#TestNs.TestVM.Properties.g.verified.cs @@ -15,9 +15,8 @@ public partial class TestVM [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] public int Test3 - { + { get => _test3; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test3")] set { this.RaiseAndSetIfChanged(ref _test3, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs index bc0452d..e98728f 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs @@ -14,11 +14,11 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public string? Name + public virtual string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - set + protected set { this.RaiseAndSetIfChanged(ref _name, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs index 4ef72d3..21637b2 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs @@ -14,11 +14,11 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Runtime.Serialization.DataMemberAttribute()] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] - public string? Name + public virtual string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - set + protected set { this.RaiseAndSetIfChanged(ref _name, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithInit#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithInit#TestNs.TestVM.Properties.g.verified.cs index 89a4276..5da35b5 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithInit#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithInit#TestNs.TestVM.Properties.g.verified.cs @@ -12,11 +12,11 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public string MustBeSet + public required string MustBeSet { get => _mustBeSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_mustBeSet")] - set + init { this.RaiseAndSetIfChanged(ref _mustBeSet, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs index ea1d0b8..f562531 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs @@ -15,9 +15,8 @@ public partial class TestInnerClass1 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner1 - { + { get => _testInner1; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner1")] set { this.RaiseAndSetIfChanged(ref _testInner1, value); @@ -27,9 +26,8 @@ public int TestInner1 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner11 - { + { get => _testInner11; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner11")] set { this.RaiseAndSetIfChanged(ref _testInner11, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs index a14e45a..2c39569 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs @@ -17,9 +17,8 @@ public partial class TestInnerClass3 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner3 - { + { get => _testInner3; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner3")] set { this.RaiseAndSetIfChanged(ref _testInner3, value); @@ -29,9 +28,8 @@ public int TestInner3 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner33 - { + { get => _testInner33; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner33")] set { this.RaiseAndSetIfChanged(ref _testInner33, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs index e347d04..476fef6 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs @@ -15,9 +15,8 @@ public partial class TestInnerClass2 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner2 - { + { get => _testInner2; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner2")] set { this.RaiseAndSetIfChanged(ref _testInner2, value); @@ -27,9 +26,8 @@ public int TestInner2 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int TestInner22 - { + { get => _testInner22; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner22")] set { this.RaiseAndSetIfChanged(ref _testInner22, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs index 7471c8a..796ad8b 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.WithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs @@ -13,9 +13,8 @@ public partial class TestViewModel3 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public float TestVM3Property - { + { get => _testVM3Property; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testVM3Property")] set { this.RaiseAndSetIfChanged(ref _testVM3Property, value); @@ -25,9 +24,8 @@ public float TestVM3Property /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public float TestVM3Property2 - { + { get => _testVM3Property2; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testVM3Property2")] set { this.RaiseAndSetIfChanged(ref _testVM3Property2, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4+Level5.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4+Level5.Properties.g.verified.cs index 74fbe23..9e2acfd 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4+Level5.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4+Level5.Properties.g.verified.cs @@ -21,9 +21,8 @@ public partial class Level5 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level5Prop - { + { get => _level5Prop; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level5Prop")] set { this.RaiseAndSetIfChanged(ref _level5Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4.Properties.g.verified.cs index 5f87ac3..3225bd0 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3+Level4.Properties.g.verified.cs @@ -19,9 +19,8 @@ public partial class Level4 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level4Prop - { + { get => _level4Prop; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level4Prop")] set { this.RaiseAndSetIfChanged(ref _level4Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3.Properties.g.verified.cs index 106ffdf..7c55edd 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2+Level3.Properties.g.verified.cs @@ -17,9 +17,8 @@ public partial class Level3 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level3Prop - { + { get => _level3Prop; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level3Prop")] set { this.RaiseAndSetIfChanged(ref _level3Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2.Properties.g.verified.cs index f35f1ee..ff0fa21 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1+Level2.Properties.g.verified.cs @@ -15,9 +15,8 @@ public partial class Level2 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level2Prop - { + { get => _level2Prop; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level2Prop")] set { this.RaiseAndSetIfChanged(ref _level2Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1.Properties.g.verified.cs index 54c7f15..3a658ea 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.DeepNested#TestNs.Level1.Properties.g.verified.cs @@ -13,9 +13,8 @@ public partial class Level1 /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Level1Prop - { + { get => _level1Prop; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_level1Prop")] set { this.RaiseAndSetIfChanged(ref _level1Prop, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Enums#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Enums#TestNs.TestVM.Properties.g.verified.cs index 6e0e85a..0836b98 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Enums#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Enums#TestNs.TestVM.Properties.g.verified.cs @@ -24,9 +24,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::TestNs.Status? NullableStatus - { + { get => _nullableStatus; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableStatus")] set { this.RaiseAndSetIfChanged(ref _nullableStatus, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.GenClass#TestNs.GenericVM`1.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.GenClass#TestNs.GenericVM`1.Properties.g.verified.cs index 41de4a1..5f998cc 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.GenClass#TestNs.GenericVM`1.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.GenClass#TestNs.GenericVM`1.Properties.g.verified.cs @@ -25,9 +25,8 @@ public T? Item /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Count - { + { get => _count; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_count")] set { this.RaiseAndSetIfChanged(ref _count, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MixedAccess#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MixedAccess#TestNs.TestVM.Properties.g.verified.cs index 1fb9cdc..7b7f649 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MixedAccess#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MixedAccess#TestNs.TestVM.Properties.g.verified.cs @@ -28,7 +28,7 @@ public string? ProtectedSet { get => _protectedSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_protectedSet")] - set + protected set { this.RaiseAndSetIfChanged(ref _protectedSet, value); } @@ -40,7 +40,7 @@ public string? InternalSet { get => _internalSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_internalSet")] - set + internal set { this.RaiseAndSetIfChanged(ref _internalSet, value); } @@ -52,7 +52,7 @@ public string? PrivateSet { get => _privateSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_privateSet")] - set + private set { this.RaiseAndSetIfChanged(ref _privateSet, value); } @@ -64,7 +64,7 @@ public string? InternalProtectedSet { get => _internalProtectedSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_internalProtectedSet")] - set + protected internal set { this.RaiseAndSetIfChanged(ref _internalProtectedSet, value); } @@ -76,7 +76,7 @@ public string? PrivateProtectedSet { get => _privateProtectedSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_privateProtectedSet")] - set + private protected set { this.RaiseAndSetIfChanged(ref _privateProtectedSet, value); } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAlso#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAlso#TestNs.TestVM.Properties.g.verified.cs index a24b39d..3282705 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAlso#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAlso#TestNs.TestVM.Properties.g.verified.cs @@ -21,6 +21,8 @@ public string? FirstName this.RaiseAndSetIfChanged(ref _firstName, value); this.RaisePropertyChanged(nameof(FullName)); this.RaisePropertyChanged(nameof(DisplayName)); + this.RaisePropertyChanged(nameof(FullName)); + this.RaisePropertyChanged(nameof(DisplayName)); } } @@ -35,6 +37,8 @@ public string? LastName this.RaiseAndSetIfChanged(ref _lastName, value); this.RaisePropertyChanged(nameof(FullName)); this.RaisePropertyChanged(nameof(DisplayName)); + this.RaisePropertyChanged(nameof(FullName)); + this.RaisePropertyChanged(nameof(DisplayName)); } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAttr#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAttr#TestNs.TestVM.Properties.g.verified.cs index 67c6f88..e64a89c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAttr#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiAttr#TestNs.TestVM.Properties.g.verified.cs @@ -12,7 +12,7 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - [global::System.Runtime.Serialization.DataMemberAttribute()] + [global::System.Runtime.Serialization.DataMemberAttribute(Name="userName")] [global::System.Text.Json.Serialization.JsonIncludeAttribute()] [global::System.Text.Json.Serialization.JsonPropertyNameAttribute("user_name")] public string? UserName diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiPartial#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiPartial#TestNs.TestVM.Properties.g.verified.cs index 7118d30..6df2a26 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiPartial#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.MultiPartial#TestNs.TestVM.Properties.g.verified.cs @@ -37,9 +37,8 @@ public string? LastName /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Age - { + { get => _age; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_age")] set { this.RaiseAndSetIfChanged(ref _age, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.NewMod#TestNs.DerivedVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.NewMod#TestNs.DerivedVM.Properties.g.verified.cs index ea7af18..0203a84 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.NewMod#TestNs.DerivedVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.NewMod#TestNs.DerivedVM.Properties.g.verified.cs @@ -12,7 +12,7 @@ public partial class DerivedVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public string? ShadowedProp + public new string? ShadowedProp { get => _shadowedProp; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_shadowedProp")] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Nullable#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Nullable#TestNs.TestVM.Properties.g.verified.cs index ba41dac..3b367fd 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Nullable#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Nullable#TestNs.TestVM.Properties.g.verified.cs @@ -13,9 +13,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int? NullableInt - { + { get => _nullableInt; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableInt")] set { this.RaiseAndSetIfChanged(ref _nullableInt, value); @@ -25,9 +24,8 @@ public int? NullableInt /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.DateTime? NullableDateTime - { + { get => _nullableDateTime; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableDateTime")] set { this.RaiseAndSetIfChanged(ref _nullableDateTime, value); @@ -37,9 +35,8 @@ public int? NullableInt /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.Guid? NullableGuid - { + { get => _nullableGuid; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableGuid")] set { this.RaiseAndSetIfChanged(ref _nullableGuid, value); @@ -49,9 +46,8 @@ public int? NullableInt /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public decimal? NullableDecimal - { + { get => _nullableDecimal; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_nullableDecimal")] set { this.RaiseAndSetIfChanged(ref _nullableDecimal, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.BaseVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.BaseVM.Properties.g.verified.cs index 24dd0d9..e00794c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.BaseVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.BaseVM.Properties.g.verified.cs @@ -12,7 +12,7 @@ public partial class BaseVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public string? BaseName + public virtual string? BaseName { get => _baseName; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_baseName")] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.DerivedVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.DerivedVM.Properties.g.verified.cs index 5caa1f1..ae72ca0 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.DerivedVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Override#TestNs.DerivedVM.Properties.g.verified.cs @@ -12,7 +12,7 @@ public partial class DerivedVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public string? BaseName + public override string? BaseName { get => _baseName; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_baseName")] diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.ReadOnly#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.ReadOnly#TestNs.TestVM.Properties.g.verified.cs index 990c447..1f0b57a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.ReadOnly#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.ReadOnly#TestNs.TestVM.Properties.g.verified.cs @@ -24,9 +24,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::TestNs.ImmutablePoint? OptionalPoint - { + { get => _optionalPoint; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_optionalPoint")] set { this.RaiseAndSetIfChanged(ref _optionalPoint, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Record#TestNs.TestVMRecord.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Record#TestNs.TestVMRecord.Properties.g.verified.cs index 9077e34..60bc961 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Record#TestNs.TestVMRecord.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Record#TestNs.TestVMRecord.Properties.g.verified.cs @@ -25,9 +25,8 @@ public string? Name /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public int Age - { + { get => _age; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_age")] set { this.RaiseAndSetIfChanged(ref _age, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Struct#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Struct#TestNs.TestVM.Properties.g.verified.cs index 76357cd..5825ffb 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Struct#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Struct#TestNs.TestVM.Properties.g.verified.cs @@ -24,9 +24,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::TestNs.Point? OptionalLocation - { + { get => _optionalLocation; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_optionalLocation")] set { this.RaiseAndSetIfChanged(ref _optionalLocation, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Time#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Time#TestNs.TestVM.Properties.g.verified.cs index 3fb76f4..a7da656 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Time#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Time#TestNs.TestVM.Properties.g.verified.cs @@ -13,9 +13,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.TimeSpan Duration - { + { get => _duration; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_duration")] set { this.RaiseAndSetIfChanged(ref _duration, value); @@ -25,9 +24,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.TimeSpan? OptionalDuration - { + { get => _optionalDuration; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_optionalDuration")] set { this.RaiseAndSetIfChanged(ref _optionalDuration, value); @@ -37,9 +35,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.DateTimeOffset Timestamp - { + { get => _timestamp; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_timestamp")] set { this.RaiseAndSetIfChanged(ref _timestamp, value); @@ -49,9 +46,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.DateTimeOffset? OptionalTimestamp - { + { get => _optionalTimestamp; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_optionalTimestamp")] set { this.RaiseAndSetIfChanged(ref _optionalTimestamp, value); @@ -61,9 +57,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.TimeOnly TimeOnly - { + { get => _timeOnly; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_timeOnly")] set { this.RaiseAndSetIfChanged(ref _timeOnly, value); @@ -73,9 +68,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::System.DateOnly DateOnly - { + { get => _dateOnly; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_dateOnly")] set { this.RaiseAndSetIfChanged(ref _dateOnly, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Tuples#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Tuples#TestNs.TestVM.Properties.g.verified.cs index de8bf84..356dd00 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Tuples#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/RxGenExtTests.Tuples#TestNs.TestVM.Properties.g.verified.cs @@ -13,9 +13,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public (int Id, string Name)? NamedTuple - { + { get => _namedTuple; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_namedTuple")] set { this.RaiseAndSetIfChanged(ref _namedTuple, value); @@ -37,9 +36,8 @@ public partial class TestVM /// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public (string, int, bool) ValueTuple - { + { get => _valueTuple; - [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_valueTuple")] set { this.RaiseAndSetIfChanged(ref _valueTuple, value); diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.Access#TestNs.TestVM.ReactiveCommands.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.Access#TestNs.TestVM.ReactiveCommands.g.verified.cs index 7b3f721..77c1462 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.Access#TestNs.TestVM.ReactiveCommands.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/ReactiveCMDGeneratorTests.Access#TestNs.TestVM.ReactiveCommands.g.verified.cs @@ -1,4 +1,4 @@ -//HintName: TestNs.TestVM.ReactiveCommands.g.cs +//HintName: TestNs.TestVM.ReactiveCommands.g.cs // #pragma warning disable @@ -13,7 +13,7 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public global::ReactiveUI.ReactiveCommand Test1Command { get => _test1Command ??= global::ReactiveUI.ReactiveCommand.Create(Test1); } + internal global::ReactiveUI.ReactiveCommand Test1Command { get => _test1Command ??= global::ReactiveUI.ReactiveCommand.Create(Test1); } } } #nullable restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromMultipleReactiveCommands#TestNs.TestVM.ReactiveCommands.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromMultipleReactiveCommands#TestNs.TestVM.ReactiveCommands.g.verified.cs index 46f7d19..0c7f7db 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromMultipleReactiveCommands#TestNs.TestVM.ReactiveCommands.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromMultipleReactiveCommands#TestNs.TestVM.ReactiveCommands.g.verified.cs @@ -1,4 +1,4 @@ -//HintName: TestNs.TestVM.ReactiveCommands.g.cs +//HintName: TestNs.TestVM.ReactiveCommands.g.cs // #pragma warning disable @@ -28,8 +28,8 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public global::ReactiveUI.ReactiveCommand CalculateCommand { get => _calculateCommand ??= global::ReactiveUI.ReactiveCommand.Create(Calculate); } + internal global::ReactiveUI.ReactiveCommand CalculateCommand { get => _calculateCommand ??= global::ReactiveUI.ReactiveCommand.Create(Calculate); } } } #nullable restore -#pragma warning restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandInGenericClass#TestNs.GenericVM`1.ReactiveCommands.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandInGenericClass#TestNs.GenericVM`1.ReactiveCommands.g.verified.cs index 1eaab91..33a9bda 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandInGenericClass#TestNs.GenericVM`1.ReactiveCommands.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandInGenericClass#TestNs.GenericVM`1.ReactiveCommands.g.verified.cs @@ -14,11 +14,11 @@ public partial class GenericVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::ReactiveUI.ReactiveCommand ProcessItemCommand { get => _processItemCommand ??= global::ReactiveUI.ReactiveCommand.Create(ProcessItem); } - private global::ReactiveUI.ReactiveCommand? _processItemCommand; + private global::ReactiveUI.ReactiveCommand? _processItemLaterCommand; [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public global::ReactiveUI.ReactiveCommand ProcessItemCommand { get => _processItemCommand ??= global::ReactiveUI.ReactiveCommand.CreateFromTask(ProcessItemAsync); } + public global::ReactiveUI.ReactiveCommand ProcessItemLaterCommand { get => _processItemLaterCommand ??= global::ReactiveUI.ReactiveCommand.CreateFromTask(ProcessItemLater); } } } #nullable restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithCanExecuteMethod#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithCanExecuteMethod#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs new file mode 100644 index 0000000..42a5e54 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithCanExecuteMethod#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -0,0 +1,44 @@ +//HintName: ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.cs +// Copyright (c) 2026 .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; + +/// +/// ReactiveCommand Attribute. +/// +/// +[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +internal sealed class ReactiveCommandAttribute : global::System.Attribute +{ + /// + /// Gets the can execute method or property. + /// + /// + /// The name of the CanExecute Observable of bool. + /// + public string? CanExecute { get; init; } + + /// + /// Gets the output scheduler. + /// + /// + /// The output scheduler. + /// + public string? OutputScheduler { get; init; } + + /// + /// Gets the AccessModifier of the ReactiveCommand property. + /// + /// + /// The AccessModifier of the property. + /// + public PropertyAccessModifier AccessModifier { get; init; } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithCanExecuteMethod#TestNs.TestVM.ReactiveCommands.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithCanExecuteMethod#TestNs.TestVM.ReactiveCommands.g.verified.cs new file mode 100644 index 0000000..be917d9 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithCanExecuteMethod#TestNs.TestVM.ReactiveCommands.g.verified.cs @@ -0,0 +1,20 @@ +//HintName: TestNs.TestVM.ReactiveCommands.g.cs +// + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + private global::ReactiveUI.ReactiveCommand? _runCommand; + + + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::ReactiveUI.ReactiveCommand RunCommand { get => _runCommand ??= global::ReactiveUI.ReactiveCommand.Create(Run, CanRun()); } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithPrivateAccess#TestNs.TestVM.ReactiveCommands.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithPrivateAccess#TestNs.TestVM.ReactiveCommands.g.verified.cs index cbaf4d4..1cefe47 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithPrivateAccess#TestNs.TestVM.ReactiveCommands.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithPrivateAccess#TestNs.TestVM.ReactiveCommands.g.verified.cs @@ -1,4 +1,4 @@ -//HintName: TestNs.TestVM.ReactiveCommands.g.cs +//HintName: TestNs.TestVM.ReactiveCommands.g.cs // #pragma warning disable @@ -13,8 +13,8 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public global::ReactiveUI.ReactiveCommand PrivateCommandCommand { get => _privateCommandCommand ??= global::ReactiveUI.ReactiveCommand.Create(PrivateCommand); } + private global::ReactiveUI.ReactiveCommand PrivateCommandCommand { get => _privateCommandCommand ??= global::ReactiveUI.ReactiveCommand.Create(PrivateCommand); } } } #nullable restore -#pragma warning restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithProtectedAccess#TestNs.TestVM.ReactiveCommands.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithProtectedAccess#TestNs.TestVM.ReactiveCommands.g.verified.cs index 79413af..14c5426 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithProtectedAccess#TestNs.TestVM.ReactiveCommands.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandWithProtectedAccess#TestNs.TestVM.ReactiveCommands.g.verified.cs @@ -1,4 +1,4 @@ -//HintName: TestNs.TestVM.ReactiveCommands.g.cs +//HintName: TestNs.TestVM.ReactiveCommands.g.cs // #pragma warning disable @@ -13,8 +13,8 @@ public partial class TestVM [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public global::ReactiveUI.ReactiveCommand ProtectedCommandCommand { get => _protectedCommandCommand ??= global::ReactiveUI.ReactiveCommand.Create(ProtectedCommand); } + protected global::ReactiveUI.ReactiveCommand ProtectedCommandCommand { get => _protectedCommandCommand ??= global::ReactiveUI.ReactiveCommand.Create(ProtectedCommand); } } } #nullable restore -#pragma warning restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandsAcrossPartialDeclarations#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandsAcrossPartialDeclarations#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs new file mode 100644 index 0000000..42a5e54 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandsAcrossPartialDeclarations#ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.verified.cs @@ -0,0 +1,44 @@ +//HintName: ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.cs +// Copyright (c) 2026 .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; + +/// +/// ReactiveCommand Attribute. +/// +/// +[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +internal sealed class ReactiveCommandAttribute : global::System.Attribute +{ + /// + /// Gets the can execute method or property. + /// + /// + /// The name of the CanExecute Observable of bool. + /// + public string? CanExecute { get; init; } + + /// + /// Gets the output scheduler. + /// + /// + /// The output scheduler. + /// + public string? OutputScheduler { get; init; } + + /// + /// Gets the AccessModifier of the ReactiveCommand property. + /// + /// + /// The AccessModifier of the property. + /// + public PropertyAccessModifier AccessModifier { get; init; } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandsAcrossPartialDeclarations#TestNs.TestVM.ReactiveCommands.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandsAcrossPartialDeclarations#TestNs.TestVM.ReactiveCommands.g.verified.cs new file mode 100644 index 0000000..aa900e9 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVECMD/RxCmdExtTests.FromReactiveCommandsAcrossPartialDeclarations#TestNs.TestVM.ReactiveCommands.g.verified.cs @@ -0,0 +1,25 @@ +//HintName: TestNs.TestVM.ReactiveCommands.g.cs +// + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + private global::ReactiveUI.ReactiveCommand? _createCommand; + + + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::ReactiveUI.ReactiveCommand CreateCommand { get => _createCommand ??= global::ReactiveUI.ReactiveCommand.Create(Create); } + private global::ReactiveUI.ReactiveCommand? _loadCommand; + + + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public global::ReactiveUI.ReactiveCommand LoadCommand { get => _loadCommand ??= global::ReactiveUI.ReactiveCommand.CreateFromTask(LoadAsync); } + } +} +#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 c7e726d..ace91f0 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj +++ b/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj @@ -9,27 +9,23 @@ false true $(NoWarn);CA1812;CA1001 + true - - - - - - - + + @@ -40,9 +36,15 @@ - - - + + + + + + + + + diff --git a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs index b032917..3badd66 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs @@ -4,10 +4,6 @@ // See the LICENSE file in the project root for full license information. using System.Reflection; -using System.Runtime.CompilerServices; -using ReactiveMarbles.NuGet.Helpers; - -using ReactiveMarbles.SourceGenerator.TestNuGetHelper.Compilation; using ReactiveUI.SourceGenerators.WinForms; namespace ReactiveUI.SourceGenerator.Tests; @@ -21,38 +17,6 @@ namespace ReactiveUI.SourceGenerator.Tests; public sealed partial class TestHelper : IDisposable where T : IIncrementalGenerator, new() { - /// - /// Represents the NuGet library dependency for the Splat library. - /// - private static readonly LibraryRange SplatLibrary = - new("Splat", VersionRange.AllStable, LibraryDependencyTarget.Package); - - /// - /// Represents the NuGet library dependency for the ReactiveUI library. - /// - private static readonly LibraryRange ReactiveuiLibrary = - new("ReactiveUI", VersionRange.AllStable, LibraryDependencyTarget.Package); - - private static readonly string mscorlibPath = Path.Combine( - System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(), - "mscorlib.dll"); - - private static readonly Assembly[] References = - [ - typeof(object).Assembly, - typeof(Enumerable).Assembly, - typeof(T).Assembly, - typeof(TestHelper).Assembly, - typeof(IViewFor).Assembly, - ]; - - /// - /// Holds the compiler instance used for event-related code generation. - /// - private static readonly Lazy> SharedEventCompiler = new(CreateSharedEventCompilerAsync); - - private EventBuilderCompiler? _eventCompiler; - /// /// Verifieds the file path. /// @@ -78,28 +42,26 @@ public string VerifiedFilePath() } /// - /// Asynchronously initializes the source generator helper by downloading required packages. + /// Asynchronously initializes the source generator helper. /// - /// A task representing the asynchronous initialization operation. - public async Task InitializeAsync() => _eventCompiler = await SharedEventCompiler.Value.ConfigureAwait(false); + /// A task representing the completed initialization operation. + public Task InitializeAsync() => Task.CompletedTask; /// /// Tests a generator expecting it to fail by throwing an . /// /// The source code to test. /// A task representing the asynchronous assertion operation. - public async Task TestFail( + public Task TestFail( string source) { - await EnsureInitializedAsync().ConfigureAwait(false); - - var utility = new SourceGeneratorUtility(WriteTestOutput); - #pragma warning disable IDE0053 // Use expression body for lambda expression #pragma warning disable RCS1021 // Convert lambda expression body to expression body Assert.Throws(() => { RunGeneratorAndCheck(source); }); #pragma warning restore RCS1021 // Convert lambda expression body to expression body #pragma warning restore IDE0053 // Use expression body for lambda expression + + return Task.CompletedTask; } /// @@ -110,14 +72,10 @@ public async Task TestFail( /// A task representing the asynchronous verification operation. /// Must have valid compiler instance. /// callerType. - public async Task TestPass( + public Task TestPass( string source, bool withPreDiagnosics = false) - { - await EnsureInitializedAsync().ConfigureAwait(false); - - await RunGeneratorAndCheck(source, withPreDiagnosics); - } + => RunGeneratorAndCheck(source, withPreDiagnosics); /// public void Dispose() @@ -133,42 +91,87 @@ public void Dispose() /// /// The generator driver used to run the generator. /// - /// Thrown if the compiler instance is not valid or if the compilation fails. + /// Thrown if the compilation fails. public SettingsTask RunGeneratorAndCheck( string code, bool withPreDiagnosics = false, bool rerunCompilation = true) { - if (_eventCompiler is null) - { - throw new InvalidOperationException("Must have a valid compiler instance."); - } - - IEnumerable basicReferences; -#if NET10_0_OR_GREATER - basicReferences = Basic.Reference.Assemblies.Net100.References.All; -#elif NET9_0_OR_GREATER - basicReferences = Basic.Reference.Assemblies.Net90.References.All; -#else - basicReferences = Basic.Reference.Assemblies.Net80.References.All; -#endif - - // Collect required assembly references. + // Collect required assembly references: runtime assemblies plus a support assembly + // that provides attribute/enum definitions for generators OTHER than the active generator T. + // Generator T injects its own definitions via RegisterPostInitializationOutput, so those + // are excluded from the support assembly to avoid CS0433 duplicate-type errors. var assemblies = new HashSet( - basicReferences - .Concat([MetadataReference.CreateFromFile(mscorlibPath)]) - .Concat(basicReferences) - .Concat(GetTransitiveReferences(References)) - .Concat(_eventCompiler.Modules.Select(x => MetadataReference.CreateFromFile(x.PEFile!.FileName))) - .Concat(_eventCompiler.ReferencedModules.Select(x => MetadataReference.CreateFromFile(x.PEFile!.FileName))) - .Concat(_eventCompiler.NeededModules.Select(x => MetadataReference.CreateFromFile(x.PEFile!.FileName)))); + TestCompilationReferences.CreateDefault().Concat(CreateSupportReferences())); var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13); var syntaxTrees = new List { + // Mirror the test project's GlobalUsings.g.cs so test sources can use unqualified + // attribute names (e.g. [BindableDerivedList]) without an explicit 'using' directive. + CSharpSyntaxTree.ParseText( + "global using ReactiveUI.SourceGenerators;", + parseOptions, + path: "GlobalUsings.g.cs"), CSharpSyntaxTree.ParseText(code, parseOptions), }; + // When the active generator is NOT ReactiveGenerator, the shared enum types + // (AccessModifier, PropertyAccessModifier, InheritanceModifier, SplatRegistrationType) + // are not injected by any generator but may be referenced by test source code or by the + // generator's own output. Add them directly as source trees so they are visible in both + // the input and output compilations at the correct (non-internal) accessibility level. + if (typeof(T) != typeof(ReactiveGenerator)) + { + syntaxTrees.Add(CSharpSyntaxTree.ParseText( + GetAttributeDefinitionsMethodResult("GetAccessModifierEnum"), + parseOptions, + path: "AccessModifierEnum.g.cs")); + } + + // When the active generator is IViewForGenerator, the [Reactive] and [ReactiveCommand] + // attributes are not injected (those belong to ReactiveGenerator and ReactiveCommandGenerator). + // They are also excluded from the support DLL (above), so add them directly as inline source + // trees — this makes them visible in the test source compilation without CS0122. + if (typeof(T) == typeof(IViewForGenerator)) + { + syntaxTrees.Add(CSharpSyntaxTree.ParseText( + GetAttributeDefinitionsPropertyResult("ReactiveAttribute"), + parseOptions, + path: "ReactiveAttribute.g.cs")); + syntaxTrees.Add(CSharpSyntaxTree.ParseText( + GetAttributeDefinitionsPropertyResult("ReactiveCommandAttribute"), + parseOptions, + path: "ReactiveCommandAttribute.g.cs")); + } + + // When the active generator is ReactiveObjectGenerator, [Reactive] and [ObservableAsProperty] + // attributes are not injected by this generator (they belong to ReactiveGenerator and + // ObservableAsPropertyGenerator). They are excluded from the support DLL to avoid CS0433, + // so add them directly as inline source trees for accessibility. + if (typeof(T) == typeof(ReactiveObjectGenerator)) + { + syntaxTrees.Add(CSharpSyntaxTree.ParseText( + GetAttributeDefinitionsPropertyResult("ReactiveAttribute"), + parseOptions, + path: "ReactiveAttribute.g.cs")); + syntaxTrees.Add(CSharpSyntaxTree.ParseText( + GetAttributeDefinitionsPropertyResult("ObservableAsPropertyAttribute"), + parseOptions, + path: "ObservableAsPropertyAttribute.g.cs")); + } + + // BindableDerivedListGenerator and ReactiveCollectionGenerator inject their own attribute + // via RegisterPostInitializationOutput. Tests that also use [Reactive] (WithReactive tests) + // need ReactiveAttribute as an inline source tree because it is excluded from the support DLL. + if (typeof(T) == typeof(BindableDerivedListGenerator) || typeof(T) == typeof(ReactiveCollectionGenerator)) + { + syntaxTrees.Add(CSharpSyntaxTree.ParseText( + GetAttributeDefinitionsPropertyResult("ReactiveAttribute"), + parseOptions, + path: "ReactiveAttribute.g.cs")); + } + // Create a compilation with the provided source code. var compilation = CSharpCompilation.Create( "TestProject", @@ -217,6 +220,23 @@ public SettingsTask RunGeneratorAndCheck( throw new InvalidOperationException("Compilation failed due to the above diagnostics."); } + var outputDiagnosticsToReport = outputCompilation.GetDiagnostics() + .Where(d => d.Severity >= DiagnosticSeverity.Error) + .Where(d => !IsKnownExpectedOutputDiagnostic(d)) + .ToList(); + + if (outputDiagnosticsToReport.Count > 0) + { + var diagnosticMessage = string.Join(Environment.NewLine, outputDiagnosticsToReport.Select(static d => $"{d.Id} - {d.GetMessage()}")); + + foreach (var diagnostic in outputDiagnosticsToReport) + { + WriteTestOutput($"Output diagnostic: {diagnostic.Id} - {diagnostic.GetMessage()}"); + } + + throw new InvalidOperationException($"Output compilation failed due to the above diagnostics.{Environment.NewLine}{diagnosticMessage}"); + } + // Validate generated code contains expected features ValidateGeneratedCode(code, rerunDriver); @@ -227,65 +247,85 @@ public SettingsTask RunGeneratorAndCheck( return VerifyGenerator(driver.RunGenerators(compilation)); } + /// + /// Returns all attribute/enum source strings that are NOT already injected by generator T + /// via RegisterPostInitializationOutput. Including sources that the active generator also + /// emits would create CS0433 (duplicate type) in the output compilation. + /// private static IEnumerable GetGeneratedSupportSources() { - yield return "using System.Runtime.CompilerServices;\n[assembly: InternalsVisibleTo(\"TestProject\")]"; - + // Always include the shared enum block (AccessModifier, PropertyAccessModifier, + // InheritanceModifier, SplatRegistrationType). These are internal types so they + // live inside the support-assembly DLL and never cause CS0433 conflicts, even when + // ReactiveGenerator also injects them into the test compilation as source. + // Omitting this block breaks ReactiveCommandAttribute (needs PropertyAccessModifier) + // and IViewForAttribute (needs SplatRegistrationType). yield return GetAttributeDefinitionsMethodResult("GetAccessModifierEnum"); - if (typeof(T) == typeof(ReactiveCommandGenerator)) + // Yield each attribute definition only if generator T does NOT inject it. + // Note: for IViewForGenerator, ReactiveAttribute and ReactiveCommandAttribute are + // added as inline SyntaxTrees below (not in the support DLL) so they are accessible + // in the test source compilation without CS0122 internal-visibility errors. + if (typeof(T) != typeof(ReactiveCommandGenerator) && typeof(T) != typeof(IViewForGenerator)) { yield return GetAttributeDefinitionsPropertyResult("ReactiveCommandAttribute"); - yield return GetAttributeDefinitionsPropertyResult("ReactiveAttribute"); } - else if (typeof(T) == typeof(IViewForGenerator)) + + if (typeof(T) != typeof(ReactiveGenerator) && typeof(T) != typeof(IViewForGenerator) && typeof(T) != typeof(ReactiveObjectGenerator) + && typeof(T) != typeof(BindableDerivedListGenerator) && typeof(T) != typeof(ReactiveCollectionGenerator)) { - yield return GetAttributeDefinitionsPropertyResult("IViewForAttribute"); + yield return GetAttributeDefinitionsPropertyResult("ReactiveAttribute"); } - else if (typeof(T) == typeof(ReactiveGenerator)) + + if (typeof(T) != typeof(IViewForGenerator)) { - yield return GetAttributeDefinitionsPropertyResult("ReactiveAttribute"); + yield return GetAttributeDefinitionsPropertyResult("IViewForAttribute"); } - else if (typeof(T) == typeof(ObservableAsPropertyGenerator)) + + if (typeof(T) != typeof(ObservableAsPropertyGenerator) && typeof(T) != typeof(ReactiveObjectGenerator)) { yield return GetAttributeDefinitionsPropertyResult("ObservableAsPropertyAttribute"); } - else if (typeof(T) == typeof(BindableDerivedListGenerator)) + + if (typeof(T) != typeof(BindableDerivedListGenerator)) { yield return GetAttributeDefinitionsPropertyResult("BindableDerivedListAttribute"); } - else if (typeof(T) == typeof(ReactiveCollectionGenerator)) + + if (typeof(T) != typeof(ReactiveCollectionGenerator)) { yield return GetAttributeDefinitionsPropertyResult("ReactiveCollectionAttribute"); } - else if (typeof(T) == typeof(ReactiveObjectGenerator)) + + if (typeof(T) != typeof(ReactiveObjectGenerator)) { yield return GetAttributeDefinitionsPropertyResult("ReactiveObjectAttribute"); } + + if (typeof(T) != typeof(RoutedControlHostGenerator)) + { + yield return GetAttributeDefinitionsMethodResult("GetRoutedControlHostAttribute"); + } + + if (typeof(T) != typeof(ViewModelControlHostGenerator)) + { + yield return GetAttributeDefinitionsPropertyResult("ViewModelControlHostAttribute"); + } } private static ImmutableArray CreateSupportReferences() { var supportSources = GetGeneratedSupportSources().ToArray(); - if (supportSources.Length == 0) { return []; } - IEnumerable basicReferences; -#if NET10_0_OR_GREATER - basicReferences = Basic.Reference.Assemblies.Net100.References.All; -#elif NET9_0_OR_GREATER - basicReferences = Basic.Reference.Assemblies.Net90.References.All; -#else - basicReferences = Basic.Reference.Assemblies.Net80.References.All; -#endif - + var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13); var supportCompilation = CSharpCompilation.Create( $"{typeof(T).Name}.Support", - supportSources.Select((source, index) => CSharpSyntaxTree.ParseText(source, path: $"Support{index}.g.cs")), - basicReferences.Concat([MetadataReference.CreateFromFile(mscorlibPath)]), + supportSources.Select((source, index) => CSharpSyntaxTree.ParseText(source, parseOptions, path: $"Support{index}.g.cs")), + TestCompilationReferences.CreateDefault(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, deterministic: true)); using var stream = new MemoryStream(); @@ -294,7 +334,7 @@ private static ImmutableArray CreateSupportReferences() if (!emitResult.Success) { var diagnostics = string.Join(Environment.NewLine, emitResult.Diagnostics.Select(static d => d.ToString())); - throw new InvalidOperationException($"Failed to compile support sources for {typeof(T).Name}.{Environment.NewLine}{diagnostics}"); + throw new InvalidOperationException($"Support assembly compilation failed for {typeof(T).Name}.{Environment.NewLine}{diagnostics}"); } return [MetadataReference.CreateFromImage(stream.ToArray())]; @@ -324,6 +364,9 @@ private static string GetAttributeDefinitionsPropertyResult(string propertyName) ?? throw new InvalidOperationException($"AttributeDefinitions.{propertyName} returned null."); } + private static bool IsKnownExpectedOutputDiagnostic(Diagnostic d) => + d.Id is "CS0579" or "CS8864" or "CS0115" or "CS8867" or "CS8866"; + [GeneratedRegex(@"\[Reactive\((?:.*?nameof\((\w+)\))+", RegexOptions.Singleline)] private static partial Regex ReactiveRegex(); @@ -341,6 +384,27 @@ private static void ValidateGeneratedCode(string sourceCode, GeneratorDriver dri var generatedTrees = runResult.Results.SelectMany(r => r.GeneratedSources).ToList(); var allGeneratedCode = string.Join("\n", generatedTrees.Select(t => t.SourceText.ToString())); + if (typeof(T) == typeof(ReactiveCommandGenerator)) + { + var hasReactiveCommandOutput = generatedTrees.Any(static s => s.HintName.EndsWith(".ReactiveCommands.g.cs", StringComparison.Ordinal)); + + if (!hasReactiveCommandOutput) + { + WriteTestOutput("=== VALIDATION FAILURE ==="); + WriteTestOutput("ReactiveCommand generator produced no command source output."); + WriteTestOutput("=== GENERATED HINTS ==="); + + foreach (var generatedTree in generatedTrees) + { + WriteTestOutput(generatedTree.HintName); + } + + WriteTestOutput("=== END ==="); + + throw new InvalidOperationException("ReactiveCommand generator produced no command source output."); + } + } + // Check for AlsoNotify feature in Reactive attributes // Pattern matches: [Reactive(nameof(PropertyName))] or [Reactive(nameof(Prop1), nameof(Prop2))] var alsoNotifyPattern = ReactiveRegex(); @@ -387,76 +451,10 @@ private static void ValidateGeneratedCode(string sourceCode, GeneratorDriver dri } } - /// - /// Recursively walks assembly references from the seed assemblies to collect - /// all transitive dependencies as metadata references. - /// - /// The root assemblies to start from. - /// Metadata references for all reachable assemblies. - private static IEnumerable GetTransitiveReferences(params Assembly[] seedAssemblies) - { - var seen = new HashSet(StringComparer.OrdinalIgnoreCase); - var queue = new Queue(seedAssemblies); - - while (queue.Count > 0) - { - var assembly = queue.Dequeue(); - if (assembly.IsDynamic || string.IsNullOrEmpty(assembly.Location)) - { - continue; - } - - if (!seen.Add(assembly.Location)) - { - continue; - } - - yield return MetadataReference.CreateFromFile(assembly.Location); - - foreach (var referencedName in assembly.GetReferencedAssemblies()) - { - try - { - queue.Enqueue(System.Reflection.Assembly.Load(referencedName)); - } - catch - { - // System assemblies already covered by Basic.Reference.Assemblies - } - } - } - } - private static void WriteTestOutput(string message) => TestContext.Current?.OutputWriter.WriteLine(message); - private static async Task CreateSharedEventCompilerAsync() - { -#if NET10_0_OR_GREATER - NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(10, 0, 0, 0))]; -#elif NET9_0_OR_GREATER - NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(9, 0, 0, 0))]; -#else - NuGetFramework[] targetFrameworks = [new NuGetFramework(".NETCoreApp", new Version(8, 0, 0, 0))]; -#endif - - var inputGroup = await NuGetPackageHelper.DownloadPackageFilesAndFolder( - [SplatLibrary, ReactiveuiLibrary], - targetFrameworks, - packageOutputDirectory: null).ConfigureAwait(false); - - var framework = targetFrameworks[0]; - return new EventBuilderCompiler(inputGroup, inputGroup, framework); - } - - private SettingsTask VerifyGenerator(GeneratorDriver driver) => Verify(driver) - .UseDirectory(VerifiedFilePath()) - .ScrubLinesContaining("[global::System.CodeDom.Compiler.GeneratedCode(\""); - - private async Task EnsureInitializedAsync() - { - if (_eventCompiler is null) - { - await InitializeAsync().ConfigureAwait(false); - } + private SettingsTask VerifyGenerator(GeneratorDriver driver) + => Verify(driver) + .UseDirectory(VerifiedFilePath()) + .ScrubLinesContaining("[global::System.CodeDom.Compiler.GeneratedCode(\""); } -} diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/IViewForGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/IViewForGeneratorTests.cs index 5915ab4..63080bb 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/IViewForGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/IViewForGeneratorTests.cs @@ -20,6 +20,7 @@ public Task Basic() // Arrange: Setup the source code that matches the generator input expectations. const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCmdExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCmdExtTests.cs index 4e05f04..ef9182b 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCmdExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxCmdExtTests.cs @@ -38,6 +38,33 @@ private void DoWork() { } return TestHelper.TestPass(sourceCode); } + /// + /// Tests ReactiveCommand with CanExecute observable method. + /// + /// A task to monitor the async. + [Test] + public Task FromReactiveCommandWithCanExecuteMethod() + { + const string sourceCode = """ + using System; + using System.Reactive.Linq; + using ReactiveUI; + using ReactiveUI.SourceGenerators; + + namespace TestNs; + + public partial class TestVM : ReactiveObject + { + [ReactiveCommand(CanExecute = nameof(CanRun))] + private int Run() => 42; + + private IObservable CanRun() => Observable.Return(true); + } + """; + + return TestHelper.TestPass(sourceCode); + } + /// /// Tests ReactiveCommand with CancellationToken parameter. /// @@ -67,6 +94,41 @@ private async Task LongRunningOperation(CancellationToken ct) return TestHelper.TestPass(sourceCode); } + /// + /// Tests ReactiveCommands distributed across partial declarations. + /// + /// A task to monitor the async. + [Test] + public Task FromReactiveCommandsAcrossPartialDeclarations() + { + const string sourceCode = """ + using System; + using System.Threading.Tasks; + using ReactiveUI; + using ReactiveUI.SourceGenerators; + + namespace TestNs; + + public partial class TestVM : ReactiveObject + { + [ReactiveCommand] + private void Create() { } + } + + public partial class TestVM + { + [ReactiveCommand] + private async Task LoadAsync() + { + await Task.Delay(10); + return 5; + } + } + """; + + return TestHelper.TestPass(sourceCode); + } + /// /// Tests ReactiveCommand with CancellationToken and parameter. /// @@ -336,7 +398,7 @@ public partial class GenericVM : ReactiveObject where T : class } [ReactiveCommand] - private async Task ProcessItemAsync(T? item) + private async Task ProcessItemLater(T? item) { await Task.Delay(10); return item; @@ -529,7 +591,7 @@ public Task FromReactiveCommandInRecordClass() namespace TestNs; - public partial record TestVMRecord : ReactiveObject + public partial record TestVMRecord { [ReactiveCommand] private void DoSomething() { } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxObjExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxObjExtTests.cs index 5fd6395..ff1c66a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxObjExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/RxObjExtTests.cs @@ -486,8 +486,6 @@ public partial class TestVM [Reactive] private string? _lastName; - - public string FullName => $"{FirstName} {LastName}"; } """; diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs index a8058c6..500eb7a 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs @@ -4,72 +4,239 @@ // See the LICENSE file in the project root for full license information. using System.Reflection; +using System.Runtime.InteropServices; namespace ReactiveUI.SourceGenerator.Tests; internal static class TestCompilationReferences { + /// + /// Returns metadata references for all assemblies required by the in-memory test compilations. + /// Uses only runtime assemblies already loaded into the current process — no NuGet downloads, + /// no Basic.Reference.Assemblies mixing — to avoid CS1704/CS0433/CS0518 duplicate-type errors. + /// internal static ImmutableArray CreateDefault() { - // Use assemblies already referenced by the test project to create a compilation that - // can resolve ReactiveUI types used in the in-memory source strings. - var root = typeof(ReactiveUI.SourceGenerators.CodeFixers.PropertyToReactiveFieldAnalyzer).Assembly; + var visited = new HashSet(StringComparer.OrdinalIgnoreCase); + var result = ImmutableArray.CreateBuilder(); - var assemblies = new HashSet + // Seed with the key assemblies whose transitive closure covers BCL + ReactiveUI + Splat + + // System.Reactive and everything else the test source strings depend on. + var seeds = new[] { - typeof(object).Assembly, - typeof(Enumerable).Assembly, - root, + typeof(object).Assembly, // System.Private.CoreLib + typeof(Enumerable).Assembly, // System.Linq + typeof(System.ComponentModel.INotifyPropertyChanged).Assembly, // System.ObjectModel + typeof(ReactiveUI.ReactiveObject).Assembly, // ReactiveUI + typeof(ReactiveUI.SourceGenerators.ReactiveGenerator).Assembly, // ReactiveUI.SourceGenerators + typeof(ReactiveUI.SourceGenerators.CodeFixers.PropertyToReactiveFieldAnalyzer).Assembly, // analyzer assembly + typeof(Splat.Locator).Assembly, // Splat }; - // Load the dependency closure for the analyzer assembly to ensure ReactiveUI is present. - TryAdd(root.GetName(), assemblies); + foreach (var seed in seeds) + { + AddTransitive(seed, visited, result); + } - // Also add currently loaded assemblies (helps when running under different test hosts). - foreach (var assemblyName in AppDomain.CurrentDomain.GetAssemblies() - .Select(static a => a.GetName()) - .DistinctBy(static a => a.FullName)) + // Also sweep all assemblies already loaded — catches System.Reactive, DynamicData, etc. + foreach (var loaded in AppDomain.CurrentDomain.GetAssemblies()) { - TryAdd(assemblyName, assemblies); + if (!loaded.IsDynamic && !string.IsNullOrWhiteSpace(loaded.Location) + && visited.Add(loaded.Location)) + { + result.Add(MetadataReference.CreateFromFile(loaded.Location)); + } } - return assemblies - .Where(static a => !string.IsNullOrWhiteSpace(a.Location)) - .Select(static a => (MetadataReference)MetadataReference.CreateFromFile(a.Location)) - .ToImmutableArray(); + // Add WPF and WinForms assemblies on Windows so test source strings that inherit from + // Window or use Windows Forms controls compile correctly. + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + AddWindowsDesktopAssemblies(visited, result); + } + + return result.ToImmutable(); } - private static void TryAdd(AssemblyName assemblyName, HashSet set) + /// + /// Adds WPF (PresentationFramework + dependencies) and Windows Forms assemblies to the + /// reference set, resolving them from the Microsoft.WindowsDesktop.App shared framework + /// directory that corresponds to the current runtime version. + /// + private static void AddWindowsDesktopAssemblies( + HashSet visited, + ImmutableArray.Builder result) { - try + var versionDir = FindWindowsDesktopAppVersionDir(); + if (versionDir is null) { - var loaded = System.Reflection.Assembly.Load(assemblyName); + return; + } - if (!string.IsNullOrWhiteSpace(loaded.Location)) + // WPF assemblies required for tests that use Window as a base class. + var wpfAssemblies = new[] + { + "PresentationFramework.dll", + "PresentationCore.dll", + "WindowsBase.dll", + "System.Xaml.dll", + }; + + // WinForms assemblies required for tests that use Windows Forms controls. + var winFormsAssemblies = new[] + { + "System.Windows.Forms.dll", + "System.Windows.Forms.Primitives.dll", + }; + + foreach (var name in wpfAssemblies.Concat(winFormsAssemblies)) + { + var path = Path.Combine(versionDir, name); + if (File.Exists(path) && visited.Add(path)) { - set.Add(loaded); + result.Add(MetadataReference.CreateFromFile(path)); } + } + } - foreach (var referenced in loaded.GetReferencedAssemblies()) + /// + /// Locates the best matching Microsoft.WindowsDesktop.App version directory. + /// Uses multiple discovery strategies: runtime-relative path, DOTNET_ROOT env var, + /// and well-known installation paths. + /// + private static string? FindWindowsDesktopAppVersionDir() + { + var runtimeVersion = Environment.Version; + var majorMinor = $"{runtimeVersion.Major}.{runtimeVersion.Minor}"; + + // Collect unique candidate parent directories to try, in priority order. + var candidateRoots = new List(); + + // Strategy 1a: RuntimeEnvironment.GetRuntimeDirectory() — the most reliable way to + // locate the actual .NET shared framework even when running under a VS test host + // or PowerShell where typeof(object).Assembly.Location may point elsewhere. + // Returns e.g. C:\Program Files\dotnet\shared\Microsoft.NETCore.App\9.0.14\ + var runtimeDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); + candidateRoots.Add(Path.GetDirectoryName(runtimeDir?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar))); + + // Strategy 1b: Walk up from typeof(object).Assembly.Location (works under dotnet CLI). + var coreLibDir = Path.GetDirectoryName(typeof(object).Assembly.Location); + candidateRoots.Add(coreLibDir); + + // Try each root two levels up to reach shared\Microsoft.WindowsDesktop.App + foreach (var root in candidateRoots.Where(r => !string.IsNullOrEmpty(r))) + { + var candidate = Path.GetFullPath(Path.Combine(root!, "..", "Microsoft.WindowsDesktop.App")); + var dir = PickBestVersionDir(candidate, majorMinor); + if (dir is not null) + { + return dir; + } + + // One extra level for layouts where root is already the version directory. + candidate = Path.GetFullPath(Path.Combine(root!, "..", "..", "Microsoft.WindowsDesktop.App")); + dir = PickBestVersionDir(candidate, majorMinor); + if (dir is not null) + { + return dir; + } + } + + // Strategy 2: DOTNET_ROOT environment variable. + var dotnetRoot = Environment.GetEnvironmentVariable("DOTNET_ROOT") + ?? Environment.GetEnvironmentVariable("DOTNET_ROOT(x64)"); + if (!string.IsNullOrEmpty(dotnetRoot)) + { + var candidate = Path.Combine(dotnetRoot, "shared", "Microsoft.WindowsDesktop.App"); + var dir = PickBestVersionDir(candidate, majorMinor); + if (dir is not null) { - try - { - var referencedLoaded = System.Reflection.Assembly.Load(referenced); - - if (!string.IsNullOrWhiteSpace(referencedLoaded.Location)) - { - set.Add(referencedLoaded); - } - } - catch - { - // Best-effort only. - } + return dir; } } - catch + + // Strategy 3: Standard installation paths on Windows. + foreach (var programFiles in new[] + { + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), + }) { - // Best-effort only. + if (string.IsNullOrEmpty(programFiles)) + { + continue; + } + + var candidate = Path.Combine(programFiles, "dotnet", "shared", "Microsoft.WindowsDesktop.App"); + var dir = PickBestVersionDir(candidate, majorMinor); + if (dir is not null) + { + return dir; + } + } + + return null; + } + + /// + /// Returns the best version directory under that matches + /// (e.g., "9.0"), falling back to the newest available. + /// + private static string? PickBestVersionDir(string sharedRoot, string majorMinor) + { + if (!Directory.Exists(sharedRoot)) + { + return null; + } + + var dirs = Directory.GetDirectories(sharedRoot); + if (dirs.Length == 0) + { + return null; + } + + // Prefer exact major.minor match, ordered descending (newest patch first). + var best = dirs + .Where(d => Path.GetFileName(d).StartsWith(majorMinor + ".", StringComparison.Ordinal) + || Path.GetFileName(d).Equals(majorMinor, StringComparison.Ordinal)) + .OrderByDescending(d => d, StringComparer.OrdinalIgnoreCase) + .FirstOrDefault() + ?? dirs.OrderByDescending(d => d, StringComparer.OrdinalIgnoreCase).FirstOrDefault(); + + // Validate it actually contains PresentationFramework.dll + return best is not null && File.Exists(Path.Combine(best, "PresentationFramework.dll")) + ? best + : null; + } + + private static void AddTransitive( + Assembly assembly, + HashSet visited, + ImmutableArray.Builder result) + { + if (assembly.IsDynamic || string.IsNullOrWhiteSpace(assembly.Location)) + { + return; + } + + if (!visited.Add(assembly.Location)) + { + return; + } + + result.Add(MetadataReference.CreateFromFile(assembly.Location)); + + foreach (var referencedName in assembly.GetReferencedAssemblies()) + { + try + { + var referenced = System.Reflection.Assembly.Load(referencedName); + AddTransitive(referenced, visited, result); + } + catch + { + // Best-effort — system assemblies not found in some environments are skipped. + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ViewForExtTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ViewForExtTests.cs index 8785a90..3e28732 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ViewForExtTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ViewForExtTests.cs @@ -19,6 +19,7 @@ public Task LazySingle() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -48,6 +49,7 @@ public Task Constant() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -77,6 +79,7 @@ public Task PerReq() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -106,6 +109,7 @@ public Task FromIViewForWithViewModelRegistration() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -137,6 +141,7 @@ public Task Nested() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -171,6 +176,7 @@ public Task FromIViewForWithStringViewModelType() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -200,25 +206,28 @@ public Task DiffNs() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; - namespace ViewModels; - - public partial class ProductViewModel : ReactiveObject + namespace ViewModels { - public string? ProductName { get; set; } - public decimal Price { get; set; } + public partial class ProductViewModel : ReactiveObject + { + public string? ProductName { get; set; } + public decimal Price { get; set; } + } } - namespace Views; - - using ViewModels; - - [IViewFor] - public partial class ProductView : Window + namespace Views { - public ProductView() => ViewModel = new ProductViewModel(); + using ViewModels; + + [IViewFor] + public partial class ProductView : Window + { + public ProductView() => ViewModel = new ProductViewModel(); + } } """; @@ -234,6 +243,7 @@ public Task FromMultipleIViewForInSameNamespace() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -285,12 +295,13 @@ public Task Generic() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace TestNs; - public partial class GenericViewModel : ReactiveObject where T : class + public partial class GenericViewModel { public T? Item { get; set; } } @@ -314,12 +325,13 @@ public Task Record() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace TestNs; - public partial record RecordViewModel : ReactiveObject + public partial record RecordViewModel { public string? Name { get; set; } public int Age { get; set; } @@ -344,6 +356,7 @@ public Task FromIViewForWithNestedViewClass() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -379,12 +392,13 @@ public Task FromIViewForWithReactivePropertiesViewModel() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace TestNs; - public partial class ReactivePropertiesViewModel : ReactiveObject + public partial class ReactivePropertiesViewModel { [Reactive] private string? _firstName; @@ -417,6 +431,7 @@ public Task FromIViewForWithReactiveCommandsViewModel() using System; using System.Threading.Tasks; using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -453,12 +468,13 @@ public Task AllRegOpts() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace TestNs; - public partial class FullViewModel : ReactiveObject + public partial class FullViewModel { public string? Title { get; set; } } @@ -484,6 +500,7 @@ public Task Interface() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; @@ -518,6 +535,7 @@ public Task ExtNs() { const string sourceCode = """ using System.Collections.ObjectModel; + using System.Windows; using ReactiveUI; using ReactiveUI.SourceGenerators; diff --git a/src/ReactiveUI.SourceGenerators.Execute.Maui/ReactiveUI.SourceGenerators.Execute.Maui.csproj b/src/ReactiveUI.SourceGenerators.Execute.Maui/ReactiveUI.SourceGenerators.Execute.Maui.csproj index 32309f1..c5a6349 100644 --- a/src/ReactiveUI.SourceGenerators.Execute.Maui/ReactiveUI.SourceGenerators.Execute.Maui.csproj +++ b/src/ReactiveUI.SourceGenerators.Execute.Maui/ReactiveUI.SourceGenerators.Execute.Maui.csproj @@ -7,6 +7,7 @@ enable false latest + true 12.2 15.0 diff --git a/src/ReactiveUI.SourceGenerators.Execute.Nested1/ReactiveUI.SourceGenerators.Execute.Nested1.csproj b/src/ReactiveUI.SourceGenerators.Execute.Nested1/ReactiveUI.SourceGenerators.Execute.Nested1.csproj index 398d0c0..aaa1737 100644 --- a/src/ReactiveUI.SourceGenerators.Execute.Nested1/ReactiveUI.SourceGenerators.Execute.Nested1.csproj +++ b/src/ReactiveUI.SourceGenerators.Execute.Nested1/ReactiveUI.SourceGenerators.Execute.Nested1.csproj @@ -6,6 +6,7 @@ enable false 13.0 + true diff --git a/src/ReactiveUI.SourceGenerators.Execute.Nested2/ReactiveUI.SourceGenerators.Execute.Nested2.csproj b/src/ReactiveUI.SourceGenerators.Execute.Nested2/ReactiveUI.SourceGenerators.Execute.Nested2.csproj index b72210e..df9cde6 100644 --- a/src/ReactiveUI.SourceGenerators.Execute.Nested2/ReactiveUI.SourceGenerators.Execute.Nested2.csproj +++ b/src/ReactiveUI.SourceGenerators.Execute.Nested2/ReactiveUI.SourceGenerators.Execute.Nested2.csproj @@ -6,6 +6,7 @@ enable false 13.0 + true diff --git a/src/ReactiveUI.SourceGenerators.Execute.Nested3/ReactiveUI.SourceGenerators.Execute.Nested3.csproj b/src/ReactiveUI.SourceGenerators.Execute.Nested3/ReactiveUI.SourceGenerators.Execute.Nested3.csproj index d1e5031..a41196e 100644 --- a/src/ReactiveUI.SourceGenerators.Execute.Nested3/ReactiveUI.SourceGenerators.Execute.Nested3.csproj +++ b/src/ReactiveUI.SourceGenerators.Execute.Nested3/ReactiveUI.SourceGenerators.Execute.Nested3.csproj @@ -6,6 +6,7 @@ enable false 13.0 + true diff --git a/src/ReactiveUI.SourceGenerators.Execute/ReactiveUI.SourceGenerators.Execute.csproj b/src/ReactiveUI.SourceGenerators.Execute/ReactiveUI.SourceGenerators.Execute.csproj index 8848a56..4182983 100644 --- a/src/ReactiveUI.SourceGenerators.Execute/ReactiveUI.SourceGenerators.Execute.csproj +++ b/src/ReactiveUI.SourceGenerators.Execute/ReactiveUI.SourceGenerators.Execute.csproj @@ -10,6 +10,7 @@ false preview $(NoWarn);CA1812 + 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 diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.Execute.cs b/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.Execute.cs index 8ef736a..280ec47 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.Execute.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.Execute.cs @@ -120,11 +120,16 @@ public partial class IViewForGenerator viewModelRegistrationType); } - private static string GenerateSource(string containingTypeName, string containingNamespace, string containingClassVisibility, string containingType, IViewForInfo iviewForInfo) + private static string GenerateSource(string containingTypeName, string containingNamespace, string containingClassVisibility, string containingType, IViewForInfo iviewForInfo, Models.TargetInfo? parentInfo = null) { // Prepare any forwarded property attributes var forwardedAttributesString = string.Join("\n ", AttributeDefinitions.ExcludeFromCodeCoverage); + // Build parent class wrapping (for nested types) + var (parentDeclarations, parentClosing) = parentInfo is null + ? (string.Empty, string.Empty) + : Models.TargetInfo.GenerateParentClassDeclarations([parentInfo]); + switch (iviewForInfo.BaseType) { case IViewForBaseType.None: @@ -158,7 +163,7 @@ private static string GenerateSource(string containingTypeName, string containin namespace {{containingNamespace}} { - /// +{{parentDeclarations}} /// /// Partial class for the {{containingTypeName}} which contains ReactiveUI IViewFor initialization. /// {{forwardedAttributesString}} @@ -181,7 +186,7 @@ namespace {{containingNamespace}} /// object? IViewFor.ViewModel { get => ViewModel; set => ViewModel = ({{iviewForInfo.ViewModelTypeName}})value; } } -} +{{parentClosing}}} #nullable restore #pragma warning restore """; @@ -196,7 +201,7 @@ namespace {{containingNamespace}} namespace {{containingNamespace}} { - /// +{{parentDeclarations}} /// /// Partial class for the {{containingTypeName}} which contains ReactiveUI IViewFor initialization. /// {{forwardedAttributesString}} @@ -213,7 +218,7 @@ namespace {{containingNamespace}} /// object? IViewFor.ViewModel {get => ViewModel; set => ViewModel = ({{iviewForInfo.ViewModelTypeName}}? )value; } } -} +{{parentClosing}}} #nullable restore #pragma warning restore """; @@ -230,7 +235,7 @@ namespace {{containingNamespace}} namespace {{containingNamespace}} { - /// +{{parentDeclarations}} /// /// Partial class for the {{containingTypeName}} which contains ReactiveUI IViewFor initialization. /// {{forwardedAttributesString}} @@ -273,7 +278,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang } } } -} +{{parentClosing}}} #nullable restore #pragma warning restore """; @@ -289,7 +294,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang namespace {{containingNamespace}} { - {{forwardedAttributesString}} +{{parentDeclarations}} {{forwardedAttributesString}} {{containingClassVisibility}} partial {{containingType}} {{containingTypeName}} : IViewFor<{{iviewForInfo.ViewModelTypeName}}> { public static readonly BindableProperty ViewModelProperty = BindableProperty.Create(nameof(ViewModel), typeof({{iviewForInfo.ViewModelTypeName}}), typeof(IViewFor<{{iviewForInfo.ViewModelTypeName}}>), default({{iviewForInfo.ViewModelTypeName}}), BindingMode.OneWay, propertyChanged: OnViewModelChanged); @@ -314,7 +319,7 @@ protected override void OnBindingContextChanged() private static void OnViewModelChanged(BindableObject bindableObject, object oldValue, object newValue) => bindableObject.BindingContext = newValue; } -} +{{parentClosing}}} #nullable restore #pragma warning restore """; diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.cs b/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.cs index e281572..ea96745 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/IViewFor/IViewForGenerator.cs @@ -67,7 +67,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) continue; } - var source = GenerateSource(grouping.Key.TargetName, grouping.Key.TargetNamespace, grouping.Key.TargetVisibility, grouping.Key.TargetType, grouping.FirstOrDefault()); + var source = GenerateSource(grouping.Key.TargetName, grouping.Key.TargetNamespace, grouping.Key.TargetVisibility, grouping.Key.TargetType, grouping.FirstOrDefault(), grouping.FirstOrDefault()?.TargetInfo?.ParentInfo); // Only add source if it's not empty (i.e., a supported UI framework base type was detected) if (!string.IsNullOrWhiteSpace(source)) From b34aa9f8dd84fbb0f914efae9a13a4db9f56c499 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sat, 4 Apr 2026 00:29:29 +0100 Subject: [PATCH 03/10] Remove unused package references from test project Delete Microsoft.NET.Test.Sdk and System.Formats.Asn1 PackageReference entries from src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj to clean up unused dependencies in the test project. --- .../ReactiveUI.SourceGenerators.Tests.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj b/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj index ace91f0..b297f9e 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj +++ b/src/ReactiveUI.SourceGenerator.Tests/ReactiveUI.SourceGenerators.Tests.csproj @@ -24,8 +24,6 @@ - - From dbadfe2071a0e0339acb92ec0292c951321546ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 23:38:54 +0000 Subject: [PATCH 04/10] Add cross-platform WPF source stubs for non-Windows test compilation Agent-Logs-Url: https://github.com/reactiveui/ReactiveUI.SourceGenerators/sessions/ca39e5bc-25d7-48a1-99c8-92b23e6a977b Co-authored-by: ChrisPulman <4910015+ChrisPulman@users.noreply.github.com> --- .../TestHelper.cs | 13 +++++++++ .../UnitTests/TestCompilationReferences.cs | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs index 3badd66..fde0730 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs @@ -4,6 +4,7 @@ // See the LICENSE file in the project root for full license information. using System.Reflection; +using System.Runtime.InteropServices; using ReactiveUI.SourceGenerators.WinForms; namespace ReactiveUI.SourceGenerator.Tests; @@ -172,6 +173,18 @@ public SettingsTask RunGeneratorAndCheck( path: "ReactiveAttribute.g.cs")); } + // On non-Windows platforms the Microsoft.WindowsDesktop.App shared framework is unavailable, + // so test sources that inherit from System.Windows.Window (WPF) or use Windows Forms types + // cannot resolve those types from assembly references. Inject lightweight source stubs so + // the in-memory compilation succeeds cross-platform. + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + syntaxTrees.Add(CSharpSyntaxTree.ParseText( + TestCompilationReferences.WindowsDesktopStubs, + parseOptions, + path: "WindowsDesktopStubs.g.cs")); + } + // Create a compilation with the provided source code. var compilation = CSharpCompilation.Create( "TestProject", diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs index 500eb7a..d942efd 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs @@ -10,6 +10,34 @@ namespace ReactiveUI.SourceGenerator.Tests; internal static class TestCompilationReferences { + /// + /// Minimal source stubs for WPF and WinForms types that are only available + /// via the Microsoft.WindowsDesktop.App shared framework on Windows. + /// Used in non-Windows test compilations to allow test sources that reference + /// System.Windows.Window or System.Windows.Forms.UserControl + /// to compile cross-platform without requiring platform-specific assemblies. + /// + internal const string WindowsDesktopStubs = """ + namespace System.Windows + { + public class DependencyObject { } + public class UIElement : DependencyObject { } + public class FrameworkElement : UIElement { } + public class Window : FrameworkElement { } + } + namespace System.Windows.Controls + { + public class UserControl : System.Windows.FrameworkElement { } + public class Page : System.Windows.FrameworkElement { } + } + namespace System.Windows.Forms + { + public class Control { } + public class Form : Control { } + public class UserControl : Control { } + } + """; + /// /// Returns metadata references for all assemblies required by the in-memory test compilations. /// Uses only runtime assemblies already loaded into the current process — no NuGet downloads, From 2089d9c470e16e10703bf8198f5f1e02836d7d79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:30:37 +0000 Subject: [PATCH 05/10] Extend WindowsDesktopStubs with DependencyProperty/PropertyMetadata for generated WPF output Agent-Logs-Url: https://github.com/reactiveui/ReactiveUI.SourceGenerators/sessions/07f5ac96-b377-4dce-9e68-25f253f3cbb6 Co-authored-by: ChrisPulman <4910015+ChrisPulman@users.noreply.github.com> --- .../UnitTests/TestCompilationReferences.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs index d942efd..4b595ec 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs @@ -20,7 +20,19 @@ internal static class TestCompilationReferences internal const string WindowsDesktopStubs = """ namespace System.Windows { - public class DependencyObject { } + public class DependencyProperty + { + public static DependencyProperty Register(string name, global::System.Type propertyType, global::System.Type ownerType, PropertyMetadata typeMetadata) => null!; + } + public class PropertyMetadata + { + public PropertyMetadata(object? defaultValue) { } + } + public class DependencyObject + { + public object GetValue(DependencyProperty dp) => null!; + public void SetValue(DependencyProperty dp, object value) { } + } public class UIElement : DependencyObject { } public class FrameworkElement : UIElement { } public class Window : FrameworkElement { } From e056e5c1f61bf6f9e4a7179caa260267c628f7ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 01:45:34 +0000 Subject: [PATCH 06/10] Enable parallel test execution to fix Linux CI slowness (46+ min runs) Agent-Logs-Url: https://github.com/reactiveui/ReactiveUI.SourceGenerators/sessions/bd63c6ca-b336-41be-b352-42b895d258c1 Co-authored-by: ChrisPulman <4910015+ChrisPulman@users.noreply.github.com> --- src/testconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testconfig.json b/src/testconfig.json index 8f7dd8c..bd14f0f 100644 --- a/src/testconfig.json +++ b/src/testconfig.json @@ -1,7 +1,7 @@ { "platform": { "execution": { - "parallel": false + "parallel": true } }, "extensions": [ From 691aef407e91ed59de6c15ac424c8bbc808eb4ba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 02:33:10 +0000 Subject: [PATCH 07/10] Cache support references and default references to eliminate per-test recompilation overhead Previously CreateSupportReferences() and TestCompilationReferences.CreateDefault() were called on every test invocation, doing a full Roslyn compilation + Emit and an assembly scan + file I/O on each of the 217 tests. Both methods produce identical output for all tests with the same generator type T, so the results are now cached via static Lazy<> fields. Result: 217 tests with coverage now complete in ~6s per TFM locally (was ~37s), expected to reduce CI from ~13 min to ~2-3 min per TFM on Linux and macOS. Agent-Logs-Url: https://github.com/reactiveui/ReactiveUI.SourceGenerators/sessions/d5d0b260-3c81-4047-bf50-ebbe264480d4 Co-authored-by: ChrisPulman <4910015+ChrisPulman@users.noreply.github.com> --- src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs | 8 +++++++- .../UnitTests/TestCompilationReferences.cs | 10 +++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs index fde0730..338ef29 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs @@ -18,6 +18,12 @@ namespace ReactiveUI.SourceGenerator.Tests; public sealed partial class TestHelper : IDisposable where T : IIncrementalGenerator, new() { + // Cache support references per generator type T. The support assembly compiles attribute + // definitions that are NOT injected by T via RegisterPostInitializationOutput — an expensive + // Roslyn compilation + Emit step that produces an identical result for every test in the same + // generator class. Compute it once and reuse it for all subsequent tests. + private static readonly Lazy> supportReferences = + new(CreateSupportReferences, LazyThreadSafetyMode.ExecutionAndPublication); /// /// Verifieds the file path. /// @@ -103,7 +109,7 @@ public SettingsTask RunGeneratorAndCheck( // Generator T injects its own definitions via RegisterPostInitializationOutput, so those // are excluded from the support assembly to avoid CS0433 duplicate-type errors. var assemblies = new HashSet( - TestCompilationReferences.CreateDefault().Concat(CreateSupportReferences())); + TestCompilationReferences.CreateDefault().Concat(supportReferences.Value)); var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13); var syntaxTrees = new List diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs index 4b595ec..fa7a5fa 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/TestCompilationReferences.cs @@ -50,12 +50,20 @@ public class UserControl : Control { } } """; + // Cache the default references so that the expensive assembly-scanning/file-I/O is only + // performed once per process, not on every test invocation. + private static readonly Lazy> defaultReferences = + new(CreateDefaultCore, LazyThreadSafetyMode.ExecutionAndPublication); + /// /// Returns metadata references for all assemblies required by the in-memory test compilations. /// Uses only runtime assemblies already loaded into the current process — no NuGet downloads, /// no Basic.Reference.Assemblies mixing — to avoid CS1704/CS0433/CS0518 duplicate-type errors. + /// The result is cached after the first call to avoid repeated assembly scanning and file I/O. /// - internal static ImmutableArray CreateDefault() + internal static ImmutableArray CreateDefault() => defaultReferences.Value; + + private static ImmutableArray CreateDefaultCore() { var visited = new HashSet(StringComparer.OrdinalIgnoreCase); var result = ImmutableArray.CreateBuilder(); From 4771e641126c7e4e2affac13cf3eac5cf02eac88 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 02:36:32 +0000 Subject: [PATCH 08/10] =?UTF-8?q?Fix=20doc=20comment=20spelling:=20Verifie?= =?UTF-8?q?ds=20=E2=86=92=20Gets=20the=20verified=20file=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/reactiveui/ReactiveUI.SourceGenerators/sessions/d5d0b260-3c81-4047-bf50-ebbe264480d4 Co-authored-by: ChrisPulman <4910015+ChrisPulman@users.noreply.github.com> --- src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs index 338ef29..abd8a9c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/TestHelper.cs @@ -25,7 +25,7 @@ public sealed partial class TestHelper : IDisposable private static readonly Lazy> supportReferences = new(CreateSupportReferences, LazyThreadSafetyMode.ExecutionAndPublication); /// - /// Verifieds the file path. + /// Gets the verified file path for generator type . /// /// /// A string. From a3d01cbb17af30b7750586c8d332fd084ef697ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 06:24:14 +0000 Subject: [PATCH 09/10] Replace catch(NullReferenceException) with IsDefaultOrEmpty guard in AttributeDataExtensions The NamedArguments property returns a default ImmutableArray when attribute data is incomplete/malformed at analysis time. Guard with .IsDefaultOrEmpty before iterating rather than swallowing NullReferenceException, which could mask real Roslyn API bugs. Agent-Logs-Url: https://github.com/reactiveui/ReactiveUI.SourceGenerators/sessions/7c58663a-a9ce-4cfa-a3ff-9a57bc0347a9 Co-authored-by: ChrisPulman <4910015+ChrisPulman@users.noreply.github.com> --- .../Core/Extensions/AttributeDataExtensions.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/AttributeDataExtensions.cs b/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/AttributeDataExtensions.cs index caa2ee2..bffae8e 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/AttributeDataExtensions.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/Core/Extensions/AttributeDataExtensions.cs @@ -37,7 +37,9 @@ public static bool TryGetNamedArgument(this AttributeData attributeData, stri return false; } - try + // NamedArguments returns a default ImmutableArray when attribute data is incomplete/malformed. + // Guard with IsDefaultOrEmpty rather than catching NullReferenceException to avoid masking real bugs. + if (!attributeData.NamedArguments.IsDefaultOrEmpty) { foreach (var properties in attributeData.NamedArguments) { @@ -47,9 +49,6 @@ public static bool TryGetNamedArgument(this AttributeData attributeData, stri } } } - catch (NullReferenceException) - { - } value = default; @@ -70,7 +69,9 @@ public static bool TryGetNamedArgument(this AttributeData attributeData, stri return default; } - try + // NamedArguments returns a default ImmutableArray when attribute data is incomplete/malformed. + // Guard with IsDefaultOrEmpty rather than catching NullReferenceException to avoid masking real bugs. + if (!attributeData.NamedArguments.IsDefaultOrEmpty) { foreach (var properties in attributeData.NamedArguments) { @@ -80,9 +81,6 @@ public static bool TryGetNamedArgument(this AttributeData attributeData, stri } } } - catch (NullReferenceException) - { - } return default; } From 60c70d8124af9a1bca38605619449588d10a043e Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sat, 4 Apr 2026 10:15:25 +0100 Subject: [PATCH 10/10] Add unit tests, CLAUDE doc, fix EquatableArray Add a CLAUDE.md contributor/AI guidance document and a suite of new unit tests under src/ReactiveUI.SourceGenerator.Tests/UnitTests (AttributeDataExtensionTests, EquatableArrayTests, FieldSyntaxExtensionTests, ImmutableArrayBuilderTests, SymbolExtensionTests). Also apply minor updates to EquatableArray{T}.cs in the Analyzers.CodeFixes and Roslyn helper projects and update ReactiveUI.SourceGenerators.Roslyn4120.csproj. These changes add test coverage for core helpers/extensions and include documentation for contributors/AI assistants. --- CLAUDE.md | 230 ++++++++ .../UnitTests/AttributeDataExtensionTests.cs | 401 ++++++++++++++ .../UnitTests/EquatableArrayTests.cs | 264 +++++++++ .../UnitTests/FieldSyntaxExtensionTests.cs | 216 ++++++++ .../UnitTests/ImmutableArrayBuilderTests.cs | 269 +++++++++ .../UnitTests/SymbolExtensionTests.cs | 524 ++++++++++++++++++ .../Core/Helpers/EquatableArray{T}.cs | 2 +- .../Core/Helpers/EquatableArray{T}.cs | 2 +- ...ctiveUI.SourceGenerators.Roslyn4120.csproj | 1 + 9 files changed, 1907 insertions(+), 2 deletions(-) create mode 100644 CLAUDE.md create mode 100644 src/ReactiveUI.SourceGenerator.Tests/UnitTests/AttributeDataExtensionTests.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/UnitTests/EquatableArrayTests.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/UnitTests/FieldSyntaxExtensionTests.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/UnitTests/ImmutableArrayBuilderTests.cs create mode 100644 src/ReactiveUI.SourceGenerator.Tests/UnitTests/SymbolExtensionTests.cs diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..1093fae --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,230 @@ +# CLAUDE.md — ReactiveUI.SourceGenerators + +This document provides guidance for AI assistants and contributors working in this repository. + +## Overview + +ReactiveUI.SourceGenerators is a Roslyn incremental source-generator package that automates ReactiveUI boilerplate at compile-time. It generates reactive properties, observable-as-property helpers, reactive commands, IViewFor registrations, bindable derived lists, reactive collections, and full reactive-object scaffolding — all with zero runtime reflection, making generated code fully AOT-compatible. + +**Minimum consumer requirements:** C# 12.0 · Visual Studio 17.8.0 · ReactiveUI 19.5.31+ + +## Architecture Overview + +The repository ships **three versioned generator assemblies** built from a single shared source folder: + +| Project | Roslyn version | Preprocessor constant | Extra features | +|---------|---------------|-----------------------|----------------| +| `ReactiveUI.SourceGenerators.Roslyn480` | 4.8.x (baseline) | _(none)_ | Field-based `[Reactive]`, `[ObservableAsProperty]`, `[ReactiveCommand]`, etc. | +| `ReactiveUI.SourceGenerators.Roslyn4120` | 4.12.0 | `ROSYLN_412` | + partial-property `[Reactive]` and `[ObservableAsProperty]` | +| `ReactiveUI.SourceGenerators.Roslyn5000` | 5.0.0 | `ROSYLN_500` | + same partial-property support on Roslyn 5 | + +Each versioned project links all `.cs` files from `ReactiveUI.SourceGenerators.Roslyn/` via: + +```xml + +``` + +`#if ROSYLN_412 || ROSYLN_500` guards inside the shared source enable partial-property pipelines only on the newer Roslyn builds. + +The `ReactiveUI.SourceGenerators` NuGet project packages all three DLLs under separate `analyzers/dotnet/roslyn4.8/cs`, `analyzers/dotnet/roslyn4.12/cs`, and `analyzers/dotnet/roslyn5.0/cs` paths, so NuGet/MSBuild automatically selects the right build based on the host compiler. + +Diagnostics are **not** reported by generators. All `RXUISG*` diagnostics live in the separate `ReactiveUI.SourceGenerators.Analyzers.CodeFixes` project. + +## Project Structure + +``` +src/ +├── ReactiveUI.SourceGenerators.Roslyn/ # Shared source (linked into all versioned projects) +│ ├── AttributeDefinitions.cs # Injected attribute source texts +│ ├── Reactive/ # [Reactive] generator + Execute + models +│ ├── ReactiveCommand/ # [ReactiveCommand] generator + Execute + models +│ ├── ObservableAsProperty/ # [ObservableAsProperty] generator + Execute + models +│ ├── IViewFor/ # [IViewFor] generator + Execute + models +│ ├── RoutedControlHost/ # [RoutedControlHost] generator +│ ├── ViewModelControlHost/ # [ViewModelControlHost] generator +│ ├── BindableDerivedList/ # [BindableDerivedList] generator +│ ├── ReactiveCollection/ # [ReactiveCollection] generator +│ ├── ReactiveObject/ # [IReactiveObject] generator +│ ├── Diagnostics/ # DiagnosticDescriptors, SuppressionDescriptors +│ └── Core/ +│ ├── Extensions/ # ISymbol*, ITypeSymbol*, INamedTypeSymbol*, AttributeData extensions +│ ├── Helpers/ # ImmutableArrayBuilder, EquatableArray, HashCode, etc. +│ └── Models/ # Result, DiagnosticInfo, TargetInfo, etc. +├── ReactiveUI.SourceGenerators.Roslyn480/ # Roslyn 4.8 build (no define) +├── ReactiveUI.SourceGenerators.Roslyn4120/ # Roslyn 4.12 build (ROSYLN_412) +├── ReactiveUI.SourceGenerators.Roslyn5000/ # Roslyn 5.0 build (ROSYLN_500) +├── ReactiveUI.SourceGenerators.Analyzers.CodeFixes/ # Analyzers + code fixers +├── ReactiveUI.SourceGenerators/ # NuGet packaging project (bundles all three DLLs) +├── ReactiveUI.SourceGenerator.Tests/ # TUnit + Verify snapshot tests +├── ReactiveUI.SourceGenerators.Execute*/ # Compile-time execution verification projects +└── TestApps/ # Manual test applications (WPF, WinForms, MAUI, Avalonia) +``` + +## Code Generation Strategy + +All generated C# source is produced using **raw string literals** (`$$"""..."""`). Do **not** use `StringBuilder` or `SyntaxFactory` for code generation. + +```csharp +// CORRECT — raw string literal with $$ interpolation +internal static string GenerateProperty(string name, string type) => $$""" + public {{type}} {{name}} + { + get => _{{char.ToLower(name[0])}{{name.Substring(1)}}}; + set => this.RaiseAndSetIfChanged(ref _{{char.ToLower(name[0])}{{name.Substring(1)}}}, value); + } + """; + +// WRONG — do not use StringBuilder +var sb = new StringBuilder(); +sb.AppendLine($"public {type} {name}"); +// ... + +// WRONG — do not use SyntaxFactory +SyntaxFactory.PropertyDeclaration(...) +``` + +Raw string literals preserve formatting intent, are trivially diffable in code review, and do not require the overhead of SyntaxFactory node construction. + +The injected attribute source texts (in `AttributeDefinitions.cs`) also use `$$"""..."""` raw string literals. + +## Roslyn Incremental Pipeline Pattern + +Each generator follows this structure: + +1. **`Initialize`** — registers post-initialization output (inject attribute source), then calls one or more `Run*` methods. +2. **`Run*`** — builds the `IncrementalValuesProvider` using `ForAttributeWithMetadataName` + a syntax predicate + a semantic extraction function. +3. **`Get*Info` (Execute file)** — stateless extraction function. Returns `Result` with embedded diagnostics. Must be pure; must not capture any `ISymbol` or `SyntaxNode` beyond this call. +4. **`GenerateSource` (Execute file)** — pure function that converts model → raw string source text. No Roslyn symbols allowed here. + +``` +Initialize() + ├─ RegisterPostInitializationOutput → inject attribute definitions + └─ SyntaxProvider.ForAttributeWithMetadataName + ├─ syntax predicate (fast, node-type check only) + ├─ semantic extraction → Get*Info() → Result + └─ RegisterSourceOutput → GenerateSource() → AddSource() +``` + +**Incremental caching rules:** +- All pipeline output models must implement value equality (`record`, `IEquatable`, or `EquatableArray`). +- Never store `ISymbol`, `SyntaxNode`, `SemanticModel`, or `CancellationToken` in a model. +- Use `EquatableArray` (from `Core/Helpers`) instead of `ImmutableArray` in models. + +## Generators + +| Generator class | Attribute | Input target | +|-----------------|-----------|--------------| +| `ReactiveGenerator` | `[Reactive]` | Field (all Roslyn) or partial property (ROSYLN_412+) | +| `ReactiveCommandGenerator` | `[ReactiveCommand]` | Method | +| `ObservableAsPropertyGenerator` | `[ObservableAsProperty]` | Field or observable method | +| `IViewForGenerator` | `[IViewFor]` | Class | +| `RoutedControlHostGenerator` | `[RoutedControlHost]` | Class | +| `ViewModelControlHostGenerator` | `[ViewModelControlHost]` | Class | +| `BindableDerivedListGenerator` | `[BindableDerivedList]` | Field (`ReadOnlyObservableCollection`) | +| `ReactiveCollectionGenerator` | `[ReactiveCollection]` | Field (`ObservableCollection`) | +| `ReactiveObjectGenerator` | `[IReactiveObject]` | Class | + +## Analyzers & Suppressors + +All diagnostics use the `RXUISG` prefix. All suppressions use the `RXUISPR` prefix. + +| Class | ID range | Purpose | +|-------|----------|---------| +| `PropertyToReactiveFieldAnalyzer` | RXUISG0016 | Suggests converting auto-properties to `[Reactive]` fields | +| `ReactiveAttributeMisuseAnalyzer` | RXUISG0020 | Detects `[Reactive]` on non-partial or non-partial-type members | +| `PropertyToReactiveFieldCodeFixProvider` | — | Converts auto-property → `[Reactive]` field | +| `ReactiveAttributeMisuseCodeFixProvider` | — | Fixes misuse of `[Reactive]` attribute | + +Suppressors silence noisy Roslyn/Roslynator diagnostics that are expected for generator-backed patterns (e.g. fields never read, methods that don't need to be static). + +### Analyzer Separation (Roslyn Best Practice) + +- Generators do **not** report diagnostics — they only call `context.ReportDiagnostic` for internal invariant violations via `DiagnosticInfo` models. +- The `ReactiveUI.SourceGenerators.Analyzers.CodeFixes` project owns all `RXUISG*` diagnostic descriptors and code fixers. +- `DiagnosticDescriptors.cs` and related files are compiled from the shared Roslyn source via the linked `` items. + +## Testing + +### Framework + +- **TUnit** — test runner and assertion library (replaces xUnit/NUnit). +- **Verify.SourceGenerators** — snapshot-based verification of generated source output. +- **Microsoft.Testing.Platform** — native test execution (configured via `testconfig.json`). + +### Test project targets + +The test project multi-targets `net8.0;net9.0;net10.0` (controlled by `$(TestTfms)` in `Directory.Build.props`). Tests run against all three frameworks in CI. + +### Snapshot tests + +Generator tests extend `TestBase` and call `TestHelper.TestPass(sourceCode)`. Verify saves `.verified.txt` snapshots in the appropriate subdirectory (`REACTIVE/`, `REACTIVECMD/`, `OAPH/`, `IVIEWFOR/`, `DERIVEDLIST/`, `REACTIVECOLL/`, `REACTIVEOBJ/`). + +#### Accepting snapshot changes + +1. Enable `VerifierSettings.AutoVerify()` in `ModuleInitializer.cs`. +2. Run `dotnet test --project src/ReactiveUI.SourceGenerator.Tests -c Release`. +3. Disable `VerifierSettings.AutoVerify()`. +4. Re-run tests to confirm all pass without AutoVerify. + +### Test source language version + +Test source strings are parsed with **CSharp13** (`LanguageVersion.CSharp13`). This is the version used by `TestHelper.RunGeneratorAndCheck`. + +### Non-snapshot (unit) tests + +Analyzer and helper tests use direct `CSharpCompilation` / `CompilationWithAnalyzers` to verify diagnostics without snapshots. See `PropertyToReactiveFieldAnalyzerTests.cs` for the pattern. + +## Common Tasks + +### Adding a New Generator + +1. Create a value-equatable model record in `Core/Models/` or the generator's own `Models/` folder. +2. Add attribute source text to `AttributeDefinitions.cs` using a `$$"""..."""` raw string literal. +3. Create `Generator.cs` with `Initialize` wiring up `ForAttributeWithMetadataName`. +4. Create `Generator.Execute.cs` with `Get*Info` (extraction) and `GenerateSource` (raw string template). +5. Add snapshot tests in `ReactiveUI.SourceGenerator.Tests/UnitTests/`. +6. Accept snapshots using the AutoVerify trick above. + +### Adding a New Analyzer Diagnostic + +1. Add a `DiagnosticDescriptor` to `DiagnosticDescriptors.cs`. +2. Update `AnalyzerReleases.Unshipped.md`. +3. Implement the analyzer in `ReactiveUI.SourceGenerators.Analyzers.CodeFixes/`. +4. Add unit tests in `ReactiveUI.SourceGenerator.Tests/UnitTests/`. + +### Running Tests + +```pwsh +dotnet test src/ReactiveUI.SourceGenerator.Tests --configuration Release +``` + +### Building + +```pwsh +dotnet build src/ReactiveUI.SourceGenerators.sln +``` + +## What to Avoid + +- **`ISymbol` / `SyntaxNode` in pipeline output models** — breaks incremental caching; use value-equatable data records instead. +- **`SyntaxFactory` for code generation** — use `$$"""..."""` raw string literals. +- **`StringBuilder` for code generation** — use `$$"""..."""` raw string literals. +- **Diagnostics reported inside generators** — use the separate analyzer project for all `RXUISG*` diagnostics. +- **LINQ in hot Roslyn pipeline paths** — use `foreach` loops (Roslyn convention for incremental generators). +- **Non-value-equatable models** in the incremental pipeline — will defeat caching and cause unnecessary regeneration. +- **APIs unavailable in `netstandard2.0`** inside `ReactiveUI.SourceGenerators.Roslyn*` projects — the generator must run inside the compiler host which targets netstandard2.0. +- **Runtime reflection** in generated code — breaks Native AOT compatibility. +- **`#nullable enable` / nullable annotations in generated output** — these require C# 8+ features; generated code must be compatible with the minimum consumer C# version (12.0). +- **File-scoped namespaces in generated output** — requires C# 10; use block-scoped namespaces. + +## Important Notes + +- **Required .NET SDKs:** .NET 8.0, 9.0, and 10.0 (all required for multi-targeting the test project). +- **Generator + Analyzer targets:** `netstandard2.0` (Roslyn host requirement). +- **Test project targets:** `net8.0;net9.0;net10.0`. +- **No shallow clones:** The repository uses Nerdbank.GitVersioning; a full `git clone` is required for correct versioning. +- **NuGet packaging:** The `ReactiveUI.SourceGenerators` project bundles all three versioned generator DLLs at different `analyzers/dotnet/roslyn*/cs` paths. +- **Cross-platform tests:** On non-Windows platforms, WPF/WinForms types are injected as source stubs so generator tests compile cross-platform. +- **`SyntaxFactory` helper:** https://roslynquoter.azurewebsites.net/ — useful for inspecting how Roslyn models a given syntax construct (reference only; do not use SyntaxFactory in code-gen paths). + +**Philosophy:** Generate zero-reflection, AOT-compatible ReactiveUI boilerplate at compile-time. Separate diagnostic reporting from code generation. Keep the incremental pipeline pure and value-equatable so Roslyn can cache and skip unchanged work. diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/AttributeDataExtensionTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/AttributeDataExtensionTests.cs new file mode 100644 index 0000000..5879d24 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/AttributeDataExtensionTests.cs @@ -0,0 +1,401 @@ +// Copyright (c) 2026 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 Microsoft.CodeAnalysis.CSharp.Syntax; +using ReactiveUI.SourceGenerators.Extensions; + +namespace ReactiveUI.SourceGenerator.Tests; + +/// +/// Unit tests for covering +/// TryGetNamedArgument, GetNamedArgument, GetConstructorArguments, +/// and GetGenericType. +/// +public sealed class AttributeDataExtensionTests +{ + /// + /// TryGetNamedArgument returns true and the correct value when the argument exists. + /// + /// A task to monitor the async. + [Test] + public async Task WhenNamedArgumentPresentThenTryGetReturnsTrue() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute + { + public int Count { get; set; } + } + [MyAttr(Count = 42)] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var found = attribute.TryGetNamedArgument("Count", out int? value); + + await Assert.That(found).IsTrue(); + await Assert.That(value).IsEqualTo(42); + } + + /// + /// TryGetNamedArgument returns false when the argument is not present. + /// + /// A task to monitor the async. + [Test] + public async Task WhenNamedArgumentAbsentThenTryGetReturnsFalse() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute + { + public int Count { get; set; } + } + [MyAttr] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var found = attribute.TryGetNamedArgument("Count", out int? value); + + await Assert.That(found).IsFalse(); + await Assert.That(value).IsNull(); + } + + /// + /// TryGetNamedArgument returns false and default when the argument name does not match. + /// + /// A task to monitor the async. + [Test] + public async Task WhenWrongArgumentNameThenTryGetReturnsFalse() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute + { + public int Count { get; set; } + } + [MyAttr(Count = 5)] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var found = attribute.TryGetNamedArgument("Other", out int? value); + + await Assert.That(found).IsFalse(); + await Assert.That(value).IsNull(); + } + + /// + /// TryGetNamedArgument returns false when called on a null AttributeData. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAttributeDataIsNullThenTryGetReturnsFalse() + { + AttributeData? nullAttr = null; + var found = nullAttr!.TryGetNamedArgument("X", out int? value); + + await Assert.That(found).IsFalse(); + await Assert.That(value).IsNull(); + } + + /// + /// TryGetNamedArgument retrieves a string named argument. + /// + /// A task to monitor the async. + [Test] + public async Task WhenStringNamedArgumentPresentThenTryGetReturnsValue() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute + { + public string? Name { get; set; } + } + [MyAttr(Name = "hello")] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var found = attribute.TryGetNamedArgument("Name", out string? value); + + await Assert.That(found).IsTrue(); + await Assert.That(value).IsEqualTo("hello"); + } + + /// + /// TryGetNamedArgument retrieves a bool named argument. + /// + /// A task to monitor the async. + [Test] + public async Task WhenBoolNamedArgumentPresentThenTryGetReturnsValue() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute + { + public bool IsEnabled { get; set; } + } + [MyAttr(IsEnabled = true)] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var found = attribute.TryGetNamedArgument("IsEnabled", out bool? value); + + await Assert.That(found).IsTrue(); + await Assert.That(value).IsTrue(); + } + + /// + /// GetNamedArgument returns the value when the argument is present. + /// + /// A task to monitor the async. + [Test] + public async Task WhenNamedArgumentPresentThenGetNamedArgumentReturnsValue() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute + { + public int Count { get; set; } + } + [MyAttr(Count = 7)] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var value = attribute.GetNamedArgument("Count"); + + await Assert.That(value).IsEqualTo(7); + } + + /// + /// GetNamedArgument returns default when the argument is absent. + /// + /// A task to monitor the async. + [Test] + public async Task WhenNamedArgumentAbsentThenGetNamedArgumentReturnsDefault() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute + { + public int Count { get; set; } + } + [MyAttr] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var value = attribute.GetNamedArgument("Count"); + + await Assert.That(value).IsEqualTo(0); + } + + /// + /// GetNamedArgument returns default when called on a null AttributeData. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAttributeDataIsNullThenGetNamedArgumentReturnsDefault() + { + AttributeData? nullAttr = null; + var value = nullAttr!.GetNamedArgument("X"); + + await Assert.That(value).IsEqualTo(0); + } + + /// + /// GetConstructorArguments yields all string constructor arguments. + /// + /// A task to monitor the async. + [Test] + public async Task WhenStringConstructorArgsPresentThenGetConstructorArgumentsYieldsAll() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute + { + public MyAttr(string a, string b) { } + } + [MyAttr("hello", "world")] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var args = attribute.GetConstructorArguments().ToList(); + + await Assert.That(args.Count).IsEqualTo(2); + await Assert.That(args[0]).IsEqualTo("hello"); + await Assert.That(args[1]).IsEqualTo("world"); + } + + /// + /// GetConstructorArguments yields nothing when there are no constructor arguments of the requested type. + /// + /// A task to monitor the async. + [Test] + public async Task WhenNoMatchingConstructorArgsThenGetConstructorArgumentsIsEmpty() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute { } + [MyAttr] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var args = attribute.GetConstructorArguments().ToList(); + + await Assert.That(args.Count).IsEqualTo(0); + } + + /// + /// GetGenericType returns the type argument name for a generic attribute. + /// + /// A task to monitor the async. + [Test] + public async Task WhenGenericAttributeThenGetGenericTypeReturnsTypeName() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute { } + [MyAttr] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var type = attribute.GetGenericType(); + + await Assert.That(type).IsEqualTo("int"); + } + + /// + /// GetGenericType returns null for a non-generic attribute. + /// + /// A task to monitor the async. + [Test] + public async Task WhenNonGenericAttributeThenGetGenericTypeReturnsNull() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class MyAttr : Attribute { } + [MyAttr] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "MyAttr"); + + var type = attribute.GetGenericType(); + + await Assert.That(type).IsNull(); + } + + /// + /// GetGenericType returns the type keyword for a generic argument using a built-in type. + /// + /// A task to monitor the async. + [Test] + public async Task WhenGenericAttributeWithClassTypeThenGetGenericTypeReturnsClassName() + { + const string source = """ + using System; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class WrapAttr : Attribute { } + [WrapAttr] + public class C { } + """; + var attribute = GetAttribute(source, "T.C", "WrapAttr"); + + var type = attribute.GetGenericType(); + + await Assert.That(type).IsEqualTo("string"); + } + + /// + /// GatherForwardedAttributesFromClass collects non-trigger attributes from the class declaration. + /// + /// A task to monitor the async. + [Test] + public async Task WhenClassHasAttributesThenForwardedAttributesCollected() + { + const string source = """ + using System; + using System.ComponentModel; + namespace T; + [AttributeUsage(AttributeTargets.Class)] + public class TriggerAttr : Attribute { } + [TriggerAttr] + [Description("test")] + public class C { } + """; + + var compilation = CreateCompilation(source); + var classDecl = compilation.SyntaxTrees + .SelectMany(t => t.GetRoot().DescendantNodes()) + .OfType() + .First(c => c.Identifier.Text == "C"); + + var semanticModel = compilation.GetSemanticModel(classDecl.SyntaxTree); + var typeSymbol = (INamedTypeSymbol)compilation.GetTypeByMetadataName("T.C")!; + var triggerAttr = typeSymbol.GetAttributes() + .First(a => a.AttributeClass?.Name == "TriggerAttr"); + + triggerAttr.GatherForwardedAttributesFromClass( + semanticModel, + classDecl, + default, + out var forwarded); + + await Assert.That(forwarded.Length).IsGreaterThan(0); + await Assert.That(forwarded.Any(a => a.TypeName.Contains("TriggerAttr"))).IsFalse(); + } + + private static AttributeData GetAttribute(string source, string typeName, string attributeSimpleName) + { + var compilation = CreateCompilation(source); + var typeSymbol = compilation.GetTypeByMetadataName(typeName) + ?? throw new InvalidOperationException($"Type '{typeName}' not found in compilation."); + + return typeSymbol.GetAttributes() + .First(a => a.AttributeClass?.Name == attributeSimpleName); + } + + private static CSharpCompilation CreateCompilation(string source) + { + var syntaxTree = CSharpSyntaxTree.ParseText( + source, + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13)); + + return CSharpCompilation.Create( + assemblyName: "AttrDataExtTests", + syntaxTrees: [syntaxTree], + references: TestCompilationReferences.CreateDefault(), + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + } +} diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/EquatableArrayTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/EquatableArrayTests.cs new file mode 100644 index 0000000..01869a2 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/EquatableArrayTests.cs @@ -0,0 +1,264 @@ +// Copyright (c) 2026 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.Helpers; + +namespace ReactiveUI.SourceGenerator.Tests; + +/// +/// Unit tests for . +/// +public sealed class EquatableArrayTests +{ + /// + /// Two arrays with identical elements are equal. + /// + /// A task to monitor the async. + [Test] + public async Task WhenSameElementsThenEqual() + { + var a = ImmutableArray.Create(1, 2, 3).AsEquatableArray(); + var b = ImmutableArray.Create(1, 2, 3).AsEquatableArray(); + + await Assert.That(a == b).IsTrue(); + await Assert.That(a.Equals(b)).IsTrue(); + await Assert.That(a != b).IsFalse(); + } + + /// + /// Two arrays with different elements are not equal. + /// + /// A task to monitor the async. + [Test] + public async Task WhenDifferentElementsThenNotEqual() + { + var a = ImmutableArray.Create(1, 2, 3).AsEquatableArray(); + var b = ImmutableArray.Create(1, 2, 4).AsEquatableArray(); + + await Assert.That(a == b).IsFalse(); + await Assert.That(a != b).IsTrue(); + } + + /// + /// Arrays with the same elements in different order are not equal. + /// + /// A task to monitor the async. + [Test] + public async Task WhenDifferentOrderThenNotEqual() + { + var a = ImmutableArray.Create(1, 2, 3).AsEquatableArray(); + var b = ImmutableArray.Create(3, 2, 1).AsEquatableArray(); + + await Assert.That(a == b).IsFalse(); + } + + /// + /// An empty array equals another empty array. + /// + /// A task to monitor the async. + [Test] + public async Task WhenBothEmptyThenEqual() + { + var a = ImmutableArray.Empty.AsEquatableArray(); + var b = ImmutableArray.Empty.AsEquatableArray(); + + await Assert.That(a == b).IsTrue(); + await Assert.That(a.IsEmpty).IsTrue(); + } + + /// + /// An empty array is not equal to a non-empty array. + /// + /// A task to monitor the async. + [Test] + public async Task WhenOneEmptyThenNotEqual() + { + var a = ImmutableArray.Empty.AsEquatableArray(); + var b = ImmutableArray.Create(1).AsEquatableArray(); + + await Assert.That(a == b).IsFalse(); + } + + /// + /// The indexer returns the element at the given position. + /// + /// A task to monitor the async. + [Test] + public async Task WhenIndexedThenReturnsCorrectElement() + { + var arr = ImmutableArray.Create(10, 20, 30).AsEquatableArray(); + + await Assert.That(arr[0]).IsEqualTo(10); + await Assert.That(arr[1]).IsEqualTo(20); + await Assert.That(arr[2]).IsEqualTo(30); + } + + /// + /// Enumeration yields all elements in order. + /// + /// A task to monitor the async. + [Test] + public async Task WhenEnumeratedThenYieldsAllElements() + { + var expected = new[] { 1, 2, 3 }; + var arr = ImmutableArray.Create(expected).AsEquatableArray(); + + var actual = arr.ToList(); + + await Assert.That(actual.Count).IsEqualTo(3); + await Assert.That(actual[0]).IsEqualTo(1); + await Assert.That(actual[1]).IsEqualTo(2); + await Assert.That(actual[2]).IsEqualTo(3); + } + + /// + /// Implicit conversion from ImmutableArray preserves elements. + /// + /// A task to monitor the async. + [Test] + public async Task WhenImplicitlyConvertedFromImmutableArrayThenPreservesElements() + { + var immutable = ImmutableArray.Create(5, 6, 7); + EquatableArray equatable = immutable; + + await Assert.That(equatable[0]).IsEqualTo(5); + await Assert.That(equatable[1]).IsEqualTo(6); + await Assert.That(equatable[2]).IsEqualTo(7); + } + + /// + /// Implicit conversion to ImmutableArray preserves elements. + /// + /// A task to monitor the async. + [Test] + public async Task WhenImplicitlyConvertedToImmutableArrayThenPreservesElements() + { + var equatable = ImmutableArray.Create(8, 9).AsEquatableArray(); + ImmutableArray immutable = equatable; + + await Assert.That(immutable.Length).IsEqualTo(2); + await Assert.That(immutable[0]).IsEqualTo(8); + await Assert.That(immutable[1]).IsEqualTo(9); + } + + /// + /// ToArray returns a mutable copy with the same elements. + /// + /// A task to monitor the async. + [Test] + public async Task WhenToArrayCalledThenReturnsMutableCopy() + { + var arr = ImmutableArray.Create(1, 2, 3).AsEquatableArray(); + var copy = arr.ToArray(); + + await Assert.That(copy.Length).IsEqualTo(3); + await Assert.That(copy[0]).IsEqualTo(1); + await Assert.That(copy[2]).IsEqualTo(3); + } + + /// + /// AsSpan returns a span over the elements. + /// + [Test] + public void WhenAsSpanCalledThenSpanCoversElements() + { + var arr = ImmutableArray.Create(1, 2, 3).AsEquatableArray(); + var span = arr.AsSpan(); + var length = span.Length; + var mid = span[1]; + + if (length != 3) + { + throw new InvalidOperationException($"Expected span length 3, got {length}."); + } + + if (mid != 2) + { + throw new InvalidOperationException($"Expected span[1] == 2, got {mid}."); + } + } + + /// + /// GetHashCode returns the same value for equal arrays. + /// + /// A task to monitor the async. + [Test] + public async Task WhenEqualArraysThenSameHashCode() + { + var a = ImmutableArray.Create(1, 2, 3).AsEquatableArray(); + var b = ImmutableArray.Create(1, 2, 3).AsEquatableArray(); + + await Assert.That(a.GetHashCode()).IsEqualTo(b.GetHashCode()); + } + + /// + /// Equals(object) returns true when passed an equal EquatableArray. + /// + /// A task to monitor the async. + [Test] + public async Task WhenEqualsObjectCalledWithEqualArrayThenReturnsTrue() + { + var a = ImmutableArray.Create(1, 2).AsEquatableArray(); + object b = ImmutableArray.Create(1, 2).AsEquatableArray(); + + await Assert.That(a.Equals(b)).IsTrue(); + } + + /// + /// Equals(object) returns false when passed null. + /// + /// A task to monitor the async. + [Test] + public async Task WhenEqualsObjectCalledWithNullThenReturnsFalse() + { + var a = ImmutableArray.Create(1).AsEquatableArray(); + + await Assert.That(a.Equals(null)).IsFalse(); + } + + /// + /// AsImmutableArray round-trips back to ImmutableArray. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAsImmutableArrayCalledThenRoundTrips() + { + var source = ImmutableArray.Create("x", "y", "z"); + var equatable = source.AsEquatableArray(); + var roundTripped = equatable.AsImmutableArray(); + + await Assert.That(roundTripped.SequenceEqual(source)).IsTrue(); + } + + /// + /// FromImmutableArray static factory produces an equal instance to the extension method. + /// + /// A task to monitor the async. + [Test] + public async Task WhenCreatedViaFactoryThenEqualsExtensionMethod() + { + var immutable = ImmutableArray.Create(1, 2, 3); + var viaExtension = immutable.AsEquatableArray(); + var viaFactory = EquatableArray.FromImmutableArray(immutable); + + await Assert.That(viaExtension == viaFactory).IsTrue(); + } + + /// + /// IEnumerable<T> explicit interface yields elements correctly. + /// + /// A task to monitor the async. + [Test] + public async Task WhenEnumeratedAsIEnumerableThenYieldsCorrectly() + { + IEnumerable arr = ImmutableArray.Create(7, 8, 9).AsEquatableArray(); + var list = arr.ToList(); + + await Assert.That(list.Count).IsEqualTo(3); + await Assert.That(list[0]).IsEqualTo(7); + await Assert.That(list[1]).IsEqualTo(8); + await Assert.That(list[2]).IsEqualTo(9); + } +} diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/FieldSyntaxExtensionTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/FieldSyntaxExtensionTests.cs new file mode 100644 index 0000000..bc31ed9 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/FieldSyntaxExtensionTests.cs @@ -0,0 +1,216 @@ +// Copyright (c) 2026 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.Extensions; + +namespace ReactiveUI.SourceGenerator.Tests; + +/// +/// Unit tests for covering +/// GetGeneratedPropertyName and GetGeneratedFieldName. +/// These are verified by running the generator over source strings and inspecting +/// the field/property symbols extracted from the resulting compilation. +/// +public sealed class FieldSyntaxExtensionTests +{ + /// + /// A field named with leading underscore prefix has the underscore stripped + /// and the first letter upper-cased. + /// + /// A task to monitor the async. + [Test] + public async Task WhenFieldHasLeadingUnderscoreThenPropertyNameCapitalises() + { + const string source = """ + namespace T; + public class C + { + private int _myField; + } + """; + var fieldSymbol = GetFieldSymbol(source, "_myField"); + + var name = fieldSymbol.GetGeneratedPropertyName(); + + await Assert.That(name).IsEqualTo("MyField"); + } + + /// + /// A field named with "m_" prefix has the prefix stripped and the first remaining + /// letter upper-cased. + /// + /// A task to monitor the async. + [Test] + public async Task WhenFieldHasMUnderscorePrefixThenPropertyNameCapitalises() + { + const string source = """ + namespace T; + public class C + { + private int m_value; + } + """; + var fieldSymbol = GetFieldSymbol(source, "m_value"); + + var name = fieldSymbol.GetGeneratedPropertyName(); + + await Assert.That(name).IsEqualTo("Value"); + } + + /// + /// A field named with lowerCamel (no prefix) has its first letter upper-cased. + /// + /// A task to monitor the async. + [Test] + public async Task WhenFieldHasLowerCamelThenPropertyNameCapitalises() + { + const string source = """ + namespace T; + public class C + { + private int count; + } + """; + var fieldSymbol = GetFieldSymbol(source, "count"); + + var name = fieldSymbol.GetGeneratedPropertyName(); + + await Assert.That(name).IsEqualTo("Count"); + } + + /// + /// Multiple leading underscores are all stripped before capitalisation. + /// + /// A task to monitor the async. + [Test] + public async Task WhenFieldHasMultipleLeadingUnderscoresThenAllStripped() + { + const string source = """ + namespace T; + public class C + { + private int __item; + } + """; + var fieldSymbol = GetFieldSymbol(source, "__item"); + + var name = fieldSymbol.GetGeneratedPropertyName(); + + await Assert.That(name).IsEqualTo("Item"); + } + + /// + /// A single-character field name (after stripping) still capitalises correctly. + /// + /// A task to monitor the async. + [Test] + public async Task WhenFieldIsOneCharacterThenCapitalisedCorrectly() + { + const string source = """ + namespace T; + public class C + { + private int _x; + } + """; + var fieldSymbol = GetFieldSymbol(source, "_x"); + + var name = fieldSymbol.GetGeneratedPropertyName(); + + await Assert.That(name).IsEqualTo("X"); + } + + /// + /// A property named "MyProperty" produces a backing field named "_myProperty". + /// + /// A task to monitor the async. + [Test] + public async Task WhenPropertyNamedMyPropertyThenFieldIsUnderscoreLower() + { + const string source = """ + namespace T; + public class C + { + public int MyProperty { get; set; } + } + """; + var propertySymbol = GetPropertySymbol(source, "MyProperty"); + + var name = propertySymbol.GetGeneratedFieldName(); + + await Assert.That(name).IsEqualTo("_myProperty"); + } + + /// + /// A single-character property name produces a correct field name. + /// + /// A task to monitor the async. + [Test] + public async Task WhenPropertyIsSingleCharacterThenFieldNameIsCorrect() + { + const string source = """ + namespace T; + public class C + { + public int X { get; set; } + } + """; + var propertySymbol = GetPropertySymbol(source, "X"); + + var name = propertySymbol.GetGeneratedFieldName(); + + await Assert.That(name).IsEqualTo("_x"); + } + + /// + /// A property already starting with a lowercase letter still prefixes underscore. + /// + /// A task to monitor the async. + [Test] + public async Task WhenPropertyStartsWithLowercaseThenFieldNameHasUnderscore() + { + const string source = """ + namespace T; + public class C + { + public int value { get; set; } + } + """; + var propertySymbol = GetPropertySymbol(source, "value"); + + var name = propertySymbol.GetGeneratedFieldName(); + + await Assert.That(name).IsEqualTo("_value"); + } + + private static IFieldSymbol GetFieldSymbol(string source, string fieldName) + { + var compilation = CreateCompilation(source); + return compilation.GetSymbolsWithName(fieldName, SymbolFilter.Member) + .OfType() + .Single(); + } + + private static IPropertySymbol GetPropertySymbol(string source, string propertyName) + { + var compilation = CreateCompilation(source); + return compilation.GetSymbolsWithName(propertyName, SymbolFilter.Member) + .OfType() + .Single(); + } + + private static CSharpCompilation CreateCompilation(string source) + { + var syntaxTree = CSharpSyntaxTree.ParseText( + source, + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13)); + + return CSharpCompilation.Create( + assemblyName: "FieldSyntaxTests", + syntaxTrees: [syntaxTree], + references: TestCompilationReferences.CreateDefault(), + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + } +} diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ImmutableArrayBuilderTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ImmutableArrayBuilderTests.cs new file mode 100644 index 0000000..6a5a0b1 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ImmutableArrayBuilderTests.cs @@ -0,0 +1,269 @@ +// Copyright (c) 2026 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.Helpers; + +namespace ReactiveUI.SourceGenerator.Tests; + +/// +/// Unit tests for . +/// +public sealed class ImmutableArrayBuilderTests +{ + /// + /// A freshly rented builder starts with Count == 0. + /// + /// A task to monitor the async. + [Test] + public async Task WhenRentedThenCountIsZero() + { + int count; + using (var builder = ImmutableArrayBuilder.Rent()) + { + count = builder.Count; + } + + await Assert.That(count).IsEqualTo(0); + } + + /// + /// Adding a single item increments Count to 1. + /// + /// A task to monitor the async. + [Test] + public async Task WhenItemAddedThenCountIncrements() + { + int count; + using (var builder = ImmutableArrayBuilder.Rent()) + { + builder.Add(42); + count = builder.Count; + } + + await Assert.That(count).IsEqualTo(1); + } + + /// + /// Multiple adds are reflected in Count. + /// + /// A task to monitor the async. + [Test] + public async Task WhenMultipleItemsAddedThenCountMatchesAdded() + { + int count; + using (var builder = ImmutableArrayBuilder.Rent()) + { + builder.Add(1); + builder.Add(2); + builder.Add(3); + count = builder.Count; + } + + await Assert.That(count).IsEqualTo(3); + } + + /// + /// ToImmutable returns an array containing all added items in order. + /// + /// A task to monitor the async. + [Test] + public async Task WhenToImmutableCalledThenContainsAddedItems() + { + ImmutableArray result; + using (var builder = ImmutableArrayBuilder.Rent()) + { + builder.Add(10); + builder.Add(20); + builder.Add(30); + result = builder.ToImmutable(); + } + + await Assert.That(result.Length).IsEqualTo(3); + await Assert.That(result[0]).IsEqualTo(10); + await Assert.That(result[1]).IsEqualTo(20); + await Assert.That(result[2]).IsEqualTo(30); + } + + /// + /// ToArray returns a mutable array with the same elements. + /// + /// A task to monitor the async. + [Test] + public async Task WhenToArrayCalledThenReturnsMutableArray() + { + string[] result; + using (var builder = ImmutableArrayBuilder.Rent()) + { + builder.Add("a"); + builder.Add("b"); + result = builder.ToArray(); + } + + await Assert.That(result.Length).IsEqualTo(2); + await Assert.That(result[0]).IsEqualTo("a"); + await Assert.That(result[1]).IsEqualTo("b"); + } + + /// + /// AddRange appends all items from the span. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAddRangeCalledThenAllItemsAppended() + { + int count; + ImmutableArray result; + using (var builder = ImmutableArrayBuilder.Rent()) + { + ReadOnlySpan items = [1, 2, 3, 4, 5]; + builder.AddRange(items); + count = builder.Count; + result = builder.ToImmutable(); + } + + await Assert.That(count).IsEqualTo(5); + await Assert.That(result[4]).IsEqualTo(5); + } + + /// + /// WrittenSpan reflects the items added so far. + /// + [Test] + public void WhenWrittenSpanAccessedThenReflectsCurrentItems() + { + int length; + int first; + int second; + using (var builder = ImmutableArrayBuilder.Rent()) + { + builder.Add(7); + builder.Add(8); + var span = builder.WrittenSpan; + length = span.Length; + first = span[0]; + second = span[1]; + } + + if (length != 2) + { + throw new InvalidOperationException($"Expected WrittenSpan.Length 2, got {length}."); + } + + if (first != 7 || second != 8) + { + throw new InvalidOperationException($"Expected 7, 8 but got {first}, {second}."); + } + } + + /// + /// AsEnumerable returns an IEnumerable containing all added items. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAsEnumerableCalledThenYieldsAllItems() + { + List list; + using (var builder = ImmutableArrayBuilder.Rent()) + { + builder.Add(100); + builder.Add(200); + list = builder.AsEnumerable().ToList(); + } + + await Assert.That(list.Count).IsEqualTo(2); + await Assert.That(list[0]).IsEqualTo(100); + await Assert.That(list[1]).IsEqualTo(200); + } + + /// + /// Builder can hold more than the initial capacity (pool growth). + /// + /// A task to monitor the async. + [Test] + public async Task WhenManyItemsAddedThenBuilderGrowsCorrectly() + { + int count; + ImmutableArray result; + using (var builder = ImmutableArrayBuilder.Rent()) + { + for (var i = 0; i < 100; i++) + { + builder.Add(i); + } + + count = builder.Count; + result = builder.ToImmutable(); + } + + await Assert.That(count).IsEqualTo(100); + await Assert.That(result[99]).IsEqualTo(99); + } + + /// + /// ToImmutable on an empty builder returns an empty ImmutableArray. + /// + /// A task to monitor the async. + [Test] + public async Task WhenEmptyThenToImmutableReturnsEmpty() + { + ImmutableArray result; + using (var builder = ImmutableArrayBuilder.Rent()) + { + result = builder.ToImmutable(); + } + + await Assert.That(result.IsEmpty).IsTrue(); + } + + /// + /// ToString returns the WrittenSpan string representation without throwing. + /// + /// A task to monitor the async. + [Test] + public async Task WhenToStringCalledThenDoesNotThrow() + { + string result; + using (var builder = ImmutableArrayBuilder.Rent()) + { + builder.Add('H'); + builder.Add('i'); + result = builder.ToString(); + } + + await Assert.That(result).IsNotNull(); + } + + /// + /// Dispose can be called multiple times without throwing. + /// + [Test] + public void WhenDisposedTwiceThenDoesNotThrow() + { + var builder = ImmutableArrayBuilder.Rent(); + builder.Add(1); + builder.Dispose(); + builder.Dispose(); + } + + /// + /// AddRange followed by Add correctly appends items in order. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAddRangeThenAddThenOrderPreserved() + { + ImmutableArray result; + using (var builder = ImmutableArrayBuilder.Rent()) + { + ReadOnlySpan range = [1, 2, 3]; + builder.AddRange(range); + builder.Add(4); + result = builder.ToImmutable(); + } + + await Assert.That(result.Length).IsEqualTo(4); + await Assert.That(result[3]).IsEqualTo(4); + } +} diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/SymbolExtensionTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/SymbolExtensionTests.cs new file mode 100644 index 0000000..87f56c9 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/SymbolExtensionTests.cs @@ -0,0 +1,524 @@ +// Copyright (c) 2026 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.Extensions; + +namespace ReactiveUI.SourceGenerator.Tests; + +/// +/// Unit tests for , , +/// , and . +/// All tests compile small in-memory programs to obtain real Roslyn symbol instances. +/// +public sealed class SymbolExtensionTests +{ + /// + /// GetFullyQualifiedName returns the global:: prefixed name. + /// + /// A task to monitor the async. + [Test] + public async Task WhenGetFullyQualifiedNameCalledThenReturnsGlobalPrefixedName() + { + var symbol = GetTypeSymbol( + """ + namespace Foo.Bar; + public class MyClass { } + """, + "MyClass"); + + var name = symbol.GetFullyQualifiedName(); + + await Assert.That(name).IsEqualTo("global::Foo.Bar.MyClass"); + } + + /// + /// GetFullyQualifiedNameWithNullabilityAnnotations includes the nullable annotation marker. + /// + /// A task to monitor the async. + [Test] + public async Task WhenGetFullyQualifiedNameWithNullabilityCalledThenIncludesAnnotation() + { + var symbol = GetFieldSymbol( + """ + #nullable enable + namespace T; + public class C + { + public string? _name; + } + """, + "_name"); + + var name = symbol.Type.GetFullyQualifiedNameWithNullabilityAnnotations(); + + await Assert.That(name).IsEqualTo("string?"); + } + + /// + /// HasAttributeWithFullyQualifiedMetadataName returns true when the attribute is present. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAttributePresentThenHasAttributeWithNameReturnsTrue() + { + var symbol = GetTypeSymbol( + """ + using System; + namespace T; + [Obsolete] + public class C { } + """, + "C"); + + var result = symbol.HasAttributeWithFullyQualifiedMetadataName("System.ObsoleteAttribute"); + + await Assert.That(result).IsTrue(); + } + + /// + /// HasAttributeWithFullyQualifiedMetadataName returns false when the attribute is absent. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAttributeAbsentThenHasAttributeWithNameReturnsFalse() + { + var symbol = GetTypeSymbol( + """ + namespace T; + public class C { } + """, + "C"); + + var result = symbol.HasAttributeWithFullyQualifiedMetadataName("System.ObsoleteAttribute"); + + await Assert.That(result).IsFalse(); + } + + /// + /// TryGetAttributeWithFullyQualifiedMetadataName returns true and outputs AttributeData when present. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAttributePresentThenTryGetAttributeSucceeds() + { + var symbol = GetTypeSymbol( + """ + using System; + namespace T; + [Obsolete("old")] + public class C { } + """, + "C"); + + var found = symbol.TryGetAttributeWithFullyQualifiedMetadataName( + "System.ObsoleteAttribute", + out var attributeData); + + await Assert.That(found).IsTrue(); + await Assert.That(attributeData).IsNotNull(); + } + + /// + /// TryGetAttributeWithFullyQualifiedMetadataName returns false when attribute is absent. + /// + /// A task to monitor the async. + [Test] + public async Task WhenAttributeAbsentThenTryGetAttributeFails() + { + var symbol = GetTypeSymbol( + """ + namespace T; + public class C { } + """, + "C"); + + var found = symbol.TryGetAttributeWithFullyQualifiedMetadataName( + "System.ObsoleteAttribute", + out var attributeData); + + await Assert.That(found).IsFalse(); + await Assert.That(attributeData).IsNull(); + } + + /// + /// GetEffectiveAccessibility returns Public for a public class. + /// + /// A task to monitor the async. + [Test] + public async Task WhenPublicClassThenEffectiveAccessibilityIsPublic() + { + var symbol = GetTypeSymbol( + """ + namespace T; + public class C { } + """, + "C"); + + var accessibility = symbol.GetEffectiveAccessibility(); + + await Assert.That(accessibility).IsEqualTo(Accessibility.Public); + } + + /// + /// GetEffectiveAccessibility returns Internal for an internal class. + /// + /// A task to monitor the async. + [Test] + public async Task WhenInternalClassThenEffectiveAccessibilityIsInternal() + { + var symbol = GetTypeSymbol( + """ + namespace T; + internal class C { } + """, + "C"); + + var accessibility = symbol.GetEffectiveAccessibility(); + + await Assert.That(accessibility).IsEqualTo(Accessibility.Internal); + } + + /// + /// GetAccessibilityString returns "public" for a public symbol. + /// + /// A task to monitor the async. + [Test] + public async Task WhenPublicThenGetAccessibilityStringReturnsPublic() + { + var symbol = GetTypeSymbol( + """ + namespace T; + public class C { } + """, + "C"); + + await Assert.That(symbol.GetAccessibilityString()).IsEqualTo("public"); + } + + /// + /// GetAccessibilityString returns "internal" for an internal symbol. + /// + /// A task to monitor the async. + [Test] + public async Task WhenInternalThenGetAccessibilityStringReturnsInternal() + { + var symbol = GetTypeSymbol( + """ + namespace T; + internal class C { } + """, + "C"); + + await Assert.That(symbol.GetAccessibilityString()).IsEqualTo("internal"); + } + + /// + /// HasOrInheritsFromFullyQualifiedMetadataName returns true for the type itself. + /// + /// A task to monitor the async. + [Test] + public async Task WhenTypeIsSelfThenHasOrInheritsReturnsTrue() + { + var symbol = GetTypeSymbol( + """ + namespace T; + public class C { } + """, + "C"); + + var result = symbol.HasOrInheritsFromFullyQualifiedMetadataName("T.C"); + + await Assert.That(result).IsTrue(); + } + + /// + /// HasOrInheritsFromFullyQualifiedMetadataName returns true for a direct base class. + /// + /// A task to monitor the async. + [Test] + public async Task WhenTypeDerivedFromBaseThenHasOrInheritsReturnsTrue() + { + var compilation = CreateCompilation(""" + namespace T; + public class Base { } + public class Derived : Base { } + """); + + var derived = compilation.GetTypeByMetadataName("T.Derived")!; + var result = derived.HasOrInheritsFromFullyQualifiedMetadataName("T.Base"); + + await Assert.That(result).IsTrue(); + } + + /// + /// HasOrInheritsFromFullyQualifiedMetadataName returns false for an unrelated type. + /// + /// A task to monitor the async. + [Test] + public async Task WhenTypeUnrelatedThenHasOrInheritsReturnsFalse() + { + var compilation = CreateCompilation(""" + namespace T; + public class A { } + public class B { } + """); + + var a = compilation.GetTypeByMetadataName("T.A")!; + var result = a.HasOrInheritsFromFullyQualifiedMetadataName("T.B"); + + await Assert.That(result).IsFalse(); + } + + /// + /// InheritsFromFullyQualifiedMetadataName returns false for the type itself (not inherited). + /// + /// A task to monitor the async. + [Test] + public async Task WhenTypeSelfThenInheritsReturnsFalse() + { + var symbol = GetTypeSymbol( + """ + namespace T; + public class C { } + """, + "C"); + + var result = symbol.InheritsFromFullyQualifiedMetadataName("T.C"); + + await Assert.That(result).IsFalse(); + } + + /// + /// ImplementsFullyQualifiedMetadataName returns true when the interface is implemented. + /// + /// A task to monitor the async. + [Test] + public async Task WhenInterfaceImplementedThenImplementsReturnsTrue() + { + var compilation = CreateCompilation(""" + namespace T; + public interface IFoo { } + public class C : IFoo { } + """); + + var c = compilation.GetTypeByMetadataName("T.C")!; + var result = c.ImplementsFullyQualifiedMetadataName("T.IFoo"); + + await Assert.That(result).IsTrue(); + } + + /// + /// GetFullyQualifiedMetadataName returns dotted name without global:: prefix. + /// + /// A task to monitor the async. + [Test] + public async Task WhenGetFullyQualifiedMetadataNameCalledThenReturnsDottedName() + { + var symbol = GetTypeSymbol( + """ + namespace Foo.Bar; + public class Baz { } + """, + "Baz"); + + var name = symbol.GetFullyQualifiedMetadataName(); + + await Assert.That(name).IsEqualTo("Foo.Bar.Baz"); + } + + /// + /// GetAllMembers returns members from both the type and its base types. + /// + /// A task to monitor the async. + [Test] + public async Task WhenGetAllMembersCalledThenIncludesInheritedMembers() + { + var compilation = CreateCompilation(""" + namespace T; + public class Base + { + public int BaseField; + } + public class Derived : Base + { + public int DerivedField; + } + """); + + var derived = (INamedTypeSymbol)compilation.GetTypeByMetadataName("T.Derived")!; + var members = derived.GetAllMembers().Select(m => m.Name).ToList(); + + await Assert.That(members.Contains("DerivedField")).IsTrue(); + await Assert.That(members.Contains("BaseField")).IsTrue(); + } + + /// + /// GetAllMembers(name) returns members with the matching name from base types. + /// + /// A task to monitor the async. + [Test] + public async Task WhenGetAllMembersWithNameCalledThenFiltersCorrectly() + { + var compilation = CreateCompilation(""" + namespace T; + public class Base + { + public int Shared; + } + public class Derived : Base + { + public int Unique; + } + """); + + var derived = (INamedTypeSymbol)compilation.GetTypeByMetadataName("T.Derived")!; + var members = derived.GetAllMembers("Shared").ToList(); + + await Assert.That(members.Count).IsEqualTo(1); + await Assert.That(members[0].Name).IsEqualTo("Shared"); + } + + /// + /// GetTypeString returns "class" for a regular class. + /// + /// A task to monitor the async. + [Test] + public async Task WhenRegularClassThenGetTypeStringReturnsClass() + { + var symbol = (INamedTypeSymbol)GetTypeSymbol( + """ + namespace T; + public class C { } + """, + "C"); + + await Assert.That(symbol.GetTypeString()).IsEqualTo("class"); + } + + /// + /// GetTypeString returns "record" for a record class. + /// + /// A task to monitor the async. + [Test] + public async Task WhenRecordClassThenGetTypeStringReturnsRecord() + { + var symbol = (INamedTypeSymbol)GetTypeSymbol( + """ + namespace T; + public record C { } + """, + "C"); + + await Assert.That(symbol.GetTypeString()).IsEqualTo("record"); + } + + /// + /// GetTypeString returns "struct" for a regular struct. + /// + /// A task to monitor the async. + [Test] + public async Task WhenStructThenGetTypeStringReturnsStruct() + { + var symbol = (INamedTypeSymbol)GetTypeSymbol( + """ + namespace T; + public struct S { } + """, + "S"); + + await Assert.That(symbol.GetTypeString()).IsEqualTo("struct"); + } + + /// + /// GetTypeString returns "record struct" for a record struct. + /// + /// A task to monitor the async. + [Test] + public async Task WhenRecordStructThenGetTypeStringReturnsRecordStruct() + { + var symbol = (INamedTypeSymbol)GetTypeSymbol( + """ + namespace T; + public record struct RS { } + """, + "RS"); + + await Assert.That(symbol.GetTypeString()).IsEqualTo("record struct"); + } + + /// + /// GetTypeString returns "interface" for an interface. + /// + /// A task to monitor the async. + [Test] + public async Task WhenInterfaceThenGetTypeStringReturnsInterface() + { + var symbol = (INamedTypeSymbol)GetTypeSymbol( + """ + namespace T; + public interface IFoo { } + """, + "IFoo"); + + await Assert.That(symbol.GetTypeString()).IsEqualTo("interface"); + } + + /// + /// HasAccessibleTypeWithMetadataName returns true for System.String (always accessible). + /// + /// A task to monitor the async. + [Test] + public async Task WhenWellKnownTypeThenHasAccessibleTypeReturnsTrue() + { + var compilation = CreateCompilation("namespace T; public class C {}"); + + var result = compilation.HasAccessibleTypeWithMetadataName("System.String"); + + await Assert.That(result).IsTrue(); + } + + /// + /// HasAccessibleTypeWithMetadataName returns false for a type that doesn't exist. + /// + /// A task to monitor the async. + [Test] + public async Task WhenUnknownTypeThenHasAccessibleTypeReturnsFalse() + { + var compilation = CreateCompilation("namespace T; public class C {}"); + + var result = compilation.HasAccessibleTypeWithMetadataName("DoesNot.Exist.Type"); + + await Assert.That(result).IsFalse(); + } + + private static ITypeSymbol GetTypeSymbol(string source, string typeName) + { + var compilation = CreateCompilation(source); + return compilation.GetSymbolsWithName(typeName, SymbolFilter.Type) + .OfType() + .Single(); + } + + private static IFieldSymbol GetFieldSymbol(string source, string fieldName) + { + var compilation = CreateCompilation(source); + return compilation.GetSymbolsWithName(fieldName, SymbolFilter.Member) + .OfType() + .Single(); + } + + private static CSharpCompilation CreateCompilation(string source) + { + var syntaxTree = CSharpSyntaxTree.ParseText( + source, + CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13)); + + return CSharpCompilation.Create( + assemblyName: "SymbolExtTests", + syntaxTrees: [syntaxTree], + references: TestCompilationReferences.CreateDefault(), + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + } +} diff --git a/src/ReactiveUI.SourceGenerators.Analyzers.CodeFixes/Core/Helpers/EquatableArray{T}.cs b/src/ReactiveUI.SourceGenerators.Analyzers.CodeFixes/Core/Helpers/EquatableArray{T}.cs index b2c726c..95c56a1 100644 --- a/src/ReactiveUI.SourceGenerators.Analyzers.CodeFixes/Core/Helpers/EquatableArray{T}.cs +++ b/src/ReactiveUI.SourceGenerators.Analyzers.CodeFixes/Core/Helpers/EquatableArray{T}.cs @@ -98,7 +98,7 @@ public ref readonly T this[int index] /// /// The object. /// A bool. - public override bool Equals([NotNullWhen(true)] object? obj) => obj is EquatableArray array && Equals(this, array); + public override bool Equals([NotNullWhen(true)] object? obj) => obj is EquatableArray array && Equals(array); /// /// Gets the hash code. diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/Core/Helpers/EquatableArray{T}.cs b/src/ReactiveUI.SourceGenerators.Roslyn/Core/Helpers/EquatableArray{T}.cs index b2c726c..95c56a1 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/Core/Helpers/EquatableArray{T}.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/Core/Helpers/EquatableArray{T}.cs @@ -98,7 +98,7 @@ public ref readonly T this[int index] /// /// The object. /// A bool. - public override bool Equals([NotNullWhen(true)] object? obj) => obj is EquatableArray array && Equals(this, array); + public override bool Equals([NotNullWhen(true)] object? obj) => obj is EquatableArray array && Equals(array); /// /// Gets the hash code. diff --git a/src/ReactiveUI.SourceGenerators.Roslyn4120/ReactiveUI.SourceGenerators.Roslyn4120.csproj b/src/ReactiveUI.SourceGenerators.Roslyn4120/ReactiveUI.SourceGenerators.Roslyn4120.csproj index 660fb21..4b46181 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn4120/ReactiveUI.SourceGenerators.Roslyn4120.csproj +++ b/src/ReactiveUI.SourceGenerators.Roslyn4120/ReactiveUI.SourceGenerators.Roslyn4120.csproj @@ -27,6 +27,7 @@ +