Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitek Karas <vitek.karas@microsoft.com>2021-06-17 15:04:44 +0300
committerGitHub <noreply@github.com>2021-06-17 15:04:44 +0300
commitbee7f73564e495e6ab8627e7c595dacc32a4b096 (patch)
treeefa4d4c7116898b736223e24b431843f124bb668
parent4f68312aeb4b8b906bee4e06438020ad6721c522 (diff)
Warning suppressions in compiler generated code (#2075)
This change implements the following high-level functionality: * `UnconditionalSuppressMessage` applies to the entire method body even for iterators, async methods * `RequiresUnreferencedCode` automatically suppresses trim analysis warnings from entire method body for iterators, async methods Solution approach: * Detect compiler generated code by using the `IteratorStateMachineAttribute`, `AsyncStateMachineAttribute` and `AyncIteratorStateMachineAttribute`. * When a method which is compiler generated (detected by looing for `<` in its name) is processed the original "user method" is determined by looking for a method with the "state machine" attribute pointing to the compiler generated type. * This information is cached to avoid duplication of relatively expensive detection logic. * Looks for `UnconditionalSuppressMessage` and `RequriesUnreferencedCode` in: * If the warning origin is not a compiler generated code - simply use the warning origin (method) - existing behavior * If the warning origin is compiler generated use both the origin as well as the user defined method (non-compiler-generated) which is the source of the code for the compiler generated origin This is done by storing additional `SuppressionContextMember` on `MessageOrigin` which should always point to non-compiler-generated item. Added lot of new tests for these scenarios. This implements warning suppression part of https://github.com/mono/linker/issues/2001 for state machines.
-rw-r--r--docs/error-codes.md76
-rw-r--r--src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs18
-rw-r--r--src/linker/Linker.Steps/MarkScopeStack.cs22
-rw-r--r--src/linker/Linker.Steps/MarkStep.cs32
-rw-r--r--src/linker/Linker/CompilerGeneratedState.cs94
-rw-r--r--src/linker/Linker/LinkContext.cs12
-rw-r--r--src/linker/Linker/MessageOrigin.cs25
-rw-r--r--src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs34
-rw-r--r--test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs2
-rw-r--r--test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs2
-rw-r--r--test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs202
-rw-r--r--test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeInCompilerGeneratedCode.cs1076
-rw-r--r--test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInCompilerGeneratedCode.cs481
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs11
14 files changed, 1986 insertions, 101 deletions
diff --git a/docs/error-codes.md b/docs/error-codes.md
index c28da8a99..3f59b374d 100644
--- a/docs/error-codes.md
+++ b/docs/error-codes.md
@@ -1561,36 +1561,36 @@ class Test
#### `IL2103`: Trim analysis: Value passed to the 'propertyAccessor' parameter of method 'System.Linq.Expressions.Expression.Property(Expression, MethodInfo)' cannot be statically determined as a property accessor
-The value passed to the `propertyAccessor` parameter of `Expression.Property(expression, propertyAccessor)` was not recognized as a property accessor method. Trimmer can't guarantee the presence of the property.
+- The value passed to the `propertyAccessor` parameter of `Expression.Property(expression, propertyAccessor)` was not recognized as a property accessor method. Trimmer can't guarantee the presence of the property.
-```C#
-void TestMethod(MethodInfo methodInfo)
-{
- // IL2103: Value passed to the 'propertyAccessor' parameter of method 'System.Linq.Expressions.Expression.Property(Expression, MethodInfo)' cannot be statically determined as a property accessor.
- Expression.Property(null, methodInfo);
-}
-```
+ ```C#
+ void TestMethod(MethodInfo methodInfo)
+ {
+ // IL2103: Value passed to the 'propertyAccessor' parameter of method 'System.Linq.Expressions.Expression.Property(Expression, MethodInfo)' cannot be statically determined as a property accessor.
+ Expression.Property(null, methodInfo);
+ }
+ ```
#### `IL2104`: Assembly 'assembly' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
-The assembly 'assembly' produced trim analysis warnings in the context of the app. This means the assembly has not been fully annotated for trimming. Consider contacting the library author to request they add trim annotations to the library. To see detailed warnings for this assembly, turn off grouped warnings by passing either `--singlewarn-` to show detailed warnings for all assemblies, or `--singlewarn- "assembly"` to show detailed warnings for that assembly. https://aka.ms/dotnet-illink/libraries has more information on annotating libraries for trimming.
+- The assembly 'assembly' produced trim analysis warnings in the context of the app. This means the assembly has not been fully annotated for trimming. Consider contacting the library author to request they add trim annotations to the library. To see detailed warnings for this assembly, turn off grouped warnings by passing either `--singlewarn-` to show detailed warnings for all assemblies, or `--singlewarn- "assembly"` to show detailed warnings for that assembly. https://aka.ms/dotnet-illink/libraries has more information on annotating libraries for trimming.
#### `IL2105`: Type 'type' was not found in the caller assembly nor in the base library. Type name strings used for dynamically accessing a type should be assembly qualified.
-Type name strings representing dynamically accessed types must be assembly qualified, otherwise linker will first search for the type name in the caller's assembly and then in System.Private.CoreLib.
-If the linker fails to resolve the type name, null will be returned.
+- Type name strings representing dynamically accessed types must be assembly qualified, otherwise linker will first search for the type name in the caller's assembly and then in System.Private.CoreLib.
+ If the linker fails to resolve the type name, null will be returned.
-```C#
-void TestInvalidTypeName()
-{
- RequirePublicMethodOnAType("Foo.Unqualified.TypeName");
-}
-void RequirePublicMethodOnAType(
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- string typeName)
-{
-}
-```
+ ```C#
+ void TestInvalidTypeName()
+ {
+ RequirePublicMethodOnAType("Foo.Unqualified.TypeName");
+ }
+ void RequirePublicMethodOnAType(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ string typeName)
+ {
+ }
+ ```
#### `IL2106`: Trim analysis: Return type of method 'method' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'
@@ -1604,6 +1604,38 @@ void RequirePublicMethodOnAType(
}
```
+#### `IL2107`: Trim analysis: Methods 'method1' and 'method2' are both associated with state machine type 'type'. This is currently unsupported and may lead to incorrectly reported warnings.
+
+- Trimmer currently can't correctly handle if the same compiler generated state machine type is associated (via the state machine attributes) with two different methods.
+ Since the trimmer currently derives warning suppressions from the method which produced the state machine and currently doesn't support reprocessing the same method/type more than once.
+
+ Only a meta-sample:
+
+ ```C#
+ class <compiler_generated_state_machine>_type {
+ void MoveNext()
+ {
+ // This should normally produce IL2026
+ CallSomethingWhichRequiresUnreferencedCode ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("")] // This should suppress all warnings from the method
+ [IteratorStateMachine(typeof(<compiler_generated_state_machine>_type))]
+ IEnumerable<int> UserDefinedMethod()
+ {
+ // Uses the state machine type
+ // The IL2026 from the state machine should be suppressed in this case
+ }
+
+ // IL2107: Methods 'UserDefinedMethod' and 'SecondUserDefinedMethod' are both associated with state machine type '<compiler_generated_state_machine>_type'.
+ [IteratorStateMachine(typeof(<compiler_generated_state_machine>_type))]
+ IEnumerable<int> SecondUserDefinedMethod()
+ {
+ // Uses the state machine type
+ // The IL2026 from the state should be reported in this case
+ }
+ ```
## Single-File Warning Codes
diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index a453702d0..582bde492 100644
--- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -59,9 +59,12 @@ namespace Mono.Linker.Dataflow
return context.Annotations.FlowAnnotations.RequiresDataFlowAnalysis (fieldDefinition);
}
- bool ShouldEnableReflectionPatternReporting (MethodDefinition method)
+ bool ShouldEnableReflectionPatternReporting ()
{
- return !_context.Annotations.HasLinkerAttribute<RequiresUnreferencedCodeAttribute> (method);
+ if (_markStep.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode ())
+ return false;
+
+ return true;
}
public ReflectionMethodBodyScanner (LinkContext context, MarkStep parent, MarkScopeStack scopeStack)
@@ -79,7 +82,7 @@ namespace Mono.Linker.Dataflow
var method = methodBody.Method;
var requiredMemberTypes = _context.Annotations.FlowAnnotations.GetReturnParameterAnnotation (method);
if (requiredMemberTypes != 0) {
- var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (method), _scopeStack.CurrentScope.Origin, method.MethodReturnType);
+ var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (), _scopeStack.CurrentScope.Origin, method.MethodReturnType);
reflectionContext.AnalyzingPattern ();
RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, MethodReturnValue, method.MethodReturnType);
reflectionContext.Dispose ();
@@ -151,9 +154,8 @@ namespace Mono.Linker.Dataflow
ValueNode valueNode = GetTypeValueNodeFromGenericArgument (genericArgument);
var currentScopeOrigin = _scopeStack.CurrentScope.Origin;
- bool enableReflectionPatternReporting = !(currentScopeOrigin.MemberDefinition is MethodDefinition sourceMethod) || ShouldEnableReflectionPatternReporting (sourceMethod);
- var reflectionContext = new ReflectionPatternContext (_context, enableReflectionPatternReporting, currentScopeOrigin, genericParameter);
+ var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (), currentScopeOrigin, genericParameter);
reflectionContext.AnalyzingPattern ();
RequireDynamicallyAccessedMembers (ref reflectionContext, annotation, valueNode, genericParameter);
reflectionContext.Dispose ();
@@ -228,7 +230,7 @@ namespace Mono.Linker.Dataflow
var requiredMemberTypes = _context.Annotations.FlowAnnotations.GetFieldAnnotation (field);
if (requiredMemberTypes != 0) {
_scopeStack.UpdateCurrentScopeInstructionOffset (operation.Offset);
- var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (method), _scopeStack.CurrentScope.Origin, field, operation);
+ var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (), _scopeStack.CurrentScope.Origin, field, operation);
reflectionContext.AnalyzingPattern ();
RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, valueToStore, field);
reflectionContext.Dispose ();
@@ -241,7 +243,7 @@ namespace Mono.Linker.Dataflow
if (requiredMemberTypes != 0) {
ParameterDefinition parameter = method.Parameters[index - (method.HasImplicitThis () ? 1 : 0)];
_scopeStack.UpdateCurrentScopeInstructionOffset (operation.Offset);
- var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (method), _scopeStack.CurrentScope.Origin, parameter, operation);
+ var reflectionContext = new ReflectionPatternContext (_context, ShouldEnableReflectionPatternReporting (), _scopeStack.CurrentScope.Origin, parameter, operation);
reflectionContext.AnalyzingPattern ();
RequireDynamicallyAccessedMembers (ref reflectionContext, requiredMemberTypes, valueToStore, parameter);
reflectionContext.Dispose ();
@@ -649,7 +651,7 @@ namespace Mono.Linker.Dataflow
_scopeStack.UpdateCurrentScopeInstructionOffset (operation.Offset);
var reflectionContext = new ReflectionPatternContext (
_context,
- ShouldEnableReflectionPatternReporting (callingMethodDefinition),
+ ShouldEnableReflectionPatternReporting (),
_scopeStack.CurrentScope.Origin,
calledMethodDefinition,
operation);
diff --git a/src/linker/Linker.Steps/MarkScopeStack.cs b/src/linker/Linker.Steps/MarkScopeStack.cs
index 1804b4d69..4aea40c3f 100644
--- a/src/linker/Linker.Steps/MarkScopeStack.cs
+++ b/src/linker/Linker.Steps/MarkScopeStack.cs
@@ -15,12 +15,13 @@ namespace Mono.Linker.Steps
{
public readonly MessageOrigin Origin;
- public Scope (MessageOrigin origin)
+ public Scope (in MessageOrigin origin)
{
Origin = origin;
}
}
+ readonly LinkContext _context;
readonly Stack<Scope> _scopeStack;
readonly struct LocalScope : IDisposable
@@ -32,7 +33,16 @@ namespace Mono.Linker.Steps
{
_origin = origin;
_scopeStack = scopeStack;
- _scopeStack.Push (new Scope (origin));
+
+ // Compiler generated methods and types should "inherit" suppression context
+ // from the user defined method from which the compiler generated them.
+ // Detecting which method produced which piece of compiler generated code
+ // is currently not possible in all cases, but in cases where it works
+ // we will store the suppression context in the SuppressionContextMember.
+ // For code which is not compiler generated the suppression context
+ // is the same as the message's origin member.
+ IMemberDefinition suppressionContextMember = _scopeStack.GetSuppressionContext (origin.MemberDefinition);
+ _scopeStack.Push (new Scope (new MessageOrigin (origin.MemberDefinition, origin.ILOffset, suppressionContextMember)));
}
public LocalScope (in Scope scope, MarkScopeStack scopeStack)
@@ -73,8 +83,9 @@ namespace Mono.Linker.Steps
}
}
- public MarkScopeStack ()
+ public MarkScopeStack (LinkContext context)
{
+ _context = context;
_scopeStack = new Stack<Scope> ();
}
@@ -108,7 +119,7 @@ namespace Mono.Linker.Steps
if (scope.Origin.MemberDefinition is not MethodDefinition)
throw new InternalErrorException ($"Trying to update instruction offset of scope stack which is not a method. Current stack scope is '{scope}'.");
- _scopeStack.Push (new Scope (new MessageOrigin (scope.Origin.MemberDefinition, offset)));
+ _scopeStack.Push (new Scope (new MessageOrigin (scope.Origin.MemberDefinition, offset, scope.Origin.SuppressionContextMember)));
}
void Push (in Scope scope)
@@ -126,5 +137,8 @@ namespace Mono.Linker.Steps
[Conditional ("DEBUG")]
public void AssertIsEmpty () => Debug.Assert (_scopeStack.Count == 0);
+
+ IMemberDefinition GetSuppressionContext (IMemberDefinition sourceMember) =>
+ _context.CompilerGeneratedState.GetUserDefinedMethodForCompilerGeneratedMember (sourceMember) ?? sourceMember;
}
}
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index d17c8f6ce..23b44c37b 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -60,7 +60,7 @@ namespace Mono.Linker.Steps
MarkStepContext _markContext;
readonly Dictionary<TypeDefinition, bool> _entireTypesMarked; // The value is markBaseAndInterfaceTypes flag used to mark the type
DynamicallyAccessedMembersTypeHierarchy _dynamicallyAccessedMembersTypeHierarchy;
- readonly MarkScopeStack _scopeStack;
+ MarkScopeStack _scopeStack;
internal DynamicallyAccessedMembersTypeHierarchy DynamicallyAccessedMembersTypeHierarchy {
get => _dynamicallyAccessedMembersTypeHierarchy;
@@ -192,7 +192,6 @@ namespace Mono.Linker.Steps
_unreachableBodies = new List<(MethodBody, MarkScopeStack.Scope)> ();
_pending_isinst_instr = new List<(TypeDefinition, MethodBody, Instruction)> ();
_entireTypesMarked = new Dictionary<TypeDefinition, bool> ();
- _scopeStack = new MarkScopeStack ();
}
public AnnotationStore Annotations => _context.Annotations;
@@ -204,6 +203,7 @@ namespace Mono.Linker.Steps
_context = context;
_unreachableBlocksOptimizer = new UnreachableBlocksOptimizer (_context);
_markContext = new MarkStepContext ();
+ _scopeStack = new MarkScopeStack (_context);
_dynamicallyAccessedMembersTypeHierarchy = new DynamicallyAccessedMembersTypeHierarchy (_context, this, _scopeStack);
Initialize ();
@@ -2720,14 +2720,34 @@ namespace Mono.Linker.Steps
CheckAndReportRequiresUnreferencedCode (method);
}
+ internal bool ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode ()
+ {
+ // Check if the current scope method has RequiresUnreferencedCode on it
+ // since that attribute automatically suppresses all trim analysis warnings.
+ // Check both the immediate origin method as well as suppression context method
+ // since that will be different for compiler generated code.
+ var currentOrigin = _scopeStack.CurrentScope.Origin;
+
+ IMemberDefinition suppressionContextMember = currentOrigin.SuppressionContextMember;
+ if (suppressionContextMember != null &&
+ Annotations.HasLinkerAttribute<RequiresUnreferencedCodeAttribute> (suppressionContextMember))
+ return true;
+
+ IMemberDefinition originMember = currentOrigin.MemberDefinition;
+ if (suppressionContextMember != originMember && originMember != null &&
+ Annotations.HasLinkerAttribute<RequiresUnreferencedCodeAttribute> (originMember))
+ return true;
+
+ return false;
+ }
+
internal void CheckAndReportRequiresUnreferencedCode (MethodDefinition method)
{
- var currentScope = _scopeStack.CurrentScope;
+ var currentOrigin = _scopeStack.CurrentScope.Origin;
// If the caller of a method is already marked with `RequiresUnreferencedCodeAttribute` a new warning should not
// be produced for the callee.
- if (currentScope.Origin.MemberDefinition != null &&
- Annotations.HasLinkerAttribute<RequiresUnreferencedCodeAttribute> (currentScope.Origin.MemberDefinition))
+ if (ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode ())
return;
if (Annotations.TryGetLinkerAttribute (method, out RequiresUnreferencedCodeAttribute requiresUnreferencedCode)) {
@@ -2738,7 +2758,7 @@ namespace Mono.Linker.Steps
if (!string.IsNullOrEmpty (requiresUnreferencedCode.Url))
message += " " + requiresUnreferencedCode.Url;
- _context.LogWarning (message, 2026, currentScope.Origin, MessageSubCategory.TrimAnalysis);
+ _context.LogWarning (message, 2026, currentOrigin, MessageSubCategory.TrimAnalysis);
}
}
diff --git a/src/linker/Linker/CompilerGeneratedState.cs b/src/linker/Linker/CompilerGeneratedState.cs
new file mode 100644
index 000000000..9df15ab50
--- /dev/null
+++ b/src/linker/Linker/CompilerGeneratedState.cs
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Collections.Generic;
+using Mono.Cecil;
+
+namespace Mono.Linker
+{
+ // Currently this is implemented using heuristics
+ public class CompilerGeneratedState
+ {
+ readonly LinkContext _context;
+ readonly Dictionary<TypeDefinition, MethodDefinition> _compilerGeneratedTypeToUserCodeMethod;
+ readonly HashSet<TypeDefinition> _typesWithPopulatedCache;
+
+ public CompilerGeneratedState (LinkContext context)
+ {
+ _context = context;
+ _compilerGeneratedTypeToUserCodeMethod = new Dictionary<TypeDefinition, MethodDefinition> ();
+ _typesWithPopulatedCache = new HashSet<TypeDefinition> ();
+ }
+
+ static bool HasRoslynCompilerGeneratedName (TypeDefinition type) =>
+ type.Name.Contains ('<') || (type.DeclaringType != null && HasRoslynCompilerGeneratedName (type.DeclaringType));
+
+ void PopulateCacheForType (TypeDefinition type)
+ {
+ // Avoid repeat scans of the same type
+ if (!_typesWithPopulatedCache.Add (type))
+ return;
+
+ foreach (MethodDefinition method in type.Methods) {
+ if (!method.HasCustomAttributes)
+ continue;
+
+ foreach (var attribute in method.CustomAttributes) {
+ if (attribute.AttributeType.Namespace != "System.Runtime.CompilerServices")
+ continue;
+
+ switch (attribute.AttributeType.Name) {
+ case "AsyncIteratorStateMachineAttribute":
+ case "AsyncStateMachineAttribute":
+ case "IteratorStateMachineAttribute":
+ TypeDefinition stateMachineType = GetFirstConstructorArgumentAsType (attribute);
+ if (stateMachineType != null) {
+ if (!_compilerGeneratedTypeToUserCodeMethod.TryAdd (stateMachineType, method)) {
+ var alreadyAssociatedMethod = _compilerGeneratedTypeToUserCodeMethod[stateMachineType];
+ _context.LogWarning (
+ $"Methods '{method.GetDisplayName ()}' and '{alreadyAssociatedMethod.GetDisplayName ()}' are both associated with state machine type '{stateMachineType.GetDisplayName ()}'. This is currently unsupported and may lead to incorrectly reported warnings.",
+ 2107,
+ new MessageOrigin (method),
+ MessageSubCategory.TrimAnalysis);
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ static TypeDefinition GetFirstConstructorArgumentAsType (CustomAttribute attribute)
+ {
+ if (!attribute.HasConstructorArguments)
+ return null;
+
+ return attribute.ConstructorArguments[0].Value as TypeDefinition;
+ }
+
+ public MethodDefinition GetUserDefinedMethodForCompilerGeneratedMember (IMemberDefinition sourceMember)
+ {
+ if (sourceMember == null)
+ return null;
+
+ TypeDefinition compilerGeneratedType = (sourceMember as TypeDefinition) ?? sourceMember.DeclaringType;
+ if (_compilerGeneratedTypeToUserCodeMethod.TryGetValue (compilerGeneratedType, out MethodDefinition userDefinedMethod))
+ return userDefinedMethod;
+
+ // Only handle async or iterator state machine
+ // So go to the declaring type and check if it's compiler generated (as a perf optimization)
+ if (!HasRoslynCompilerGeneratedName (compilerGeneratedType) || compilerGeneratedType.DeclaringType == null)
+ return null;
+
+ // Now go to its declaring type and search all methods to find the one which points to the type as its
+ // state machine implementation.
+ PopulateCacheForType (compilerGeneratedType.DeclaringType);
+ if (_compilerGeneratedTypeToUserCodeMethod.TryGetValue (compilerGeneratedType, out userDefinedMethod))
+ return userDefinedMethod;
+
+ return null;
+ }
+ }
+}
diff --git a/src/linker/Linker/LinkContext.cs b/src/linker/Linker/LinkContext.cs
index d6d6ef02f..58e3e0499 100644
--- a/src/linker/Linker/LinkContext.cs
+++ b/src/linker/Linker/LinkContext.cs
@@ -70,6 +70,7 @@ namespace Mono.Linker
readonly AnnotationStore _annotations;
readonly CustomAttributeSource _customAttributes;
+ readonly CompilerGeneratedState _compilerGeneratedState;
readonly List<MessageContainer> _cachedWarningMessageContainers;
readonly ILogger _logger;
readonly Dictionary<AssemblyDefinition, bool> _isTrimmable;
@@ -78,13 +79,11 @@ namespace Mono.Linker
get { return _pipeline; }
}
- public CustomAttributeSource CustomAttributes {
- get { return _customAttributes; }
- }
+ public CustomAttributeSource CustomAttributes => _customAttributes;
- public AnnotationStore Annotations {
- get { return _annotations; }
- }
+ public CompilerGeneratedState CompilerGeneratedState => _compilerGeneratedState;
+
+ public AnnotationStore Annotations => _annotations;
public bool DeterministicOutput { get; set; }
@@ -210,6 +209,7 @@ namespace Mono.Linker
_actions = new Dictionary<string, AssemblyAction> ();
_parameters = new Dictionary<string, string> (StringComparer.Ordinal);
_customAttributes = new CustomAttributeSource (this);
+ _compilerGeneratedState = new CompilerGeneratedState (this);
_cachedWarningMessageContainers = new List<MessageContainer> ();
_isTrimmable = new Dictionary<AssemblyDefinition, bool> ();
FeatureSettings = new Dictionary<string, bool> (StringComparer.Ordinal);
diff --git a/src/linker/Linker/MessageOrigin.cs b/src/linker/Linker/MessageOrigin.cs
index c28a3b134..701f3c0e5 100644
--- a/src/linker/Linker/MessageOrigin.cs
+++ b/src/linker/Linker/MessageOrigin.cs
@@ -15,6 +15,9 @@ namespace Mono.Linker
#nullable enable
public string? FileName { get; }
public IMemberDefinition? MemberDefinition { get; }
+
+ readonly IMemberDefinition _suppressionContextMember;
+ public IMemberDefinition? SuppressionContextMember { get => _suppressionContextMember ?? MemberDefinition; }
#nullable disable
public int SourceLine { get; }
public int SourceColumn { get; }
@@ -33,13 +36,20 @@ namespace Mono.Linker
SourceLine = sourceLine;
SourceColumn = sourceColumn;
MemberDefinition = null;
+ _suppressionContextMember = null;
ILOffset = null;
}
public MessageOrigin (IMemberDefinition memberDefinition, int? ilOffset)
+ : this (memberDefinition, ilOffset, null)
+ {
+ }
+
+ public MessageOrigin (IMemberDefinition memberDefinition, int? ilOffset, IMemberDefinition suppressionContextMember)
{
FileName = null;
MemberDefinition = memberDefinition;
+ _suppressionContextMember = suppressionContextMember;
SourceLine = 0;
SourceColumn = 0;
ILOffset = ilOffset;
@@ -85,7 +95,7 @@ namespace Mono.Linker
}
public bool Equals (MessageOrigin other) =>
- (FileName, MemberDefinition, SourceLine, SourceColumn) == (other.FileName, other.MemberDefinition, other.SourceLine, other.SourceColumn);
+ (FileName, MemberDefinition, SourceLine, SourceColumn, ILOffset) == (other.FileName, other.MemberDefinition, other.SourceLine, other.SourceColumn, other.ILOffset);
public override bool Equals (object obj) => obj is MessageOrigin messageOrigin && Equals (messageOrigin);
public override int GetHashCode () => (FileName, MemberDefinition, SourceLine, SourceColumn).GetHashCode ();
@@ -95,8 +105,17 @@ namespace Mono.Linker
public int CompareTo (MessageOrigin other)
{
if (MemberDefinition != null && other.MemberDefinition != null) {
- return (MemberDefinition.DeclaringType?.Module?.Assembly?.Name?.Name, MemberDefinition.DeclaringType?.Name, MemberDefinition?.Name).CompareTo
- ((other.MemberDefinition.DeclaringType?.Module?.Assembly?.Name?.Name, other.MemberDefinition.DeclaringType?.Name, other.MemberDefinition?.Name));
+ TypeDefinition thisTypeDef = (MemberDefinition as TypeDefinition) ?? MemberDefinition.DeclaringType;
+ TypeDefinition otherTypeDef = (other.MemberDefinition as TypeDefinition) ?? other.MemberDefinition.DeclaringType;
+ int result = (thisTypeDef?.Module?.Assembly?.Name?.Name, thisTypeDef?.Name, MemberDefinition?.Name).CompareTo
+ ((otherTypeDef?.Module?.Assembly?.Name?.Name, otherTypeDef?.Name, other.MemberDefinition?.Name));
+ if (result != 0)
+ return result;
+
+ if (ILOffset != null && other.ILOffset != null)
+ return ILOffset.Value.CompareTo (other.ILOffset);
+
+ return ILOffset == null ? (other.ILOffset == null ? 0 : 1) : -1;
} else if (MemberDefinition == null && other.MemberDefinition == null) {
if (FileName != null && other.FileName != null) {
return string.Compare (FileName, other.FileName);
diff --git a/src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs b/src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
index 0da5c74f4..686b4ad46 100644
--- a/src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
+++ b/src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
@@ -45,29 +45,45 @@ namespace Mono.Linker
public bool IsSuppressed (int id, MessageOrigin warningOrigin, out SuppressMessageInfo info)
{
+ // Check for suppressions on both the suppression context as well as the original member
+ // (if they're different). This is to correctly handle compiler generated code
+ // which needs to use suppressions from both the compiler generated scope
+ // as well as the original user defined method.
+ IMemberDefinition suppressionContextMember = warningOrigin.SuppressionContextMember;
+ if (IsSuppressed (id, suppressionContextMember, out info))
+ return true;
+
+ IMemberDefinition originMember = warningOrigin.MemberDefinition;
+ if (suppressionContextMember != originMember && IsSuppressed (id, originMember, out info))
+ return true;
+
+ return false;
+ }
+
+ bool IsSuppressed (int id, IMemberDefinition warningOriginMember, out SuppressMessageInfo info)
+ {
info = default;
- if (warningOrigin.MemberDefinition == null)
+ if (warningOriginMember == null)
return false;
- IMemberDefinition elementContainingWarning = warningOrigin.MemberDefinition;
- ModuleDefinition module = GetModuleFromProvider (warningOrigin.MemberDefinition);
+ ModuleDefinition module = GetModuleFromProvider (warningOriginMember);
DecodeModuleLevelAndGlobalSuppressMessageAttributes (module);
- while (elementContainingWarning != null) {
- if (IsSuppressed (id, elementContainingWarning, out info))
+ while (warningOriginMember != null) {
+ if (IsSuppressedOnElement (id, warningOriginMember, out info))
return true;
- elementContainingWarning = elementContainingWarning.DeclaringType;
+ warningOriginMember = warningOriginMember.DeclaringType;
}
// Check if there's an assembly or module level suppression.
- if (IsSuppressed (id, module, out info) ||
- IsSuppressed (id, module.Assembly, out info))
+ if (IsSuppressedOnElement (id, module, out info) ||
+ IsSuppressedOnElement (id, module.Assembly, out info))
return true;
return false;
}
- bool IsSuppressed (int id, ICustomAttributeProvider provider, out SuppressMessageInfo info)
+ bool IsSuppressedOnElement (int id, ICustomAttributeProvider provider, out SuppressMessageInfo info)
{
info = default;
if (provider == null)
diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs
index 85bd85d67..04ba3fdcb 100644
--- a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs
+++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs
@@ -18,5 +18,7 @@ namespace Mono.Linker.Tests.Cases.Expectations.Assertions
// Set to true if the warning only applies to global analysis (ILLinker, as opposed to Roslyn Analyzer)
public bool GlobalAnalysisOnly { get; set; }
+
+ public bool CompilerGeneratedCode { get; set; }
}
}
diff --git a/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs b/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs
index 776647232..1ced566df 100644
--- a/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs
+++ b/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs
@@ -7,7 +7,7 @@ namespace Mono.Linker.Tests.Cases.Logging
#if !NETCOREAPP
[IgnoreTestCase ("Can be enabled once MonoBuild produces a dll from which we can grab the types in the Mono.Linker namespace.")]
#else
- [SetupCompileBefore ("LogStep.dll", new[] { "Dependencies/LogStep.cs" }, new[] { "illink.dll" })]
+ [SetupCompileBefore ("LogStep.dll", new[] { "Dependencies/LogStep.cs" }, new[] { "illink.dll", "Mono.Cecil.dll" })]
#endif
[SetupLinkerArgument ("--custom-step", "Log.LogStep,LogStep.dll")]
[SetupLinkerArgument ("--verbose")]
diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs
index 9c9c324de..3d3f0afda 100644
--- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs
+++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs
@@ -39,7 +39,8 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
TestRequiresWithMessageAndUrlOnMethod ();
TestRequiresOnConstructor ();
TestRequiresOnPropertyGetterAndSetter ();
- TestRequiresSuppressesWarningsFromReflectionAnalysis ();
+ SuppressMethodBodyReferences.Test ();
+ SuppressGenericParameters<TestType, TestType>.Test ();
TestDuplicateRequiresAttribute ();
TestRequiresUnreferencedCodeOnlyThroughReflection ();
TestBaseTypeVirtualMethodRequiresUnreferencedCode ();
@@ -60,7 +61,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
TestRequiresInDynamicDependency ();
TestThatTrailingPeriodIsAddedToMessage ();
TestThatTrailingPeriodIsNotDuplicatedInWarningMessage ();
- TestRequiresOnAttributeOnGenericParameter ();
+ RequiresOnAttribute.Test ();
}
[ExpectedWarning ("IL2026", "Message for --RequiresWithMessageOnly--.")]
@@ -115,45 +116,113 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
set { }
}
- [ExpectedWarning ("IL2026", "Message for --RequiresAndCallsOtherRequiresMethods--.")]
- static void TestRequiresSuppressesWarningsFromReflectionAnalysis ()
+ [ExpectedNoWarnings]
+ class SuppressMethodBodyReferences
{
- RequiresAndCallsOtherRequiresMethods<TestType> ();
- }
+ static Type _unknownType;
+ static Type GetUnknownType () => null;
- [RequiresUnreferencedCode ("Message for --RequiresAndCallsOtherRequiresMethods--")]
- [LogDoesNotContain ("Message for --RequiresUnreferencedCodeMethod--")]
- [RecognizedReflectionAccessPattern]
- static void RequiresAndCallsOtherRequiresMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> ()
- {
- // Normally this would warn, but with the attribute on this method it should be auto-suppressed
- RequiresUnreferencedCodeMethod ();
+ [RequiresUnreferencedCode ("Message for --RequiresUnreferencedCodeMethod--")]
+ static void RequiresUnreferencedCodeMethod ()
+ {
+ }
- // Normally this would warn due to incompatible annotations, but with the attribute on this method it should be auto-suppressed
- GetTypeWithPublicMethods ().RequiresPublicFields ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
+ static Type _requiresPublicConstructors;
- TypeRequiresPublicFields<TPublicMethods>.Method ();
+ [RequiresUnreferencedCode ("")]
+ static void TestRUCMethod ()
+ {
+ // Normally this would warn, but with the attribute on this method it should be auto-suppressed
+ RequiresUnreferencedCodeMethod ();
+ }
- MethodRequiresPublicFields<TPublicMethods> ();
- }
+ [RequiresUnreferencedCode ("")]
+ static void TestParameter ()
+ {
+ _unknownType.RequiresPublicMethods ();
+ }
- [RequiresUnreferencedCode ("Message for --RequiresUnreferencedCodeMethod--")]
- static void RequiresUnreferencedCodeMethod ()
- {
- }
+ [RequiresUnreferencedCode ("")]
+ static void TestReturnValue ()
+ {
+ GetUnknownType ().RequiresPublicEvents ();
+ }
- [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
- static Type GetTypeWithPublicMethods ()
- {
- return null;
+ [RequiresUnreferencedCode ("")]
+ static void TestField ()
+ {
+ _requiresPublicConstructors = _unknownType;
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ public static void Test ()
+ {
+ TestRUCMethod ();
+ TestParameter ();
+ TestReturnValue ();
+ TestField ();
+ }
}
- class TypeRequiresPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T>
+ [ExpectedNoWarnings]
+ class SuppressGenericParameters<TUnknown, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] TPublicProperties>
{
- public static void Method () { }
- }
+ static Type _unknownType;
+
+ static void GenericMethodRequiresPublicMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () { }
+
+ class GenericTypeRequiresPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> { }
+
+ [RequiresUnreferencedCode ("")]
+ static void TestGenericMethod ()
+ {
+ GenericMethodRequiresPublicMethods<TUnknown> ();
+ }
- static void MethodRequiresPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> () { }
+ [RequiresUnreferencedCode ("")]
+ static void TestGenericMethodMismatch ()
+ {
+ GenericMethodRequiresPublicMethods<TPublicProperties> ();
+ }
+
+ [RequiresUnreferencedCode ("")]
+ static void TestGenericType ()
+ {
+ new GenericTypeRequiresPublicFields<TUnknown> ();
+ }
+
+ [RequiresUnreferencedCode ("")]
+ static void TestMakeGenericTypeWithStaticTypes ()
+ {
+ typeof (GenericTypeRequiresPublicFields<>).MakeGenericType (typeof (TUnknown));
+ }
+
+ [RequiresUnreferencedCode ("")]
+ static void TestMakeGenericTypeWithDynamicTypes ()
+ {
+ typeof (GenericTypeRequiresPublicFields<>).MakeGenericType (_unknownType);
+ }
+
+ [RequiresUnreferencedCode ("")]
+ static void TestMakeGenericMethod ()
+ {
+ typeof (SuppressGenericParameters<TUnknown, TPublicProperties>)
+ .GetMethod ("GenericMethodRequiresPublicMethods", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
+ .MakeGenericMethod (typeof (TPublicProperties));
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ public static void Test ()
+ {
+ TestGenericMethod ();
+ TestGenericMethodMismatch ();
+ TestGenericType ();
+ TestMakeGenericTypeWithStaticTypes ();
+ TestMakeGenericTypeWithDynamicTypes ();
+ TestMakeGenericMethod ();
+ }
+ }
class TestType { }
@@ -426,23 +495,72 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
WarningMessageEndsWithPeriod ();
}
- class AttributeWhichRequiresUnreferencedCodeAttribute : Attribute
+ [ExpectedNoWarnings]
+ class RequiresOnAttribute
{
- [RequiresUnreferencedCode ("Message for --AttributeWhichRequiresUnreferencedCodeAttribute.ctor--")]
- public AttributeWhichRequiresUnreferencedCodeAttribute ()
+ class AttributeWhichRequiresUnreferencedCodeAttribute : Attribute
{
+ [RequiresUnreferencedCode ("Message for --AttributeWhichRequiresUnreferencedCodeAttribute.ctor--")]
+ public AttributeWhichRequiresUnreferencedCodeAttribute ()
+ {
+ }
}
- }
- [ExpectedWarning ("IL2026", "--AttributeWhichRequiresUnreferencedCodeAttribute.ctor--")]
- class GenericTypeWithAttributedParameter<[AttributeWhichRequiresUnreferencedCode] T>
- {
- public static void TestMethod () { }
- }
+ [ExpectedWarning ("IL2026", "--AttributeWhichRequiresUnreferencedCodeAttribute.ctor--")]
+ class GenericTypeWithAttributedParameter<[AttributeWhichRequiresUnreferencedCode] T>
+ {
+ public static void TestMethod () { }
+ }
- static void TestRequiresOnAttributeOnGenericParameter ()
- {
- GenericTypeWithAttributedParameter<int>.TestMethod ();
+ // https://github.com/mono/linker/issues/2094 - should be supported by the analyzer
+ [ExpectedWarning ("IL2026", "--AttributeWhichRequiresUnreferencedCodeAttribute.ctor--", GlobalAnalysisOnly = true)]
+ static void GenericMethodWithAttributedParameter<[AttributeWhichRequiresUnreferencedCode] T> () { }
+
+ static void TestRequiresOnAttributeOnGenericParameter ()
+ {
+ GenericTypeWithAttributedParameter<int>.TestMethod ();
+ GenericMethodWithAttributedParameter<int> ();
+ }
+
+ // https://github.com/mono/linker/issues/2094 - should be supported by the analyzer
+ [ExpectedWarning ("IL2026", "--AttributeWhichRequiresUnreferencedCodeAttribute.ctor--", GlobalAnalysisOnly = true)]
+ [AttributeWhichRequiresUnreferencedCode]
+ class TypeWithAttributeWhichRequires
+ {
+ }
+
+ // https://github.com/mono/linker/issues/2094 - should be supported by the analyzer
+ [ExpectedWarning ("IL2026", "--AttributeWhichRequiresUnreferencedCodeAttribute.ctor--", GlobalAnalysisOnly = true)]
+ [AttributeWhichRequiresUnreferencedCode]
+ static void MethodWithAttributeWhichRequires () { }
+
+ [ExpectedWarning ("IL2026", "--AttributeWhichRequiresUnreferencedCodeAttribute.ctor--")]
+ [AttributeWhichRequiresUnreferencedCode]
+ static int _fieldWithAttributeWhichRequires;
+
+ [ExpectedWarning ("IL2026", "--AttributeWhichRequiresUnreferencedCodeAttribute.ctor--")]
+ [AttributeWhichRequiresUnreferencedCode]
+ static bool PropertyWithAttributeWhichRequires { get; set; }
+
+ [AttributeWhichRequiresUnreferencedCode]
+ [RequiresUnreferencedCode ("--MethodWhichRequiresWithAttributeWhichRequires--")]
+ static void MethodWhichRequiresWithAttributeWhichRequires () { }
+
+ [ExpectedWarning ("IL2026", "--MethodWhichRequiresWithAttributeWhichRequires--")]
+ static void TestMethodWhichRequiresWithAttributeWhichRequires ()
+ {
+ MethodWhichRequiresWithAttributeWhichRequires ();
+ }
+
+ public static void Test ()
+ {
+ TestRequiresOnAttributeOnGenericParameter ();
+ new TypeWithAttributeWhichRequires ();
+ MethodWithAttributeWhichRequires ();
+ _fieldWithAttributeWhichRequires = 0;
+ PropertyWithAttributeWhichRequires = false;
+ TestMethodWhichRequiresWithAttributeWhichRequires ();
+ }
}
}
} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeInCompilerGeneratedCode.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeInCompilerGeneratedCode.cs
new file mode 100644
index 000000000..0bdd62526
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeInCompilerGeneratedCode.cs
@@ -0,0 +1,1076 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Helpers;
+
+namespace Mono.Linker.Tests.Cases.RequiresCapability
+{
+ [SkipKeptItemsValidation]
+ [ExpectedNoWarnings]
+ public class RequiresUnreferencedCodeInCompilerGeneratedCode
+ {
+ public static void Main ()
+ {
+ WarnInIteratorBody.Test ();
+ SuppressInIteratorBody.Test ();
+
+ WarnInAsyncBody.Test ();
+ SuppressInAsyncBody.Test ();
+
+ WarnInAsyncIteratorBody.Test ();
+ SuppressInAsyncIteratorBody.Test ();
+
+ WarnInLocalFunction.Test ();
+ SuppressInLocalFunction.Test ();
+
+ WarnInLambda.Test ();
+ SuppressInLambda.Test ();
+
+ WarnInComplex.Test ();
+ SuppressInComplex.Test ();
+
+ StateMachinesOnlyReferencedViaReflection.Test ();
+
+ ComplexCases.AsyncBodyCallingRUCMethod.Test ();
+ ComplexCases.GenericAsyncBodyCallingRUCMethod.Test ();
+ ComplexCases.GenericAsyncEnumerableBodyCallingRUCWithAnnotations.Test ();
+ }
+
+ class WarnInIteratorBody
+ {
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static IEnumerable<int> TestCallBeforeYieldReturn ()
+ {
+ RequiresUnreferencedCodeMethod ();
+ yield return 0;
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static IEnumerable<int> TestCallAfterYieldReturn ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static IEnumerable<int> TestReflectionAccess ()
+ {
+ yield return 0;
+ typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ yield return 1;
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static IEnumerable<int> TestLdftn ()
+ {
+ yield return 0;
+ yield return 1;
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithRUCMethod.RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static IEnumerable<int> TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ yield return 0;
+ yield return 1;
+ }
+
+ public static void Test ()
+ {
+ TestCallBeforeYieldReturn ();
+ TestCallAfterYieldReturn ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInIteratorBody
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static IEnumerable<int> TestCall ()
+ {
+ RequiresUnreferencedCodeMethod ();
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ yield return 1;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static IEnumerable<int> TestReflectionAccess ()
+ {
+ yield return 0;
+ typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ yield return 1;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static IEnumerable<int> TestLdftn ()
+ {
+ yield return 0;
+ yield return 1;
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static IEnumerable<int> TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ yield return 0;
+ yield return 1;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static IEnumerable<int> TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ unknownType.RequiresNonPublicMethods ();
+ yield return 0;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static IEnumerable<int> TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ yield return 0;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static IEnumerable<int> TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ yield return 0;
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ }
+ }
+
+ class WarnInAsyncBody
+ {
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static async void TestCallBeforeYieldReturn ()
+ {
+ RequiresUnreferencedCodeMethod ();
+ await MethodAsync ();
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static async void TestCallAfterYieldReturn ()
+ {
+ await MethodAsync ();
+ RequiresUnreferencedCodeMethod ();
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static async void TestReflectionAccess ()
+ {
+ await MethodAsync ();
+ typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static async void TestLdftn ()
+ {
+ await MethodAsync ();
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithRUCMethod.RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static async void TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ await MethodAsync ();
+ }
+
+ public static void Test ()
+ {
+ TestCallBeforeYieldReturn ();
+ TestCallAfterYieldReturn ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInAsyncBody
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestCall ()
+ {
+ RequiresUnreferencedCodeMethod ();
+ await MethodAsync ();
+ RequiresUnreferencedCodeMethod ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestReflectionAccess ()
+ {
+ await MethodAsync ();
+ typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestLdftn ()
+ {
+ await MethodAsync ();
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ unknownType.RequiresNonPublicMethods ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ }
+ }
+
+ class WarnInAsyncIteratorBody
+ {
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static async IAsyncEnumerable<int> TestCallBeforeYieldReturn ()
+ {
+ await MethodAsync ();
+ RequiresUnreferencedCodeMethod ();
+ yield return 0;
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static async IAsyncEnumerable<int> TestCallAfterYieldReturn ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ await MethodAsync ();
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static async IAsyncEnumerable<int> TestReflectionAccess ()
+ {
+ yield return 0;
+ await MethodAsync ();
+ typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ yield return 1;
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static async IAsyncEnumerable<int> TestLdftn ()
+ {
+ await MethodAsync ();
+ yield return 0;
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithRUCMethod.RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static async IAsyncEnumerable<int> TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ yield return 0;
+ await MethodAsync ();
+ }
+
+ public static void Test ()
+ {
+ TestCallBeforeYieldReturn ();
+ TestCallAfterYieldReturn ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInAsyncIteratorBody
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async IAsyncEnumerable<int> TestCall ()
+ {
+ RequiresUnreferencedCodeMethod ();
+ await MethodAsync ();
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async IAsyncEnumerable<int> TestReflectionAccess ()
+ {
+ await MethodAsync ();
+ yield return 0;
+ typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ yield return 0;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async IAsyncEnumerable<int> TestLdftn ()
+ {
+ await MethodAsync ();
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ yield return 0;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async IAsyncEnumerable<int> TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ yield return 0;
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async IAsyncEnumerable<int> TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ unknownType.RequiresNonPublicMethods ();
+ await MethodAsync ();
+ yield return 0;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async IAsyncEnumerable<int> TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ yield return 0;
+ MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async IAsyncEnumerable<int> TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ yield return 0;
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ }
+ }
+
+ class WarnInLocalFunction
+ {
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static void TestCall ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => RequiresUnreferencedCodeMethod ();
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static void TestCallWithClosure (int p = 0)
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ p++;
+ RequiresUnreferencedCodeMethod ();
+ }
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static void TestReflectionAccess ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static void TestLdftn ()
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ }
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithRUCMethod.RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static void TestDynamicallyAccessedMethod ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ }
+
+ public static void Test ()
+ {
+ TestCall ();
+ TestCallWithClosure ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInLocalFunction
+ {
+ // RequiresUnreferencedCode doesn't propagate into local functions yet
+ // so its suppression effect also doesn't propagate
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestCall ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => RequiresUnreferencedCodeMethod ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestCallWithClosure (int p = 0)
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction ()
+ {
+ p++;
+ RequiresUnreferencedCodeMethod ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestReflectionAccess ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestLdftn ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction ()
+ {
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestDynamicallyAccessedMethod ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2077")]
+ void LocalFunction () => unknownType.RequiresNonPublicMethods ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2091")]
+ void LocalFunction () => MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2091")]
+ void LocalFunction () => new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestGenericLocalFunction<TUnknown> ()
+ {
+ LocalFunction<TUnknown> ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> ()
+ {
+ typeof (T).RequiresPublicMethods ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestGenericLocalFunctionInner<TUnknown> ()
+ {
+ LocalFunction<TUnknown> ();
+
+ [ExpectedWarning ("IL2087")]
+ void LocalFunction<TSecond> ()
+ {
+ typeof (TUnknown).RequiresPublicMethods ();
+ typeof (TSecond).RequiresPublicMethods ();
+ }
+ }
+
+ static void TestGenericLocalFunctionWithAnnotations<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> ()
+ {
+ LocalFunction<TPublicMethods> ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TInnerPublicMethods> ()
+ {
+ typeof (TPublicMethods).RequiresPublicMethods ();
+ typeof (TInnerPublicMethods).RequiresPublicMethods ();
+ }
+ }
+
+ static void TestGenericLocalFunctionWithAnnotationsAndClosure<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> (int p = 0)
+ {
+ LocalFunction<TPublicMethods> ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TInnerPublicMethods> ()
+ {
+ p++;
+ typeof (TPublicMethods).RequiresPublicMethods ();
+ typeof (TInnerPublicMethods).RequiresPublicMethods ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestCallRUCMethodInLtftnLocalFunction ()
+ {
+ var _ = new Action (LocalFunction);
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => RequiresUnreferencedCodeMethod ();
+ }
+
+ class DynamicallyAccessedLocalFunction
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ public static void TestCallRUCMethodInDynamicallyAccessedLocalFunction ()
+ {
+ typeof (DynamicallyAccessedLocalFunction).RequiresNonPublicMethods ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => RequiresUnreferencedCodeMethod ();
+ }
+ }
+
+ [ExpectedWarning ("IL2026")]
+ static void TestSuppressionLocalFunction ()
+ {
+ LocalFunction (); // This will produce a warning since the location function has RUC on it
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ void LocalFunction (Type unknownType = null)
+ {
+ RequiresUnreferencedCodeMethod ();
+ unknownType.RequiresNonPublicMethods ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestSuppressionOnOuterAndLocalFunction ()
+ {
+ LocalFunction ();
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ void LocalFunction (Type unknownType = null)
+ {
+ RequiresUnreferencedCodeMethod ();
+ unknownType.RequiresNonPublicMethods ();
+ }
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestCallWithClosure ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestMethodParameterWithRequirements ();
+ TestDynamicallyAccessedMethod ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ TestGenericLocalFunction<TestType> ();
+ TestGenericLocalFunctionInner<TestType> ();
+ TestGenericLocalFunctionWithAnnotations<TestType> ();
+ TestGenericLocalFunctionWithAnnotationsAndClosure<TestType> ();
+ TestCallRUCMethodInLtftnLocalFunction ();
+ DynamicallyAccessedLocalFunction.TestCallRUCMethodInDynamicallyAccessedLocalFunction ();
+ TestSuppressionLocalFunction ();
+ TestSuppressionOnOuterAndLocalFunction ();
+ }
+ }
+
+ class WarnInLambda
+ {
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static void TestCall ()
+ {
+ Action _ = () => RequiresUnreferencedCodeMethod ();
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static void TestCallWithClosure (int p = 0)
+ {
+ Action _ = () => {
+ p++;
+ RequiresUnreferencedCodeMethod ();
+ };
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static void TestReflectionAccess ()
+ {
+ Action _ = () => {
+ typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ };
+ }
+
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static void TestLdftn ()
+ {
+ Action _ = () => {
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ };
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithRUCMethod.RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static void TestDynamicallyAccessedMethod ()
+ {
+ Action _ = () => {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ };
+ }
+
+ public static void Test ()
+ {
+ TestCall ();
+ TestCallWithClosure ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInLambda
+ {
+ // RequiresUnreferencedCode doesn't propagate into lambdas
+
+ // C# currently doesn't allow attributes on lambdas
+ // - This would be useful as a workaround for the limitation as RUC could be applied to the lambda directly
+ // - Would be useful for testing - have to use the CompilerGeneratedCode = true trick instead
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestCall ()
+ {
+ Action _ = () => RequiresUnreferencedCodeMethod ();
+ }
+
+ // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet
+ [ExpectedWarning ("IL2067", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestCallWithReflectionAnalysisWarning ()
+ {
+ // This should not produce warning because the RUC
+ Action<Type> _ = (t) => t.RequiresPublicMethods ();
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestCallWithClosure (int p = 0)
+ {
+ Action _ = () => {
+ p++;
+ RequiresUnreferencedCodeMethod ();
+ };
+ }
+
+ // Analyzer doesn't recognize reflection access - so doesn't warn in this case
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestReflectionAccess ()
+ {
+ Action _ = () => {
+ typeof (RequiresUnreferencedCodeInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ };
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestLdftn ()
+ {
+ Action _ = () => {
+ var action = new Action (RequiresUnreferencedCodeMethod);
+ };
+ }
+
+ // Analyzer doesn't apply DAM - so won't see this warnings
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestDynamicallyAccessedMethod ()
+ {
+ Action _ = () => {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ };
+ }
+
+ // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet
+ [ExpectedWarning ("IL2077", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ Action _ = () => unknownType.RequiresNonPublicMethods ();
+ }
+
+ // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet
+ [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ Action _ = () => {
+ MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ };
+ }
+
+ // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet
+ [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static void TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ Action _ = () => {
+ new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ };
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestCallWithReflectionAnalysisWarning ();
+ TestCallWithClosure ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ }
+ }
+
+ class WarnInComplex
+ {
+ [ExpectedWarning ("IL2026", "--RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true)]
+ static async void TestIteratorLocalFunctionInAsync ()
+ {
+ await MethodAsync ();
+ LocalFunction ();
+ await MethodAsync ();
+
+ IEnumerable<int> LocalFunction ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ yield return 1;
+ }
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithRUCMethod.RequiresUnreferencedCodeMethod--", CompilerGeneratedCode = true, GlobalAnalysisOnly = true)]
+ static IEnumerable<int> TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ()
+ {
+ yield return 1;
+ MethodWithGenericWhichRequiresMethods<TypeWithRUCMethod> ();
+ }
+
+ public static void Test ()
+ {
+ TestIteratorLocalFunctionInAsync ();
+ TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ();
+ }
+ }
+
+ class SuppressInComplex
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestIteratorLocalFunctionInAsync ()
+ {
+ await MethodAsync ();
+ LocalFunction ();
+ await MethodAsync ();
+
+ [RequiresUnreferencedCode ("Suppress in local function")]
+ IEnumerable<int> LocalFunction ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ yield return 1;
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static async void TestIteratorLocalFunctionInAsyncWithoutInner ()
+ {
+ await MethodAsync ();
+ LocalFunction ();
+ await MethodAsync ();
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ IEnumerable<int> LocalFunction ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ yield return 1;
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ static IEnumerable<int> TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ()
+ {
+ MethodWithGenericWhichRequiresMethods<TypeWithRUCMethod> ();
+ yield return 0;
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ public static void Test ()
+ {
+ TestIteratorLocalFunctionInAsync ();
+ TestIteratorLocalFunctionInAsyncWithoutInner ();
+ TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ();
+ }
+ }
+
+ class StateMachinesOnlyReferencedViaReflection
+ {
+ [RequiresUnreferencedCode ("RUC to suppress")]
+ static IEnumerable<int> TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ }
+
+ [RequiresUnreferencedCode ("RUC to suppress")]
+ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress ()
+ {
+ await MethodAsync ();
+ RequiresUnreferencedCodeMethod ();
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ static IEnumerable<int> TestIteratorOnlyReferencedViaReflectionWhichShouldWarn ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldWarn ()
+ {
+ await MethodAsync ();
+ RequiresUnreferencedCodeMethod ();
+ }
+
+ [ExpectedWarning ("IL2026", "RUC to suppress", GlobalAnalysisOnly = true)]
+ public static void Test ()
+ {
+ // This is not a 100% reliable test, since in theory it can be marked in any order and so it could happen that the
+ // user method is marked before the nested state machine gets marked. But it's the best we can do right now.
+ // (Note that currently linker will mark the state machine first actually so the test is effective).
+ typeof (StateMachinesOnlyReferencedViaReflection).RequiresAll ();
+ }
+ }
+
+ class ComplexCases
+ {
+ public class AsyncBodyCallingRUCMethod
+ {
+ [RequiresUnreferencedCode ("")]
+ static Task<object> MethodWithRUCAsync (Type type)
+ {
+ return Task.FromResult (new object ());
+ }
+
+ [RequiresUnreferencedCode ("ParentSuppression")]
+ static async Task<object> AsyncMethodCallingRUC (Type type)
+ {
+ using (var diposable = await GetDisposableAsync ()) {
+ return await MethodWithRUCAsync (type);
+ }
+ }
+
+ [ExpectedWarning ("IL2026", "ParentSuppression")]
+ public static void Test ()
+ {
+ AsyncMethodCallingRUC (typeof (object));
+ }
+ }
+
+ public class GenericAsyncBodyCallingRUCMethod
+ {
+ [RequiresUnreferencedCode ("")]
+ static ValueTask<TValue> MethodWithRUCAsync<TValue> ()
+ {
+ return ValueTask.FromResult (default (TValue));
+ }
+
+ [RequiresUnreferencedCode ("ParentSuppression")]
+ static async Task<T> AsyncMethodCallingRUC<T> ()
+ {
+ using (var disposable = await GetDisposableAsync ()) {
+ return await MethodWithRUCAsync<T> ();
+ }
+ }
+
+ [ExpectedWarning ("IL2026", "ParentSuppression")]
+ public static void Test ()
+ {
+ AsyncMethodCallingRUC<object> ();
+ }
+ }
+
+ public class GenericAsyncEnumerableBodyCallingRUCWithAnnotations
+ {
+ class RUCOnCtor
+ {
+ [RequiresUnreferencedCode ("")]
+ public RUCOnCtor ()
+ {
+ }
+ }
+
+ [RequiresUnreferencedCode ("ParentSuppression")]
+ static IAsyncEnumerable<TValue> AsyncEnumMethodCallingRUC<
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] TValue> ()
+ {
+ return CreateAsync ();
+
+ [RequiresUnreferencedCode ("")]
+ static async IAsyncEnumerable<TValue> CreateAsync ()
+ {
+ await MethodAsync ();
+ new RUCOnCtor ();
+ yield return default (TValue);
+ }
+ }
+
+ [ExpectedWarning ("IL2026", "ParentSuppression")]
+ public static void Test ()
+ {
+ AsyncEnumMethodCallingRUC<object> ();
+ }
+ }
+
+ class Disposable : IDisposable { public void Dispose () { } }
+
+ static Task<Disposable> GetDisposableAsync () { return Task.FromResult (new Disposable ()); }
+ }
+
+ static async Task<int> MethodAsync ()
+ {
+ return await Task.FromResult (0);
+ }
+
+ [RequiresUnreferencedCode ("--RequiresUnreferencedCodeMethod--")]
+ static void RequiresUnreferencedCodeMethod ()
+ {
+ }
+
+ class TypeWithRUCMethod
+ {
+ [RequiresUnreferencedCode ("--TypeWithRUCMethod.RequiresUnreferencedCodeMethod--")]
+ static void RequiresUnreferencedCodeMethod ()
+ {
+ }
+ }
+
+ static void MethodWithGenericWhichRequiresMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] T> ()
+ {
+ }
+
+ class TypeWithGenericWhichRequiresNonPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicFields)] T> { }
+
+ class TestType { }
+ }
+}
diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInCompilerGeneratedCode.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInCompilerGeneratedCode.cs
new file mode 100644
index 000000000..db0172178
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInCompilerGeneratedCode.cs
@@ -0,0 +1,481 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Helpers;
+
+namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression
+{
+ [SkipKeptItemsValidation]
+ [ExpectedNoWarnings]
+ public class SuppressWarningsInCompilerGeneratedCode
+ {
+ public static void Main ()
+ {
+ SuppressInIteratorBody.Test ();
+ SuppressInAsyncBody.Test ();
+ SuppressInLocalFunction.Test ();
+ SuppressInLambda.Test ();
+ SuppressInComplex.Test ();
+ }
+ class SuppressInIteratorBody
+ {
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static IEnumerable<int> TestCallRUCMethod ()
+ {
+ RequiresUnreferencedCodeMethod ();
+ yield return 0;
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static IEnumerable<int> TestReflectionAccessRUCMethod ()
+ {
+ yield return 0;
+ typeof (SuppressWarningsInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ yield return 0;
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static IEnumerable<int> TestLdftnOnRUCMethod ()
+ {
+ yield return 0;
+ var _ = new Action (RequiresUnreferencedCodeMethod);
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static IEnumerable<int> TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ yield return 0;
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2077")]
+ static IEnumerable<int> TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ unknownType.RequiresNonPublicMethods ();
+ yield return 0;
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static IEnumerable<int> TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ yield return 0;
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static IEnumerable<int> TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ yield return 0;
+ }
+
+ public static void Test ()
+ {
+ TestCallRUCMethod ();
+ TestReflectionAccessRUCMethod ();
+ TestLdftnOnRUCMethod ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ }
+ }
+
+ class SuppressInAsyncBody
+ {
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static async void TestCallRUCMethod ()
+ {
+ RequiresUnreferencedCodeMethod ();
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static async void TestReflectionAccessRUCMethod ()
+ {
+ await MethodAsync ();
+ typeof (SuppressWarningsInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static async void TestLdftnOnRUCMethod ()
+ {
+ await MethodAsync ();
+ var _ = new Action (RequiresUnreferencedCodeMethod);
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static async void TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2077")]
+ static async void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ unknownType.RequiresNonPublicMethods ();
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static async void TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static async void TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ await MethodAsync ();
+ }
+
+ public static void Test ()
+ {
+ TestCallRUCMethod ();
+ TestReflectionAccessRUCMethod ();
+ TestLdftnOnRUCMethod ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ }
+ }
+
+ class SuppressInLocalFunction
+ {
+ // Suppression currently doesn't propagate to local functions
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestCallRUCMethod ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => RequiresUnreferencedCodeMethod ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestReflectionAccessRUCMethod ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => typeof (SuppressWarningsInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestLdftnOnRUCMethod ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction ()
+ { var _ = new Action (RequiresUnreferencedCodeMethod); }
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestDynamicallyAccessedMethod ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2077")]
+ static void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2077")]
+ void LocalFunction () => unknownType.RequiresNonPublicMethods ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static void TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2091")]
+ void LocalFunction () => MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static void TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2091")]
+ void LocalFunction () => new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static void TestGenericLocalFunction<TUnknown> ()
+ {
+ LocalFunction<TUnknown> ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> ()
+ {
+ typeof (T).RequiresPublicMethods ();
+ }
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2087")]
+ static void TestGenericLocalFunctionInner<TUnknown> ()
+ {
+ LocalFunction<TUnknown> ();
+
+ [ExpectedWarning ("IL2087")]
+ void LocalFunction<TSecond> ()
+ {
+ typeof (TUnknown).RequiresPublicMethods ();
+ typeof (TSecond).RequiresPublicMethods ();
+ }
+ }
+
+ static void TestGenericLocalFunctionWithAnnotations<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> ()
+ {
+ LocalFunction<TPublicMethods> ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TInnerPublicMethods> ()
+ {
+ typeof (TPublicMethods).RequiresPublicMethods ();
+ typeof (TInnerPublicMethods).RequiresPublicMethods ();
+ }
+ }
+
+ static void TestGenericLocalFunctionWithAnnotationsAndClosure<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> (int p = 0)
+ {
+ LocalFunction<TPublicMethods> ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TInnerPublicMethods> ()
+ {
+ p++;
+ typeof (TPublicMethods).RequiresPublicMethods ();
+ typeof (TInnerPublicMethods).RequiresPublicMethods ();
+ }
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestCallRUCMethodInLtftnLocalFunction ()
+ {
+ var _ = new Action (LocalFunction);
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => RequiresUnreferencedCodeMethod ();
+ }
+
+ class DynamicallyAccessedLocalFunction
+ {
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ public static void TestCallRUCMethodInDynamicallyAccessedLocalFunction ()
+ {
+ typeof (DynamicallyAccessedLocalFunction).RequiresNonPublicMethods ();
+
+ [ExpectedWarning ("IL2026")]
+ void LocalFunction () => RequiresUnreferencedCodeMethod ();
+ }
+ }
+
+ static void TestSuppressionOnLocalFunction ()
+ {
+ LocalFunction ();
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")] // This supresses the RequiresUnreferencedCodeMethod
+ void LocalFunction (Type unknownType = null)
+ {
+ RequiresUnreferencedCodeMethod ();
+ }
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2067")] // This suppresses the unknownType.RequiresNonPublicMethods
+ static void TestSuppressionOnOuterAndLocalFunction ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2067")]
+ [UnconditionalSuppressMessage ("Test", "IL2026")] // This supresses the RequiresUnreferencedCodeMethod
+ void LocalFunction (Type unknownType = null)
+ {
+ RequiresUnreferencedCodeMethod ();
+ unknownType.RequiresNonPublicMethods ();
+ }
+ }
+
+ public static void Test ()
+ {
+ TestCallRUCMethod ();
+ TestReflectionAccessRUCMethod ();
+ TestLdftnOnRUCMethod ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ TestGenericLocalFunction<TestType> ();
+ TestGenericLocalFunctionInner<TestType> ();
+ TestCallRUCMethodInLtftnLocalFunction ();
+ DynamicallyAccessedLocalFunction.TestCallRUCMethodInDynamicallyAccessedLocalFunction ();
+ TestSuppressionOnLocalFunction ();
+ TestSuppressionOnOuterAndLocalFunction ();
+ }
+ }
+
+ class SuppressInLambda
+ {
+ // Suppression currently doesn't propagate to local functions
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestCallRUCMethod ()
+ {
+ Action _ = () => RequiresUnreferencedCodeMethod ();
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestReflectionAccessRUCMethod ()
+ {
+ Action _ = () => typeof (SuppressWarningsInCompilerGeneratedCode)
+ .GetMethod ("RequiresUnreferencedCodeMethod", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestLdftnOnRUCMethod ()
+ {
+ Action _ = () => { var _ = new Action (RequiresUnreferencedCodeMethod); };
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static void TestDynamicallyAccessedMethod ()
+ {
+ Action _ = () => typeof (TypeWithRUCMethod).RequiresNonPublicMethods ();
+ }
+
+ [ExpectedWarning ("IL2077", CompilerGeneratedCode = true)]
+ [UnconditionalSuppressMessage ("Test", "IL2077")]
+ static void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ Action _ = () => unknownType.RequiresNonPublicMethods ();
+ }
+
+ [ExpectedWarning ("IL2091", CompilerGeneratedCode = true)]
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static void TestGenericMethodParameterRequirement<TUnknown> ()
+ {
+ Action _ = () => MethodWithGenericWhichRequiresMethods<TUnknown> ();
+ }
+
+ [ExpectedWarning ("IL2091", CompilerGeneratedCode = true)]
+ [UnconditionalSuppressMessage ("Test", "IL2091")]
+ static void TestGenericTypeParameterRequirement<TUnknown> ()
+ {
+ Action _ = () => new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> ();
+ }
+
+ public static void Test ()
+ {
+ TestCallRUCMethod ();
+ TestReflectionAccessRUCMethod ();
+ TestLdftnOnRUCMethod ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement<TestType> ();
+ TestGenericTypeParameterRequirement<TestType> ();
+ }
+ }
+
+ class SuppressInComplex
+ {
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static async void TestIteratorLocalFunctionInAsync ()
+ {
+ await MethodAsync ();
+ LocalFunction ();
+ await MethodAsync ();
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ IEnumerable<int> LocalFunction ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ yield return 1;
+ }
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static async void TestIteratorLocalFunctionInAsyncWithoutInner ()
+ {
+ await MethodAsync ();
+ LocalFunction ();
+ await MethodAsync ();
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ IEnumerable<int> LocalFunction ()
+ {
+ yield return 0;
+ RequiresUnreferencedCodeMethod ();
+ yield return 1;
+ }
+ }
+
+ [UnconditionalSuppressMessage ("Test", "IL2026")]
+ static IEnumerable<int> TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ()
+ {
+ MethodWithGenericWhichRequiresMethods<TypeWithRUCMethod> ();
+ yield return 0;
+ }
+
+ public static void Test ()
+ {
+ TestIteratorLocalFunctionInAsync ();
+ TestIteratorLocalFunctionInAsyncWithoutInner ();
+ TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ();
+ }
+ }
+
+ static async Task<int> MethodAsync ()
+ {
+ return await Task.FromResult (0);
+ }
+
+ [RequiresUnreferencedCode ("--RequiresUnreferencedCodeMethod--")]
+ static void RequiresUnreferencedCodeMethod ()
+ {
+ }
+
+ class TypeWithRUCMethod
+ {
+ [RequiresUnreferencedCode ("--TypeWithRUCMethod.RequiresUnreferencedCodeMethod--")]
+ static void RequiresUnreferencedCodeMethod ()
+ {
+ }
+ }
+
+ static void MethodWithGenericWhichRequiresMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] T> ()
+ {
+ }
+
+ class TypeWithGenericWhichRequiresNonPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicFields)] T> { }
+
+ class TestType { }
+ }
+}
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs
index b4508e15e..18a32880d 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs
@@ -707,6 +707,7 @@ namespace Mono.Linker.Tests.TestCasesRunner
string fileName = (string) attr.GetPropertyValue ("FileName");
int? sourceLine = (int?) attr.GetPropertyValue ("SourceLine");
int? sourceColumn = (int?) attr.GetPropertyValue ("SourceColumn");
+ bool? isCompilerGeneratedCode = (bool?) attr.GetPropertyValue ("CompilerGeneratedCode");
int expectedWarningCodeNumber = int.Parse (expectedWarningCode.Substring (2));
var actualMethod = attrProvider as MethodDefinition;
@@ -751,6 +752,16 @@ namespace Mono.Linker.Tests.TestCasesRunner
if (!actualOrigin.ToString ().EndsWith (expectedOrigin, StringComparison.OrdinalIgnoreCase))
return false;
}
+ } else if (isCompilerGeneratedCode == true) {
+ MethodDefinition methodDefinition = mc.Origin?.MemberDefinition as MethodDefinition;
+ if (methodDefinition != null) {
+ string actualName = methodDefinition.DeclaringType.FullName + "." + methodDefinition.Name;
+ if (actualName.StartsWith (attrProvider.DeclaringType.FullName) &&
+ actualName.Contains ("<" + attrProvider.Name + ">"))
+ return true;
+ }
+
+ return false;
} else {
if (mc.Origin?.MemberDefinition?.FullName == attrProvider.FullName)
return true;