Skip to content

Commit 2f02f12

Browse files
authored
Support for RequiresAttributeMismatch testing (#72496)
The RequiresAttributeMismatch warnings were not being generated since one of the answers from the MultiFileSharedCompilatioModuleGroup was to generate Vtables from everything. The logic for checking for warning mismatch is gated by not having a vtable being generated so needed to create a copy of the MultiFileSharedCompilationModuleGroup for testing purposes. Adding testing also unveils some issues with the current way of producing warnings in NativeAOT that are addressed in this PR. - Create a copy of the MultiFileSharedCompilationModuleGroup into the test infrastructure - Default answer of ShouldProduceFullVTable to false in the TestInfraMultiFileSharedCompilationModuleGroup, otherwise, the logic for checking for mismatch in NativeAOT will not work as currently implemented. - Property names don't need parenthesis, escape before they are added. - Small fix when ExplicitInterface names are used, cannot rely on name starting with get_/set_ in all cases. - Additional RUC warning check when a method is marked via DAM and is not TypeHierarchy marking - Adds RequiresAttributeMismatch test file from linker (includes adding NativeAOT specific ProducedBy attributes)
1 parent bac2229 commit 2f02f12

File tree

9 files changed

+822
-215
lines changed

9 files changed

+822
-215
lines changed

src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public static string GetDisplayName(this MethodDesc method)
4545
sb.Append(property.Name);
4646
sb.Append('.');
4747
sb.Append(property.GetMethod == method ? "get" : "set");
48+
return sb.ToString();
4849
}
4950
else
5051
{
@@ -104,7 +105,7 @@ public static string GetDisplayName(this PropertyPseudoDesc property)
104105
.Append('.')
105106
.Append(property.Name).ToString();
106107
}
107-
108+
108109
public static string GetDisplayName(this EventPseudoDesc @event)
109110
{
110111
return new StringBuilder(@event.OwningType.GetDisplayName())

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,20 @@ void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystemEntity en
204204
MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage(requiresAttribute.Value)),
205205
MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl(requiresAttribute.Value)));
206206
}
207+
else
208+
{
209+
var diagnosticContext = new DiagnosticContext(
210+
origin,
211+
_logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute),
212+
_logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresDynamicCodeAttribute),
213+
_logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresAssemblyFilesAttribute),
214+
_logger);
215+
216+
string arg1 = MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage(requiresAttribute.Value));
217+
string arg2 = MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl(requiresAttribute.Value));
218+
219+
diagnosticContext.AddDiagnostic(DiagnosticId.RequiresUnreferencedCode, entity.GetDisplayName(), arg1, arg2);
220+
}
207221
}
208222

209223
if (!Annotations.ShouldWarnWhenAccessedForReflection(entity))

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ public sealed class UsageBasedMetadataManager : GeneratingMetadataManager
4141

4242
private readonly FeatureSwitchHashtable _featureSwitchHashtable;
4343

44+
private static (string AttributeName, DiagnosticId Id)[] _requiresAttributeMismatchNameAndId = new[]
45+
{
46+
(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, DiagnosticId.RequiresUnreferencedCodeAttributeMismatch),
47+
(DiagnosticUtilities.RequiresDynamicCodeAttribute, DiagnosticId.RequiresDynamicCodeAttributeMismatch),
48+
(DiagnosticUtilities.RequiresAssemblyFilesAttribute, DiagnosticId.RequiresAssemblyFilesAttributeMismatch)
49+
};
50+
4451
private readonly List<ModuleDesc> _modulesWithMetadata = new List<ModuleDesc>();
4552
private readonly List<FieldDesc> _fieldsWithMetadata = new List<FieldDesc>();
4653
private readonly List<MethodDesc> _methodsWithMetadata = new List<MethodDesc>();
@@ -783,15 +790,19 @@ public bool GeneratesAttributeMetadata(TypeDesc attributeType)
783790

784791
public override void NoteOverridingMethod(MethodDesc baseMethod, MethodDesc overridingMethod)
785792
{
786-
// We validate that the various dataflow/Requires* annotations are consistent across virtual method overrides
787-
if (HasMismatchingAttributes(baseMethod, overridingMethod, "RequiresUnreferencedCodeAttribute"))
793+
bool baseMethodTypeIsInterface = baseMethod.OwningType.IsInterface;
794+
foreach (var requiresAttribute in _requiresAttributeMismatchNameAndId)
788795
{
789-
Logger.LogWarning(overridingMethod, DiagnosticId.RequiresUnreferencedCodeAttributeMismatch, overridingMethod.GetDisplayName(), baseMethod.GetDisplayName());
790-
}
796+
// We validate that the various dataflow/Requires* annotations are consistent across virtual method overrides
797+
if (HasMismatchingAttributes(baseMethod, overridingMethod, requiresAttribute.AttributeName))
798+
{
799+
string overridingMethodName = overridingMethod.GetDisplayName();
800+
string baseMethodName = baseMethod.GetDisplayName();
801+
string message = MessageFormat.FormatRequiresAttributeMismatch(overridingMethod.DoesMethodRequire(requiresAttribute.AttributeName, out _),
802+
baseMethodTypeIsInterface, requiresAttribute.AttributeName, overridingMethodName, baseMethodName);
791803

792-
if (HasMismatchingAttributes(baseMethod, overridingMethod, "RequiresDynamicCodeAttribute"))
793-
{
794-
Logger.LogWarning(overridingMethod, DiagnosticId.RequiresDynamicCodeAttributeMismatch, overridingMethod.GetDisplayName(), baseMethod.GetDisplayName());
804+
Logger.LogWarning(overridingMethod, requiresAttribute.Id, message);
805+
}
795806
}
796807

797808
bool baseMethodRequiresDataflow = FlowAnnotations.RequiresDataflowAnalysis(baseMethod);
@@ -802,7 +813,7 @@ public override void NoteOverridingMethod(MethodDesc baseMethod, MethodDesc over
802813
}
803814
}
804815

805-
public static bool HasMismatchingAttributes (MethodDesc baseMethod, MethodDesc overridingMethod, string requiresAttributeName)
816+
public static bool HasMismatchingAttributes(MethodDesc baseMethod, MethodDesc overridingMethod, string requiresAttributeName)
806817
{
807818
bool baseMethodCreatesRequirement = baseMethod.DoesMethodRequire(requiresAttributeName, out _);
808819
bool overridingMethodCreatesRequirement = overridingMethod.DoesMethodRequire(requiresAttributeName, out _);

src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ public void Method1 () { }
171171
public void Method2 () { }
172172

173173
// https://github.com/dotnet/linker/issues/2273
174-
[ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer)]
175-
[ExpectedWarning ("IL2026", "--Method2--", ProducedBy = ProducedBy.Trimmer)]
174+
[ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
175+
[ExpectedWarning ("IL2026", "--Method2--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
176176
public static void Test ()
177177
{
178178
Type.GetType ("Mono.Linker.Tests.Cases.DataFlow." + nameof (GetTypeDataFlow) + "+" + nameof (TypeWithWarnings)).RequiresPublicMethods ();
@@ -187,7 +187,7 @@ class OverConstTypeName
187187
public void Method1 () { }
188188

189189
// https://github.com/dotnet/linker/issues/2273
190-
[ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer)]
190+
[ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
191191
public static void Test ()
192192
{
193193
Type.GetType (s_ConstTypeName).RequiresPublicMethods ();
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies
12+
{
13+
public class ReferenceInterfaces
14+
{
15+
public interface IBaseWithRequiresInReference
16+
{
17+
[RequiresUnreferencedCode ("Message")]
18+
[RequiresAssemblyFiles ("Message")]
19+
[RequiresDynamicCode ("Message")]
20+
public void Method ();
21+
22+
public string PropertyAnnotationInAccesor {
23+
[RequiresUnreferencedCode ("Message")]
24+
[RequiresAssemblyFiles ("Message")]
25+
[RequiresDynamicCode ("Message")]
26+
get;
27+
set;
28+
}
29+
30+
[RequiresAssemblyFiles ("Message")]
31+
public string PropertyAnnotationInProperty { get; set; }
32+
}
33+
34+
public interface IBaseWithoutRequiresInReference
35+
{
36+
public void Method ();
37+
38+
public string PropertyAnnotationInAccesor {
39+
get;
40+
set;
41+
}
42+
43+
public string PropertyAnnotationInProperty { get; set; }
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)