diff --git a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs index 549d8fbd290b2d..d5bd6f726533de 100644 --- a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs +++ b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs @@ -45,6 +45,7 @@ public static string GetDisplayName(this MethodDesc method) sb.Append(property.Name); sb.Append('.'); sb.Append(property.GetMethod == method ? "get" : "set"); + return sb.ToString(); } else { @@ -104,7 +105,7 @@ public static string GetDisplayName(this PropertyPseudoDesc property) .Append('.') .Append(property.Name).ToString(); } - + public static string GetDisplayName(this EventPseudoDesc @event) { return new StringBuilder(@event.OwningType.GetDisplayName()) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs index 7a396cfe0e18b1..c20596b08e45f8 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs @@ -204,6 +204,20 @@ void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystemEntity en MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage(requiresAttribute.Value)), MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl(requiresAttribute.Value))); } + else + { + var diagnosticContext = new DiagnosticContext( + origin, + _logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute), + _logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresDynamicCodeAttribute), + _logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresAssemblyFilesAttribute), + _logger); + + string arg1 = MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage(requiresAttribute.Value)); + string arg2 = MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl(requiresAttribute.Value)); + + diagnosticContext.AddDiagnostic(DiagnosticId.RequiresUnreferencedCode, entity.GetDisplayName(), arg1, arg2); + } } if (!Annotations.ShouldWarnWhenAccessedForReflection(entity)) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs index e366e80708f4b1..ed4369a3231ce2 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs @@ -41,6 +41,13 @@ public sealed class UsageBasedMetadataManager : GeneratingMetadataManager private readonly FeatureSwitchHashtable _featureSwitchHashtable; + private static (string AttributeName, DiagnosticId Id)[] _requiresAttributeMismatchNameAndId = new[] + { + (DiagnosticUtilities.RequiresUnreferencedCodeAttribute, DiagnosticId.RequiresUnreferencedCodeAttributeMismatch), + (DiagnosticUtilities.RequiresDynamicCodeAttribute, DiagnosticId.RequiresDynamicCodeAttributeMismatch), + (DiagnosticUtilities.RequiresAssemblyFilesAttribute, DiagnosticId.RequiresAssemblyFilesAttributeMismatch) + }; + private readonly List _modulesWithMetadata = new List(); private readonly List _fieldsWithMetadata = new List(); private readonly List _methodsWithMetadata = new List(); @@ -783,15 +790,19 @@ public bool GeneratesAttributeMetadata(TypeDesc attributeType) public override void NoteOverridingMethod(MethodDesc baseMethod, MethodDesc overridingMethod) { - // We validate that the various dataflow/Requires* annotations are consistent across virtual method overrides - if (HasMismatchingAttributes(baseMethod, overridingMethod, "RequiresUnreferencedCodeAttribute")) + bool baseMethodTypeIsInterface = baseMethod.OwningType.IsInterface; + foreach (var requiresAttribute in _requiresAttributeMismatchNameAndId) { - Logger.LogWarning(overridingMethod, DiagnosticId.RequiresUnreferencedCodeAttributeMismatch, overridingMethod.GetDisplayName(), baseMethod.GetDisplayName()); - } + // We validate that the various dataflow/Requires* annotations are consistent across virtual method overrides + if (HasMismatchingAttributes(baseMethod, overridingMethod, requiresAttribute.AttributeName)) + { + string overridingMethodName = overridingMethod.GetDisplayName(); + string baseMethodName = baseMethod.GetDisplayName(); + string message = MessageFormat.FormatRequiresAttributeMismatch(overridingMethod.DoesMethodRequire(requiresAttribute.AttributeName, out _), + baseMethodTypeIsInterface, requiresAttribute.AttributeName, overridingMethodName, baseMethodName); - if (HasMismatchingAttributes(baseMethod, overridingMethod, "RequiresDynamicCodeAttribute")) - { - Logger.LogWarning(overridingMethod, DiagnosticId.RequiresDynamicCodeAttributeMismatch, overridingMethod.GetDisplayName(), baseMethod.GetDisplayName()); + Logger.LogWarning(overridingMethod, requiresAttribute.Id, message); + } } bool baseMethodRequiresDataflow = FlowAnnotations.RequiresDataflowAnalysis(baseMethod); @@ -802,7 +813,7 @@ public override void NoteOverridingMethod(MethodDesc baseMethod, MethodDesc over } } - public static bool HasMismatchingAttributes (MethodDesc baseMethod, MethodDesc overridingMethod, string requiresAttributeName) + public static bool HasMismatchingAttributes(MethodDesc baseMethod, MethodDesc overridingMethod, string requiresAttributeName) { bool baseMethodCreatesRequirement = baseMethod.DoesMethodRequire(requiresAttributeName, out _); bool overridingMethodCreatesRequirement = overridingMethod.DoesMethodRequire(requiresAttributeName, out _); diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs index ef58eac310f4f5..108d8ee5f2edd1 100644 --- a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs @@ -171,8 +171,8 @@ public void Method1 () { } public void Method2 () { } // https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer)] - [ExpectedWarning ("IL2026", "--Method2--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "--Method2--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)] public static void Test () { Type.GetType ("Mono.Linker.Tests.Cases.DataFlow." + nameof (GetTypeDataFlow) + "+" + nameof (TypeWithWarnings)).RequiresPublicMethods (); @@ -187,7 +187,7 @@ class OverConstTypeName public void Method1 () { } // https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)] public static void Test () { Type.GetType (s_ConstTypeName).RequiresPublicMethods (); diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs new file mode 100644 index 00000000000000..44c724e12d80c3 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs @@ -0,0 +1,46 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies +{ + public class ReferenceInterfaces + { + public interface IBaseWithRequiresInReference + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + public void Method (); + + public string PropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + public string PropertyAnnotationInProperty { get; set; } + } + + public interface IBaseWithoutRequiresInReference + { + public void Method (); + + public string PropertyAnnotationInAccesor { + get; + set; + } + + public string PropertyAnnotationInProperty { get; set; } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAttributeMismatch.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAttributeMismatch.cs new file mode 100644 index 00000000000000..3f24aeae963b86 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAttributeMismatch.cs @@ -0,0 +1,491 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.RequiresCapability.Dependencies; + +namespace Mono.Linker.Tests.Cases.RequiresCapability +{ + [SetupLinkerAction ("copy", "lib1")] + [SetupCompileBefore ("lib1.dll", new[] { "Dependencies/ReferenceInterfaces.cs" })] + [KeptAllTypesAndMembersInAssembly ("lib1.dll")] + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + class RequiresAttributeMismatch + { + // Base/Derived and Implementation/Interface differs between linker and analyzer https://github.com/dotnet/linker/issues/2533 + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL2026", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.set", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.set", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualMethod()")] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualMethod()")] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualMethod()")] + [ExpectedWarning ("IL2026", "DerivedClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL2026", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "IBaseWithRequires.Method()")] + [ExpectedWarning ("IL2026", "ImplementationClassWithRequires.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "ImplementationClassWithRequiresInSource.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] + [ExpectedWarning ("IL2026", "PropertyAnnotationInPropertyAndAccessor.set")] + + public static void Main () + { + typeof (BaseClassWithRequires).RequiresPublicMethods (); + typeof (BaseClassWithoutRequires).RequiresPublicMethods (); + typeof (DerivedClassWithRequires).RequiresPublicMethods (); + typeof (DerivedClassWithoutRequires).RequiresPublicMethods (); + typeof (DerivedClassWithAllWarnings).RequiresPublicMethods (); + typeof (IBaseWithRequires).RequiresPublicMethods (); + typeof (IBaseWithoutRequires).RequiresPublicMethods (); + typeof (ImplementationClassWithRequires).RequiresPublicMethods (); + typeof (ImplementationClassWithoutRequires).RequiresPublicMethods (); + typeof (ExplicitImplementationClassWithRequires).RequiresPublicMethods (); + typeof (ExplicitImplementationClassWithoutRequires).RequiresPublicMethods (); + typeof (ImplementationClassWithoutRequiresInSource).RequiresPublicMethods (); + typeof (ImplementationClassWithRequiresInSource).RequiresPublicMethods (); + } + + class BaseClassWithRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + public virtual void VirtualMethod () + { + } + + public virtual string VirtualPropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + public virtual string VirtualPropertyAnnotationInProperty { get; set; } + + [RequiresAssemblyFiles ("Message")] + public virtual string VirtualPropertyAnnotationInPropertyAndAccessor { + [RequiresAssemblyFiles ("Message")] + [RequiresUnreferencedCode ("Message")] + get; + set; + } + } + + class BaseClassWithoutRequires + { + public virtual void VirtualMethod () + { + } + + public virtual string VirtualPropertyAnnotationInAccesor { get; set; } + + public virtual string VirtualPropertyAnnotationInProperty { get; set; } + } + + class DerivedClassWithRequires : BaseClassWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + [ExpectedWarning ("IL2046", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public override void VirtualMethod () + { + } + + private string name; + public override string VirtualPropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + get { return name; } + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithoutRequires.VirtualPropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInProperty { get; set; } + } + + class DerivedClassWithoutRequires : BaseClassWithRequires + { + [ExpectedWarning ("IL2046", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()")] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public override void VirtualMethod () + { + } + + private string name; + public override string VirtualPropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get { return name; } + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInProperty { get; set; } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInPropertyAndAccessor", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInPropertyAndAccessor { + [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get; + set; + } + } + + class DerivedClassWithAllWarnings : BaseClassWithRequires + { + [ExpectedWarning ("IL2046", "DerivedClassWithAllWarnings.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()")] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "DerivedClassWithAllWarnings.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public override void VirtualMethod () + { + } + + private string name; + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get { return name; } + [RequiresAssemblyFiles ("Message")] + [RequiresUnreferencedCode ("Message")] + [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInAccesor.set", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.set")] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.set", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.set", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInProperty { + [RequiresAssemblyFiles ("Message")] + [RequiresUnreferencedCode ("Message")] + [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInProperty.get", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.get", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get; + [RequiresAssemblyFiles ("Message")] + [RequiresUnreferencedCode ("Message")] + [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInProperty.set", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.set")] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.set", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.set", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + set; + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInPropertyAndAccessor", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInPropertyAndAccessor { + [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get; + [RequiresAssemblyFiles ("Message")] + [RequiresUnreferencedCode ("Message")] + [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInPropertyAndAccessor.set", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.set")] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInPropertyAndAccessor.set", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.set", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + set; + } + } + + public interface IBaseWithRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + void Method (); + + string PropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + string PropertyAnnotationInProperty { get; set; } + + [RequiresAssemblyFiles ("Message")] + string PropertyAnnotationInPropertyAndAccessor { + get; + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + set; + } + } + + public interface IBaseWithoutRequires + { + void Method (); + + string PropertyAnnotationInAccesor { get; set; } + + string PropertyAnnotationInProperty { get; set; } + + string PropertyAnnotationInPropertyAndAccessor { get; set; } + } + + class ImplementationClassWithRequires : IBaseWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + get { return name; } + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInPropertyAndAccessor { + [RequiresAssemblyFiles ("Message")] + [RequiresUnreferencedCode ("Message")] + [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get; + set; + } + } + + class ExplicitImplementationClassWithRequires : IBaseWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + // Linker member string format includes namespace of explicit interface method. + [ExpectedWarning ("IL2046", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.NativeAot)] + [ExpectedWarning ("IL2046", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL3051", "IBaseWithoutRequires.Method()", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + void IBaseWithoutRequires.Method () + { + } + + private string name; + string IBaseWithoutRequires.PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + get { return name; } + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + string IBaseWithoutRequires.PropertyAnnotationInProperty { get; set; } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = ProducedBy.Analyzer)] + string IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor { + [RequiresAssemblyFiles ("Message")] + [RequiresUnreferencedCode ("Message")] + [ExpectedWarning ("IL2046", "PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get; + set; + } + } + + class ImplementationClassWithoutRequires : IBaseWithRequires + { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get { return name; } + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInPropertyAndAccessor { + [RequiresAssemblyFiles ("Message")] + [RequiresUnreferencedCode ("Message")] + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get; + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + set; + } + } + + class ExplicitImplementationClassWithoutRequires : IBaseWithRequires + { + // Linker member string format includes namespace of explicit interface method. + [ExpectedWarning ("IL2046", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3003", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", ProducedBy = ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", ProducedBy = ProducedBy.NativeAot)] + [ExpectedWarning ("IL2046", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL3003", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL3051", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + void IBaseWithRequires.Method () + { + } + + private string name; + string IBaseWithRequires.PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get { return name; } + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + string IBaseWithRequires.PropertyAnnotationInProperty { get; set; } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = ProducedBy.Analyzer)] + string IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor { + get; + [ExpectedWarning ("IL2046", "PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + set; + } + } + + class ImplementationClassWithoutRequiresInSource : ReferenceInterfaces.IBaseWithRequiresInReference + { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + get { return name; } + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty", "IBaseWithRequiresInReference.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithRequiresInSource : ReferenceInterfaces.IBaseWithoutRequiresInReference + { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3051", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [RequiresDynamicCode ("Message")] + get { return name; } + set { name = value; } + } + + // NativeAOT does not look at associated Property/Event to produce warnings + // https://github.com/dotnet/runtime/issues/71985 + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + [RequiresAssemblyFiles ("Message")] + public string PropertyAnnotationInProperty { get; set; } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/CecilExtensions.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/CecilExtensions.cs index afcefb93804888..f88c4d8cf177fd 100644 --- a/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/CecilExtensions.cs +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/CecilExtensions.cs @@ -163,206 +163,198 @@ public static object GetConstructorArgumentValue (this CustomAttribute attr, int return null; } - public static bool IsEventMethod(this MethodDefinition md) - { - return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 || - (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 || - (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0; - } - - public static string GetDisplayName(this MethodReference method) - { - var sb = new System.Text.StringBuilder(); - - // Match C# syntaxis name if setter or getter - var methodDefinition = method.Resolve(); - if (methodDefinition != null && (methodDefinition.IsSetter || methodDefinition.IsGetter)) - { - // Append property name - string name = methodDefinition.IsSetter ? string.Concat(methodDefinition.Name.AsSpan(4), ".set") : string.Concat(methodDefinition.Name.AsSpan(4), ".get"); - sb.Append(name); - // Insert declaring type name and namespace - sb.Insert(0, '.').Insert(0, method.DeclaringType?.GetDisplayName()); - return sb.ToString(); - } - - if (methodDefinition != null && methodDefinition.IsEventMethod()) - { - // Append event name - string name = methodDefinition.SemanticsAttributes switch - { - MethodSemanticsAttributes.AddOn => string.Concat(methodDefinition.Name.AsSpan(4), ".add"), - MethodSemanticsAttributes.RemoveOn => string.Concat(methodDefinition.Name.AsSpan(7), ".remove"), - MethodSemanticsAttributes.Fire => string.Concat(methodDefinition.Name.AsSpan(6), ".raise"), - _ => throw new NotSupportedException(), - }; - sb.Append(name); - // Insert declaring type name and namespace - sb.Insert(0, '.').Insert(0, method.DeclaringType.GetDisplayName()); - return sb.ToString(); - } - - // Append parameters - sb.Append("("); - if (method.HasParameters) - { - for (int i = 0; i < method.Parameters.Count - 1; i++) - sb.Append(method.Parameters[i].ParameterType.GetDisplayNameWithoutNamespace()).Append(", "); - - sb.Append(method.Parameters[method.Parameters.Count - 1].ParameterType.GetDisplayNameWithoutNamespace()); - } - - sb.Append(")"); - - // Insert generic parameters - if (method.HasGenericParameters) - { - PrependGenericParameters(method.GenericParameters, sb); - } - - // Insert method name - if (method.Name == ".ctor") - sb.Insert(0, method.DeclaringType.Name); - else - sb.Insert(0, method.Name); - - // Insert declaring type name and namespace - if (method.DeclaringType != null) - sb.Insert(0, '.').Insert(0, method.DeclaringType.GetDisplayName()); - - return sb.ToString(); - } - - public static string GetDisplayName(this TypeReference type) - { - var builder = GetDisplayNameWithoutNamespace(type); - var namespaceDisplayName = type.GetNamespaceDisplayName(); - if (!string.IsNullOrEmpty(namespaceDisplayName)) - { - builder.Insert(0, "."); - builder.Insert(0, namespaceDisplayName); - } - - return builder.ToString(); - } - - public static string GetDisplayName(this FieldReference field) - { - var builder = new StringBuilder(); - if (field.DeclaringType != null) - { - builder.Append(field.DeclaringType.GetDisplayName()); - builder.Append("."); - } - - builder.Append(field.Name); - - return builder.ToString(); - } - - public static string GetNamespaceDisplayName(this MemberReference member) - { - var type = member is TypeReference typeReference ? typeReference : member.DeclaringType; - while (type.DeclaringType != null) - type = type.DeclaringType; - - return type.Namespace; - } - - public static StringBuilder GetDisplayNameWithoutNamespace(this TypeReference type) - { - var sb = new StringBuilder(); - if (type == null) - return sb; - - Stack? genericArguments = null; - while (true) - { - switch (type) - { - case ArrayType arrayType: - AppendArrayType(arrayType, sb); - break; - case GenericInstanceType genericInstanceType: - genericArguments = new Stack(genericInstanceType.GenericArguments); - type = genericInstanceType.ElementType; - continue; - default: - if (type.HasGenericParameters) - { - int genericParametersCount = type.GenericParameters.Count; - int declaringTypeGenericParametersCount = type.DeclaringType?.GenericParameters?.Count ?? 0; - - string simpleName; - if (genericParametersCount > declaringTypeGenericParametersCount) - { - if (genericArguments?.Count > 0) - PrependGenericArguments(genericArguments, genericParametersCount - declaringTypeGenericParametersCount, sb); - else - PrependGenericParameters(type.GenericParameters.Skip(declaringTypeGenericParametersCount).ToList(), sb); - - int explicitArityIndex = type.Name.IndexOf('`'); - simpleName = explicitArityIndex != -1 ? type.Name.Substring(0, explicitArityIndex) : type.Name; - } - else - simpleName = type.Name; - - sb.Insert(0, simpleName); - break; - } - - sb.Insert(0, type.Name); - break; - } - - if (type.DeclaringType is not TypeReference declaringType) - break; - - type = declaringType; - - sb.Insert(0, '.'); - } - - return sb; - } - - public static void PrependGenericParameters(IList genericParameters, StringBuilder sb) - { - sb.Insert(0, '>').Insert(0, genericParameters[genericParameters.Count - 1]); - for (int i = genericParameters.Count - 2; i >= 0; i--) - sb.Insert(0, ',').Insert(0, genericParameters[i]); - - sb.Insert(0, '<'); - } - - static void PrependGenericArguments(Stack genericArguments, int argumentsToTake, StringBuilder sb) - { - sb.Insert(0, '>').Insert(0, genericArguments.Pop().GetDisplayNameWithoutNamespace().ToString()); - while (--argumentsToTake > 0) - sb.Insert(0, ',').Insert(0, genericArguments.Pop().GetDisplayNameWithoutNamespace().ToString()); - - sb.Insert(0, '<'); - } - - static void AppendArrayType(ArrayType arrayType, StringBuilder sb) - { - void parseArrayDimensions(ArrayType at) - { - sb.Append('['); - for (int i = 0; i < at.Dimensions.Count - 1; i++) - sb.Append(','); - - sb.Append(']'); - } - - sb.Append(arrayType.Name.AsSpan(0, arrayType.Name.IndexOf('['))); - parseArrayDimensions(arrayType); - var element = arrayType.ElementType as ArrayType; - while (element != null) - { - parseArrayDimensions(element); - element = element.ElementType as ArrayType; - } - } - } + public static bool IsEventMethod (this MethodDefinition md) + { + return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 || + (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 || + (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0; + } + + public static string GetDisplayName (this MethodReference method) + { + var sb = new System.Text.StringBuilder (); + + // Match C# syntaxis name if setter or getter + var methodDefinition = method.Resolve (); + if (methodDefinition != null && (methodDefinition.IsSetter || methodDefinition.IsGetter)) { + // Append property name + string name = GetPropertyNameFromAccessorName (methodDefinition.Name, methodDefinition.IsSetter); + sb.Append (name); + // Insert declaring type name and namespace + sb.Insert (0, '.').Insert (0, method.DeclaringType?.GetDisplayName ()); + return sb.ToString (); + } + + if (methodDefinition != null && methodDefinition.IsEventMethod ()) { + // Append event name + string name = methodDefinition.SemanticsAttributes switch { + MethodSemanticsAttributes.AddOn => string.Concat (methodDefinition.Name.AsSpan (4), ".add"), + MethodSemanticsAttributes.RemoveOn => string.Concat (methodDefinition.Name.AsSpan (7), ".remove"), + MethodSemanticsAttributes.Fire => string.Concat (methodDefinition.Name.AsSpan (6), ".raise"), + _ => throw new NotSupportedException (), + }; + sb.Append (name); + // Insert declaring type name and namespace + sb.Insert (0, '.').Insert (0, method.DeclaringType.GetDisplayName ()); + return sb.ToString (); + } + + // Append parameters + sb.Append ("("); + if (method.HasParameters) { + for (int i = 0; i < method.Parameters.Count - 1; i++) + sb.Append (method.Parameters[i].ParameterType.GetDisplayNameWithoutNamespace ()).Append (", "); + + sb.Append (method.Parameters[method.Parameters.Count - 1].ParameterType.GetDisplayNameWithoutNamespace ()); + } + + sb.Append (")"); + + // Insert generic parameters + if (method.HasGenericParameters) { + PrependGenericParameters (method.GenericParameters, sb); + } + + // Insert method name + if (method.Name == ".ctor") + sb.Insert (0, method.DeclaringType.Name); + else + sb.Insert (0, method.Name); + + // Insert declaring type name and namespace + if (method.DeclaringType != null) + sb.Insert (0, '.').Insert (0, method.DeclaringType.GetDisplayName ()); + + return sb.ToString (); + } + + private static string GetPropertyNameFromAccessorName (string methodName, bool isSetter) => + isSetter ? + string.Concat (methodName.StartsWith ("set_") ? methodName.AsSpan (4) : methodName.Replace (".set_", "."), ".set") : + string.Concat (methodName.StartsWith ("get_") ? methodName.AsSpan (4) : methodName.Replace (".get_", "."), ".get"); + + public static string GetDisplayName (this TypeReference type) + { + var builder = GetDisplayNameWithoutNamespace (type); + var namespaceDisplayName = type.GetNamespaceDisplayName (); + if (!string.IsNullOrEmpty (namespaceDisplayName)) { + builder.Insert (0, "."); + builder.Insert (0, namespaceDisplayName); + } + + return builder.ToString (); + } + + public static string GetDisplayName (this FieldReference field) + { + var builder = new StringBuilder (); + if (field.DeclaringType != null) { + builder.Append (field.DeclaringType.GetDisplayName ()); + builder.Append ("."); + } + + builder.Append (field.Name); + + return builder.ToString (); + } + + public static string GetNamespaceDisplayName (this MemberReference member) + { + var type = member is TypeReference typeReference ? typeReference : member.DeclaringType; + while (type.DeclaringType != null) + type = type.DeclaringType; + + return type.Namespace; + } + + public static StringBuilder GetDisplayNameWithoutNamespace (this TypeReference type) + { + var sb = new StringBuilder (); + if (type == null) + return sb; + + Stack? genericArguments = null; + while (true) { + switch (type) { + case ArrayType arrayType: + AppendArrayType (arrayType, sb); + break; + case GenericInstanceType genericInstanceType: + genericArguments = new Stack (genericInstanceType.GenericArguments); + type = genericInstanceType.ElementType; + continue; + default: + if (type.HasGenericParameters) { + int genericParametersCount = type.GenericParameters.Count; + int declaringTypeGenericParametersCount = type.DeclaringType?.GenericParameters?.Count ?? 0; + + string simpleName; + if (genericParametersCount > declaringTypeGenericParametersCount) { + if (genericArguments?.Count > 0) + PrependGenericArguments (genericArguments, genericParametersCount - declaringTypeGenericParametersCount, sb); + else + PrependGenericParameters (type.GenericParameters.Skip (declaringTypeGenericParametersCount).ToList (), sb); + + int explicitArityIndex = type.Name.IndexOf ('`'); + simpleName = explicitArityIndex != -1 ? type.Name.Substring (0, explicitArityIndex) : type.Name; + } else + simpleName = type.Name; + + sb.Insert (0, simpleName); + break; + } + + sb.Insert (0, type.Name); + break; + } + + if (type.DeclaringType is not TypeReference declaringType) + break; + + type = declaringType; + + sb.Insert (0, '.'); + } + + return sb; + } + + public static void PrependGenericParameters (IList genericParameters, StringBuilder sb) + { + sb.Insert (0, '>').Insert (0, genericParameters[genericParameters.Count - 1]); + for (int i = genericParameters.Count - 2; i >= 0; i--) + sb.Insert (0, ',').Insert (0, genericParameters[i]); + + sb.Insert (0, '<'); + } + + static void PrependGenericArguments (Stack genericArguments, int argumentsToTake, StringBuilder sb) + { + sb.Insert (0, '>').Insert (0, genericArguments.Pop ().GetDisplayNameWithoutNamespace ().ToString ()); + while (--argumentsToTake > 0) + sb.Insert (0, ',').Insert (0, genericArguments.Pop ().GetDisplayNameWithoutNamespace ().ToString ()); + + sb.Insert (0, '<'); + } + + static void AppendArrayType (ArrayType arrayType, StringBuilder sb) + { + void parseArrayDimensions (ArrayType at) + { + sb.Append ('['); + for (int i = 0; i < at.Dimensions.Count - 1; i++) + sb.Append (','); + + sb.Append (']'); + } + + sb.Append (arrayType.Name.AsSpan (0, arrayType.Name.IndexOf ('['))); + parseArrayDimensions (arrayType); + var element = arrayType.ElementType as ArrayType; + while (element != null) { + parseArrayDimensions (element); + element = element.ElementType as ArrayType; + } + } + } } diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs index b970f5ac587f80..5c8c44267edb61 100644 --- a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs @@ -35,7 +35,7 @@ public void Trim (ILCompilerOptions options, ILogWriter logWriter) inputModules.Add (module); } - CompilationModuleGroup compilationGroup = new MultiFileSharedCompilationModuleGroup (typeSystemContext, inputModules); + CompilationModuleGroup compilationGroup = new TestInfraMultiFileSharedCompilationModuleGroup (typeSystemContext, inputModules); List compilationRoots = new List (); EcmaModule? entrypointModule = null; diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestInfraMultiFileCompilationModuleGroup.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestInfraMultiFileCompilationModuleGroup.cs new file mode 100644 index 00000000000000..0ce32dfb4f33a4 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestInfraMultiFileCompilationModuleGroup.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +using ILCompiler; +using ILCompiler.DependencyAnalysis; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + + /// + /// Represents a non-leaf multifile compilation group where types contained in the group are always fully expanded. + /// + public class TestInfraMultiFileSharedCompilationModuleGroup : MultiFileCompilationModuleGroup + { + public TestInfraMultiFileSharedCompilationModuleGroup(CompilerTypeSystemContext context, IEnumerable compilationModuleSet) + : base(context, compilationModuleSet) + { + } + + public override bool ShouldProduceFullVTable(TypeDesc type) + { + return false; + } + + public override bool ShouldPromoteToFullType(TypeDesc type) + { + return ShouldProduceFullVTable(type); + } + + public override bool PresenceOfEETypeImpliesAllMethodsOnType(TypeDesc type) + { + return (type.HasInstantiation || type.IsArray) && ShouldProduceFullVTable(type) && + type.ConvertToCanonForm(CanonicalFormKind.Specific).IsCanonicalSubtype(CanonicalFormKind.Any); + } + + public override bool AllowInstanceMethodOptimization(MethodDesc method) + { + // Both the instance methods and the owning type are homed in a single compilation group + // so if we're able to generate the body, we would also generate the owning type here + // and nowhere else. + Debug.Assert(ContainsMethodBody(method, unboxingStub: false)); + TypeDesc owningType = method.OwningType; + return owningType.IsDefType && !owningType.HasInstantiation && !method.HasInstantiation; + } + } +}