diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs index 49dfbe918a90d9..40e81f21702528 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs @@ -592,39 +592,21 @@ protected override TypeAnnotations CreateValueFromKey(TypeDesc key) } } - if (IsAutoProperty(property)) + FieldDesc? backingField = backingFieldFromSetter ?? backingFieldFromGetter; + if (backingField is not null) { - FieldDesc? backingField = null; - if ((property.SetMethod is not null - && property.SetMethod.HasCustomAttribute("System.Runtime.CompilerServices", "CompilerGeneratedAttribute") - && backingFieldFromSetter is null) - || (property.GetMethod is not null - && property.GetMethod.HasCustomAttribute("System.Runtime.CompilerServices", "CompilerGeneratedAttribute") - && backingFieldFromGetter is null)) + bool validBackingFieldFound = backingFieldFromGetter is null + || backingFieldFromSetter is null + || backingFieldFromGetter == backingFieldFromSetter; + if (validBackingFieldFound) { - // We failed to find the backing field of an auto-property accessor - _logger.LogWarning(property, DiagnosticId.DynamicallyAccessedMembersCouldNotFindBackingField, property.GetDisplayName()); - } - else if (backingFieldFromGetter is not null && backingFieldFromSetter is not null - && backingFieldFromSetter != backingFieldFromGetter) - { - // We found two different backing fields for the getter and the setter - _logger.LogWarning(property, DiagnosticId.DynamicallyAccessedMembersCouldNotFindBackingField, property.GetDisplayName()); - } - else - { - // We either have a single auto-property accessor or both accessors point to the same backing field - backingField = backingFieldFromSetter ?? backingFieldFromGetter; - } - - if (backingField != null) - { - if (annotatedFields.Any(a => a.Field == backingField)) + if (annotatedFields.Any(a => a.Field == backingField && a.Annotation != annotation)) { _logger.LogWarning(backingField, DiagnosticId.DynamicallyAccessedMembersOnPropertyConflictsWithBackingField, property.GetDisplayName(), backingField.GetDisplayName()); } else { + // Unique backing field with no conflicts with property or existing field annotatedFields.Add(new FieldAnnotation(backingField, annotation)); } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs index dd210c6eea3297..5846ce2ca201d5 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs @@ -117,11 +117,11 @@ internal static DynamicallyAccessedMemberTypes GetFieldAnnotation(IFieldSymbol f if (!field.OriginalDefinition.Type.IsTypeInterestingForDataflow(isByRef: field.RefKind is not RefKind.None)) return DynamicallyAccessedMemberTypes.None; - if (field.AssociatedSymbol is IPropertySymbol property) + if (field.AssociatedSymbol is IPropertySymbol property + && property.IsAutoProperty()) { // If this is an auto property, we get the property annotation - if (property.IsAutoProperty()) - return property.GetDynamicallyAccessedMemberTypes(); + return property.GetDynamicallyAccessedMemberTypes(); } return field.GetDynamicallyAccessedMemberTypes(); diff --git a/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs b/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs index dba2ccee7ad288..a1e0e3bc04ee91 100644 --- a/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs +++ b/src/tools/illink/src/ILLink.Shared/DiagnosticId.cs @@ -101,7 +101,7 @@ public enum DiagnosticId XmlInvalidValueForAttributeActionForResource = 2039, XmlCouldNotFindResourceToRemoveInAssembly = 2040, DynamicallyAccessedMembersIsNotAllowedOnMethods = 2041, - DynamicallyAccessedMembersCouldNotFindBackingField = 2042, + unused_DynamicallyAccessedMembersCouldNotFindBackingField = 2042, DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor = 2043, XmlCouldNotFindAnyTypeInNamespace = 2044, AttributeIsReferencedButTrimmerRemoveAllInstances = 2045, diff --git a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs index 200710a9b1a679..e1406b9d2c2203 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -433,39 +433,22 @@ TypeAnnotations BuildTypeAnnotations(TypeDefinition type) } } - if (IsAutoProperty(property)) + + FieldDefinition? backingField = backingFieldFromSetter ?? backingFieldFromGetter; + if (backingField is not null) { - FieldDefinition? backingField = null; - // If it's an annotated auto-prop, we should be able to find the compiler generated field - if ((property.SetMethod is not null - && property.SetMethod.IsCompilerGenerated() - && backingFieldFromSetter is null) - || (property.GetMethod is not null - && property.GetMethod.IsCompilerGenerated() - && backingFieldFromGetter is null)) - { - // We failed to find the backing field of an auto-property accessor - _context.LogWarning(property, DiagnosticId.DynamicallyAccessedMembersCouldNotFindBackingField, property.GetDisplayName()); - } - else if (backingFieldFromGetter is not null && backingFieldFromSetter is not null - && backingFieldFromSetter != backingFieldFromGetter) - { - // We found two different backing fields for the getter and the setter - _context.LogWarning(property, DiagnosticId.DynamicallyAccessedMembersCouldNotFindBackingField, property.GetDisplayName()); - } - else - { - // We either have a single auto-property accessor or both accessors point to the same backing field - backingField = backingFieldFromSetter ?? backingFieldFromGetter; - } - if (backingField != null) + bool validBackingFieldFound = backingFieldFromGetter is null + || backingFieldFromSetter is null + || backingFieldFromGetter == backingFieldFromSetter; + if (validBackingFieldFound) { - if (annotatedFields.Any(a => a.Field == backingField)) + if (annotatedFields.Any(a => a.Field == backingField && a.Annotation != annotation)) { _context.LogWarning(backingField, DiagnosticId.DynamicallyAccessedMembersOnPropertyConflictsWithBackingField, property.GetDisplayName(), backingField.GetDisplayName()); } else { + // Unique backing field with no conflicts with property or existing field annotatedFields.Add(new FieldAnnotation(backingField, annotation)); } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs index 1fc8ed65bc8379..7b0272a85de43a 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs @@ -288,8 +288,6 @@ public void TestPropertyWithDifferentBackingFields() private Type PropertyWithDifferentBackingFields_SetterField; // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning("IL2042", - "Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.PropertyWithDifferentBackingFields", Tool.Trimmer | Tool.NativeAot, "Requires IL")] [ExpectedWarning("IL2078", nameof(TestAutomaticPropagationType) + "." + nameof(PropertyWithDifferentBackingFields) + ".get", "Type", Tool.Analyzer, "")] @@ -313,32 +311,57 @@ Type PropertyWithDifferentBackingFields public void TestPropertyWithExistingAttributes() { - _ = PropertyWithExistingAttributes; - PropertyWithExistingAttributes = null; + _ = PropertyWithExistingMatchingAttributes; + PropertyWithExistingMatchingAttributes = null; + _ = PropertyWithExistingMismatchedAttributes; + PropertyWithExistingMismatchedAttributes = null; } // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning("IL2056", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes_Field", Tool.Trimmer | Tool.NativeAot, "")] [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] [CompilerGenerated] - Type PropertyWithExistingAttributes_Field; + Type PropertyWithExistingMatchingAttributes_Field; - [ExpectedWarning("IL2043", ["PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get"], Tool.Analyzer, "")] - [ExpectedWarning("IL2043", ["PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set"], Tool.Analyzer, "")] + [ExpectedWarning("IL2043", ["PropertyWithExistingMatchingAttributes", "PropertyWithExistingMatchingAttributes.get"], Tool.Analyzer, "")] + [ExpectedWarning("IL2043", ["PropertyWithExistingMatchingAttributes", "PropertyWithExistingMatchingAttributes.set"], Tool.Analyzer, "")] [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - Type PropertyWithExistingAttributes + Type PropertyWithExistingMatchingAttributes { - // On property/accessor mismatch, ILLink warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654 - [ExpectedWarning("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning("IL2043", ["PropertyWithExistingMatchingAttributes", "PropertyWithExistingMatchingAttributes.get"], Tool.Trimmer | Tool.NativeAot, "")] [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] [CompilerGenerated] - get { return PropertyWithExistingAttributes_Field; } + get { return PropertyWithExistingMatchingAttributes_Field; } - // On property/accessor mismatch, ILLink warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654 - [ExpectedWarning("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning("IL2043", ["PropertyWithExistingMatchingAttributes", "PropertyWithExistingMatchingAttributes.set"], Tool.Trimmer | Tool.NativeAot, "")] [param: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] [CompilerGenerated] - set { PropertyWithExistingAttributes_Field = value; } + set { PropertyWithExistingMatchingAttributes_Field = value; } + } + + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning("IL2056", "PropertyWithExistingMismatchedAttributes", "PropertyWithExistingMismatchedAttributes_Field", Tool.Trimmer | Tool.NativeAot, "")] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + [CompilerGenerated] + Type PropertyWithExistingMismatchedAttributes_Field; + + [ExpectedWarning("IL2043", ["PropertyWithExistingMismatchedAttributes", "PropertyWithExistingMismatchedAttributes.get"], Tool.Analyzer, "")] + [ExpectedWarning("IL2043", ["PropertyWithExistingMismatchedAttributes", "PropertyWithExistingMismatchedAttributes.set"], Tool.Analyzer, "")] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] + Type PropertyWithExistingMismatchedAttributes + { + // On property/accessor mismatch, ILLink warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654 + [ExpectedWarning("IL2043", "PropertyWithExistingMismatchedAttributes", "PropertyWithExistingMismatchedAttributes.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning("IL2078", "return value", "PropertyWithExistingMismatchedAttributes_Field")] + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + [CompilerGenerated] + get { return PropertyWithExistingMismatchedAttributes_Field; } + + // On property/accessor mismatch, ILLink warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654 + [ExpectedWarning("IL2043", "PropertyWithExistingMismatchedAttributes", "PropertyWithExistingMismatchedAttributes.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning("IL2069", "PropertyWithExistingMismatchedAttributes_Field", "parameter 'value'")] + [param: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + [CompilerGenerated] + set { PropertyWithExistingMismatchedAttributes_Field = value; } } // When the property annotation conflicts with the getter/setter annotation, @@ -959,7 +982,6 @@ class AutoPropertyUnrecognizedField private Type Property_BackingField; [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - [ExpectedWarning("IL2042", Tool.NativeAot | Tool.Trimmer, "Requires IL")] // Can't find backing field public Type Property { [CompilerGenerated] @@ -980,7 +1002,6 @@ public Type Property } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - [ExpectedWarning("IL2042", Tool.NativeAot | Tool.Trimmer, "Requires IL")] // Can't find backing field public Type PropertyAutoSet { [CompilerGenerated] @@ -995,10 +1016,8 @@ public Type PropertyAutoSet } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - [ExpectedWarning("IL2042", Tool.NativeAot | Tool.Trimmer, "Requires IL")] // Can't find backing field public Type PropertyAutoGet { - [ExpectedWarning("IL2078", ["return value", nameof(PropertyAutoGet), "BackingField"], producedBy: Tool.NativeAot | Tool.Trimmer, "Requires IL")] get; [CompilerGenerated] set @@ -1010,7 +1029,6 @@ public Type PropertyAutoGet } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - [ExpectedWarning("IL2042", Tool.NativeAot | Tool.Trimmer, "Requires IL")] // Can't find backing field public Type PropertyManualSet { [CompilerGenerated] @@ -1025,7 +1043,6 @@ public Type PropertyManualSet } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - [ExpectedWarning("IL2042", Tool.NativeAot | Tool.Trimmer, "Requires IL")] // Can't find backing field public Type PropertyManualGet { [ExpectedWarning("IL2078", "return value", nameof(Property_BackingField))] @@ -1040,7 +1057,6 @@ public Type PropertyManualGet } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - [ExpectedWarning("IL2042", Tool.NativeAot | Tool.Trimmer, "Requires IL")] // Can't find backing field public Type PropertyOnlyGet { [CompilerGenerated] @@ -1054,7 +1070,6 @@ public Type PropertyOnlyGet } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - [ExpectedWarning("IL2042", nameof(PropertyOnlySet), Tool.NativeAot | Tool.Trimmer, "Requires IL")] // Can't find backing field public Type PropertyOnlySet { [CompilerGenerated]