diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/Models/PropertyInfo.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/Models/PropertyInfo.cs
index 2bf62d0de..1f23747ca 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/Models/PropertyInfo.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/Models/PropertyInfo.cs
@@ -20,6 +20,7 @@ namespace CommunityToolkit.Mvvm.SourceGenerators.ComponentModel.Models;
/// Whether the old property value is being directly referenced.
/// Indicates whether the property is of a reference type or an unconstrained type parameter.
/// Indicates whether to include nullability annotations on the setter.
+/// Indicates whether the generated property should hide an inherited property declaration.
/// The sequence of forwarded attributes for the generated property.
internal sealed record PropertyInfo(
string TypeNameWithNullabilityAnnotations,
@@ -33,4 +34,5 @@ internal sealed record PropertyInfo(
bool IsOldPropertyValueDirectlyReferenced,
bool IsReferenceTypeOrUnconstraindTypeParameter,
bool IncludeMemberNotNullOnSetAccessor,
+ bool hidesInheritedProperty,
EquatableArray ForwardedAttributes);
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs
index 855dce1fb..8aab9e152 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
@@ -118,6 +119,7 @@ public static bool TryGetInfo(
bool hasOrInheritsClassLevelNotifyPropertyChangedRecipients = false;
bool hasOrInheritsClassLevelNotifyDataErrorInfo = false;
bool hasAnyValidationAttributes = false;
+ bool hidesInheritedProperty = false;
bool isOldPropertyValueDirectlyReferenced = IsOldPropertyValueDirectlyReferenced(fieldSymbol, propertyName);
token.ThrowIfCancellationRequested();
@@ -194,6 +196,15 @@ public static bool TryGetInfo(
forwardedAttributes.Add(AttributeInfo.Create(attributeData));
}
+ // Check if the generated property should hide an inherited property declaration
+ if (attributeData.AttributeClass?.HasFullyQualifiedMetadataName("CommunityToolkit.Mvvm.ComponentModel.ObservablePropertyAttribute") == true)
+ {
+ if (Convert.ToBoolean(attributeData.ConstructorArguments[0].Value) == true)
+ {
+ hidesInheritedProperty = true;
+ }
+ }
+
// Also track the current attribute for forwarding if it is of any of the following types:
// - Display attributes (System.ComponentModel.DataAnnotations.DisplayAttribute)
// - UI hint attributes(System.ComponentModel.DataAnnotations.UIHintAttribute)
@@ -308,6 +319,7 @@ public static bool TryGetInfo(
isOldPropertyValueDirectlyReferenced,
isReferenceTypeOrUnconstraindTypeParameter,
includeMemberNotNullOnSetAccessor,
+ hidesInheritedProperty,
forwardedAttributes.ToImmutable());
diagnostics = builder.ToImmutable();
@@ -1016,11 +1028,18 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
// [global::System.CodeDom.Compiler.GeneratedCode("...", "...")]
// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
//
- // public
+ // public
// {
// get => ;
//
// }
+
+ List propertyDeclarationModifier = new() { Token(SyntaxKind.PublicKeyword) };
+ if (propertyInfo.hidesInheritedProperty)
+ {
+ propertyDeclarationModifier.Add(Token(SyntaxKind.NewKeyword));
+ }
+
return
PropertyDeclaration(propertyType, Identifier(propertyInfo.PropertyName))
.AddAttributeLists(
@@ -1032,7 +1051,7 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
.WithOpenBracketToken(Token(TriviaList(Comment($"/// ")), SyntaxKind.OpenBracketToken, TriviaList())),
AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage")))))
.AddAttributeLists(forwardedAttributes.ToArray())
- .AddModifiers(Token(SyntaxKind.PublicKeyword))
+ .AddModifiers(propertyDeclarationModifier.ToArray())
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithExpressionBody(ArrowExpressionClause(getterFieldExpression))
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs
index 0d03495d5..c6373961f 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs
@@ -60,10 +60,17 @@ public CompilationUnitSyntax GetCompilationUnit(
//
//
// #pragma warning disable
+ // #pragma warning restore CS0108 // Member hides inherited member; missing new keyword
+ //
// #nullable enable
+
+ SeparatedSyntaxList pragmaWarningCodesToPreserve = new SeparatedSyntaxList()
+ .Add(IdentifierName(Identifier(default, SyntaxKind.IdentifierName, "CS0108", "CS0108", TriviaList(Comment("// Member hides inherited member; missing new keyword")))));
+
SyntaxTriviaList syntaxTriviaList = TriviaList(
Comment("// "),
Trivia(PragmaWarningDirectiveTrivia(Token(SyntaxKind.DisableKeyword), true)),
+ Trivia(PragmaWarningDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), pragmaWarningCodesToPreserve, true)),
Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true)));
if (Namespace is "")
diff --git a/src/CommunityToolkit.Mvvm/ComponentModel/Attributes/ObservablePropertyAttribute.cs b/src/CommunityToolkit.Mvvm/ComponentModel/Attributes/ObservablePropertyAttribute.cs
index 0e765267a..a1e22b122 100644
--- a/src/CommunityToolkit.Mvvm/ComponentModel/Attributes/ObservablePropertyAttribute.cs
+++ b/src/CommunityToolkit.Mvvm/ComponentModel/Attributes/ObservablePropertyAttribute.cs
@@ -54,4 +54,19 @@ namespace CommunityToolkit.Mvvm.ComponentModel;
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public sealed class ObservablePropertyAttribute : Attribute
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Specifies if the generated property will hide an inherited property declaration.
+ ///
+ public ObservablePropertyAttribute(bool hidesInheritedProperty = false)
+ {
+ Hidesinheritedproperty = hidesInheritedProperty;
+ }
+
+ ///
+ /// Specifies if the generated property will hide an inherited property declaration.
+ ///
+ public bool Hidesinheritedproperty { get; }
}