Skip to content

Commit 7a0c3a3

Browse files
authored
Avoid warnings due to RUC on type when marking assembly as library (#84620)
Marking an assembly as "library" will mark all public APIs. If some of the marked members have RUC on them we decided we don't want to produce warnings, since there's nothing especially wrong with the library. The callers of those members would still get the right warnings. Currently linker implements this correctly for methods and properties, but it fails for fields and events and it still produces some warnings, especially if the RUC is on the parent type. This change fixes those cases and adds a special test for the library marked assembly in combination with several RUCs. Fixes #81864
1 parent 965a1be commit 7a0c3a3

File tree

4 files changed

+104
-10
lines changed

4 files changed

+104
-10
lines changed

src/tools/illink/src/linker/Linker.Steps/MarkStep.cs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,9 +1775,19 @@ void ProcessAnalysisAnnotationsForField (FieldDefinition field, DependencyKind d
17751775
(origin.Provider is MethodDefinition originMethod && CompilerGeneratedState.IsNestedFunctionOrStateMachineMember (originMethod)));
17761776
}
17771777

1778-
if (dependencyKind == DependencyKind.DynamicallyAccessedMemberOnType) {
1778+
switch (dependencyKind) {
1779+
// Marked through things like descriptor - don't want to warn as it's intentional choice
1780+
case DependencyKind.AlreadyMarked:
1781+
case DependencyKind.TypePreserve:
1782+
case DependencyKind.PreservedMethod:
1783+
return;
1784+
1785+
case DependencyKind.DynamicallyAccessedMemberOnType:
17791786
ReportWarningsForTypeHierarchyReflectionAccess (field, origin);
17801787
return;
1788+
1789+
default:
1790+
break;
17811791
}
17821792

17831793
if (Annotations.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode (origin.Provider, out _))
@@ -3189,9 +3199,10 @@ protected virtual void ProcessMethod (MethodDefinition method, in DependencyInfo
31893199
if (!Annotations.ProcessSatelliteAssemblies && KnownMembers.IsSatelliteAssemblyMarker (method))
31903200
Annotations.ProcessSatelliteAssemblies = true;
31913201
} else if (method.TryGetProperty (out PropertyDefinition? property))
3192-
MarkProperty (property, new DependencyInfo (DependencyKind.PropertyOfPropertyMethod, method));
3193-
else if (method.TryGetEvent (out EventDefinition? @event))
3194-
MarkEvent (@event, new DependencyInfo (DependencyKind.EventOfEventMethod, method));
3202+
MarkProperty (property, new DependencyInfo (PropagateDependencyKindToAccessors (reason.Kind, DependencyKind.PropertyOfPropertyMethod), method));
3203+
else if (method.TryGetEvent (out EventDefinition? @event)) {
3204+
MarkEvent (@event, new DependencyInfo (PropagateDependencyKindToAccessors(reason.Kind, DependencyKind.EventOfEventMethod), method));
3205+
}
31953206

31963207
if (method.HasMetadataParameters ()) {
31973208
#pragma warning disable RS0030 // MethodReference.Parameters is banned. It's easiest to leave the code as is for now
@@ -3270,6 +3281,20 @@ protected virtual void DoAdditionalMethodProcessing (MethodDefinition method)
32703281
{
32713282
}
32723283

3284+
static DependencyKind PropagateDependencyKindToAccessors(DependencyKind parentDependencyKind, DependencyKind kind)
3285+
{
3286+
switch (parentDependencyKind) {
3287+
// If the member is marked due to descriptor or similar, propagate the original reason to suppress some warnings correctly
3288+
case DependencyKind.AlreadyMarked:
3289+
case DependencyKind.TypePreserve:
3290+
case DependencyKind.PreservedMethod:
3291+
return parentDependencyKind;
3292+
3293+
default:
3294+
return kind;
3295+
}
3296+
}
3297+
32733298
void MarkImplicitlyUsedFields (TypeDefinition type)
32743299
{
32753300
if (type?.HasFields != true)
@@ -3506,9 +3531,12 @@ protected internal virtual void MarkEvent (EventDefinition evt, in DependencyInf
35063531
using var eventScope = ScopeStack.PushScope (new MessageOrigin (evt));
35073532

35083533
MarkCustomAttributes (evt, new DependencyInfo (DependencyKind.CustomAttribute, evt));
3509-
MarkMethodIfNotNull (evt.AddMethod, new DependencyInfo (DependencyKind.EventMethod, evt), ScopeStack.CurrentScope.Origin);
3510-
MarkMethodIfNotNull (evt.InvokeMethod, new DependencyInfo (DependencyKind.EventMethod, evt), ScopeStack.CurrentScope.Origin);
3511-
MarkMethodIfNotNull (evt.RemoveMethod, new DependencyInfo (DependencyKind.EventMethod, evt), ScopeStack.CurrentScope.Origin);
3534+
3535+
DependencyKind dependencyKind = PropagateDependencyKindToAccessors(reason.Kind, DependencyKind.EventMethod);
3536+
MarkMethodIfNotNull (evt.AddMethod, new DependencyInfo (dependencyKind, evt), ScopeStack.CurrentScope.Origin);
3537+
MarkMethodIfNotNull (evt.InvokeMethod, new DependencyInfo (dependencyKind, evt), ScopeStack.CurrentScope.Origin);
3538+
MarkMethodIfNotNull (evt.RemoveMethod, new DependencyInfo (dependencyKind, evt), ScopeStack.CurrentScope.Origin);
3539+
35123540
DoAdditionalEventProcessing (evt);
35133541
}
35143542

src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ public Task RequiresInCompilerGeneratedCodeRelease ()
5858
return RunTest ();
5959
}
6060

61+
[Fact]
62+
public Task RequiresInLibraryAssembly ()
63+
{
64+
return RunTest ();
65+
}
66+
6167
[Fact]
6268
public Task RequiresOnAttribute ()
6369
{
@@ -112,4 +118,4 @@ public Task SuppressRequires ()
112118
return RunTest (nameof (SuppressRequires));
113119
}
114120
}
115-
}
121+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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.Diagnostics.CodeAnalysis;
6+
using Mono.Linker.Tests.Cases.Expectations.Assertions;
7+
using Mono.Linker.Tests.Cases.Expectations.Metadata;
8+
9+
namespace Mono.Linker.Tests.Cases.RequiresCapability
10+
{
11+
[SetupLinkerArgument ("-a", "test.exe", "library")]
12+
13+
[SkipKeptItemsValidation]
14+
[ExpectedNoWarnings]
15+
public class RequiresInLibraryAssembly
16+
{
17+
public static void Main ()
18+
{
19+
}
20+
21+
[RequiresDynamicCode ("--MethodWhichRequires--")]
22+
public static void MethodWhichRequires () { }
23+
24+
[RequiresDynamicCode ("--InstanceMethodWhichRequires--")]
25+
public void InstanceMethodWhichRequires () { }
26+
}
27+
28+
[ExpectedNoWarnings]
29+
public sealed class ClassWithDAMAnnotatedMembers
30+
{
31+
public static void Method ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { }
32+
33+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
34+
public static Type Field;
35+
}
36+
37+
[ExpectedNoWarnings]
38+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
39+
public sealed class ClassWithDAMAnnotation
40+
{
41+
public void Method () { }
42+
}
43+
44+
[ExpectedNoWarnings]
45+
[RequiresUnreferencedCode ("--ClassWithRequires--")]
46+
public sealed class ClassWithRequires
47+
{
48+
public static int Field;
49+
50+
internal static int InternalField;
51+
52+
private static int PrivateField;
53+
54+
public static void Method () { }
55+
56+
public void InstanceMethod () { }
57+
58+
public static int Property { get; set; }
59+
60+
public static event EventHandler PropertyChanged;
61+
}
62+
}

src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
1717
[SetupLinkerDescriptorFile ("RequiresViaXml.descriptor.xml")]
1818
[SkipKeptItemsValidation]
1919
[ExpectedNoWarnings]
20-
// [LogContains ("--RequiresOnlyViaDescriptor--")] // https://github.com/dotnet/linker/issues/2103
21-
[ExpectedWarning ("IL2026", "RequiresOnFieldOnlyViaDescriptor.Field", FileName = "RequiresViaXml.descriptor.xml", ProducedBy = Tool.Trimmer)]
2220
class RequiresViaXml
2321
{
2422

0 commit comments

Comments
 (0)