From a6095c7c8687876470553349c3bc62f71cb03466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 3 Jan 2025 21:34:38 +0100 Subject: [PATCH 1/4] Fix modifiers --- ReactiveGenerator/ReactiveGenerator.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ReactiveGenerator/ReactiveGenerator.cs b/ReactiveGenerator/ReactiveGenerator.cs index 01f4cff..16946c1 100644 --- a/ReactiveGenerator/ReactiveGenerator.cs +++ b/ReactiveGenerator/ReactiveGenerator.cs @@ -21,6 +21,9 @@ public string GetPropertyModifiers() { var modifiers = new List(); + if (Property.IsStatic) + modifiers.Add("static"); + if (Property.IsOverride) modifiers.Add("override"); else if (Property.IsVirtual) @@ -28,6 +31,12 @@ public string GetPropertyModifiers() else if (Property.IsAbstract) modifiers.Add("abstract"); + if (Property.IsSealed) + modifiers.Add("sealed"); + + if (Property.IsRequired) + modifiers.Add("required"); + return string.Join(" ", modifiers); } } @@ -711,11 +720,9 @@ private static void GenerateFieldKeywordProperty( var getterAccessibility = TypeHelper.GetAccessorAccessibility(property.GetMethod); var setterAccessibility = TypeHelper.GetAccessorAccessibility(property.SetMethod); - // Create PropertyInfo to get modifiers var propInfo = new PropertyInfo(property, false, false, false); var modifiers = propInfo.GetPropertyModifiers(); - // Combine modifiers with accessibility and partial var declarationModifiers = new List { propertyAccessibility }; if (!string.IsNullOrEmpty(modifiers)) declarationModifiers.Add(modifiers); From 81a30798f1dbaa920296ee90e44ebd6ccbbaa9ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 3 Jan 2025 21:34:45 +0100 Subject: [PATCH 2/4] Add modifiers tests --- .../ReactiveGeneratorTests.cs | 293 ++++++++++++++++++ ...orTests.AccessorModifiersTest.verified.txt | 127 ++++++++ ...ests.AllPropertyModifiersTest.verified.txt | 228 ++++++++++++++ ...sts.ClassWithStaticProperties.verified.txt | 2 +- ...ests.InheritanceModifiersTest.verified.txt | 144 +++++++++ ...ratorTests.MixedModifiersTest.verified.txt | 127 ++++++++ ...torTests.ModifierOrderingTest.verified.txt | 214 +++++++++++++ ...sWithStaticAndInstanceMembers.verified.txt | 2 +- ...eneratorTests.NewModifierTest.verified.txt | 116 +++++++ ...torTests.RequiredModifierTest.verified.txt | 127 ++++++++ ...torTests.RequiredPropertyTest.verified.txt | 113 +++++++ ...edPropertyWithInheritanceTest.verified.txt | 116 +++++++ ...ropertyWithMixedModifiersTest.verified.txt | 130 ++++++++ ...ropertyWithReactiveObjectTest.verified.txt | 56 ++++ ...ratorTests.SealedOverrideTest.verified.txt | 116 +++++++ ...ratorTests.StaticPropertyTest.verified.txt | 99 ++++++ 16 files changed, 2008 insertions(+), 2 deletions(-) create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AccessorModifiersTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AllPropertyModifiersTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.InheritanceModifiersTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.MixedModifiersTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ModifierOrderingTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NewModifierTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredModifierTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithInheritanceTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithMixedModifiersTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithReactiveObjectTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.SealedOverrideTest.verified.txt create mode 100644 ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.StaticPropertyTest.verified.txt diff --git a/ReactiveGenerator.Tests/ReactiveGenerator/ReactiveGeneratorTests.cs b/ReactiveGenerator.Tests/ReactiveGenerator/ReactiveGeneratorTests.cs index 2e5f710..205874f 100644 --- a/ReactiveGenerator.Tests/ReactiveGenerator/ReactiveGeneratorTests.cs +++ b/ReactiveGenerator.Tests/ReactiveGenerator/ReactiveGeneratorTests.cs @@ -1269,4 +1269,297 @@ public partial class RegularClass return TestAndVerify(source); } + + [Fact] + public Task RequiredPropertyTest() + { + var source = @" + [Reactive] + public partial class Person + { + public required partial string Name { get; set; } + public required partial int Age { get; set; } + public partial string? OptionalNickname { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task RequiredPropertyWithReactiveObjectTest() + { + var source = @" + using ReactiveUI; + + [Reactive] + public partial class Person : ReactiveObject + { + public required partial string Name { get; set; } + public required partial DateOnly BirthDate { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task RequiredPropertyWithInheritanceTest() + { + var source = @" + [Reactive] + public abstract partial class Entity + { + public required partial string Id { get; set; } + } + + [Reactive] + public partial class Person : Entity + { + public required partial string Name { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task RequiredPropertyWithMixedModifiersTest() + { + var source = @" + [Reactive] + public partial class BaseClass + { + public required virtual partial string VirtualRequired { get; set; } + } + + [Reactive] + public partial class DerivedClass : BaseClass + { + public required override partial string VirtualRequired { get; set; } + public required partial string LocalRequired { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task AllPropertyModifiersTest() + { + var source = @" + [Reactive] + public partial class Base + { + // Static properties + public static partial string StaticProp { get; set; } + protected static partial string ProtectedStaticProp { get; set; } + + // Virtual and abstract properties + public virtual partial string VirtualProp { get; set; } + public abstract partial string AbstractProp { get; set; } + + // Required properties + public required partial string RequiredProp { get; set; } + + // Mixed modifiers + public required virtual partial string RequiredVirtualProp { get; set; } + } + + [Reactive] + public partial class Derived : Base + { + // New properties (shadowing) + public new partial string VirtualProp { get; set; } + + // Override properties + public override partial string AbstractProp { get; set; } + + // Sealed override properties + public sealed override partial string RequiredVirtualProp { get; set; } + + // Static shadows + public new static partial string StaticProp { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task StaticPropertyTest() + { + var source = @" + [Reactive] + public partial class TestClass + { + public static partial string GlobalConfig { get; set; } + private static partial int Counter { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task NewModifierTest() + { + var source = @" + [Reactive] + public partial class Base + { + public partial string Name { get; set; } + } + + [Reactive] + public partial class Derived : Base + { + public new partial string Name { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task SealedOverrideTest() + { + var source = @" + [Reactive] + public partial class Base + { + public virtual partial string VirtualProp { get; set; } + } + + [Reactive] + public partial class Derived : Base + { + public sealed override partial string VirtualProp { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task MixedModifiersTest() + { + var source = @" + [Reactive] + public partial class TestClass + { + // Static + Required + public static required partial string StaticRequired { get; set; } + + // New + Static + public new static partial string NewStatic { get; set; } + + // Virtual + Required + public virtual required partial string VirtualRequired { get; set; } + + // Override + Sealed + public sealed override partial string SealedOverride { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task AccessorModifiersTest() + { + var source = @" + [Reactive] + public partial class TestClass + { + // Property with private setter + public partial string Name { get; private set; } + + // Protected property with private getter + protected partial string Id { private get; set; } + + // Internal property with protected setter + internal partial string Code { get; protected set; } + + // Public property with protected internal setter + public partial string Key { get; protected internal set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task ModifierOrderingTest() + { + var source = @" + [Reactive] + public partial class Base + { + // Base class properties for override/shadowing + public virtual partial string VirtualProp { get; set; } + protected virtual partial string ProtectedVirtualProp { get; set; } + public static partial string StaticProp { get; set; } + public abstract partial string AbstractProp { get; set; } + } + + [Reactive] + public partial class Derived : Base + { + // Test new modifier comes first + public new partial string VirtualProp { get; set; } + + // Test new + static ordering + public new static partial string StaticProp { get; set; } + + // Test override + sealed + required ordering + public sealed override required partial string ProtectedVirtualProp { get; set; } + + // Test override + required ordering + public override required partial string AbstractProp { get; set; } + + // Test required only + public required partial string RequiredProp { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task InheritanceModifiersTest() + { + var source = @" + [Reactive] + public abstract partial class BaseClass + { + // Virtual property + public virtual partial string VirtualProp { get; set; } + + // Abstract property + public abstract partial string AbstractProp { get; set; } + } + + [Reactive] + public partial class DerivedClass : BaseClass + { + // Override property + public override partial string VirtualProp { get; set; } + + // Sealed override property + public sealed override partial string AbstractProp { get; set; } + }"; + + return TestAndVerify(source); + } + + [Fact] + public Task RequiredModifierTest() + { + var source = @" + [Reactive] + public partial class TestClass + { + // Required property + public required partial string Name { get; set; } + + // Required with virtual + public virtual required partial string VirtualRequired { get; set; } + + // Required with different access levels + protected required partial string ProtectedRequired { get; set; } + private required partial string PrivateRequired { get; set; } + }"; + + return TestAndVerify(source); + } } diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AccessorModifiersTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AccessorModifiersTest.verified.txt new file mode 100644 index 0000000..e31311e --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AccessorModifiersTest.verified.txt @@ -0,0 +1,127 @@ +{ + Sources: [ + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + }, + { + FileName: TestClass.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class TestClass : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: TestClass.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for TestClass. +/// +public partial class TestClass +{ + private static readonly PropertyChangedEventArgs _nameChangedEventArgs = new PropertyChangedEventArgs(nameof(Name)); + private static readonly PropertyChangedEventArgs _idChangedEventArgs = new PropertyChangedEventArgs(nameof(Id)); + private static readonly PropertyChangedEventArgs _codeChangedEventArgs = new PropertyChangedEventArgs(nameof(Code)); + private static readonly PropertyChangedEventArgs _keyChangedEventArgs = new PropertyChangedEventArgs(nameof(Key)); + + public partial string Name + { + get => field; + private set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_nameChangedEventArgs); + } + } + } + + protected partial string Id + { + private get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_idChangedEventArgs); + } + } + } + + internal partial string Code + { + get => field; + protected set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_codeChangedEventArgs); + } + } + } + + public partial string Key + { + get => field; + protected internal set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_keyChangedEventArgs); + } + } + } +} + + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AllPropertyModifiersTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AllPropertyModifiersTest.verified.txt new file mode 100644 index 0000000..d7ed0cb --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AllPropertyModifiersTest.verified.txt @@ -0,0 +1,228 @@ +{ + Sources: [ + { + FileName: Base.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class Base : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: Base.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Base. +/// +public partial class Base +{ + private static readonly PropertyChangedEventArgs _staticPropChangedEventArgs = new PropertyChangedEventArgs(nameof(StaticProp)); + private static readonly PropertyChangedEventArgs _protectedStaticPropChangedEventArgs = new PropertyChangedEventArgs(nameof(ProtectedStaticProp)); + private static readonly PropertyChangedEventArgs _virtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualProp)); + private static readonly PropertyChangedEventArgs _abstractPropChangedEventArgs = new PropertyChangedEventArgs(nameof(AbstractProp)); + private static readonly PropertyChangedEventArgs _requiredPropChangedEventArgs = new PropertyChangedEventArgs(nameof(RequiredProp)); + private static readonly PropertyChangedEventArgs _requiredVirtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(RequiredVirtualProp)); + + public static partial string StaticProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_staticPropChangedEventArgs); + } + } + } + + protected static partial string ProtectedStaticProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_protectedStaticPropChangedEventArgs); + } + } + } + + public virtual partial string VirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualPropChangedEventArgs); + } + } + } + + public abstract partial string AbstractProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_abstractPropChangedEventArgs); + } + } + } + + public required partial string RequiredProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_requiredPropChangedEventArgs); + } + } + } + + public virtual required partial string RequiredVirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_requiredVirtualPropChangedEventArgs); + } + } + } +} + + }, + { + FileName: Derived.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Derived. +/// +public partial class Derived +{ + private static readonly PropertyChangedEventArgs _virtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualProp)); + private static readonly PropertyChangedEventArgs _abstractPropChangedEventArgs = new PropertyChangedEventArgs(nameof(AbstractProp)); + private static readonly PropertyChangedEventArgs _requiredVirtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(RequiredVirtualProp)); + private static readonly PropertyChangedEventArgs _staticPropChangedEventArgs = new PropertyChangedEventArgs(nameof(StaticProp)); + + public partial string VirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualPropChangedEventArgs); + } + } + } + + public override partial string AbstractProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_abstractPropChangedEventArgs); + } + } + } + + public override sealed partial string RequiredVirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_requiredVirtualPropChangedEventArgs); + } + } + } + + public static partial string StaticProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_staticPropChangedEventArgs); + } + } + } +} + + }, + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ClassWithStaticProperties.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ClassWithStaticProperties.verified.txt index e819cae..6d85940 100644 --- a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ClassWithStaticProperties.verified.txt +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ClassWithStaticProperties.verified.txt @@ -66,7 +66,7 @@ public partial class TestClass private static readonly PropertyChangedEventArgs _staticPropChangedEventArgs = new PropertyChangedEventArgs(nameof(StaticProp)); private static readonly PropertyChangedEventArgs _instancePropChangedEventArgs = new PropertyChangedEventArgs(nameof(InstanceProp)); - public partial string StaticProp + public static partial string StaticProp { get => field; set diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.InheritanceModifiersTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.InheritanceModifiersTest.verified.txt new file mode 100644 index 0000000..703cc3b --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.InheritanceModifiersTest.verified.txt @@ -0,0 +1,144 @@ +{ + Sources: [ + { + FileName: BaseClass.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class BaseClass : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: BaseClass.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for BaseClass. +/// +public partial class BaseClass +{ + private static readonly PropertyChangedEventArgs _virtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualProp)); + private static readonly PropertyChangedEventArgs _abstractPropChangedEventArgs = new PropertyChangedEventArgs(nameof(AbstractProp)); + + public virtual partial string VirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualPropChangedEventArgs); + } + } + } + + public abstract partial string AbstractProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_abstractPropChangedEventArgs); + } + } + } +} + + }, + { + FileName: DerivedClass.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for DerivedClass. +/// +public partial class DerivedClass +{ + private static readonly PropertyChangedEventArgs _virtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualProp)); + private static readonly PropertyChangedEventArgs _abstractPropChangedEventArgs = new PropertyChangedEventArgs(nameof(AbstractProp)); + + public override partial string VirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualPropChangedEventArgs); + } + } + } + + public override sealed partial string AbstractProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_abstractPropChangedEventArgs); + } + } + } +} + + }, + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.MixedModifiersTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.MixedModifiersTest.verified.txt new file mode 100644 index 0000000..1f8555a --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.MixedModifiersTest.verified.txt @@ -0,0 +1,127 @@ +{ + Sources: [ + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + }, + { + FileName: TestClass.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class TestClass : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: TestClass.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for TestClass. +/// +public partial class TestClass +{ + private static readonly PropertyChangedEventArgs _staticRequiredChangedEventArgs = new PropertyChangedEventArgs(nameof(StaticRequired)); + private static readonly PropertyChangedEventArgs _newStaticChangedEventArgs = new PropertyChangedEventArgs(nameof(NewStatic)); + private static readonly PropertyChangedEventArgs _virtualRequiredChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualRequired)); + private static readonly PropertyChangedEventArgs _sealedOverrideChangedEventArgs = new PropertyChangedEventArgs(nameof(SealedOverride)); + + public static partial string StaticRequired + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_staticRequiredChangedEventArgs); + } + } + } + + public static partial string NewStatic + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_newStaticChangedEventArgs); + } + } + } + + public virtual required partial string VirtualRequired + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualRequiredChangedEventArgs); + } + } + } + + public override sealed partial string SealedOverride + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_sealedOverrideChangedEventArgs); + } + } + } +} + + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ModifierOrderingTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ModifierOrderingTest.verified.txt new file mode 100644 index 0000000..35eda30 --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ModifierOrderingTest.verified.txt @@ -0,0 +1,214 @@ +{ + Sources: [ + { + FileName: Base.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class Base : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: Base.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Base. +/// +public partial class Base +{ + private static readonly PropertyChangedEventArgs _virtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualProp)); + private static readonly PropertyChangedEventArgs _protectedVirtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(ProtectedVirtualProp)); + private static readonly PropertyChangedEventArgs _staticPropChangedEventArgs = new PropertyChangedEventArgs(nameof(StaticProp)); + private static readonly PropertyChangedEventArgs _abstractPropChangedEventArgs = new PropertyChangedEventArgs(nameof(AbstractProp)); + + public virtual partial string VirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualPropChangedEventArgs); + } + } + } + + protected virtual partial string ProtectedVirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_protectedVirtualPropChangedEventArgs); + } + } + } + + public static partial string StaticProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_staticPropChangedEventArgs); + } + } + } + + public abstract partial string AbstractProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_abstractPropChangedEventArgs); + } + } + } +} + + }, + { + FileName: Derived.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Derived. +/// +public partial class Derived +{ + private static readonly PropertyChangedEventArgs _virtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualProp)); + private static readonly PropertyChangedEventArgs _staticPropChangedEventArgs = new PropertyChangedEventArgs(nameof(StaticProp)); + private static readonly PropertyChangedEventArgs _protectedVirtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(ProtectedVirtualProp)); + private static readonly PropertyChangedEventArgs _abstractPropChangedEventArgs = new PropertyChangedEventArgs(nameof(AbstractProp)); + private static readonly PropertyChangedEventArgs _requiredPropChangedEventArgs = new PropertyChangedEventArgs(nameof(RequiredProp)); + + public partial string VirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualPropChangedEventArgs); + } + } + } + + public static partial string StaticProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_staticPropChangedEventArgs); + } + } + } + + public override sealed required partial string ProtectedVirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_protectedVirtualPropChangedEventArgs); + } + } + } + + public override required partial string AbstractProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_abstractPropChangedEventArgs); + } + } + } + + public required partial string RequiredProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_requiredPropChangedEventArgs); + } + } + } +} + + }, + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NestedClassesWithStaticAndInstanceMembers.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NestedClassesWithStaticAndInstanceMembers.verified.txt index 353c47a..6ed3988 100644 --- a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NestedClassesWithStaticAndInstanceMembers.verified.txt +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NestedClassesWithStaticAndInstanceMembers.verified.txt @@ -47,7 +47,7 @@ public partial class Container private static readonly PropertyChangedEventArgs _staticPropChangedEventArgs = new PropertyChangedEventArgs(nameof(StaticProp)); private static readonly PropertyChangedEventArgs _instancePropChangedEventArgs = new PropertyChangedEventArgs(nameof(InstanceProp)); - public partial string StaticProp + public static partial string StaticProp { get => field; set diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NewModifierTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NewModifierTest.verified.txt new file mode 100644 index 0000000..6d87640 --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NewModifierTest.verified.txt @@ -0,0 +1,116 @@ +{ + Sources: [ + { + FileName: Base.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class Base : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: Base.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Base. +/// +public partial class Base +{ + private static readonly PropertyChangedEventArgs _nameChangedEventArgs = new PropertyChangedEventArgs(nameof(Name)); + + public partial string Name + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_nameChangedEventArgs); + } + } + } +} + + }, + { + FileName: Derived.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Derived. +/// +public partial class Derived +{ + private static readonly PropertyChangedEventArgs _nameChangedEventArgs = new PropertyChangedEventArgs(nameof(Name)); + + public partial string Name + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_nameChangedEventArgs); + } + } + } +} + + }, + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredModifierTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredModifierTest.verified.txt new file mode 100644 index 0000000..8910e55 --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredModifierTest.verified.txt @@ -0,0 +1,127 @@ +{ + Sources: [ + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + }, + { + FileName: TestClass.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class TestClass : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: TestClass.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for TestClass. +/// +public partial class TestClass +{ + private static readonly PropertyChangedEventArgs _nameChangedEventArgs = new PropertyChangedEventArgs(nameof(Name)); + private static readonly PropertyChangedEventArgs _virtualRequiredChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualRequired)); + private static readonly PropertyChangedEventArgs _protectedRequiredChangedEventArgs = new PropertyChangedEventArgs(nameof(ProtectedRequired)); + private static readonly PropertyChangedEventArgs _privateRequiredChangedEventArgs = new PropertyChangedEventArgs(nameof(PrivateRequired)); + + public required partial string Name + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_nameChangedEventArgs); + } + } + } + + public virtual required partial string VirtualRequired + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualRequiredChangedEventArgs); + } + } + } + + protected required partial string ProtectedRequired + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_protectedRequiredChangedEventArgs); + } + } + } + + private required partial string PrivateRequired + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_privateRequiredChangedEventArgs); + } + } + } +} + + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyTest.verified.txt new file mode 100644 index 0000000..346bb09 --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyTest.verified.txt @@ -0,0 +1,113 @@ +{ + Sources: [ + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: Person.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class Person : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: Person.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Person. +/// +public partial class Person +{ + private static readonly PropertyChangedEventArgs _nameChangedEventArgs = new PropertyChangedEventArgs(nameof(Name)); + private static readonly PropertyChangedEventArgs _ageChangedEventArgs = new PropertyChangedEventArgs(nameof(Age)); + private static readonly PropertyChangedEventArgs _optionalNicknameChangedEventArgs = new PropertyChangedEventArgs(nameof(OptionalNickname)); + + public required partial string Name + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_nameChangedEventArgs); + } + } + } + + public required partial int Age + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_ageChangedEventArgs); + } + } + } + + public partial string? OptionalNickname + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_optionalNicknameChangedEventArgs); + } + } + } +} + + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithInheritanceTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithInheritanceTest.verified.txt new file mode 100644 index 0000000..3f34e72 --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithInheritanceTest.verified.txt @@ -0,0 +1,116 @@ +{ + Sources: [ + { + FileName: Entity.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class Entity : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: Entity.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Entity. +/// +public partial class Entity +{ + private static readonly PropertyChangedEventArgs _idChangedEventArgs = new PropertyChangedEventArgs(nameof(Id)); + + public required partial string Id + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_idChangedEventArgs); + } + } + } +} + + }, + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: Person.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Person. +/// +public partial class Person +{ + private static readonly PropertyChangedEventArgs _nameChangedEventArgs = new PropertyChangedEventArgs(nameof(Name)); + + public required partial string Name + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_nameChangedEventArgs); + } + } + } +} + + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithMixedModifiersTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithMixedModifiersTest.verified.txt new file mode 100644 index 0000000..75383c5 --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithMixedModifiersTest.verified.txt @@ -0,0 +1,130 @@ +{ + Sources: [ + { + FileName: BaseClass.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class BaseClass : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: BaseClass.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for BaseClass. +/// +public partial class BaseClass +{ + private static readonly PropertyChangedEventArgs _virtualRequiredChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualRequired)); + + public virtual required partial string VirtualRequired + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualRequiredChangedEventArgs); + } + } + } +} + + }, + { + FileName: DerivedClass.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for DerivedClass. +/// +public partial class DerivedClass +{ + private static readonly PropertyChangedEventArgs _virtualRequiredChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualRequired)); + private static readonly PropertyChangedEventArgs _localRequiredChangedEventArgs = new PropertyChangedEventArgs(nameof(LocalRequired)); + + public override required partial string VirtualRequired + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualRequiredChangedEventArgs); + } + } + } + + public required partial string LocalRequired + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_localRequiredChangedEventArgs); + } + } + } +} + + }, + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithReactiveObjectTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithReactiveObjectTest.verified.txt new file mode 100644 index 0000000..ca561c2 --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.RequiredPropertyWithReactiveObjectTest.verified.txt @@ -0,0 +1,56 @@ +{ + Sources: [ + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: Person.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using ReactiveUI; + +/// +/// A partial class implementation for Person. +/// +public partial class Person +{ + public required partial string Name + { + get => field; + set => this.RaiseAndSetIfChanged(ref field, value); + } + + public required partial DateOnly BirthDate + { + get => field; + set => this.RaiseAndSetIfChanged(ref field, value); + } +} + + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.SealedOverrideTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.SealedOverrideTest.verified.txt new file mode 100644 index 0000000..5d9fa86 --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.SealedOverrideTest.verified.txt @@ -0,0 +1,116 @@ +{ + Sources: [ + { + FileName: Base.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class Base : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: Base.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Base. +/// +public partial class Base +{ + private static readonly PropertyChangedEventArgs _virtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualProp)); + + public virtual partial string VirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualPropChangedEventArgs); + } + } + } +} + + }, + { + FileName: Derived.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for Derived. +/// +public partial class Derived +{ + private static readonly PropertyChangedEventArgs _virtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(VirtualProp)); + + public override sealed partial string VirtualProp + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_virtualPropChangedEventArgs); + } + } + } +} + + }, + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + } + ], + Diagnostics: null +} \ No newline at end of file diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.StaticPropertyTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.StaticPropertyTest.verified.txt new file mode 100644 index 0000000..eebfbbb --- /dev/null +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.StaticPropertyTest.verified.txt @@ -0,0 +1,99 @@ +{ + Sources: [ + { + FileName: IgnoreReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +sealed class IgnoreReactiveAttribute : Attribute +{ + public IgnoreReactiveAttribute() { } +} + }, + { + FileName: ReactiveAttribute.g.cs, + Source: +// +using System; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] +sealed class ReactiveAttribute : Attribute +{ + public ReactiveAttribute() { } +} + }, + { + FileName: TestClass.INPC.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +public partial class TestClass : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) + { + PropertyChanged?.Invoke(this, args); + } +} + + }, + { + FileName: TestClass.ReactiveProperties.g.cs, + Source: +// +#nullable enable + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +/// +/// A partial class implementation for TestClass. +/// +public partial class TestClass +{ + private static readonly PropertyChangedEventArgs _globalConfigChangedEventArgs = new PropertyChangedEventArgs(nameof(GlobalConfig)); + private static readonly PropertyChangedEventArgs _counterChangedEventArgs = new PropertyChangedEventArgs(nameof(Counter)); + + public static partial string GlobalConfig + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_globalConfigChangedEventArgs); + } + } + } + + private static partial int Counter + { + get => field; + set + { + if (!Equals(field, value)) + { + field = value; + OnPropertyChanged(_counterChangedEventArgs); + } + } + } +} + + } + ], + Diagnostics: null +} \ No newline at end of file From 07ca5262a18b3c63038b8ae7fe2c383481b33e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 3 Jan 2025 21:40:46 +0100 Subject: [PATCH 3/4] Update ReactiveGenerator.cs --- ReactiveGenerator/ReactiveGenerator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReactiveGenerator/ReactiveGenerator.cs b/ReactiveGenerator/ReactiveGenerator.cs index 16946c1..8a1a85d 100644 --- a/ReactiveGenerator/ReactiveGenerator.cs +++ b/ReactiveGenerator/ReactiveGenerator.cs @@ -31,7 +31,8 @@ public string GetPropertyModifiers() else if (Property.IsAbstract) modifiers.Add("abstract"); - if (Property.IsSealed) + // sealed only makes sense with override + if (Property.IsSealed && Property.IsOverride) modifiers.Add("sealed"); if (Property.IsRequired) From f42a18ee21850e7b7b727bf6145a832835ea7c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 3 Jan 2025 21:40:55 +0100 Subject: [PATCH 4/4] Get 'new' modifier from syntax if present --- ...neratorTests.AllPropertyModifiersTest.verified.txt | 4 ++-- ...tiveGeneratorTests.MixedModifiersTest.verified.txt | 2 +- ...veGeneratorTests.ModifierOrderingTest.verified.txt | 4 ++-- ...eactiveGeneratorTests.NewModifierTest.verified.txt | 2 +- ReactiveGenerator/ReactiveGenerator.cs | 11 +++++++++++ 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AllPropertyModifiersTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AllPropertyModifiersTest.verified.txt index d7ed0cb..4e0ceb7 100644 --- a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AllPropertyModifiersTest.verified.txt +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.AllPropertyModifiersTest.verified.txt @@ -145,7 +145,7 @@ public partial class Derived private static readonly PropertyChangedEventArgs _requiredVirtualPropChangedEventArgs = new PropertyChangedEventArgs(nameof(RequiredVirtualProp)); private static readonly PropertyChangedEventArgs _staticPropChangedEventArgs = new PropertyChangedEventArgs(nameof(StaticProp)); - public partial string VirtualProp + public new partial string VirtualProp { get => field; set @@ -184,7 +184,7 @@ public partial class Derived } } - public static partial string StaticProp + public new static partial string StaticProp { get => field; set diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.MixedModifiersTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.MixedModifiersTest.verified.txt index 1f8555a..55d83e7 100644 --- a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.MixedModifiersTest.verified.txt +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.MixedModifiersTest.verified.txt @@ -81,7 +81,7 @@ public partial class TestClass } } - public static partial string NewStatic + public new static partial string NewStatic { get => field; set diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ModifierOrderingTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ModifierOrderingTest.verified.txt index 35eda30..30d3aa5 100644 --- a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ModifierOrderingTest.verified.txt +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.ModifierOrderingTest.verified.txt @@ -118,7 +118,7 @@ public partial class Derived private static readonly PropertyChangedEventArgs _abstractPropChangedEventArgs = new PropertyChangedEventArgs(nameof(AbstractProp)); private static readonly PropertyChangedEventArgs _requiredPropChangedEventArgs = new PropertyChangedEventArgs(nameof(RequiredProp)); - public partial string VirtualProp + public new partial string VirtualProp { get => field; set @@ -131,7 +131,7 @@ public partial class Derived } } - public static partial string StaticProp + public new static partial string StaticProp { get => field; set diff --git a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NewModifierTest.verified.txt b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NewModifierTest.verified.txt index 6d87640..665e839 100644 --- a/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NewModifierTest.verified.txt +++ b/ReactiveGenerator.Tests/Snapshots/ReactiveGeneratorTests.NewModifierTest.verified.txt @@ -72,7 +72,7 @@ public partial class Derived { private static readonly PropertyChangedEventArgs _nameChangedEventArgs = new PropertyChangedEventArgs(nameof(Name)); - public partial string Name + public new partial string Name { get => field; set diff --git a/ReactiveGenerator/ReactiveGenerator.cs b/ReactiveGenerator/ReactiveGenerator.cs index 8a1a85d..0c2eec7 100644 --- a/ReactiveGenerator/ReactiveGenerator.cs +++ b/ReactiveGenerator/ReactiveGenerator.cs @@ -21,6 +21,17 @@ public string GetPropertyModifiers() { var modifiers = new List(); + // Get 'new' modifier from syntax if present + if (Property.DeclaringSyntaxReferences.Length > 0) + { + var syntax = Property.DeclaringSyntaxReferences[0].GetSyntax(); + if (syntax is PropertyDeclarationSyntax propertyDeclaration && + propertyDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.NewKeyword))) + { + modifiers.Add("new"); + } + } + if (Property.IsStatic) modifiers.Add("static");