From b9f0c2812b7fe45d2e3576b79162bc13d184a8c2 Mon Sep 17 00:00:00 2001 From: Gabriele Messina Date: Sun, 15 Oct 2023 01:11:22 +0200 Subject: [PATCH 1/3] Add pragma restore directive for the CS0108 warning --- .../Models/HierarchyInfo.Syntax.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs index 0d03495d..f35191b4 100644 --- a/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs +++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs @@ -60,10 +60,16 @@ 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(TriviaList(Comment("// Member hides inherited member; missing new keyword")), SyntaxKind.IdentifierName, "CS0108", "CS0108", default))); + 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 "") From 58ae2d965cb94f2a81349584e58adf19896f61b2 Mon Sep 17 00:00:00 2001 From: Gabriele Messina Date: Sun, 15 Oct 2023 15:31:22 +0200 Subject: [PATCH 2/3] Fix pragma warning error code and comment ordering --- .../Models/HierarchyInfo.Syntax.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs index f35191b4..c6373961 100644 --- a/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs +++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.Syntax.cs @@ -61,10 +61,11 @@ 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(TriviaList(Comment("// Member hides inherited member; missing new keyword")), SyntaxKind.IdentifierName, "CS0108", "CS0108", default))); + .Add(IdentifierName(Identifier(default, SyntaxKind.IdentifierName, "CS0108", "CS0108", TriviaList(Comment("// Member hides inherited member; missing new keyword"))))); SyntaxTriviaList syntaxTriviaList = TriviaList( Comment("// "), From 210d27e9cdf24ee4c7c333db4168da51094e7877 Mon Sep 17 00:00:00 2001 From: Gabriele Messina Date: Sun, 15 Oct 2023 18:33:53 +0200 Subject: [PATCH 3/3] Add hidesInheritedProperty argument to ObservablePropertyAttribute and handle the new keyword in the property declaration if the hidesInheritedProperty argument is true --- .../ComponentModel/Models/PropertyInfo.cs | 2 ++ .../ObservablePropertyGenerator.Execute.cs | 23 +++++++++++++++++-- .../Attributes/ObservablePropertyAttribute.cs | 15 ++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/Models/PropertyInfo.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/Models/PropertyInfo.cs index 2bf62d0d..1f23747c 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 855dce1f..8aab9e15 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/ComponentModel/Attributes/ObservablePropertyAttribute.cs b/src/CommunityToolkit.Mvvm/ComponentModel/Attributes/ObservablePropertyAttribute.cs index 0e765267..a1e22b12 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; } }