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..4e0ceb7
--- /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 new 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 new 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..55d83e7
--- /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 new 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..30d3aa5
--- /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 new partial string VirtualProp
+ {
+ get => field;
+ set
+ {
+ if (!Equals(field, value))
+ {
+ field = value;
+ OnPropertyChanged(_virtualPropChangedEventArgs);
+ }
+ }
+ }
+
+ public new 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..665e839
--- /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 new 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
diff --git a/ReactiveGenerator/ReactiveGenerator.cs b/ReactiveGenerator/ReactiveGenerator.cs
index 01f4cff..0c2eec7 100644
--- a/ReactiveGenerator/ReactiveGenerator.cs
+++ b/ReactiveGenerator/ReactiveGenerator.cs
@@ -21,6 +21,20 @@ 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");
+
if (Property.IsOverride)
modifiers.Add("override");
else if (Property.IsVirtual)
@@ -28,6 +42,13 @@ public string GetPropertyModifiers()
else if (Property.IsAbstract)
modifiers.Add("abstract");
+ // sealed only makes sense with override
+ if (Property.IsSealed && Property.IsOverride)
+ modifiers.Add("sealed");
+
+ if (Property.IsRequired)
+ modifiers.Add("required");
+
return string.Join(" ", modifiers);
}
}
@@ -711,11 +732,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);