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:
authorJackson Schuster <36744439+jtschuster@users.noreply.github.com>2022-10-27 20:50:07 +0300
committerGitHub <noreply@github.com>2022-10-27 20:50:07 +0300
commitca3999834a61bf71bb4b1c70875482492d14018e (patch)
treedf471876947945de129e170e1102e81b28aae628
parent4db6ac94ffa8bf6dae8ad9c5c68f94b58de917fd (diff)
Create `ParameterProxy` to wrap logic surrounding parameters and use one `ParameterIndex` struct to index (#3059)
This reverts commit 45e2e5944abc04763263cc1c4b3f9ed86659ae43. This commit creates a 'ParameterProxy' type and 'ParameterIndex' to represent parameters in a consistent way. This is motivated by using 'int' to represent different ways of counting parameters (sometimes offset by 1 for the 'this' parameter, sometimes not offset). ParameterIndex should now be the only type used to index into a method's parameters. ParameterIndex represents the index of the parameter as it is passed to the method in IL (i.e. 'this' is the 0 index in instance methods). ParameterProxy wraps the common convention of a MethodProxy and int to represent a parameter, and now holds a Method and a ParameterIndex to encapsulate a Parameter. No behavioral changes are expected from this change. Co-authored-by: Vitek Karas <10670590+vitek-karas@users.noreply.github.com> Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
-rw-r--r--src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs66
-rw-r--r--src/ILLink.RoslynAnalyzer/IMethodSymbolExtensions.cs72
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs4
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs53
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs27
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs21
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodThisParameterValue.cs31
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/ParameterProxy.cs57
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs5
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs2
-rw-r--r--src/ILLink.Shared/Annotations.cs20
-rw-r--r--src/ILLink.Shared/ParameterIndex.cs63
-rw-r--r--src/ILLink.Shared/SourceParameterIndex.cs19
-rw-r--r--src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs8
-rw-r--r--src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs67
-rw-r--r--src/ILLink.Shared/TrimAnalysis/Intrinsics.cs195
-rw-r--r--src/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs25
-rw-r--r--src/ILLink.Shared/TrimAnalysis/MethodThisParameterValue.cs10
-rw-r--r--src/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs2
-rw-r--r--src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs42
-rw-r--r--src/ILLink.Shared/TypeSystemProxy/ParameterCollection.cs59
-rw-r--r--src/ILLink.Shared/TypeSystemProxy/ParameterProxy.cs53
-rw-r--r--src/linker/BannedSymbols.txt2
-rw-r--r--src/linker/Linker.Dataflow/AttributeDataFlow.cs9
-rw-r--r--src/linker/Linker.Dataflow/DiagnosticUtilities.cs18
-rw-r--r--src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs2
-rw-r--r--src/linker/Linker.Dataflow/FlowAnnotations.cs117
-rw-r--r--src/linker/Linker.Dataflow/HandleCallAction.cs4
-rw-r--r--src/linker/Linker.Dataflow/MethodBodyScanner.cs100
-rw-r--r--src/linker/Linker.Dataflow/MethodParameterValue.cs27
-rw-r--r--src/linker/Linker.Dataflow/MethodProxy.cs24
-rw-r--r--src/linker/Linker.Dataflow/MethodThisParameterValue.cs40
-rw-r--r--src/linker/Linker.Dataflow/ParameterProxy.cs56
-rw-r--r--src/linker/Linker.Dataflow/ParameterReferenceValue.cs6
-rw-r--r--src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs18
-rw-r--r--src/linker/Linker.Dataflow/SingleValueExtensions.cs1
-rw-r--r--src/linker/Linker.Dataflow/ThisParameterReferenceValue.cs16
-rw-r--r--src/linker/Linker.Steps/AddBypassNGenStep.cs2
-rw-r--r--src/linker/Linker.Steps/CodeRewriterStep.cs2
-rw-r--r--src/linker/Linker.Steps/DescriptorMarker.cs10
-rw-r--r--src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs12
-rw-r--r--src/linker/Linker.Steps/LinkAttributesParser.cs17
-rw-r--r--src/linker/Linker.Steps/MarkStep.cs36
-rw-r--r--src/linker/Linker.Steps/SweepStep.cs4
-rw-r--r--src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs24
-rw-r--r--src/linker/Linker/BCL.cs2
-rw-r--r--src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs4
-rw-r--r--src/linker/Linker/DocumentationSignatureParser.cs2
-rw-r--r--src/linker/Linker/ILParameterIndex.cs22
-rw-r--r--src/linker/Linker/KnownMembers.cs5
-rw-r--r--src/linker/Linker/MethodBodyScanner.cs8
-rw-r--r--src/linker/Linker/MethodDefinitionExtensions.cs52
-rw-r--r--src/linker/Linker/MethodReferenceExtensions.cs83
-rw-r--r--src/linker/Linker/ParameterHelpers.cs54
-rw-r--r--src/linker/Linker/TypeMapInfo.cs6
-rw-r--r--src/linker/Linker/TypeReferenceExtensions.cs6
-rw-r--r--src/linker/Linker/TypeReferenceWalker.cs9
57 files changed, 986 insertions, 715 deletions
diff --git a/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
index 187ac40ea..d78468022 100644
--- a/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
+++ b/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
@@ -204,79 +204,79 @@ namespace ILLink.RoslynAnalyzer
}
}
- static void VerifyDamOnMethodsMatch (SymbolAnalysisContext context, IMethodSymbol method, IMethodSymbol overriddenMethod)
+ static void VerifyDamOnMethodsMatch (SymbolAnalysisContext context, IMethodSymbol overrideMethod, IMethodSymbol baseMethod)
{
- var methodReturnAnnotations = FlowAnnotations.GetMethodReturnValueAnnotation (method);
- var overriddenMethodReturnAnnotations = FlowAnnotations.GetMethodReturnValueAnnotation (overriddenMethod);
- if (methodReturnAnnotations != overriddenMethodReturnAnnotations) {
+ var overrideMethodReturnAnnotation = FlowAnnotations.GetMethodReturnValueAnnotation (overrideMethod);
+ var baseMethodReturnAnnotation = FlowAnnotations.GetMethodReturnValueAnnotation (baseMethod);
+ if (overrideMethodReturnAnnotation != baseMethodReturnAnnotation) {
- (IMethodSymbol attributableMethod, DynamicallyAccessedMemberTypes missingAttribute) = GetTargetAndRequirements (method,
- overriddenMethod, methodReturnAnnotations, overriddenMethodReturnAnnotations);
+ (IMethodSymbol attributableMethod, DynamicallyAccessedMemberTypes missingAttribute) = GetTargetAndRequirements (overrideMethod,
+ baseMethod, overrideMethodReturnAnnotation, baseMethodReturnAnnotation);
Location attributableSymbolLocation = attributableMethod.Locations[0];
// code fix does not support merging multiple attributes. If an attribute is present or the method is not in source, do not provide args for code fix.
(Location[]? sourceLocation, Dictionary<string, string?>? DAMArgs) = (!attributableSymbolLocation.IsInSource
- || (method.TryGetReturnAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _)
- && overriddenMethod.TryGetReturnAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _))
+ || (overrideMethod.TryGetReturnAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _)
+ && baseMethod.TryGetReturnAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _))
) ? (null, null) : CreateArguments (attributableSymbolLocation, missingAttribute);
context.ReportDiagnostic (Diagnostic.Create (
DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides),
- method.Locations[0], sourceLocation, DAMArgs?.ToImmutableDictionary (), method.GetDisplayName (), overriddenMethod.GetDisplayName ()));
+ overrideMethod.Locations[0], sourceLocation, DAMArgs?.ToImmutableDictionary (), overrideMethod.GetDisplayName (), baseMethod.GetDisplayName ()));
}
- for (int i = 0; i < method.Parameters.Length; i++) {
- var methodParameterAnnotation = FlowAnnotations.GetMethodParameterAnnotation (method.Parameters[i]);
- var overriddenParameterAnnotation = FlowAnnotations.GetMethodParameterAnnotation (overriddenMethod.Parameters[i]);
- if (methodParameterAnnotation != overriddenParameterAnnotation) {
+ foreach (var overrideParam in overrideMethod.GetMetadataParameters ()) {
+ var baseParam = baseMethod.GetParameter (overrideParam.Index);
+ var baseParameterAnnotation = FlowAnnotations.GetMethodParameterAnnotation (baseParam);
+ var overrideParameterAnnotation = FlowAnnotations.GetMethodParameterAnnotation (overrideParam);
+ if (overrideParameterAnnotation != baseParameterAnnotation) {
+ (IMethodSymbol attributableMethod, DynamicallyAccessedMemberTypes missingAttribute) = GetTargetAndRequirements (overrideMethod,
+ baseMethod, overrideParameterAnnotation, baseParameterAnnotation);
- (IMethodSymbol attributableMethod, DynamicallyAccessedMemberTypes missingAttribute) = GetTargetAndRequirements (method,
- overriddenMethod, methodParameterAnnotation, overriddenParameterAnnotation);
-
- Location attributableSymbolLocation = attributableMethod.Parameters[i].Locations[0];
+ Location attributableSymbolLocation = attributableMethod.GetParameter (overrideParam.Index).Location!;
// code fix does not support merging multiple attributes. If an attribute is present or the method is not in source, do not provide args for code fix.
(Location[]? sourceLocation, Dictionary<string, string?>? DAMArgs) = (!attributableSymbolLocation.IsInSource
- || (method.Parameters[i].TryGetAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _)
- && overriddenMethod.Parameters[i].TryGetAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _))
+ || (overrideParam.ParameterSymbol!.TryGetAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _)
+ && baseParam.ParameterSymbol!.TryGetAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _))
) ? (null, null) : CreateArguments (attributableSymbolLocation, missingAttribute);
context.ReportDiagnostic (Diagnostic.Create (
DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides),
- method.Parameters[i].Locations[0], sourceLocation, DAMArgs?.ToImmutableDictionary (),
- method.Parameters[i].GetDisplayName (), method.GetDisplayName (), overriddenMethod.Parameters[i].GetDisplayName (), overriddenMethod.GetDisplayName ()));
+ overrideParam.Location, sourceLocation, DAMArgs?.ToImmutableDictionary (),
+ overrideParam.GetDisplayName (), overrideMethod.GetDisplayName (), baseParam.GetDisplayName (), baseMethod.GetDisplayName ()));
}
}
- for (int i = 0; i < method.TypeParameters.Length; i++) {
- var methodTypeParameterAnnotation = method.TypeParameters[i].GetDynamicallyAccessedMemberTypes ();
- var overriddenMethodTypeParameterAnnotation = overriddenMethod.TypeParameters[i].GetDynamicallyAccessedMemberTypes ();
+ for (int i = 0; i < overrideMethod.TypeParameters.Length; i++) {
+ var methodTypeParameterAnnotation = overrideMethod.TypeParameters[i].GetDynamicallyAccessedMemberTypes ();
+ var overriddenMethodTypeParameterAnnotation = baseMethod.TypeParameters[i].GetDynamicallyAccessedMemberTypes ();
if (methodTypeParameterAnnotation != overriddenMethodTypeParameterAnnotation) {
- (IMethodSymbol attributableMethod, DynamicallyAccessedMemberTypes missingAttribute) = GetTargetAndRequirements (method, overriddenMethod, methodTypeParameterAnnotation, overriddenMethodTypeParameterAnnotation);
+ (IMethodSymbol attributableMethod, DynamicallyAccessedMemberTypes missingAttribute) = GetTargetAndRequirements (overrideMethod, baseMethod, methodTypeParameterAnnotation, overriddenMethodTypeParameterAnnotation);
Location attributableSymbolLocation = attributableMethod.TypeParameters[i].Locations[0];
// code fix does not support merging multiple attributes. If an attribute is present or the method is not in source, do not provide args for code fix.
(Location[]? sourceLocation, Dictionary<string, string?>? DAMArgs) = (!attributableSymbolLocation.IsInSource
- || (method.TypeParameters[i].TryGetAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _)
- && overriddenMethod.TypeParameters[i].TryGetAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _))
+ || (overrideMethod.TypeParameters[i].TryGetAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _)
+ && baseMethod.TypeParameters[i].TryGetAttribute (DynamicallyAccessedMembersAnalyzer.DynamicallyAccessedMembersAttribute, out var _))
) ? (null, null) : CreateArguments (attributableSymbolLocation, missingAttribute);
context.ReportDiagnostic (Diagnostic.Create (
DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides),
- method.TypeParameters[i].Locations[0], sourceLocation, DAMArgs?.ToImmutableDictionary (),
- method.TypeParameters[i].GetDisplayName (), method.GetDisplayName (),
- overriddenMethod.TypeParameters[i].GetDisplayName (), overriddenMethod.GetDisplayName ()));
+ overrideMethod.TypeParameters[i].Locations[0], sourceLocation, DAMArgs?.ToImmutableDictionary (),
+ overrideMethod.TypeParameters[i].GetDisplayName (), overrideMethod.GetDisplayName (),
+ baseMethod.TypeParameters[i].GetDisplayName (), baseMethod.GetDisplayName ()));
}
}
- if (!method.IsStatic && method.GetDynamicallyAccessedMemberTypes () != overriddenMethod.GetDynamicallyAccessedMemberTypes ())
+ if (!overrideMethod.IsStatic && overrideMethod.GetDynamicallyAccessedMemberTypes () != baseMethod.GetDynamicallyAccessedMemberTypes ())
context.ReportDiagnostic (Diagnostic.Create (
DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnImplicitThisBetweenOverrides),
- method.Locations[0],
- method.GetDisplayName (), overriddenMethod.GetDisplayName ()));
+ overrideMethod.Locations[0],
+ overrideMethod.GetDisplayName (), baseMethod.GetDisplayName ()));
}
static void VerifyDamOnInterfaceAndImplementationMethodsMatch (SymbolAnalysisContext context, INamedTypeSymbol type)
diff --git a/src/ILLink.RoslynAnalyzer/IMethodSymbolExtensions.cs b/src/ILLink.RoslynAnalyzer/IMethodSymbolExtensions.cs
new file mode 100644
index 000000000..cc61d3cda
--- /dev/null
+++ b/src/ILLink.RoslynAnalyzer/IMethodSymbolExtensions.cs
@@ -0,0 +1,72 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using ILLink.Shared.TypeSystemProxy;
+using Microsoft.CodeAnalysis;
+
+namespace ILLink.RoslynAnalyzer
+{
+ internal static class IMethodSymbolExtensions
+ {
+ public static bool HasImplicitThis (this IMethodSymbol method)
+ {
+ return !method.IsStatic;
+ }
+
+ /// <summary>
+ /// Returns a list of the parameters pushed onto the stack before the method call (including the implicit 'this' parameter)
+ /// </summary>
+ public static ParameterProxyEnumerable GetParameters (this IMethodSymbol method)
+ {
+ return new ParameterProxyEnumerable (0, method.GetParametersCount (), new (method));
+ }
+
+ /// <summary>
+ /// Returns a list of the parameters in the method's 'parameters' metadata section (i.e. excluding the implicit 'this' parameter)
+ /// </summary>
+ public static ParameterProxyEnumerable GetMetadataParameters (this IMethodSymbol method)
+ {
+ int implicitThisOffset = method.HasImplicitThis () ? 1 : 0;
+ return new ParameterProxyEnumerable (implicitThisOffset, method.GetParametersCount (), new (method));
+ }
+
+ /// <summary>
+ /// Gets the parameter at the <see cref="ParameterIndex"/> provided. Note ParameterIndex treat the implicit 'this' as index 0.
+ /// Throws if the index is out of bounds.
+ /// </summary>
+ public static ParameterProxy GetParameter (this IMethodSymbol method, ParameterIndex index)
+ {
+ if (method.TryGetParameter (index) is not ParameterProxy param)
+ throw new InvalidOperationException ($"Cannot get parameter at index {(int) index} of method {method.GetDisplayName ()} with {method.GetParametersCount ()} parameters.");
+ return param;
+ }
+
+ /// <summary>
+ /// Gets the parameter at the <see cref="ParameterIndex"/> provided. Note ParameterIndex treat the implicit 'this' as index 0.
+ /// Returns null if the index is out of bounds.
+ /// </summary>
+ public static ParameterProxy? TryGetParameter (this IMethodSymbol method, ParameterIndex index)
+ {
+ if (method.GetParametersCount () <= (int) index || (int) index < 0)
+ return null;
+ return new ParameterProxy (new (method), index);
+ }
+
+ /// <summary>
+ /// Gets the number of entries in the 'Parameters' section of a method's metadata (i.e. excludes the implicit 'this' from the count)
+ /// </summary>
+ public static int GetMetadataParametersCount (this IMethodSymbol method)
+ {
+ return method.Parameters.Length;
+ }
+
+ /// <summary>
+ /// Gets the number of parameters pushed onto the stack when the method is called (including the implicit 'this' paramter)
+ /// </summary>
+ public static int GetParametersCount (this IMethodSymbol method)
+ {
+ return method.Parameters.Length + (method.HasImplicitThis () ? 1 : 0);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs
index a59bd1cc0..f920a2ed6 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs
@@ -40,9 +40,9 @@ namespace ILLink.Shared.TrimAnalysis
ISymbol symbol = actualValue switch {
FieldValue field => field.FieldSymbol,
- MethodParameterValue mpv => mpv.ParameterSymbol,
+ MethodParameterValue maybeThisParameter when maybeThisParameter.Parameter.IsImplicitThis => maybeThisParameter.MethodSymbol,
+ MethodParameterValue methodParameter => methodParameter.Parameter.ParameterSymbol!,
MethodReturnValue mrv => mrv.MethodSymbol,
- MethodThisParameterValue mtpv => mtpv.MethodSymbol,
GenericParameterValue gpv => gpv.GenericParameter.TypeParameterSymbol,
_ => throw new InvalidOperationException ()
};
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs
index 207d42447..09d64065d 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs
@@ -8,6 +8,7 @@ using ILLink.RoslynAnalyzer;
using ILLink.Shared.TypeSystemProxy;
using Microsoft.CodeAnalysis;
+#nullable enable
namespace ILLink.Shared.TrimAnalysis
{
sealed partial class FlowAnnotations
@@ -23,22 +24,24 @@ namespace ILLink.Shared.TrimAnalysis
public static bool RequiresDataFlowAnalysis (IMethodSymbol method)
{
- if (method.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None)
- return true;
-
if (GetMethodReturnValueAnnotation (method) != DynamicallyAccessedMemberTypes.None)
return true;
- foreach (var parameter in method.Parameters) {
- if (GetMethodParameterAnnotation (parameter) != DynamicallyAccessedMemberTypes.None)
+ foreach (var param in method.GetParameters ()) {
+ if (GetMethodParameterAnnotation (param) != DynamicallyAccessedMemberTypes.None)
return true;
}
return false;
}
- public static DynamicallyAccessedMemberTypes GetMethodParameterAnnotation (IParameterSymbol parameter)
+ public static DynamicallyAccessedMemberTypes GetMethodParameterAnnotation (ParameterProxy param)
{
+ IMethodSymbol method = param.Method.Method;
+ if (param.IsImplicitThis)
+ return method.GetDynamicallyAccessedMemberTypes ();
+
+ IParameterSymbol parameter = param.ParameterSymbol!;
var damt = parameter.GetDynamicallyAccessedMemberTypes ();
var parameterMethod = (IMethodSymbol) parameter.ContainingSymbol;
@@ -92,20 +95,38 @@ namespace ILLink.Shared.TrimAnalysis
internal partial GenericParameterValue GetGenericParameterValue (GenericParameterProxy genericParameter)
=> new GenericParameterValue (genericParameter.TypeParameterSymbol);
- internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- => new MethodThisParameterValue (method.Method, dynamicallyAccessedMemberTypes);
-
- internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method)
- => GetMethodThisParameterValue (method, method.Method.GetDynamicallyAccessedMemberTypes ());
+ internal partial MethodParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
+ if (!method.HasImplicitThis ())
+ throw new InvalidOperationException ($"Cannot get 'this' parameter of method {method.GetDisplayName ()} with no 'this' parameter.");
+ return GetMethodParameterValue (new ParameterProxy (method, (ParameterIndex) 0), dynamicallyAccessedMemberTypes);
+ }
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- => new MethodParameterValue (method.Method.Parameters[(int) parameterIndex], dynamicallyAccessedMemberTypes);
+ // overrideIsThis is needed for backwards compatibility with MakeGenericType/Method https://github.com/dotnet/linker/issues/2428
+ internal MethodParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, bool overrideIsThis = false)
+ {
+ if (!method.HasImplicitThis () && !overrideIsThis)
+ throw new InvalidOperationException ($"Cannot get 'this' parameter of method {method.GetDisplayName ()} with no 'this' parameter.");
+ return new MethodParameterValue (new ParameterProxy (method, (ParameterIndex) 0), dynamicallyAccessedMemberTypes, overrideIsThis);
+ }
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex)
+ internal partial MethodParameterValue GetMethodThisParameterValue (MethodProxy method)
{
- var annotation = GetMethodParameterAnnotation (method.Method.Parameters[(int) parameterIndex]);
- return GetMethodParameterValue (method, parameterIndex, annotation);
+ if (!method.HasImplicitThis ())
+ throw new InvalidOperationException ($"Cannot get 'this' parameter of method {method.GetDisplayName ()} with no 'this' parameter.");
+ ParameterProxy param = new (method, (ParameterIndex) 0);
+ var damt = GetMethodParameterAnnotation (param);
+ return GetMethodParameterValue (new ParameterProxy (method, (ParameterIndex) 0), damt);
}
+
+ internal MethodParameterValue GetMethodParameterValue (MethodProxy method, ParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new MethodParameterValue (new (method, parameterIndex), dynamicallyAccessedMemberTypes);
+
+ internal partial MethodParameterValue GetMethodParameterValue (ParameterProxy param)
+ => new MethodParameterValue (param, GetMethodParameterAnnotation (param));
+
+ internal partial MethodParameterValue GetMethodParameterValue (ParameterProxy param, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new MethodParameterValue (param, dynamicallyAccessedMemberTypes);
#pragma warning restore CA1822
}
}
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs
index 8a41cd171..36915b04b 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs
@@ -1,10 +1,8 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using ILLink.RoslynAnalyzer;
-using ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
using Microsoft.CodeAnalysis;
namespace ILLink.Shared.TrimAnalysis
@@ -12,21 +10,22 @@ namespace ILLink.Shared.TrimAnalysis
partial record MethodParameterValue
{
public MethodParameterValue (IParameterSymbol parameterSymbol)
- : this (parameterSymbol, FlowAnnotations.GetMethodParameterAnnotation (parameterSymbol)) { }
+ : this (new ParameterProxy (parameterSymbol)) { }
+ public MethodParameterValue (IMethodSymbol methodSymbol, ParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ : this (new (new (methodSymbol), parameterIndex), dynamicallyAccessedMemberTypes) { }
- public MethodParameterValue (IParameterSymbol parameterSymbol, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- => (ParameterSymbol, DynamicallyAccessedMemberTypes) = (parameterSymbol, dynamicallyAccessedMemberTypes);
+ public MethodParameterValue (ParameterProxy parameter)
+ : this (parameter, FlowAnnotations.GetMethodParameterAnnotation (parameter)) { }
- public readonly IParameterSymbol ParameterSymbol;
+ public MethodParameterValue (ParameterProxy parameter, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, bool overrideIsThis = false)
+ {
+ Parameter = parameter;
+ DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ _overrideIsThis = overrideIsThis;
+ }
public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
- public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
- => new string[] { ParameterSymbol.GetDisplayName (), ParameterSymbol.ContainingSymbol.GetDisplayName () };
-
- public override SingleValue DeepCopy () => this; // This value is immutable
-
- public override string ToString ()
- => this.ValueToString (ParameterSymbol, DynamicallyAccessedMemberTypes);
+ public IMethodSymbol MethodSymbol => Parameter.Method.Method;
}
}
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs
index d42daee81..0c059e997 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs
@@ -19,14 +19,15 @@ namespace ILLink.Shared.TypeSystemProxy
internal partial bool IsDeclaredOnType (string fullTypeName) => IsTypeOf (Method.ContainingType, fullTypeName);
- internal partial bool HasParameters () => Method.Parameters.Length > 0;
+ internal partial bool HasMetadataParameters () => Method.Parameters.Length > 0;
- internal partial int GetParametersCount () => Method.Parameters.Length;
+ internal partial int GetMetadataParametersCount () => Method.GetMetadataParametersCount ();
- internal partial bool HasParameterOfType (int parameterIndex, string fullTypeName)
- => Method.Parameters.Length > parameterIndex && IsTypeOf (Method.Parameters[parameterIndex].Type, fullTypeName);
+ internal partial int GetParametersCount () => Method.GetParametersCount ();
- internal partial string GetParameterDisplayName (int parameterIndex) => Method.Parameters[parameterIndex].GetDisplayName ();
+ internal partial ParameterProxyEnumerable GetParameters () => Method.GetParameters ();
+
+ internal partial ParameterProxy GetParameter (ParameterIndex index) => Method.GetParameter (index);
internal partial bool HasGenericParameters () => Method.IsGenericMethod;
@@ -47,6 +48,8 @@ namespace ILLink.Shared.TypeSystemProxy
internal partial bool IsStatic () => Method.IsStatic;
+ internal partial bool HasImplicitThis () => Method.HasImplicitThis ();
+
internal partial bool ReturnsVoid () => Method.ReturnType.SpecialType == SpecialType.System_Void;
static bool IsTypeOf (ITypeSymbol type, string fullTypeName)
@@ -57,14 +60,6 @@ namespace ILLink.Shared.TypeSystemProxy
return namedType.HasName (fullTypeName);
}
- public ReferenceKind ParameterReferenceKind (int index)
- => Method.Parameters[index].RefKind switch {
- RefKind.In => ReferenceKind.In,
- RefKind.Out => ReferenceKind.Out,
- RefKind.Ref => ReferenceKind.Ref,
- _ => ReferenceKind.None
- };
-
public override string ToString () => Method.ToString ();
}
}
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodThisParameterValue.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodThisParameterValue.cs
deleted file mode 100644
index b97dfcc9b..000000000
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodThisParameterValue.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using ILLink.RoslynAnalyzer;
-using ILLink.Shared.DataFlow;
-using Microsoft.CodeAnalysis;
-
-namespace ILLink.Shared.TrimAnalysis
-{
- partial record MethodThisParameterValue
- {
- public MethodThisParameterValue (IMethodSymbol methodSymbol)
- : this (methodSymbol, methodSymbol.GetDynamicallyAccessedMemberTypes ()) { }
-
- public MethodThisParameterValue (IMethodSymbol methodSymbol, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- => (MethodSymbol, DynamicallyAccessedMemberTypes) = (methodSymbol, dynamicallyAccessedMemberTypes);
-
- public readonly IMethodSymbol MethodSymbol;
-
- public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
-
- public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
- => new string[] { MethodSymbol.GetDisplayName () };
-
- public override SingleValue DeepCopy () => this; // This value is immutable
-
- public override string ToString () => this.ValueToString (MethodSymbol, DynamicallyAccessedMemberTypes);
- }
-}
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/ParameterProxy.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/ParameterProxy.cs
new file mode 100644
index 000000000..6ee65cbb9
--- /dev/null
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/ParameterProxy.cs
@@ -0,0 +1,57 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using ILLink.RoslynAnalyzer;
+using Microsoft.CodeAnalysis;
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ partial struct ParameterProxy
+ {
+ public ParameterProxy (IParameterSymbol parameter)
+ {
+ Method = (new ((IMethodSymbol) parameter.ContainingSymbol));
+ Index = (ParameterIndex) parameter.Ordinal + (Method.HasImplicitThis () ? 1 : 0);
+ }
+
+ public partial ReferenceKind GetReferenceKind () =>
+ IsImplicitThis
+ ? ((ITypeSymbol) Method.Method.ContainingSymbol).IsValueType
+ ? ReferenceKind.Ref
+ : ReferenceKind.None
+ : Method.Method.Parameters[MetadataIndex].RefKind switch {
+ RefKind.Ref => ReferenceKind.Ref,
+ RefKind.In => ReferenceKind.In,
+ RefKind.Out => ReferenceKind.Out,
+ RefKind.None => ReferenceKind.None,
+ _ => throw new NotImplementedException ($"Unexpected RefKind found on parameter {GetDisplayName ()}")
+ };
+
+ /// <summary>
+ /// Returns the IParameterSymbol representing the parameter. Returns null for the implicit this paramter.
+ /// </summary>
+ public IParameterSymbol? ParameterSymbol => IsImplicitThis ? null : Method.Method.Parameters[MetadataIndex];
+
+ /// <summary>
+ /// Returns the IParameterSymbol.Location[0] for the parameter. Returns null for the implicit this paramter.
+ /// </summary>
+ public Location? Location => ParameterSymbol?.Locations[0];
+
+ public TypeProxy ParameterType
+ => IsImplicitThis
+ ? new TypeProxy (Method.Method.ContainingType)
+ : new TypeProxy (Method.Method.Parameters[MetadataIndex].Type);
+
+ public partial string GetDisplayName ()
+ {
+ if (IsImplicitThis)
+ return "this";
+ return ParameterSymbol!.GetDisplayName ();
+ }
+
+ public partial bool IsTypeOf (string typeName) => ParameterType.IsTypeOf (typeName.Substring (0, typeName.LastIndexOf ('.')), typeName.Substring (1 + typeName.LastIndexOf ('.')));
+
+ public bool IsTypeOf (WellKnownType type) => ParameterType.IsTypeOf (type);
+ }
+} \ No newline at end of file
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs
index 104a763fa..ec5f170c8 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs
@@ -82,13 +82,10 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
{
if (methodSymbol.TryGetRequiresUnreferencedCodeAttribute (out var requiresUnreferencedCodeAttributeData))
ReportRequiresUnreferencedCodeDiagnostic (diagnosticContext, requiresUnreferencedCodeAttributeData, methodSymbol);
-
- if (!methodSymbol.IsStatic && methodSymbol.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None)
- diagnosticContext.AddDiagnostic (DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection, methodSymbol.GetDisplayName ());
else if (methodSymbol.IsVirtual && FlowAnnotations.GetMethodReturnValueAnnotation (methodSymbol) != DynamicallyAccessedMemberTypes.None)
diagnosticContext.AddDiagnostic (DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection, methodSymbol.GetDisplayName ());
else {
- foreach (var parameter in methodSymbol.Parameters) {
+ foreach (var parameter in methodSymbol.GetParameters ()) {
if (FlowAnnotations.GetMethodParameterAnnotation (parameter) != DynamicallyAccessedMemberTypes.None) {
diagnosticContext.AddDiagnostic (DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection, methodSymbol.GetDisplayName ());
break;
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs
index f29eb96a8..1877947f4 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs
@@ -113,7 +113,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
// The instance reference operation represents a 'this' or 'base' reference to the containing type,
// so we get the annotation from the containing method.
if (instanceRef.Type != null && instanceRef.Type.IsTypeInterestingForDataflow ())
- return new MethodThisParameterValue (Method);
+ return new MethodParameterValue (Method, (ParameterIndex) 0, Method.GetDynamicallyAccessedMemberTypes ());
return TopValue;
}
diff --git a/src/ILLink.Shared/Annotations.cs b/src/ILLink.Shared/Annotations.cs
index ca09218c0..cd3098d1e 100644
--- a/src/ILLink.Shared/Annotations.cs
+++ b/src/ILLink.Shared/Annotations.cs
@@ -94,35 +94,35 @@ namespace ILLink.Shared
public static (DiagnosticId Id, string[] Arguments) GetDiagnosticForAnnotationMismatch (ValueWithDynamicallyAccessedMembers source, ValueWithDynamicallyAccessedMembers target, string missingAnnotations)
{
DiagnosticId diagnosticId = (source, target) switch {
+ (MethodParameterValue maybeThisSource, MethodParameterValue maybeThisTarget) when maybeThisSource.IsThisParameter () && maybeThisTarget.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter,
+ (MethodParameterValue maybeThis, MethodParameterValue) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsParameter,
+ (MethodParameterValue maybeThis, MethodReturnValue) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType,
+ (MethodParameterValue maybeThis, FieldValue) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsField,
+ (MethodParameterValue maybeThis, GenericParameterValue) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsGenericParameter,
+ (MethodParameterValue, MethodParameterValue maybeThis) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter,
(MethodParameterValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsParameter,
(MethodParameterValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType,
(MethodParameterValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsField,
- (MethodParameterValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter,
(MethodParameterValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsGenericParameter,
+ (MethodReturnValue, MethodParameterValue maybeThis) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter,
(MethodReturnValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter,
(MethodReturnValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsMethodReturnType,
(MethodReturnValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsField,
- (MethodReturnValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter,
(MethodReturnValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsGenericParameter,
+ (FieldValue, MethodParameterValue maybeThis) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter,
(FieldValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsParameter,
(FieldValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsMethodReturnType,
(FieldValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsField,
- (FieldValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter,
(FieldValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsGenericParameter,
- (MethodThisParameterValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsParameter,
- (MethodThisParameterValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType,
- (MethodThisParameterValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsField,
- (MethodThisParameterValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter,
- (MethodThisParameterValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsGenericParameter,
+ (GenericParameterValue, MethodParameterValue maybeThis) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter,
(GenericParameterValue, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter,
(GenericParameterValue, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType,
(GenericParameterValue, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsField,
- (GenericParameterValue, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter,
(GenericParameterValue, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter,
+ (NullableValueWithDynamicallyAccessedMembers, MethodParameterValue maybeThis) when maybeThis.IsThisParameter () => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter,
(NullableValueWithDynamicallyAccessedMembers, MethodParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter,
(NullableValueWithDynamicallyAccessedMembers, MethodReturnValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType,
(NullableValueWithDynamicallyAccessedMembers, FieldValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsField,
- (NullableValueWithDynamicallyAccessedMembers, MethodThisParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter,
(NullableValueWithDynamicallyAccessedMembers, GenericParameterValue) => DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter,
_ => throw new NotImplementedException ($"Unsupported source context {source} or target context {target}.")
diff --git a/src/ILLink.Shared/ParameterIndex.cs b/src/ILLink.Shared/ParameterIndex.cs
new file mode 100644
index 000000000..84113a820
--- /dev/null
+++ b/src/ILLink.Shared/ParameterIndex.cs
@@ -0,0 +1,63 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Diagnostics.CodeAnalysis;
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ /// <summary>
+ /// Used to indicate the index of the parameter in the Parameters metadata section (i.e. the first parameter that is not the implicit 'this' is 0)
+ /// It is very error prone to use an int to represent the index in parameters metadata section / source code parameter index as well as for indexing into argument lists.
+ /// Instead, use this struct whenever representing an index of a parameter.
+ /// </summary>
+ /// <example>
+ /// In a call to a non-static function Foo(int a, int b, int c)
+ /// 0 refers to 'this'
+ /// 1 refers to a,
+ /// 2 refers to b,
+ /// 3 refers to c.
+ /// In a call to a static extension function Foo(this Bar a, int b, int c)
+ /// 0 refers to "this Bar a"
+ /// 1 refers to b,
+ /// 2 refers to c.
+ /// In a call to a static function Foo(int a, int b, int c)
+ /// 0 refers to a,
+ /// 1 refers to b,
+ /// 2 refers to c.
+ /// </example>
+ public struct ParameterIndex
+ {
+ public readonly int Index;
+
+ public ParameterIndex (int x)
+ => Index = x;
+
+ public static bool operator == (ParameterIndex left, ParameterIndex right) => left.Index == right.Index;
+
+ public static bool operator != (ParameterIndex left, ParameterIndex right) => left.Index != right.Index;
+
+ public static ParameterIndex operator ++ (ParameterIndex val) => new ParameterIndex (val.Index + 1);
+
+ public override bool Equals ([NotNullWhen (true)] object? obj)
+ => obj is ParameterIndex other && this == other;
+
+ public override int GetHashCode () => Index.GetHashCode ();
+
+ public static explicit operator ParameterIndex (int x)
+ => new ParameterIndex (x);
+
+ public static explicit operator int (ParameterIndex x)
+ => x.Index;
+ public static ParameterIndex operator + (ParameterIndex left, ParameterIndex right)
+ => new ParameterIndex (left.Index + right.Index);
+
+ public static ParameterIndex operator - (ParameterIndex left, ParameterIndex right)
+ => new ParameterIndex (left.Index - right.Index);
+
+ public static ParameterIndex operator + (ParameterIndex left, int right)
+ => new ParameterIndex (left.Index + right);
+
+ public static ParameterIndex operator - (ParameterIndex left, int right)
+ => new ParameterIndex (left.Index - right);
+ }
+}
diff --git a/src/ILLink.Shared/SourceParameterIndex.cs b/src/ILLink.Shared/SourceParameterIndex.cs
deleted file mode 100644
index ecca20ac6..000000000
--- a/src/ILLink.Shared/SourceParameterIndex.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace ILLink.Shared
-{
- /// <summary>
- /// Used to indicate the index of the parameter in source code (i.e. the index is not offset by 1 if there is a `this` parameter)
- /// This enum and <see cref="T:Mono.Linker.ILParameterIndex"/> is used to enforce a differentiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system.
- /// There is no way to represent a `this` parameter with a SourceParameterIndex
- /// </summary>
- /// <example>
- /// In a call to a non-static function Foo(int a, int b, int c)
- /// 0 refers to a,
- /// 1 refers to b,
- /// 2 refers to c.
- /// </example>
- public enum SourceParameterIndex
- { }
-}
diff --git a/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs b/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs
index 40688f448..2a9f4d008 100644
--- a/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs
+++ b/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs
@@ -20,12 +20,12 @@ namespace ILLink.Shared.TrimAnalysis
internal partial GenericParameterValue GetGenericParameterValue (GenericParameterProxy genericParameter);
- internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+ internal partial MethodParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
- internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method);
+ internal partial MethodParameterValue GetMethodThisParameterValue (MethodProxy method);
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+ internal partial MethodParameterValue GetMethodParameterValue (ParameterProxy param, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex);
+ internal partial MethodParameterValue GetMethodParameterValue (ParameterProxy param);
}
} \ No newline at end of file
diff --git a/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs b/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
index 0fcf700bd..9f0ddbf45 100644
--- a/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
+++ b/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
@@ -316,7 +316,7 @@ namespace ILLink.Shared.TrimAnalysis
}
BindingFlags? bindingFlags;
- if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ if (calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
else
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
@@ -371,12 +371,12 @@ namespace ILLink.Shared.TrimAnalysis
}
BindingFlags? bindingFlags;
- if (calledMethod.HasParametersCount (1)) {
+ if (calledMethod.HasMetadataParametersCount (1)) {
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
bindingFlags = BindingFlags.Public | BindingFlags.Instance;
- } else if (calledMethod.HasParametersCount (2) && calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ } else if (calledMethod.HasMetadataParametersCount (2) && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
- else if (calledMethod.HasParametersCount (3) && calledMethod.HasParameterOfType (2, "System.Reflection.BindingFlags")) {
+ else if (calledMethod.HasMetadataParametersCount (3) && calledMethod.HasParameterOfType ((ParameterIndex) 3, "System.Reflection.BindingFlags")) {
bindingFlags = GetBindingFlagsFromValue (argumentValues[2]);
} else // Non recognized intrinsic
throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is an unexpected intrinsic.");
@@ -423,9 +423,9 @@ namespace ILLink.Shared.TrimAnalysis
}
BindingFlags? bindingFlags;
- if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ if (calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
- else if (calledMethod.HasParameterOfType (2, "System.Reflection.BindingFlags"))
+ else if (calledMethod.HasParameterOfType ((ParameterIndex) 3, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[2]);
else
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
@@ -471,7 +471,7 @@ namespace ILLink.Shared.TrimAnalysis
}
BindingFlags? bindingFlags;
- if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ if (calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
else
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
@@ -544,7 +544,7 @@ namespace ILLink.Shared.TrimAnalysis
_ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
};
- var targetValue = _annotations.GetMethodParameterValue (calledMethod, 0, requiredMemberTypes);
+ var targetValue = _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 1), requiredMemberTypes);
foreach (var value in argumentValues[0]) {
if (value is SystemTypeValue systemTypeValue) {
@@ -593,7 +593,7 @@ namespace ILLink.Shared.TrimAnalysis
// static New (Type)
//
case IntrinsicId.Expression_New: {
- var targetValue = _annotations.GetMethodParameterValue (calledMethod, 0, DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
+ var targetValue = _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 0), DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
foreach (var value in argumentValues[0]) {
if (value is SystemTypeValue systemTypeValue) {
MarkConstructorsOnType (systemTypeValue.RepresentedType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, parameterCount: null);
@@ -609,7 +609,7 @@ namespace ILLink.Shared.TrimAnalysis
//
// static Property (Expression, MethodInfo)
//
- case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo"): {
+ case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.MethodInfo"): {
if (argumentValues[1].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
@@ -629,7 +629,7 @@ namespace ILLink.Shared.TrimAnalysis
// In all other cases we may not even know which type this is about, so there's nothing we can do
// report it as a warning.
_diagnosticContext.AddDiagnostic (DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined,
- _annotations.GetMethodParameterValue (calledMethod, (SourceParameterIndex) 1, DynamicallyAccessedMemberTypes.None).GetDiagnosticArgumentsForAnnotationMismatch ().ToArray ());
+ _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 1), DynamicallyAccessedMemberTypes.None).GetDiagnosticArgumentsForAnnotationMismatch ().ToArray ());
}
}
break;
@@ -651,7 +651,7 @@ namespace ILLink.Shared.TrimAnalysis
break;
}
- var targetValue = _annotations.GetMethodParameterValue (calledMethod, (SourceParameterIndex) 1, memberTypes);
+ var targetValue = _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 1), memberTypes);
foreach (var value in argumentValues[1]) {
if (value is SystemTypeValue systemTypeValue) {
foreach (var stringParam in argumentValues[2]) {
@@ -684,8 +684,7 @@ namespace ILLink.Shared.TrimAnalysis
BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
var targetValue = _annotations.GetMethodParameterValue (
- calledMethod,
- 0,
+ new ParameterProxy (calledMethod, (ParameterIndex) 0),
GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags));
// This is true even if we "don't know" - so it's only false if we're sure that there are no type arguments
@@ -763,8 +762,8 @@ namespace ILLink.Shared.TrimAnalysis
break;
}
- if ((calledMethod.HasParametersCount (3) && calledMethod.HasParameterOfType (2, "System.Boolean") && argumentValues[2].AsConstInt () != 0) ||
- (calledMethod.HasParametersCount (5) && argumentValues[4].AsConstInt () != 0)) {
+ if ((calledMethod.HasMetadataParametersCount (3) && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Boolean") && argumentValues[2].AsConstInt () != 0) ||
+ (calledMethod.HasMetadataParametersCount (5) && argumentValues[4].AsConstInt () != 0)) {
_diagnosticContext.AddDiagnostic (DiagnosticId.CaseInsensitiveTypeGetTypeCallIsNotSupported, calledMethod.GetDisplayName ());
returnValue = MultiValueLattice.Top; // This effectively disables analysis of anything which uses the return value
break;
@@ -939,13 +938,13 @@ namespace ILLink.Shared.TrimAnalysis
}
BindingFlags? bindingFlags;
- if (calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags"))
+ if (calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[0]);
else
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
bindingFlags = BindingFlags.Public | BindingFlags.Instance;
- int? ctorParameterCount = calledMethod.GetParametersCount () switch {
+ int? ctorParameterCount = calledMethod.GetMetadataParametersCount () switch {
1 => (argumentValues[0].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
2 => (argumentValues[1].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
4 => (argumentValues[2].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
@@ -1017,8 +1016,8 @@ namespace ILLink.Shared.TrimAnalysis
case IntrinsicId.Activator_CreateInstance__Type: {
int? ctorParameterCount = null;
BindingFlags bindingFlags = BindingFlags.Instance;
- if (calledMethod.GetParametersCount () > 1) {
- if (calledMethod.HasParameterOfType (1, "System.Boolean")) {
+ if (calledMethod.GetMetadataParametersCount () > 1) {
+ if (calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Boolean")) {
// The overload that takes a "nonPublic" bool
bool nonPublic = argumentValues[1].AsConstInt () != 0;
@@ -1029,7 +1028,7 @@ namespace ILLink.Shared.TrimAnalysis
ctorParameterCount = 0;
} else {
// Overload that has the parameters as the second or fourth argument
- int argsParam = calledMethod.HasParametersCount (2) || calledMethod.HasParametersCount (3) ? 1 : 3;
+ int argsParam = calledMethod.HasMetadataParametersCount (2) || calledMethod.HasMetadataParametersCount (3) ? 1 : 3;
if (argumentValues.Count > argsParam) {
if (argumentValues[argsParam].AsSingleValue () is ArrayValue arrayValue &&
@@ -1039,7 +1038,7 @@ namespace ILLink.Shared.TrimAnalysis
ctorParameterCount = 0;
}
- if (calledMethod.GetParametersCount () > 3) {
+ if (calledMethod.GetMetadataParametersCount () > 3) {
if (argumentValues[1].AsConstInt () is int constInt)
bindingFlags |= (BindingFlags) constInt;
else
@@ -1069,7 +1068,7 @@ namespace ILLink.Shared.TrimAnalysis
requiredMemberTypes |= DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
}
- var targetValue = _annotations.GetMethodParameterValue (calledMethod, 0, requiredMemberTypes);
+ var targetValue = _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 0), requiredMemberTypes);
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
@@ -1140,13 +1139,14 @@ namespace ILLink.Shared.TrimAnalysis
case IntrinsicId.None:
// Verify the argument values match the annotations on the parameter definition
if (requiresDataFlowAnalysis) {
- if (!calledMethod.IsStatic ()) {
- _requireDynamicallyAccessedMembersAction.Invoke (instanceValue, _annotations.GetMethodThisParameterValue (calledMethod));
- }
- for (int argumentIndex = 0; argumentIndex < argumentValues.Count; argumentIndex++) {
- if (argumentIndex >= calledMethod.GetParametersCount () || calledMethod.ParameterReferenceKind (argumentIndex) == ReferenceKind.Out)
+ foreach (var parameter in calledMethod.GetParameters ()) {
+ if (parameter.GetReferenceKind () is ReferenceKind.Out)
+ continue;
+ if (parameter.IsImplicitThis) {
+ _requireDynamicallyAccessedMembersAction.Invoke (instanceValue, _annotations.GetMethodThisParameterValue (calledMethod));
continue;
- _requireDynamicallyAccessedMembersAction.Invoke (argumentValues[argumentIndex], _annotations.GetMethodParameterValue (calledMethod, (SourceParameterIndex) argumentIndex));
+ }
+ _requireDynamicallyAccessedMembersAction.Invoke (argumentValues[parameter.MetadataIndex], _annotations.GetMethodParameterValue (parameter));
}
}
break;
@@ -1255,7 +1255,7 @@ namespace ILLink.Shared.TrimAnalysis
// https://github.com/dotnet/linker/issues/2428
// We need to report the target as "this" - as that was the previous behavior
// but with the annotation from the generic parameter.
- var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, GetGenericParameterEffectiveMemberTypes (genericParameters[i]));
+ var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, GetGenericParameterEffectiveMemberTypes (genericParameters[i]), overrideIsThis: true);
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
@@ -1308,7 +1308,8 @@ namespace ILLink.Shared.TrimAnalysis
{
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
bool parameterlessConstructor = true;
- if (calledMethod.HasParametersCount (8) && calledMethod.HasParameterOfType (2, "System.Boolean")) {
+ int offset = calledMethod.HasImplicitThis () ? 1 : 0;
+ if (calledMethod.HasMetadataParametersCount (8) && calledMethod.HasParameterOfType ((ParameterIndex) 2 + offset, "System.Boolean")) {
parameterlessConstructor = false;
bindingFlags = BindingFlags.Instance;
if (argumentValues[3].AsConstInt () is int bindingFlagsInt)
@@ -1339,11 +1340,11 @@ namespace ILLink.Shared.TrimAnalysis
MarkConstructorsOnType (resolvedType, bindingFlags, parameterlessConstructor ? 0 : null);
} else {
- _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedParameterInMethodCreateInstance, calledMethod.GetParameterDisplayName (1), calledMethod.GetDisplayName ());
+ _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedParameterInMethodCreateInstance, new ParameterProxy (calledMethod, (ParameterIndex) 1 + offset).GetDisplayName (), calledMethod.GetDisplayName ());
}
}
} else {
- _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedParameterInMethodCreateInstance, calledMethod.GetParameterDisplayName (0), calledMethod.GetDisplayName ());
+ _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedParameterInMethodCreateInstance, new ParameterProxy (calledMethod, (ParameterIndex) 0 + offset).GetDisplayName (), calledMethod.GetDisplayName ());
}
}
}
diff --git a/src/ILLink.Shared/TrimAnalysis/Intrinsics.cs b/src/ILLink.Shared/TrimAnalysis/Intrinsics.cs
index 3b9ee24cd..031aa025e 100644
--- a/src/ILLink.Shared/TrimAnalysis/Intrinsics.cs
+++ b/src/ILLink.Shared/TrimAnalysis/Intrinsics.cs
@@ -25,11 +25,11 @@ namespace ILLink.Shared.TrimAnalysis
// System.Type.TypeHandle getter
"get_TypeHandle" when calledMethod.IsDeclaredOnType ("System.Type") => IntrinsicId.Type_get_TypeHandle,
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
- // System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
+ // static System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
+ // static System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
"GetMethodFromHandle" when calledMethod.IsDeclaredOnType ("System.Reflection.MethodBase")
- && calledMethod.HasParameterOfType (0, "System.RuntimeMethodHandle")
- && (calledMethod.HasParametersCount (1) || calledMethod.HasParametersCount (2))
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.RuntimeMethodHandle")
+ && (calledMethod.HasMetadataParametersCount (1) || calledMethod.HasMetadataParametersCount (2))
=> IntrinsicId.MethodBase_GetMethodFromHandle,
// System.Reflection.MethodBase.MethodHandle getter
@@ -40,87 +40,87 @@ namespace ILLink.Shared.TrimAnalysis
// static System.Reflection.RuntimeReflectionExtensions.GetRuntimeEvent (this Type type, string name)
"GetRuntimeEvent" when calledMethod.IsDeclaredOnType ("System.Reflection.RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent,
// static System.Reflection.RuntimeReflectionExtensions.GetRuntimeField (this Type type, string name)
"GetRuntimeField" when calledMethod.IsDeclaredOnType ("System.Reflection.RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParameterOfType (1, "System.,String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.,String")
=> IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField,
// static System.Reflection.RuntimeReflectionExtensions.GetRuntimeMethod (this Type type, string name, Type[] parameters)
"GetRuntimeMethod" when calledMethod.IsDeclaredOnType ("System.Reflection.RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod,
// static System.Reflection.RuntimeReflectionExtensions.GetRuntimeProperty (this Type type, string name)
"GetRuntimeProperty" when calledMethod.IsDeclaredOnType ("System.Reflection.RuntimeReflectionExtensions")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty,
// static System.Linq.Expressions.Expression.Call (Type, String, Type[], Expression[])
"Call" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions.Expression")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParametersCount (4)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasMetadataParametersCount (4)
=> IntrinsicId.Expression_Call,
// static System.Linq.Expressions.Expression.Field (Expression, Type, String)
"Field" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions.Expression")
- && calledMethod.HasParameterOfType (1, "System.Type")
- && calledMethod.HasParametersCount (3)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Type")
+ && calledMethod.HasMetadataParametersCount (3)
=> IntrinsicId.Expression_Field,
// static System.Linq.Expressions.Expression.Property (Expression, Type, String)
// static System.Linq.Expressions.Expression.Property (Expression, MethodInfo)
"Property" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions.Expression")
- && ((calledMethod.HasParameterOfType (1, "System.Type") && calledMethod.HasParametersCount (3))
- || (calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo") && calledMethod.HasParametersCount (2)))
+ && ((calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Type") && calledMethod.HasMetadataParametersCount (3))
+ || (calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.MethodInfo") && calledMethod.HasMetadataParametersCount (2)))
=> IntrinsicId.Expression_Property,
// static System.Linq.Expressions.Expression.New (Type)
"New" when calledMethod.IsDeclaredOnType ("System.Linq.Expressions.Expression")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasMetadataParametersCount (1)
=> IntrinsicId.Expression_New,
// static Array System.Enum.GetValues (Type)
"GetValues" when calledMethod.IsDeclaredOnType ("System.Enum")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasMetadataParametersCount (1)
=> IntrinsicId.Enum_GetValues,
// static int System.Runtime.InteropServices.Marshal.SizeOf (Type)
"SizeOf" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasMetadataParametersCount (1)
=> IntrinsicId.Marshal_SizeOf,
// static int System.Runtime.InteropServices.Marshal.OffsetOf (Type, string)
"OffsetOf" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
- && calledMethod.HasParameterOfType (0, "System.Type")
- && calledMethod.HasParametersCount (2)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
+ && calledMethod.HasMetadataParametersCount (2)
=> IntrinsicId.Marshal_OffsetOf,
// static object System.Runtime.InteropServices.Marshal.PtrToStructure (IntPtr, Type)
"PtrToStructure" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
- && calledMethod.HasParameterOfType (1, "System.Type")
- && calledMethod.HasParametersCount (2)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Type")
+ && calledMethod.HasMetadataParametersCount (2)
=> IntrinsicId.Marshal_PtrToStructure,
// static void System.Runtime.InteropServices.Marshal.DestroyStructure (IntPtr, Type)
"DestroyStructure" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
- && calledMethod.HasParameterOfType (1, "System.Type")
- && calledMethod.HasParametersCount (2)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Type")
+ && calledMethod.HasMetadataParametersCount (2)
=> IntrinsicId.Marshal_DestroyStructure,
// static Delegate System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer (IntPtr, Type)
"GetDelegateForFunctionPointer" when calledMethod.IsDeclaredOnType ("System.Runtime.InteropServices.Marshal")
- && calledMethod.HasParameterOfType (1, "System.Type")
- && calledMethod.HasParametersCount (2)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Type")
+ && calledMethod.HasMetadataParametersCount (2)
=> IntrinsicId.Marshal_GetDelegateForFunctionPointer,
// static System.Type.GetType (string)
@@ -130,7 +130,7 @@ namespace ILLink.Shared.TrimAnalysis
// static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean)
// static System.Type.GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean, Boolean)
"GetType" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.String")
=> IntrinsicId.Type_GetType,
// System.Type.GetConstructor (Type[])
@@ -143,8 +143,8 @@ namespace ILLink.Shared.TrimAnalysis
// System.Type.GetConstructors (BindingFlags)
"GetConstructors" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
- && calledMethod.HasParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags")
+ && calledMethod.HasMetadataParametersCount (1)
&& !calledMethod.IsStatic ()
=> IntrinsicId.Type_GetConstructors__BindingFlags,
@@ -160,102 +160,102 @@ namespace ILLink.Shared.TrimAnalysis
// System.Type.GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
// System.Type.GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
"GetMethod" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.String")
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Type_GetMethod,
// System.Type.GetMethods (BindingFlags)
"GetMethods" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
- && calledMethod.HasParametersCount (1)
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasMetadataParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags")
=> IntrinsicId.Type_GetMethods__BindingFlags,
// System.Type.GetField (string)
// System.Type.GetField (string, BindingFlags)
"GetField" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.String")
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Type_GetField,
// System.Type.GetFields (BindingFlags)
"GetFields" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
- && calledMethod.HasParametersCount (1)
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasMetadataParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags")
=> IntrinsicId.Type_GetFields__BindingFlags,
// System.Type.GetEvent (string)
// System.Type.GetEvent (string, BindingFlags)
"GetEvent" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.String")
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Type_GetEvent,
// System.Type.GetEvents (BindingFlags)
"GetEvents" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
- && calledMethod.HasParametersCount (1)
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasMetadataParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags")
=> IntrinsicId.Type_GetEvents__BindingFlags,
// System.Type.GetNestedType (string)
// System.Type.GetNestedType (string, BindingFlags)
"GetNestedType" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.String")
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Type_GetNestedType,
// System.Type.GetNestedTypes (BindingFlags)
"GetNestedTypes" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
- && calledMethod.HasParametersCount (1)
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasMetadataParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags")
=> IntrinsicId.Type_GetNestedTypes__BindingFlags,
// System.Type.GetMember (String)
// System.Type.GetMember (String, BindingFlags)
// System.Type.GetMember (String, MemberTypes, BindingFlags)
"GetMember" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.String")
- && !calledMethod.IsStatic ()
- && (calledMethod.HasParametersCount (1) ||
- (calledMethod.HasParametersCount (2) && calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags")) ||
- (calledMethod.HasParametersCount (3) && calledMethod.HasParameterOfType (2, "System.Reflection.BindingFlags")))
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
+ && (calledMethod.HasMetadataParametersCount (1) ||
+ (calledMethod.HasMetadataParametersCount (2) && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags")) ||
+ (calledMethod.HasMetadataParametersCount (3) && calledMethod.HasParameterOfType ((ParameterIndex) 3, "System.Reflection.BindingFlags")))
=> IntrinsicId.Type_GetMember,
// System.Type.GetMembers (BindingFlags)
"GetMembers" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
- && calledMethod.HasParametersCount (1)
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasMetadataParametersCount (1)
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags")
=> IntrinsicId.Type_GetMembers__BindingFlags,
// System.Type.GetInterface (string)
// System.Type.GetInterface (string, bool)
"GetInterface" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.String")
- && !calledMethod.IsStatic ()
- && (calledMethod.HasParametersCount (1) ||
- (calledMethod.HasParametersCount (2) && calledMethod.HasParameterOfType (1, "System.Boolean")))
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
+ && (calledMethod.HasMetadataParametersCount (1) ||
+ (calledMethod.HasMetadataParametersCount (2) && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Boolean")))
=> IntrinsicId.Type_GetInterface,
// System.Type.AssemblyQualifiedName
"get_AssemblyQualifiedName" when calledMethod.IsDeclaredOnType ("System.Type")
- && !calledMethod.HasParameters ()
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && !calledMethod.HasMetadataParameters ()
=> IntrinsicId.Type_get_AssemblyQualifiedName,
// System.Type.UnderlyingSystemType
"get_UnderlyingSystemType" when calledMethod.IsDeclaredOnType ("System.Type")
- && !calledMethod.HasParameters ()
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && !calledMethod.HasMetadataParameters ()
=> IntrinsicId.Type_get_UnderlyingSystemType,
// System.Type.BaseType
"get_BaseType" when calledMethod.IsDeclaredOnType ("System.Type")
- && !calledMethod.HasParameters ()
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && !calledMethod.HasMetadataParameters ()
=> IntrinsicId.Type_get_BaseType,
// System.Type.GetProperty (string)
@@ -266,15 +266,15 @@ namespace ILLink.Shared.TrimAnalysis
// System.Type.GetProperty (string, Type, Type[], ParameterModifier[])
// System.Type.GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
"GetProperty" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.String")
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Type_GetProperty,
// System.Type.GetProperties (BindingFlags)
"GetProperties" when calledMethod.IsDeclaredOnType ("System.Type")
- && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
- && calledMethod.HasParametersCount (1)
- && !calledMethod.IsStatic ()
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags")
+ && calledMethod.HasMetadataParametersCount (1)
=> IntrinsicId.Type_GetProperties__BindingFlags,
// static System.Object.GetType ()
@@ -282,7 +282,7 @@ namespace ILLink.Shared.TrimAnalysis
=> IntrinsicId.Object_GetType,
".ctor" when calledMethod.IsDeclaredOnType ("System.Reflection.TypeDelegator")
- && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Type")
=> IntrinsicId.TypeDelegator_Ctor,
"Empty" when calledMethod.IsDeclaredOnType ("System.Array")
@@ -296,7 +296,7 @@ namespace ILLink.Shared.TrimAnalysis
// static System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
"CreateInstance" when calledMethod.IsDeclaredOnType ("System.Activator")
&& !calledMethod.HasGenericParameters ()
- && calledMethod.HasParameterOfType (0, "System.Type")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
=> IntrinsicId.Activator_CreateInstance__Type,
// static System.Activator.CreateInstance (string assemblyName, string typeName)
@@ -304,8 +304,8 @@ namespace ILLink.Shared.TrimAnalysis
// static System.Activator.CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
"CreateInstance" when calledMethod.IsDeclaredOnType ("System.Activator")
&& !calledMethod.HasGenericParameters ()
- && calledMethod.HasParameterOfType (0, "System.String")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Activator_CreateInstance__AssemblyName_TypeName,
// static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName)
@@ -313,63 +313,64 @@ namespace ILLink.Shared.TrimAnalysis
// static System.Activator.CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
"CreateInstanceFrom" when calledMethod.IsDeclaredOnType ("System.Activator")
&& !calledMethod.HasGenericParameters ()
- && calledMethod.HasParameterOfType (0, "System.String")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Activator_CreateInstanceFrom,
// System.AppDomain.CreateInstance (string assemblyName, string typeName)
// System.AppDomain.CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// System.AppDomain.CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
"CreateInstance" when calledMethod.IsDeclaredOnType ("System.AppDomain")
- && calledMethod.HasParameterOfType (0, "System.String")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.String")
=> IntrinsicId.AppDomain_CreateInstance,
// System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName)
// System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// System.AppDomain.CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
"CreateInstanceAndUnwrap" when calledMethod.IsDeclaredOnType ("System.AppDomain")
- && calledMethod.HasParameterOfType (0, "System.String")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.String")
=> IntrinsicId.AppDomain_CreateInstanceAndUnwrap,
// System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName)
// System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// System.AppDomain.CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
"CreateInstanceFrom" when calledMethod.IsDeclaredOnType ("System.AppDomain")
- && calledMethod.HasParameterOfType (0, "System.String")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.String")
=> IntrinsicId.AppDomain_CreateInstanceFrom,
// System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
// System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// System.AppDomain.CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
"CreateInstanceFromAndUnwrap" when calledMethod.IsDeclaredOnType ("System.AppDomain")
- && calledMethod.HasParameterOfType (0, "System.String")
- && calledMethod.HasParameterOfType (1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.String")
=> IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap,
// System.Reflection.Assembly.CreateInstance (string typeName)
// System.Reflection.Assembly.CreateInstance (string typeName, bool ignoreCase)
// System.Reflection.Assembly.CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
"CreateInstance" when calledMethod.IsDeclaredOnType ("System.Reflection.Assembly")
- && calledMethod.HasParameterOfType (0, "System.String")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.String")
=> IntrinsicId.Assembly_CreateInstance,
// System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (RuntimeTypeHandle type)
"RunClassConstructor" when calledMethod.IsDeclaredOnType ("System.Runtime.CompilerServices.RuntimeHelpers")
- && calledMethod.HasParameterOfType (0, "System.RuntimeTypeHandle")
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.RuntimeTypeHandle")
=> IntrinsicId.RuntimeHelpers_RunClassConstructor,
// System.Reflection.MethodInfo.MakeGenericMethod (Type[] typeArguments)
"MakeGenericMethod" when calledMethod.IsDeclaredOnType ("System.Reflection.MethodInfo")
- && !calledMethod.IsStatic ()
- && calledMethod.HasParametersCount (1)
+ && calledMethod.HasImplicitThis ()
+ && calledMethod.HasMetadataParametersCount (1)
=> IntrinsicId.MethodInfo_MakeGenericMethod,
+ // static System.Nullable.GetUnderlyingType
"GetUnderlyingType" when calledMethod.IsDeclaredOnType ("System.Nullable")
- && calledMethod.HasParameterOfType (0, "System.Type")
&& calledMethod.IsStatic ()
+ && calledMethod.HasParameterOfType ((ParameterIndex) 0, "System.Type")
=> IntrinsicId.Nullable_GetUnderlyingType,
_ => IntrinsicId.None,
diff --git a/src/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs b/src/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs
index 8d2b4a6a6..108420326 100644
--- a/src/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs
+++ b/src/ILLink.Shared/TrimAnalysis/MethodParameterValue.cs
@@ -4,7 +4,30 @@
// This is needed due to NativeAOT which doesn't enable nullable globally yet
#nullable enable
+
+using System.Collections.Generic;
+using ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
+
namespace ILLink.Shared.TrimAnalysis
{
- sealed partial record MethodParameterValue : ValueWithDynamicallyAccessedMembers;
+ sealed partial record MethodParameterValue : ValueWithDynamicallyAccessedMembers
+ {
+ // _overrideIsThis is needed for backwards compatibility with MakeGenericType/Method https://github.com/dotnet/linker/issues/2428
+ private readonly bool _overrideIsThis;
+
+ public ParameterProxy Parameter { get; }
+
+ public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
+ => Parameter.GetDiagnosticArgumentsForAnnotationMismatch ();
+
+ public override string ToString ()
+ => this.ValueToString (Parameter.Method.Method, DynamicallyAccessedMemberTypes);
+
+ public bool IsThisParameter () => _overrideIsThis || Parameter.IsImplicitThis;
+
+ public override SingleValue DeepCopy () => this; // This value is immutable
+
+ public ParameterIndex Index => Parameter.Index;
+ }
}
diff --git a/src/ILLink.Shared/TrimAnalysis/MethodThisParameterValue.cs b/src/ILLink.Shared/TrimAnalysis/MethodThisParameterValue.cs
deleted file mode 100644
index baf12d256..000000000
--- a/src/ILLink.Shared/TrimAnalysis/MethodThisParameterValue.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-// This is needed due to NativeAOT which doesn't enable nullable globally yet
-#nullable enable
-
-namespace ILLink.Shared.TrimAnalysis
-{
- sealed partial record MethodThisParameterValue : ValueWithDynamicallyAccessedMembers;
-}
diff --git a/src/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs b/src/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs
index 389116f97..54a1c7ca1 100644
--- a/src/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs
+++ b/src/ILLink.Shared/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs
@@ -52,10 +52,10 @@ namespace ILLink.Shared.TrimAnalysis
// Ignore - probably unreachable path as it would fail at runtime anyway.
} else {
DiagnosticId diagnosticId = targetValue switch {
+ MethodParameterValue maybeThis when maybeThis.IsThisParameter () => DiagnosticId.ImplicitThisCannotBeStaticallyDetermined,
MethodParameterValue => DiagnosticId.MethodParameterCannotBeStaticallyDetermined,
MethodReturnValue => DiagnosticId.MethodReturnValueCannotBeStaticallyDetermined,
FieldValue => DiagnosticId.FieldValueCannotBeStaticallyDetermined,
- MethodThisParameterValue => DiagnosticId.ImplicitThisCannotBeStaticallyDetermined,
GenericParameterValue => DiagnosticId.TypePassedToGenericParameterCannotBeStaticallyDetermined,
_ => throw new NotImplementedException ($"unsupported target value {targetValue}")
};
diff --git a/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs b/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs
index a30ce2200..92ba44e63 100644
--- a/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs
+++ b/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs
@@ -13,17 +13,51 @@ namespace ILLink.Shared.TypeSystemProxy
// Currently this only needs to work on non-nested, non-generic types.
// The format of the fullTypeName parameter is 'namespace.typename', so for example 'System.Reflection.Assembly'
internal partial bool IsDeclaredOnType (string fullTypeName);
- internal partial bool HasParameters ();
+
+ /// <summary>
+ /// Returns the number of the parameters in the 'parameters' metadata section. This should map directly to the number of parameters in the C# source declaration as well.
+ /// </summary>
+ internal partial int GetMetadataParametersCount ();
+
+ /// <summary>
+ /// Returns true if the method has parameters in the 'parameters' metadata section (i.e. has parameters besides the implicit 'this' parameter)
+ /// </summary>
+ internal partial bool HasMetadataParameters ();
+
+ /// <summary>
+ /// Returns the number of parameters that are passed to the method in IL (including the implicit 'this' parameter).
+ /// In pseudocode: <code>method.HasImplicitThis() ? 1 + MetadataParametersCount : MetadataParametersCount;</code>
+ /// </summary>
internal partial int GetParametersCount ();
- internal bool HasParametersCount (int parameterCount) => GetParametersCount () == parameterCount;
+
+ /// <summary>
+ /// Returns a List of <see cref="ParameterProxy"/> representing the parameters the method takes, including the implicit 'this' parameters.
+ /// </summary>
+ internal partial ParameterProxyEnumerable GetParameters ();
+
+ /// <summary>
+ /// Returns the ParameterProxy corresponding to the parameter at <paramref name="index"/>, and throws if the index is out of bounds for the method.
+ /// <paramref name="index"/> is the index of the parameters as they are passed to the method, with 0 being the implicit this parameter if it exists.
+ /// See <see cref="ParameterIndex"/> for more info.
+ /// </summary>
+ internal partial ParameterProxy GetParameter (ParameterIndex index);
+
+ /// <summary>
+ /// Returns true if the 'parameters' metadata section has <paramref name="parameterCount"/> number of parameters.
+ /// Metadata parameters count maps directly to the number of parameters in C# source code.
+ /// Metadata parameters count excludes the implicit 'this' parameter.
+ /// </summary>
+ internal bool HasMetadataParametersCount (int parameterCount) => GetMetadataParametersCount () == parameterCount;
+
// Currently this only needs to work on non-nested, non-generic types.
// The format of the fullTypeName parameter is 'namespace.typename', so for example 'System.Reflection.Assembly'
- internal partial bool HasParameterOfType (int parameterIndex, string fullTypeName);
- internal partial string GetParameterDisplayName (int parameterIndex);
+ internal bool HasParameterOfType (ParameterIndex parameterIndex, string fullTypeName)
+ => (int) parameterIndex < GetParametersCount () && GetParameter (parameterIndex).IsTypeOf (fullTypeName);
internal partial bool HasGenericParameters ();
internal partial bool HasGenericParametersCount (int genericParameterCount);
internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters ();
internal partial bool IsStatic ();
+ internal partial bool HasImplicitThis ();
internal partial bool ReturnsVoid ();
}
}
diff --git a/src/ILLink.Shared/TypeSystemProxy/ParameterCollection.cs b/src/ILLink.Shared/TypeSystemProxy/ParameterCollection.cs
new file mode 100644
index 000000000..eaba6c5fd
--- /dev/null
+++ b/src/ILLink.Shared/TypeSystemProxy/ParameterCollection.cs
@@ -0,0 +1,59 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ /// <summary>
+ /// Enumerable struct used to enumerator over a method's parameters without allocating or going through IEnumerable
+ /// </summary>
+ internal struct ParameterProxyEnumerable : IEnumerable<ParameterProxy>
+ {
+ readonly int _start;
+
+ readonly int _end;
+
+ readonly MethodProxy _method;
+
+ public ParameterProxyEnumerable (int start, int end, MethodProxy method)
+ {
+ _start = start;
+ _end = end;
+ _method = method;
+ }
+
+ public ParameterEnumerator GetEnumerator () => new ParameterEnumerator (_start, _end, _method);
+
+ IEnumerator<ParameterProxy> IEnumerable<ParameterProxy>.GetEnumerator () => new ParameterEnumerator (_start, _end, _method);
+
+ IEnumerator IEnumerable.GetEnumerator () => new ParameterEnumerator (_start, _end, _method);
+
+ public struct ParameterEnumerator : IEnumerator<ParameterProxy>
+ {
+ readonly int _start;
+ int _current;
+ readonly int _end;
+ readonly MethodProxy _method;
+ public ParameterEnumerator (int start, int end, MethodProxy method)
+ {
+ _start = start;
+ _current = start - 1;
+ _end = end;
+ _method = method;
+ }
+
+ public ParameterProxy Current => new ParameterProxy (_method, (ParameterIndex) _current);
+
+ object IEnumerator.Current => new ParameterProxy (_method, (ParameterIndex) _current);
+
+ public bool MoveNext () => ++_current < _end;
+
+ public void Reset () => _current = _start;
+
+ void IDisposable.Dispose () { }
+ }
+ }
+}
diff --git a/src/ILLink.Shared/TypeSystemProxy/ParameterProxy.cs b/src/ILLink.Shared/TypeSystemProxy/ParameterProxy.cs
new file mode 100644
index 000000000..c31c5f383
--- /dev/null
+++ b/src/ILLink.Shared/TypeSystemProxy/ParameterProxy.cs
@@ -0,0 +1,53 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal partial struct ParameterProxy
+ {
+ public ParameterProxy (MethodProxy method, ParameterIndex index)
+ {
+ if ((int) index < 0 || (int) index >= method.GetParametersCount ())
+ throw new InvalidOperationException ($"Parameter of index {(int) index} does not exist on method {method.GetDisplayName ()} with {method.GetParametersCount ()}");
+ Method = method;
+ Index = index;
+ }
+
+ public MethodProxy Method { get; }
+
+ public ParameterIndex Index { get; }
+
+ /// <summary>
+ /// The index of the entry in the '.parameters' metadata section corresponding to this parameter.
+ /// Maps to the index of the parameter in Cecil's MethodReference.Parameters or Roslyn's IMethodSymbol.Parameters
+ /// Throws if the parameter is the implicit 'this' parameter.
+ /// </summary>
+ public int MetadataIndex {
+ get {
+ if (Method.HasImplicitThis ()) {
+ if (IsImplicitThis)
+ throw new InvalidOperationException ("Cannot get metadata index of the implicit 'this' parameter");
+ return (int) Index - 1;
+ }
+ return (int) Index;
+ }
+ }
+
+ public partial ReferenceKind GetReferenceKind ();
+
+ public partial string GetDisplayName ();
+
+ public bool IsImplicitThis => Method.HasImplicitThis () && Index == (ParameterIndex) 0;
+
+ public partial bool IsTypeOf (string typeName);
+
+ public IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
+ => IsImplicitThis ?
+ new string[] { Method.GetDisplayName () }
+
+ : new string[] { GetDisplayName (), Method.GetDisplayName () };
+ }
+}
diff --git a/src/linker/BannedSymbols.txt b/src/linker/BannedSymbols.txt
index d7c70af18..de67d0d93 100644
--- a/src/linker/BannedSymbols.txt
+++ b/src/linker/BannedSymbols.txt
@@ -1,5 +1,7 @@
T:Mono.Cecil.Cil.ILProcessor;Use LinkerILProcessor instead
M:Mono.Cecil.TypeReference.Resolve();Use LinkContext.Resolve and LinkContext.TryResolve helpers instead
+P:Mono.Cecil.MethodReference.Parameters;Use an extension method from MethodReferenceExtensions instead
+P:Mono.Cecil.MethodReference.HasParameters;Use an extension method from MethodReference.HasMetadataParameters() instead
M:Mono.Cecil.MethodReference.Resolve();Use LinkContext.Resolve and LinkContext.TryResolve helpers instead
M:Mono.Cecil.ExportedType.Resolve();Use LinkContext.Resolve and LinkContext.TryResolve helpers instead
P:Mono.Collections.Generic.Collection`1{Mono.Cecil.ParameterDefinition}.Item(System.Int32); use x
diff --git a/src/linker/Linker.Dataflow/AttributeDataFlow.cs b/src/linker/Linker.Dataflow/AttributeDataFlow.cs
index 03a32483c..fa2aa697d 100644
--- a/src/linker/Linker.Dataflow/AttributeDataFlow.cs
+++ b/src/linker/Linker.Dataflow/AttributeDataFlow.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using ILLink.Shared;
using ILLink.Shared.TrimAnalysis;
using Mono.Cecil;
using Mono.Linker.Steps;
@@ -27,10 +26,10 @@ namespace Mono.Linker.Dataflow
public void ProcessAttributeDataflow (MethodDefinition method, IList<CustomAttributeArgument> arguments)
{
- for (int i = 0; i < method.Parameters.Count; i++) {
- var parameterValue = _context.Annotations.FlowAnnotations.GetMethodParameterValue (method, (SourceParameterIndex) i);
+ foreach (var parameter in method.GetMetadataParameters ()) {
+ var parameterValue = _context.Annotations.FlowAnnotations.GetMethodParameterValue (parameter);
if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) {
- MultiValue value = GetValueForCustomAttributeArgument (arguments[i]);
+ MultiValue value = GetValueForCustomAttributeArgument (arguments[parameter.MetadataIndex]);
var diagnosticContext = new DiagnosticContext (_origin, diagnosticsEnabled: true, _context);
RequireDynamicallyAccessedMembers (diagnosticContext, value, parameterValue);
}
@@ -74,4 +73,4 @@ namespace Mono.Linker.Dataflow
requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
-} \ No newline at end of file
+}
diff --git a/src/linker/Linker.Dataflow/DiagnosticUtilities.cs b/src/linker/Linker.Dataflow/DiagnosticUtilities.cs
index e354b683e..390081bd7 100644
--- a/src/linker/Linker.Dataflow/DiagnosticUtilities.cs
+++ b/src/linker/Linker.Dataflow/DiagnosticUtilities.cs
@@ -1,30 +1,12 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System;
using Mono.Cecil;
namespace Mono.Linker.Dataflow
{
static class DiagnosticUtilities
{
- internal static IMetadataTokenProvider GetMethodParameterFromIndex (MethodDefinition method, int parameterIndex)
- {
- int declaredParameterIndex;
- if (method.HasImplicitThis ()) {
- if (parameterIndex == 0)
- return method;
-
- declaredParameterIndex = parameterIndex - 1;
- } else
- declaredParameterIndex = parameterIndex;
-
- if (declaredParameterIndex >= 0 && declaredParameterIndex < method.Parameters.Count)
- return method.Parameters[declaredParameterIndex];
-
- throw new InvalidOperationException ();
- }
-
internal static string GetParameterNameForErrorMessage (ParameterDefinition parameterDefinition) =>
string.IsNullOrEmpty (parameterDefinition.Name) ? $"#{parameterDefinition.Index}" : parameterDefinition.Name;
diff --git a/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs b/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs
index 26b67b553..dd6971040 100644
--- a/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs
+++ b/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs
@@ -41,7 +41,7 @@ namespace Mono.Linker
}
if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)) {
- foreach (var c in typeDefinition.GetConstructorsOnType (filter: m => m.IsPublic && m.Parameters.Count == 0))
+ foreach (var c in typeDefinition.GetConstructorsOnType (filter: m => m.IsPublic && !m.HasMetadataParameters ()))
yield return c;
}
diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs
index e14b1928c..183e55ce1 100644
--- a/src/linker/Linker.Dataflow/FlowAnnotations.cs
+++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs
@@ -40,28 +40,11 @@ namespace ILLink.Shared.TrimAnalysis
public bool RequiresGenericArgumentDataFlowAnalysis (GenericParameter genericParameter) =>
GetGenericParameterAnnotation (genericParameter) != DynamicallyAccessedMemberTypes.None;
- /// <summary>
- /// Retrieves the annotations for the given parameter.
- /// </summary>
- /// <param name="parameterIndex">Parameter index in the IL sense. Parameter 0 on instance methods is `this`.</param>
- /// <returns></returns>
- public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition method, SourceParameterIndex parameterIndex)
+ public DynamicallyAccessedMemberTypes GetParameterAnnotation (ParameterProxy param)
{
- if (GetAnnotations (method.DeclaringType).TryGetAnnotation (method, out var annotation) &&
+ if (GetAnnotations (param.Method.Method.DeclaringType).TryGetAnnotation (param.Method.Method, out var annotation) &&
annotation.ParameterAnnotations != null)
- return annotation.ParameterAnnotations[(int) ParameterHelpers.GetILParameterIndex (method, parameterIndex)];
-
- return DynamicallyAccessedMemberTypes.None;
- }
-
- public DynamicallyAccessedMemberTypes GetThisParameterAnnotation (MethodDefinition method)
- {
- if (!method.HasThis)
- throw new InvalidOperationException ($"Cannot get annotation of `this` of method {method.FullName} without `this`");
-
- if (GetAnnotations (method.DeclaringType).TryGetAnnotation (method, out var annotation) &&
- annotation.ParameterAnnotations != null)
- return annotation.ParameterAnnotations[0];
+ return annotation.ParameterAnnotations[(int) param.Index];
return DynamicallyAccessedMemberTypes.None;
}
@@ -238,46 +221,29 @@ namespace ILLink.Shared.TrimAnalysis
foreach (MethodDefinition method in type.Methods) {
DynamicallyAccessedMemberTypes[]? paramAnnotations = null;
- // We convert indices from metadata space to IL space here.
- // IL space assigns index 0 to the `this` parameter on instance methods.
-
-
- DynamicallyAccessedMemberTypes methodMemberTypes = GetMemberTypesForDynamicallyAccessedMembersAttribute (method);
-
- int offset;
- if (method.HasImplicitThis ()) {
- offset = 1;
- if (IsTypeInterestingForDataflow (method.DeclaringType)) {
- // If there's an annotation on the method itself and it's one of the special types (System.Type for example)
- // treat that annotation as annotating the "this" parameter.
- if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) {
- paramAnnotations = new DynamicallyAccessedMemberTypes[method.Parameters.Count + offset];
- paramAnnotations[0] = methodMemberTypes;
- }
- } else if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) {
- _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods);
- }
- } else {
- offset = 0;
- if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) {
- _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods);
- }
+ // Warn if there is an annotation on a method without a `this` parameter -- we won't catch it in the for loop if there's no parameters
+ if (GetMemberTypesForDynamicallyAccessedMembersAttribute (method) != DynamicallyAccessedMemberTypes.None
+ && !method.HasImplicitThis ()) {
+ _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods);
}
- for (int i = 0; i < method.Parameters.Count; i++) {
- var methodParameter = method.Parameters[i];
- DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMembersAttribute (method, providerIfNotMember: methodParameter);
+ // We convert indices from metadata space to IL space here.
+ // IL space assigns index 0 to the `this` parameter on instance methods.
+ foreach (var param in method.GetParameters ()) {
+ DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMembersAttribute (method, param.GetCustomAttributeProvider ());
if (pa == DynamicallyAccessedMemberTypes.None)
continue;
- if (!IsTypeInterestingForDataflow (methodParameter.ParameterType)) {
- _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings,
- DiagnosticUtilities.GetParameterNameForErrorMessage (methodParameter), DiagnosticUtilities.GetMethodSignatureDisplayName (methodParameter.Method));
+ if (!IsTypeInterestingForDataflow (param.ParameterType)) {
+ if (param.IsImplicitThis)
+ _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods);
+ else
+ _context.LogWarning (method, DiagnosticId.DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings,
+ param.GetDisplayName (), DiagnosticUtilities.GetMethodSignatureDisplayName (method));
continue;
}
-
- paramAnnotations ??= new DynamicallyAccessedMemberTypes[method.Parameters.Count + offset];
- paramAnnotations[i + offset] = pa;
+ paramAnnotations ??= new DynamicallyAccessedMemberTypes[method.GetParametersCount ()];
+ paramAnnotations[(int) param.Index] = pa;
}
DynamicallyAccessedMemberTypes returnAnnotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (method, providerIfNotMember: method.MethodReturnType);
@@ -353,13 +319,12 @@ namespace ILLink.Shared.TrimAnalysis
if (setterAnnotation?.ParameterAnnotations?[^1] is not (null or DynamicallyAccessedMemberTypes.None)) {
_context.LogWarning (setMethod, DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor, property.GetDisplayName (), setMethod.GetDisplayName ());
} else {
- int offset = setMethod.HasImplicitThis () ? 1 : 0;
if (setterAnnotation is not null)
annotatedMethods.Remove (setterAnnotation.Value);
DynamicallyAccessedMemberTypes[] paramAnnotations;
if (setterAnnotation?.ParameterAnnotations is null)
- paramAnnotations = new DynamicallyAccessedMemberTypes[setMethod.Parameters.Count + offset];
+ paramAnnotations = new DynamicallyAccessedMemberTypes[setMethod.GetParametersCount ()];
else
paramAnnotations = setterAnnotation.Value.ParameterAnnotations;
@@ -519,8 +484,8 @@ namespace ILLink.Shared.TrimAnalysis
for (int parameterIndex = 0; parameterIndex < methodAnnotations.ParameterAnnotations.Length; parameterIndex++) {
if (methodAnnotations.ParameterAnnotations[parameterIndex] != baseMethodAnnotations.ParameterAnnotations[parameterIndex])
LogValidationWarning (
- DiagnosticUtilities.GetMethodParameterFromIndex (method, parameterIndex),
- DiagnosticUtilities.GetMethodParameterFromIndex (baseMethod, parameterIndex),
+ method.TryGetParameter ((ParameterIndex) parameterIndex)?.GetCustomAttributeProvider ()!,
+ baseMethod.TryGetParameter ((ParameterIndex) parameterIndex)?.GetCustomAttributeProvider ()!,
method);
}
}
@@ -553,8 +518,8 @@ namespace ILLink.Shared.TrimAnalysis
var annotation = parameterAnnotations[parameterIndex];
if (annotation != DynamicallyAccessedMemberTypes.None)
LogValidationWarning (
- DiagnosticUtilities.GetMethodParameterFromIndex (method, parameterIndex),
- DiagnosticUtilities.GetMethodParameterFromIndex (baseMethod, parameterIndex),
+ method.GetParameter ((ParameterIndex) parameterIndex).GetCustomAttributeProvider ()!,
+ baseMethod.GetParameter ((ParameterIndex) parameterIndex).GetCustomAttributeProvider ()!,
origin);
}
}
@@ -729,19 +694,33 @@ namespace ILLink.Shared.TrimAnalysis
internal partial GenericParameterValue GetGenericParameterValue (GenericParameterProxy genericParameter)
=> new GenericParameterValue (genericParameter.GenericParameter, GetGenericParameterAnnotation (genericParameter.GenericParameter));
-#pragma warning disable CA1822 // Mark members as static - keep this an instance method for consistency with the others
- internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- => new MethodThisParameterValue (method.Method, dynamicallyAccessedMemberTypes);
-#pragma warning restore CA1822
+ internal partial MethodParameterValue GetMethodParameterValue (ParameterProxy param, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new (param.ParameterType.ResolveToTypeDefinition (_context), param, dynamicallyAccessedMemberTypes);
+
+ internal partial MethodParameterValue GetMethodParameterValue (ParameterProxy param)
+ => GetMethodParameterValue (param, GetParameterAnnotation (param));
- internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method)
- => GetMethodThisParameterValue (method, GetThisParameterAnnotation (method.Method));
+#pragma warning disable CA1822 // Mark members as static - Should be an instance method for consistency
+ // overrideIsThis is needed for backwards compatibility with MakeGenericType/Method https://github.com/dotnet/linker/issues/2428
+ internal MethodParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, bool overrideIsThis = false)
+ {
+ if (!method.HasImplicitThis () && !overrideIsThis)
+ throw new InvalidOperationException ($"Cannot get 'this' parameter of method {method.GetDisplayName ()} with no 'this' parameter.");
+ return new MethodParameterValue (method.Method.DeclaringType, new ParameterProxy (method, (ParameterIndex) 0), dynamicallyAccessedMemberTypes, overrideIsThis);
+ }
+#pragma warning restore CA1822 // Mark members as static
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- => new (method.Method.Parameters[(int) parameterIndex].ParameterType.ResolveToTypeDefinition (_context), method.Method, (int) parameterIndex, dynamicallyAccessedMemberTypes);
+ internal partial MethodParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => GetMethodThisParameterValue (method, dynamicallyAccessedMemberTypes, false);
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex)
- => GetMethodParameterValue (method, parameterIndex, GetParameterAnnotation (method.Method, parameterIndex));
+ internal partial MethodParameterValue GetMethodThisParameterValue (MethodProxy method)
+ {
+ if (!method.HasImplicitThis ())
+ throw new InvalidOperationException ($"Cannot get 'this' parameter of method {method.GetDisplayName ()} with no 'this' parameter.");
+ ParameterProxy param = new (method, (ParameterIndex) 0);
+ var damt = GetParameterAnnotation (param);
+ return GetMethodParameterValue (new ParameterProxy (method, (ParameterIndex) 0), damt);
+ }
// Linker-specific dataflow value creation. Eventually more of these should be shared.
internal SingleValue GetFieldValue (FieldDefinition field)
diff --git a/src/linker/Linker.Dataflow/HandleCallAction.cs b/src/linker/Linker.Dataflow/HandleCallAction.cs
index 69641ecc6..4b045a705 100644
--- a/src/linker/Linker.Dataflow/HandleCallAction.cs
+++ b/src/linker/Linker.Dataflow/HandleCallAction.cs
@@ -106,10 +106,10 @@ namespace ILLink.Shared.TrimAnalysis
=> _reflectionMarker.MarkPropertiesOnTypeHierarchy (_diagnosticContext.Origin, type.Type, p => p.Name == name, bindingFlags);
private partial void MarkPublicParameterlessConstructorOnType (TypeProxy type)
- => _reflectionMarker.MarkConstructorsOnType (_diagnosticContext.Origin, type.Type, m => m.IsPublic && m.Parameters.Count == 0);
+ => _reflectionMarker.MarkConstructorsOnType (_diagnosticContext.Origin, type.Type, m => m.IsPublic && m.GetMetadataParametersCount () == 0);
private partial void MarkConstructorsOnType (TypeProxy type, BindingFlags? bindingFlags, int? parameterCount)
- => _reflectionMarker.MarkConstructorsOnType (_diagnosticContext.Origin, type.Type, parameterCount == null ? null : m => m.Parameters.Count == parameterCount, bindingFlags);
+ => _reflectionMarker.MarkConstructorsOnType (_diagnosticContext.Origin, type.Type, (parameterCount == null) ? null : m => m.GetMetadataParametersCount () == parameterCount, bindingFlags);
private partial void MarkMethod (MethodProxy method)
=> _reflectionMarker.MarkMethod (_diagnosticContext.Origin, method.Method);
diff --git a/src/linker/Linker.Dataflow/MethodBodyScanner.cs b/src/linker/Linker.Dataflow/MethodBodyScanner.cs
index 0216252cc..bc729794e 100644
--- a/src/linker/Linker.Dataflow/MethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/MethodBodyScanner.cs
@@ -12,7 +12,6 @@ using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
-using static Mono.Linker.ParameterHelpers;
using LocalVariableStore = System.Collections.Generic.Dictionary<
Mono.Cecil.Cil.VariableDefinition,
Mono.Linker.Dataflow.ValueBasicBlockPair>;
@@ -716,35 +715,24 @@ namespace Mono.Linker.Dataflow
}
}
- protected abstract SingleValue GetMethodParameterValue (MethodDefinition method, SourceParameterIndex parameterIndex);
-
- protected abstract SingleValue GetMethodThisParameterValue (MethodDefinition method);
+ protected abstract SingleValue GetMethodParameterValue (ParameterProxy parameter);
private void ScanLdarg (Instruction operation, Stack<StackSlot> currentStack, MethodDefinition thisMethod)
{
Code code = operation.OpCode.Code;
- bool isByRef = code == Code.Ldarga || code == Code.Ldarga_S;
- SingleValue valueToPush;
- switch (GetSourceParameterIndex (thisMethod, operation, out var sourceIndex)) {
- case SourceParameterKind.Numbered:
- // This is semantically wrong if it returns true - we would representing a reference parameter as a reference to a parameter - but it should be fine for now
- isByRef |= thisMethod.GetParameterType (sourceIndex).IsByRefOrPointer ();
- valueToPush = isByRef
- ? new ParameterReferenceValue (thisMethod, sourceIndex)
- : GetMethodParameterValue (thisMethod, sourceIndex);
- break;
- case SourceParameterKind.This:
- isByRef |= thisMethod.DeclaringType.IsValueType;
- valueToPush = isByRef
- ? new ThisParameterReferenceValue (thisMethod)
- : GetMethodThisParameterValue (thisMethod);
- break;
- default:
- throw new InvalidOperationException ("Unexpected IParameterIndex type");
- }
+ ParameterIndex paramNum = ParameterHelpers.GetParameterIndex (thisMethod, operation);
+ ParameterProxy param = thisMethod.GetParameter (paramNum);
+ TypeReference paramType = param.ParameterType;
+
+ bool isByRef = code == Code.Ldarga || code == Code.Ldarga_S;
+ isByRef |= paramType.IsByRefOrPointer ();
+ isByRef |= param.IsImplicitThis == true && paramType.IsValueType;
- StackSlot slot = new StackSlot (valueToPush);
+ StackSlot slot = new StackSlot (
+ isByRef
+ ? new ParameterReferenceValue (param)
+ : GetMethodParameterValue (param));
currentStack.Push (slot);
}
@@ -755,18 +743,13 @@ namespace Mono.Linker.Dataflow
MethodBody methodBody)
{
var valueToStore = PopUnknown (currentStack, 1, methodBody, operation.Offset);
- switch (GetSourceParameterIndex (thisMethod, operation, out var sourceParameterIndex)) {
- case SourceParameterKind.Numbered:
- var targetValue = GetMethodParameterValue (thisMethod, sourceParameterIndex);
- if (targetValue is MethodParameterValue targetParameterValue)
- HandleStoreParameter (thisMethod, targetParameterValue, operation, valueToStore.Value);
- break;
+ ParameterIndex paramNum = ParameterHelpers.GetParameterIndex (thisMethod, operation);
+ ParameterProxy param = new (thisMethod, paramNum);
+ var targetValue = GetMethodParameterValue (param);
+ if (targetValue is MethodParameterValue targetParameterValue)
+ HandleStoreParameter (thisMethod, targetParameterValue, operation, valueToStore.Value);
+
// If the targetValue is MethodThisValue do nothing - it should never happen really, and if it does, there's nothing we can track there
- case SourceParameterKind.This:
- break;
- default:
- break;
- }
}
private void ScanLdloc (
@@ -883,13 +866,9 @@ namespace Mono.Linker.Dataflow
HandleStoreField (method, fieldValue, operation, source);
break;
case ParameterReferenceValue parameterReference
- when GetMethodParameterValue (parameterReference.MethodDefinition, parameterReference.ParameterIndex) is MethodParameterValue parameterValue:
+ when GetMethodParameterValue (parameterReference.Parameter) is MethodParameterValue parameterValue:
HandleStoreParameter (method, parameterValue, operation, source);
break;
- case ThisParameterReferenceValue parameterReference
- when GetMethodThisParameterValue (parameterReference.MethodDefinition) is MethodThisParameterValue thisParameterValue:
- HandleStoreMethodThisParameter (method, thisParameterValue, operation, source);
- break;
case MethodReturnValue methodReturnValue:
// Ref returns don't have special ReferenceValue values, so assume if the target here is a MethodReturnValue then it must be a ref return value
HandleStoreMethodReturnValue (method, methodReturnValue, operation, source);
@@ -953,10 +932,6 @@ namespace Mono.Linker.Dataflow
{
}
- protected virtual void HandleStoreMethodThisParameter (MethodDefinition method, MethodThisParameterValue thisParameter, Instruction operation, MultiValue sourceValue)
- {
- }
-
protected virtual void HandleStoreMethodReturnValue (MethodDefinition method, MethodReturnValue thisParameter, Instruction operation, MultiValue sourceValue)
{
}
@@ -1017,7 +992,7 @@ namespace Mono.Linker.Dataflow
int countToPop = 0;
if (!isNewObj && methodCalled.HasThis && !methodCalled.ExplicitThis)
countToPop++;
- countToPop += methodCalled.Parameters.Count;
+ countToPop += methodCalled.GetMetadataParametersCount ();
ValueNodeList methodParams = new ValueNodeList (countToPop);
for (int iParam = 0; iParam < countToPop; ++iParam) {
@@ -1048,7 +1023,7 @@ namespace Mono.Linker.Dataflow
case ParameterReferenceValue parameterReferenceValue:
dereferencedValue = MultiValue.Meet (
dereferencedValue,
- GetMethodParameterValue (parameterReferenceValue.MethodDefinition, parameterReferenceValue.ParameterIndex));
+ GetMethodParameterValue (parameterReferenceValue.Parameter));
break;
case LocalVariableReferenceValue localVariableReferenceValue:
if (locals.TryGetValue (localVariableReferenceValue.LocalDefinition, out var valueBasicBlockPair))
@@ -1056,11 +1031,6 @@ namespace Mono.Linker.Dataflow
else
dereferencedValue = MultiValue.Meet (dereferencedValue, UnknownValue.Instance);
break;
- case ThisParameterReferenceValue thisParameterReferenceValue:
- dereferencedValue = MultiValue.Meet (
- dereferencedValue,
- GetMethodThisParameterValue (thisParameterReferenceValue.MethodDefinition));
- break;
case ReferenceValue referenceValue:
throw new NotImplementedException ($"Unhandled dereference of ReferenceValue of type {referenceValue.GetType ().FullName}");
// Incomplete handling for ref values
@@ -1087,18 +1057,22 @@ namespace Mono.Linker.Dataflow
int curBasicBlock,
ref InterproceduralState ipState)
{
- MethodDefinition? calledMethodDefinition = _context.Resolve (calledMethod);
- bool methodIsResolved = calledMethodDefinition is not null;
- ILParameterIndex ilArgumentIndex;
- for (SourceParameterIndex parameterIndex = 0; (int) parameterIndex < calledMethod.Parameters.Count; parameterIndex++) {
- ilArgumentIndex = GetILParameterIndex (calledMethod, parameterIndex);
-
- if (calledMethod.ParameterReferenceKind ((int) ilArgumentIndex) is not (ReferenceKind.Ref or ReferenceKind.Out))
- continue;
- SingleValue newByRefValue = methodIsResolved && (int) parameterIndex < calledMethodDefinition!.Parameters.Count
- ? _context.Annotations.FlowAnnotations.GetMethodParameterValue (calledMethodDefinition!, parameterIndex)
- : UnknownValue.Instance;
- StoreInReference (methodArguments[(int) ilArgumentIndex], newByRefValue, callingMethodBody.Method, operation, locals, curBasicBlock, ref ipState);
+ if (_context.TryResolve (calledMethod) is MethodDefinition calledMethodDefinition) {
+ // We resolved the method and can put the ref/out values into the arguments
+ foreach (var parameter in calledMethodDefinition.GetParameters ()) {
+ if (parameter.GetReferenceKind () is not (ReferenceKind.Ref or ReferenceKind.Out))
+ continue;
+ var newByRefValue = _context.Annotations.FlowAnnotations.GetMethodParameterValue (parameter);
+ StoreInReference (methodArguments[(int) parameter.Index], newByRefValue, callingMethodBody.Method, operation, locals, curBasicBlock, ref ipState);
+ }
+ } else {
+ // We couldn't resolve the method, so we put unknown values into the ref and out arguments
+ // Should be a very cold path, so using Linq.Zip should be okay
+ foreach (var (argument, refKind) in methodArguments.Zip (calledMethod.GetParameterReferenceKinds ())) {
+ if (refKind is not (ReferenceKind.Ref or ReferenceKind.Out))
+ continue;
+ StoreInReference (argument, UnknownValue.Instance, callingMethodBody.Method, operation, locals, curBasicBlock, ref ipState);
+ }
}
}
diff --git a/src/linker/Linker.Dataflow/MethodParameterValue.cs b/src/linker/Linker.Dataflow/MethodParameterValue.cs
index 325b02852..8fac8fe64 100644
--- a/src/linker/Linker.Dataflow/MethodParameterValue.cs
+++ b/src/linker/Linker.Dataflow/MethodParameterValue.cs
@@ -1,10 +1,8 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using ILLink.Shared.DataFlow;
-using Mono.Cecil;
+using ILLink.Shared.TypeSystemProxy;
using Mono.Linker.Dataflow;
using TypeDefinition = Mono.Cecil.TypeDefinition;
@@ -17,33 +15,16 @@ namespace ILLink.Shared.TrimAnalysis
/// </summary>
partial record MethodParameterValue : IValueWithStaticType
{
- public MethodParameterValue (TypeDefinition? staticType, MethodDefinition method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ public MethodParameterValue (TypeDefinition? staticType, ParameterProxy param, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, bool overrideIsThis = false)
{
StaticType = staticType;
- Method = method;
- ParameterIndex = parameterIndex;
DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
+ Parameter = param;
+ _overrideIsThis = overrideIsThis;
}
- public readonly MethodDefinition Method;
-
- /// <summary>
- /// This is the index of non-implicit parameter - so the index into MethodDefinition.Parameters array.
- /// It's NOT the IL parameter index which could be offset by 1 if the method has an implicit this.
- /// </summary>
- public readonly int ParameterIndex;
-
- public ParameterDefinition ParameterDefinition => Method.Parameters[ParameterIndex];
-
public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
- public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
- => new string[] { DiagnosticUtilities.GetParameterNameForErrorMessage (ParameterDefinition), DiagnosticUtilities.GetMethodSignatureDisplayName (Method) };
-
public TypeDefinition? StaticType { get; }
-
- public override SingleValue DeepCopy () => this; // This value is immutable
-
- public override string ToString () => this.ValueToString (Method, ParameterIndex, DynamicallyAccessedMemberTypes);
}
} \ No newline at end of file
diff --git a/src/linker/Linker.Dataflow/MethodProxy.cs b/src/linker/Linker.Dataflow/MethodProxy.cs
index 6821613c4..421db0a80 100644
--- a/src/linker/Linker.Dataflow/MethodProxy.cs
+++ b/src/linker/Linker.Dataflow/MethodProxy.cs
@@ -22,13 +22,25 @@ namespace ILLink.Shared.TypeSystemProxy
internal partial bool IsDeclaredOnType (string fullTypeName) => Method.IsDeclaredOnType (fullTypeName);
- internal partial bool HasParameters () => Method.HasParameters;
+ internal partial bool HasMetadataParameters () => Method.HasMetadataParameters ();
- internal partial int GetParametersCount () => Method.Parameters.Count;
+ /// <summary>
+ /// Gets the number of entries in the 'Parameters' section of a method's metadata (i.e. excludes the implicit 'this' from the count)
+ /// </summary>
+ internal partial int GetMetadataParametersCount () => Method.GetMetadataParametersCount ();
- internal partial bool HasParameterOfType (int parameterIndex, string fullTypeName) => Method.HasParameterOfType (parameterIndex, fullTypeName);
+ /// <summary>
+ /// Returns the number of parameters that are passed to the method in IL (including the implicit 'this' parameter).
+ /// In pseudocode: <code>method.HasImplicitThis() ? 1 + MetadataParametersCount : MetadataParametersCount;</code>
+ /// </summary>
+ internal partial int GetParametersCount () => Method.GetParametersCount ();
- internal partial string GetParameterDisplayName (int parameterIndex) => Method.Parameters[parameterIndex].Name;
+ /// <summary>
+ /// Use only when iterating over all parameters. When wanting to index, use GetParameters(ParameterIndex)
+ /// </summary>
+ internal partial ParameterProxyEnumerable GetParameters () => Method.GetParameters ();
+
+ internal partial ParameterProxy GetParameter (ParameterIndex index) => Method.GetParameter (index);
internal partial bool HasGenericParameters () => Method.HasGenericParameters;
@@ -49,12 +61,12 @@ namespace ILLink.Shared.TypeSystemProxy
internal partial bool IsStatic () => Method.IsStatic;
+ internal partial bool HasImplicitThis () => Method.HasImplicitThis ();
+
internal partial bool ReturnsVoid () => Method.ReturnsVoid ();
public override string ToString () => Method.ToString ();
- public ReferenceKind ParameterReferenceKind (int index) => Method.HasImplicitThis () ? Method.ParameterReferenceKind (index + 1) : Method.ParameterReferenceKind (index);
-
public bool Equals (MethodProxy other) => Method.Equals (other.Method);
public override bool Equals (object? obj) => obj is MethodProxy other && Equals (other);
diff --git a/src/linker/Linker.Dataflow/MethodThisParameterValue.cs b/src/linker/Linker.Dataflow/MethodThisParameterValue.cs
deleted file mode 100644
index c2f46d599..000000000
--- a/src/linker/Linker.Dataflow/MethodThisParameterValue.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using ILLink.Shared.DataFlow;
-using Mono.Cecil;
-using Mono.Linker;
-using Mono.Linker.Dataflow;
-using TypeDefinition = Mono.Cecil.TypeDefinition;
-
-
-namespace ILLink.Shared.TrimAnalysis
-{
-
- /// <summary>
- /// A value that came from the implicit this parameter of a method
- /// </summary>
- partial record MethodThisParameterValue : IValueWithStaticType
- {
- public MethodThisParameterValue (MethodDefinition method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- {
- Method = method;
- DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes;
- }
-
- public readonly MethodDefinition Method;
-
- public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
-
- public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
- => new string[] { Method.GetDisplayName () };
-
- public TypeDefinition? StaticType => Method.DeclaringType;
-
- public override SingleValue DeepCopy () => this; // This value is immutable
-
- public override string ToString () => this.ValueToString (Method, DynamicallyAccessedMemberTypes);
- }
-} \ No newline at end of file
diff --git a/src/linker/Linker.Dataflow/ParameterProxy.cs b/src/linker/Linker.Dataflow/ParameterProxy.cs
new file mode 100644
index 000000000..bbcb230a4
--- /dev/null
+++ b/src/linker/Linker.Dataflow/ParameterProxy.cs
@@ -0,0 +1,56 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Mono.Cecil;
+using Mono.Linker;
+
+namespace ILLink.Shared.TypeSystemProxy
+{
+ internal partial struct ParameterProxy
+ {
+ public partial ReferenceKind GetReferenceKind ()
+ {
+ if (IsImplicitThis)
+ return Method.Method.DeclaringType.IsValueType ? ReferenceKind.Ref : ReferenceKind.None;
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- this class provides wrappers to use
+ var param = Method.Method.Parameters[MetadataIndex];
+#pragma warning restore RS0030 // Do not used banned APIs
+ if (!param.ParameterType.IsByReference)
+ return ReferenceKind.None;
+ if (param.IsIn)
+ return ReferenceKind.In;
+ if (param.IsOut)
+ return ReferenceKind.Out;
+ return ReferenceKind.Ref;
+ }
+
+ public TypeReference ParameterType {
+ get {
+ if (IsImplicitThis)
+ return Method.Method.DeclaringType;
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- this class provides wrappers to use
+ return Method.Method.Parameters[MetadataIndex].ParameterType;
+#pragma warning restore RS0030 // Do not used banned APIs
+ }
+ }
+
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- this class provides wrappers to use
+ public partial string GetDisplayName () => IsImplicitThis ? "this"
+ : !string.IsNullOrEmpty (Method.Method.Parameters[MetadataIndex].Name) ? Method.Method.Parameters[MetadataIndex].Name
+ : $"#{Index}";
+#pragma warning restore RS0030 // Do not used banned APIs
+
+ public ICustomAttributeProvider GetCustomAttributeProvider ()
+ {
+ if (IsImplicitThis)
+ return Method.Method;
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- this class provides wrappers to use
+ return Method.Method.Parameters[MetadataIndex];
+#pragma warning restore RS0030 // Do not used banned APIs
+ }
+
+ public partial bool IsTypeOf (string typeName) => ParameterType.IsTypeOf (typeName);
+
+ public bool IsTypeOf (WellKnownType type) => ParameterType.IsTypeOf (type);
+ }
+}
diff --git a/src/linker/Linker.Dataflow/ParameterReferenceValue.cs b/src/linker/Linker.Dataflow/ParameterReferenceValue.cs
index 853b31664..c6ef6ec7e 100644
--- a/src/linker/Linker.Dataflow/ParameterReferenceValue.cs
+++ b/src/linker/Linker.Dataflow/ParameterReferenceValue.cs
@@ -1,12 +1,12 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using ILLink.Shared.DataFlow;
-using Mono.Cecil;
+using ILLink.Shared.TypeSystemProxy;
namespace ILLink.Shared.TrimAnalysis
{
- public partial record ParameterReferenceValue (MethodDefinition MethodDefinition, SourceParameterIndex ParameterIndex)
- : ReferenceValue (MethodDefinition.Parameters[(int) ParameterIndex].ParameterType)
+ internal sealed partial record ParameterReferenceValue (ParameterProxy Parameter)
+ : ReferenceValue (Parameter.ParameterType)
{
public override SingleValue DeepCopy ()
{
diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index 15c5f83d8..f47941755 100644
--- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -93,16 +93,11 @@ namespace Mono.Linker.Dataflow
Debug.Fail ("Invalid IL or a bug in the scanner");
}
- protected override ValueWithDynamicallyAccessedMembers GetMethodThisParameterValue (MethodDefinition method)
- => _annotations.GetMethodThisParameterValue (method);
+ protected override ValueWithDynamicallyAccessedMembers GetMethodParameterValue (ParameterProxy parameter)
+ => GetMethodParameterValue (parameter, _context.Annotations.FlowAnnotations.GetParameterAnnotation (parameter));
- protected override ValueWithDynamicallyAccessedMembers GetMethodParameterValue (MethodDefinition method, SourceParameterIndex parameterIndex)
- => GetMethodParameterValue (method, parameterIndex, _annotations.GetParameterAnnotation (method, parameterIndex));
-
- ValueWithDynamicallyAccessedMembers GetMethodParameterValue (MethodDefinition method, SourceParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- {
- return _annotations.GetMethodParameterValue (method, parameterIndex, dynamicallyAccessedMemberTypes);
- }
+ MethodParameterValue GetMethodParameterValue (ParameterProxy parameter, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => _annotations.GetMethodParameterValue (parameter, dynamicallyAccessedMemberTypes);
protected override MultiValue GetFieldValue (FieldDefinition field) => _annotations.GetFieldValue (field);
@@ -120,9 +115,6 @@ namespace Mono.Linker.Dataflow
protected override void HandleStoreParameter (MethodDefinition method, MethodParameterValue parameter, Instruction operation, MultiValue valueToStore)
=> HandleStoreValueWithDynamicallyAccessedMembers (parameter, operation, valueToStore);
- protected override void HandleStoreMethodThisParameter (MethodDefinition method, MethodThisParameterValue thisParameter, Instruction operation, MultiValue valueToStore)
- => HandleStoreValueWithDynamicallyAccessedMembers (thisParameter, operation, valueToStore);
-
protected override void HandleStoreMethodReturnValue (MethodDefinition method, MethodReturnValue returnValue, Instruction operation, MultiValue valueToStore)
=> HandleStoreValueWithDynamicallyAccessedMembers (returnValue, operation, valueToStore);
@@ -446,9 +438,11 @@ namespace Mono.Linker.Dataflow
private static bool ComDangerousMethod (MethodDefinition methodDefinition, LinkContext context)
{
bool comDangerousMethod = IsComInterop (methodDefinition.MethodReturnType, methodDefinition.ReturnType, context);
+#pragma warning disable RS0030 // MethodDefinition.Parameters is banned. Here we iterate through the parameters and don't need to worry about the 'this' parameter.
foreach (ParameterDefinition pd in methodDefinition.Parameters) {
comDangerousMethod |= IsComInterop (pd, pd.ParameterType, context);
}
+#pragma warning restore RS0030
return comDangerousMethod;
}
diff --git a/src/linker/Linker.Dataflow/SingleValueExtensions.cs b/src/linker/Linker.Dataflow/SingleValueExtensions.cs
index 9dcb0df70..2f976cd4a 100644
--- a/src/linker/Linker.Dataflow/SingleValueExtensions.cs
+++ b/src/linker/Linker.Dataflow/SingleValueExtensions.cs
@@ -44,7 +44,6 @@ namespace ILLink.Shared.TrimAnalysis
case KnownStringValue:
case ConstIntValue:
case MethodParameterValue:
- case MethodThisParameterValue:
case MethodReturnValue:
case GenericParameterValue:
case RuntimeTypeHandleForGenericParameterValue:
diff --git a/src/linker/Linker.Dataflow/ThisParameterReferenceValue.cs b/src/linker/Linker.Dataflow/ThisParameterReferenceValue.cs
deleted file mode 100644
index 727181fbd..000000000
--- a/src/linker/Linker.Dataflow/ThisParameterReferenceValue.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using ILLink.Shared.DataFlow;
-using Mono.Cecil;
-
-namespace ILLink.Shared.TrimAnalysis
-{
- public partial record ThisParameterReferenceValue (MethodDefinition MethodDefinition)
- : ReferenceValue (MethodDefinition.DeclaringType)
- {
- public override SingleValue DeepCopy ()
- {
- return this;
- }
- }
-}
diff --git a/src/linker/Linker.Steps/AddBypassNGenStep.cs b/src/linker/Linker.Steps/AddBypassNGenStep.cs
index e8706e1d6..20d11f64d 100644
--- a/src/linker/Linker.Steps/AddBypassNGenStep.cs
+++ b/src/linker/Linker.Steps/AddBypassNGenStep.cs
@@ -102,7 +102,7 @@ namespace Mono.Linker.Steps
bypassNGenAttributeDef.Methods.Add (bypassNGenAttributeDefaultConstructor);
} else {
foreach (MethodDefinition method in bypassNGenAttributeDef.Methods) {
- if (method.IsConstructor && !method.IsStatic && !method.HasParameters) {
+ if (method.IsConstructor && !method.IsStatic && !method.HasMetadataParameters ()) {
bypassNGenAttributeDefaultConstructor = method;
break;
}
diff --git a/src/linker/Linker.Steps/CodeRewriterStep.cs b/src/linker/Linker.Steps/CodeRewriterStep.cs
index c71624451..6d70b1a09 100644
--- a/src/linker/Linker.Steps/CodeRewriterStep.cs
+++ b/src/linker/Linker.Steps/CodeRewriterStep.cs
@@ -157,8 +157,10 @@ namespace Mono.Linker.Steps
{
var body = new MethodBody (method);
+#pragma warning disable RS0030 // MethodReference.Parameters is banned. This code already works and doesn't need to be changed
if (method.HasParameters && method.Parameters.Any (l => l.IsOut))
throw new NotSupportedException ($"Cannot replace body of method '{method.GetDisplayName ()}' because it has an out parameter.");
+#pragma warning restore RS0030
var il = body.GetLinkerILProcessor ();
if (method.IsInstanceConstructor () && !method.DeclaringType.IsValueType) {
diff --git a/src/linker/Linker.Steps/DescriptorMarker.cs b/src/linker/Linker.Steps/DescriptorMarker.cs
index d48fac85d..ebacbf819 100644
--- a/src/linker/Linker.Steps/DescriptorMarker.cs
+++ b/src/linker/Linker.Steps/DescriptorMarker.cs
@@ -198,12 +198,12 @@ namespace Mono.Linker.Steps
}
sb.Append ("(");
- if (meth.HasParameters) {
- for (int i = 0; i < meth.Parameters.Count; i++) {
- if (i > 0)
+ if (meth.HasMetadataParameters ()) {
+ int i = 0;
+ foreach (var p in meth.GetMetadataParameters ()) {
+ if (i++ > 0)
sb.Append (",");
-
- sb.Append (meth.Parameters[i].ParameterType.FullName);
+ sb.Append (p.ParameterType.FullName);
}
}
sb.Append (")");
diff --git a/src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs b/src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs
index 5811555c6..b6ecb134c 100644
--- a/src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs
+++ b/src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs
@@ -164,7 +164,7 @@ namespace Mono.Linker.Steps
case "True":
case "False":
// Parameter type of a unary operator must be the declaring type
- if (method.Parameters.Count != 1 || NonNullableType (method.Parameters[0].ParameterType) != self)
+ if (method.GetMetadataParametersCount () != 1 || NonNullableType (method.GetParameter ((ParameterIndex) 0).ParameterType) != self)
return false;
// ++ and -- must return the declaring type
if (operatorName is "Increment" or "Decrement" && NonNullableType (method.ReturnType) != self)
@@ -187,10 +187,10 @@ namespace Mono.Linker.Steps
case "GreaterThan":
case "LessThanOrEqual":
case "GreaterThanOrEqual":
- if (method.Parameters.Count != 2)
+ if (method.GetMetadataParametersCount () != 2)
return false;
- var nnLeft = NonNullableType (method.Parameters[0].ParameterType);
- var nnRight = NonNullableType (method.Parameters[1].ParameterType);
+ var nnLeft = NonNullableType (method.GetParameter ((ParameterIndex) 0).ParameterType);
+ var nnRight = NonNullableType (method.GetParameter ((ParameterIndex) 1).ParameterType);
if (nnLeft == null || nnRight == null)
return false;
// << and >> must take the declaring type and int
@@ -207,9 +207,9 @@ namespace Mono.Linker.Steps
// Conversion operators
case "Implicit":
case "Explicit":
- if (method.Parameters.Count != 1)
+ if (method.GetMetadataParametersCount () != 1)
return false;
- var nnSource = NonNullableType (method.Parameters[0].ParameterType);
+ var nnSource = NonNullableType (method.GetParameter ((ParameterIndex) 0).ParameterType);
var nnTarget = NonNullableType (method.ReturnType);
// Exactly one of source/target must be the declaring type
if (nnSource == self == (nnTarget == self))
diff --git a/src/linker/Linker.Steps/LinkAttributesParser.cs b/src/linker/Linker.Steps/LinkAttributesParser.cs
index 81b89e292..6de2fde31 100644
--- a/src/linker/Linker.Steps/LinkAttributesParser.cs
+++ b/src/linker/Linker.Steps/LinkAttributesParser.cs
@@ -145,7 +145,9 @@ namespace Mono.Linker.Steps
var ctorN = new MethodDefinition (".ctor", ctorAttributes, voidType);
var paramN = new ParameterDefinition (objectArrayType);
+#pragma warning disable RS0030 // MethodReference.Parameters is banned. It's necessary to build the method definition here, though.
ctorN.Parameters.Add (paramN);
+#pragma warning restore RS0030
td.Methods.Add (ctorN);
return _context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition = td;
@@ -178,17 +180,16 @@ namespace Mono.Linker.Steps
if (!method.IsInstanceConstructor ())
continue;
- var parameters = method.Parameters;
- if (args.Length != parameters.Count)
+ if (args.Length != method.GetMetadataParametersCount ())
continue;
bool match = true;
- for (int ii = 0; match && ii < args.Length; ++ii) {
+ foreach (var p in method.GetMetadataParameters ()) {
//
// No candidates betterness, only exact matches are supported
//
- var parameterType = _context.TryResolve (parameters[ii].ParameterType);
- if (parameterType == null || parameterType != _context.TryResolve (args[ii].Type))
+ var parameterType = _context.TryResolve (p.ParameterType);
+ if (parameterType == null || parameterType != _context.TryResolve (args[p.MetadataIndex].Type))
match = false;
}
@@ -496,6 +497,7 @@ namespace Mono.Linker.Steps
var (attributes, origins) = ProcessAttributes (parameterNav, method);
if (attributes != null && origins != null) {
string paramName = GetAttribute (parameterNav, "name");
+#pragma warning disable RS0030 // MethodReference.Parameters is banned. It's easiest to leave existing code as is
foreach (ParameterDefinition parameter in method.Parameters) {
if (paramName == parameter.Name) {
if (parameter.HasCustomAttributes || _attributeInfo.CustomAttributes.ContainsKey (parameter))
@@ -504,6 +506,7 @@ namespace Mono.Linker.Steps
break;
}
}
+#pragma warning restore RS0030
}
}
}
@@ -531,6 +534,7 @@ namespace Mono.Linker.Steps
return null;
}
+#pragma warning disable RS0030 // MethdReference.Parameters is banned. It's easiest to leave existing code as is.
static string GetMethodSignature (MethodDefinition method, bool includeReturnType = false)
{
StringBuilder sb = new StringBuilder ();
@@ -549,7 +553,7 @@ namespace Mono.Linker.Steps
sb.Append (">");
}
sb.Append ("(");
- if (method.HasParameters) {
+ if (method.HasMetadataParameters ()) {
for (int i = 0; i < method.Parameters.Count; i++) {
if (i > 0)
sb.Append (",");
@@ -560,6 +564,7 @@ namespace Mono.Linker.Steps
sb.Append (")");
return sb.ToString ();
}
+#pragma warning restore RS0030
protected override void ProcessProperty (TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object? customData, bool fromSignature)
{
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index 5d4065d35..71b6e48d4 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -1082,19 +1082,18 @@ namespace Mono.Linker.Steps
continue;
}
- var mp = m.Parameters;
- if (mp.Count != signature.Length)
+ if (m.GetMetadataParametersCount () != signature.Length)
continue;
- int i = 0;
- for (; i < signature.Length; ++i) {
- if (mp[i].ParameterType.FullName != signature[i].Trim ().ToCecilName ()) {
- i = -1;
+ bool matched = true;
+ foreach (var p in m.GetMetadataParameters ()) {
+ if (p.ParameterType.FullName != signature[p.MetadataIndex].Trim ().ToCecilName ()) {
+ matched = false;
break;
}
}
- if (i < 0)
+ if (!matched)
continue;
MarkIndirectlyCalledMethod (m, reason, ScopeStack.CurrentScope.Origin);
@@ -1316,7 +1315,7 @@ namespace Mono.Linker.Steps
{
TypeDefinition? type = inputType;
while (type != null) {
- MethodDefinition? method = type.Methods.FirstOrDefault (m => m.Name == methodname && !m.HasParameters);
+ MethodDefinition? method = type.Methods.FirstOrDefault (m => m.Name == methodname && !m.HasMetadataParameters ());
if (method != null)
return method;
@@ -2477,12 +2476,11 @@ namespace Mono.Linker.Steps
if (!method.IsInstanceConstructor ())
return false;
- var parameters = method.Parameters;
- if (parameters.Count != 2)
+ if (method.GetMetadataParametersCount () != 2)
return false;
- return parameters[0].ParameterType.Name == "SerializationInfo" &&
- parameters[1].ParameterType.Name == "StreamingContext";
+ return method.TryGetParameter ((ParameterIndex) 1)?.ParameterType.Name == "SerializationInfo" &&
+ method.TryGetParameter ((ParameterIndex) 2)?.ParameterType.Name == "StreamingContext";
}
protected internal bool MarkMethodsIf (Collection<MethodDefinition> methods, Func<MethodDefinition, bool> predicate, in DependencyInfo reason, in MessageOrigin origin)
@@ -2521,8 +2519,12 @@ namespace Mono.Linker.Steps
if (!type.HasMethods)
return;
- MarkMethodIf (type.Methods, m =>
- m.Name == "GetInstance" && m.IsStatic && m.Parameters.Count == 1 && m.Parameters[0].ParameterType.MetadataType == MetadataType.String,
+ MarkMethodIf (type.Methods,
+ m =>
+ m.Name == "GetInstance"
+ && m.IsStatic
+ && m.GetMetadataParametersCount () == 1
+ && m.GetParameter ((ParameterIndex) 0).ParameterType.MetadataType == MetadataType.String,
reason,
ScopeStack.CurrentScope.Origin);
}
@@ -3150,12 +3152,14 @@ namespace Mono.Linker.Steps
else if (method.TryGetEvent (out EventDefinition? @event))
MarkEvent (@event, new DependencyInfo (DependencyKind.EventOfEventMethod, method));
- if (method.HasParameters) {
+ if (method.HasMetadataParameters ()) {
+#pragma warning disable RS0030 // MethodReference.Parameters is banned. It's easiest to leave the code as is for now
foreach (ParameterDefinition pd in method.Parameters) {
MarkType (pd.ParameterType, new DependencyInfo (DependencyKind.ParameterType, method));
MarkCustomAttributes (pd, new DependencyInfo (DependencyKind.ParameterAttribute, method));
MarkMarshalSpec (pd, new DependencyInfo (DependencyKind.ParameterMarshalSpec, method));
}
+#pragma warning restore RS0030
}
if (method.HasOverrides) {
@@ -3397,6 +3401,7 @@ namespace Mono.Linker.Steps
MarkFields (method.DeclaringType, includeStaticFields, new DependencyInfo (DependencyKind.InteropMethodDependency, method));
}
+#pragma warning disable RS0030 // MethodReference.Parameters is banned. It's easiest to leave this code as is for now
foreach (ParameterDefinition pd in method.Parameters) {
TypeReference paramTypeReference = pd.ParameterType;
if (paramTypeReference is TypeSpecification paramTypeSpecification) {
@@ -3413,6 +3418,7 @@ namespace Mono.Linker.Steps
}
}
}
+#pragma warning restore RS0030
}
protected virtual bool ShouldParseMethodBody (MethodDefinition method)
diff --git a/src/linker/Linker.Steps/SweepStep.cs b/src/linker/Linker.Steps/SweepStep.cs
index de9a4f0bd..a42d74f29 100644
--- a/src/linker/Linker.Steps/SweepStep.cs
+++ b/src/linker/Linker.Steps/SweepStep.cs
@@ -431,17 +431,19 @@ namespace Mono.Linker.Steps
SweepOverrides (method);
- if (!method.HasParameters)
+ if (!method.HasMetadataParameters ())
continue;
bool sweepNames = CanSweepNamesForMember (method, MetadataTrimming.ParameterName);
+#pragma warning disable RS0030 // MethodReference.Parameters is banned. It makes sense to use when directly working with the Cecil type system though.
foreach (var parameter in method.Parameters) {
if (sweepNames)
parameter.Name = null;
SweepCustomAttributes (parameter);
}
+#pragma warning restore RS0030
}
}
void SweepOverrides (MethodDefinition method)
diff --git a/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs b/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs
index d6bc01798..43f59dd25 100644
--- a/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs
+++ b/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs
@@ -238,7 +238,7 @@ namespace Mono.Linker.Steps
MethodResult? value;
MethodDefinition method = callee.Method;
- if (!method.HasParameters || callee.HasUnknownArguments) {
+ if (!method.HasMetadataParameters () || callee.HasUnknownArguments) {
if (!_cache_method_results.TryGetValue (method, out value) && !IsDeepStack (callStack)) {
value = AnalyzeMethodForConstantResult (callee, callStack);
_cache_method_results.Add (method, value);
@@ -310,21 +310,21 @@ namespace Mono.Linker.Steps
static Instruction[]? GetArgumentsOnStack (MethodDefinition method, Collection<Instruction> instructions, int index)
{
- if (!method.HasParameters)
+ if (!method.HasMetadataParameters ())
return Array.Empty<Instruction> ();
Instruction[]? result = null;
- for (int i = method.Parameters.Count, pos = 0; i != 0; --i, ++pos) {
+ for (int i = method.GetMetadataParametersCount (), pos = 0; i != 0; --i, ++pos) {
Instruction instr = instructions[index - i];
if (!IsConstantValue (instr))
return null;
- result ??= new Instruction[method.Parameters.Count];
+ result ??= new Instruction[method.GetMetadataParametersCount ()];
result[pos] = instr;
}
- if (result != null && HasJumpIntoTargetRange (instructions, index - method.Parameters.Count + 1, index))
+ if (result != null && HasJumpIntoTargetRange (instructions, index - method.GetMetadataParametersCount () + 1, index))
return null;
return result;
@@ -415,7 +415,7 @@ namespace Mono.Linker.Steps
if (type == null)
return null;
- return type.Methods.First (l => !l.HasParameters && l.IsStatic && l.Name == "get_Size");
+ return type.Methods.First (l => !l.HasMetadataParameters () && l.IsStatic && l.Name == "get_Size");
}
readonly struct CallInliner
@@ -465,7 +465,7 @@ namespace Mono.Linker.Steps
}
if (!md.IsStatic) {
- if (!md.HasParameters && CanInlineInstanceCall (instrs, i)) {
+ if (!md.HasMetadataParameters () && CanInlineInstanceCall (instrs, i)) {
processor.Replace (i - 1, Instruction.Create (OpCodes.Nop));
processor.Replace (i, result.GetPrototype ()!);
changed = true;
@@ -474,11 +474,11 @@ namespace Mono.Linker.Steps
continue;
}
- if (md.HasParameters) {
+ if (md.HasMetadataParameters ()) {
if (!IsCalledWithoutSideEffects (md, instrs, i))
continue;
- for (int p = 1; p <= md.Parameters.Count; ++p) {
+ for (int p = 1; p <= md.GetMetadataParametersCount (); ++p) {
processor.Replace (i - p, Instruction.Create (OpCodes.Nop));
}
}
@@ -516,7 +516,7 @@ namespace Mono.Linker.Steps
static bool IsCalledWithoutSideEffects (MethodDefinition method, Collection<Instruction> instructions, int index)
{
- for (int i = 1; i <= method.Parameters.Count; ++i) {
+ for (int i = 1; i <= method.GetMetadataParametersCount (); ++i) {
if (!IsSideEffectFreeLoad (instructions[index - i]))
return false;
}
@@ -1655,7 +1655,7 @@ namespace Mono.Linker.Steps
return false;
Instruction[]? args;
- if (!md.HasParameters) {
+ if (!md.HasMetadataParameters ()) {
args = Array.Empty<Instruction> ();
} else {
//
@@ -1816,7 +1816,7 @@ namespace Mono.Linker.Steps
Instruction[]? GetArgumentsOnStack (MethodDefinition method)
{
- int length = method.Parameters.Count;
+ int length = method.GetMetadataParametersCount ();
Debug.Assert (length != 0);
if (stack_instr?.Count < length)
return null;
diff --git a/src/linker/Linker/BCL.cs b/src/linker/Linker/BCL.cs
index f3351ca87..a14cbc780 100644
--- a/src/linker/Linker/BCL.cs
+++ b/src/linker/Linker/BCL.cs
@@ -51,7 +51,7 @@ namespace Mono.Linker
if (method.Name != "Dispose" || method.ReturnType.MetadataType != MetadataType.Void)
return false;
- if (method.HasParameters || method.HasGenericParameters || method.IsStatic)
+ if (method.HasMetadataParameters () || method.HasGenericParameters || method.IsStatic)
return false;
if (!method.IsFinal)
diff --git a/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs b/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs
index 0784e23a1..802b119c6 100644
--- a/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs
+++ b/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs
@@ -85,8 +85,10 @@ namespace Mono.Linker
if (method.HasGenericParameters)
builder.Append ("``").Append (method.GenericParameters.Count);
- if (method.HasParameters || (method.CallingConvention == MethodCallingConvention.VarArg))
+ if (method.HasMetadataParameters () || (method.CallingConvention == MethodCallingConvention.VarArg))
+#pragma warning disable RS0030 // MethodReference.Parameters is banned. This generates documentation signatures, so it's okay to use it here
VisitParameters (method.Parameters, method.CallingConvention == MethodCallingConvention.VarArg, builder, resolver);
+#pragma warning restore RS0030
if (method.Name == "op_Implicit" || method.Name == "op_Explicit") {
builder.Append ('~');
diff --git a/src/linker/Linker/DocumentationSignatureParser.cs b/src/linker/Linker/DocumentationSignatureParser.cs
index 7ca001900..fe599d0ff 100644
--- a/src/linker/Linker/DocumentationSignatureParser.cs
+++ b/src/linker/Linker/DocumentationSignatureParser.cs
@@ -564,8 +564,10 @@ namespace Mono.Linker
if (!isNameOnly || !acceptName) {
// check parameters unless we are matching a name only
+#pragma warning disable RS0030 // Do not used banned APIs
if (!AllParametersMatch (method.Parameters, parameters, resolver))
continue;
+#pragma warning restore RS0030 // Do not used banned APIs
}
results.Add (method);
diff --git a/src/linker/Linker/ILParameterIndex.cs b/src/linker/Linker/ILParameterIndex.cs
deleted file mode 100644
index 3d9da48f4..000000000
--- a/src/linker/Linker/ILParameterIndex.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Mono.Linker
-{
- /// <summary>
- /// Represents the index of arguments passed to a function in IL (i.e. (ILParameterIndex)0 represents `this` for non-static methods.
- /// This is used to enforce a differentiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system.
- /// There are no named enum values, the underlying integer value represents the index value.
- /// Generally prefer to use <see cref="ILLink.Shared.SourceParameterIndex"/> when possible.
- /// See also <seealso cref="Mono.Linker.ParameterHelpers"/>.
- /// </summary>
- /// <example>
- /// In a call to a non-static function Foo(int a, int b, int c)
- /// 0 refers to `this`,
- /// 1 refers to a,
- /// 2 refers to b.
- /// 3 referes to c.
- /// </example>
- public enum ILParameterIndex
- { }
-}
diff --git a/src/linker/Linker/KnownMembers.cs b/src/linker/Linker/KnownMembers.cs
index 4e4b85c6a..6e2a3777a 100644
--- a/src/linker/Linker/KnownMembers.cs
+++ b/src/linker/Linker/KnownMembers.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
namespace Mono.Linker
@@ -15,10 +16,10 @@ namespace Mono.Linker
public static bool IsNotSupportedExceptionCtorString (MethodDefinition method)
{
- if (!method.IsConstructor || method.IsStatic || !method.HasParameters)
+ if (!method.IsConstructor || method.IsStatic || !method.HasMetadataParameters ())
return false;
- if (method.Parameters.Count != 1 || method.Parameters[0].ParameterType.MetadataType != MetadataType.String)
+ if (method.GetMetadataParametersCount () != 1 || method.GetParameter ((ParameterIndex) 1).ParameterType.MetadataType != MetadataType.String)
return false;
return true;
diff --git a/src/linker/Linker/MethodBodyScanner.cs b/src/linker/Linker/MethodBodyScanner.cs
index 318c0930b..8f2aa05a6 100644
--- a/src/linker/Linker/MethodBodyScanner.cs
+++ b/src/linker/Linker/MethodBodyScanner.cs
@@ -106,8 +106,8 @@ namespace Mono.Linker
foreach (VariableDefinition var in body.Variables)
AddIfResolved (types, var.VariableType);
- foreach (var parameter in body.Method.Parameters)
- AddIfResolved (types, parameter.ParameterType);
+ foreach (var param in method.GetParameters ())
+ AddIfResolved (types, param.ParameterType);
foreach (ExceptionHandler eh in body.ExceptionHandlers) {
if (eh.HandlerType == ExceptionHandlerType.Catch) {
@@ -128,8 +128,8 @@ namespace Mono.Linker
var resolvedMethod = context.TryResolve (methodReference);
if (resolvedMethod != null) {
- if (resolvedMethod.HasParameters) {
- foreach (var param in resolvedMethod.Parameters)
+ if (resolvedMethod.HasMetadataParameters ()) {
+ foreach (var param in resolvedMethod.GetParameters ())
AddIfResolved (types, param.ParameterType);
}
diff --git a/src/linker/Linker/MethodDefinitionExtensions.cs b/src/linker/Linker/MethodDefinitionExtensions.cs
index 814d390d8..28ad55c65 100644
--- a/src/linker/Linker/MethodDefinitionExtensions.cs
+++ b/src/linker/Linker/MethodDefinitionExtensions.cs
@@ -1,16 +1,19 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
namespace Mono.Linker
{
- public static class MethodDefinitionExtensions
+ [SuppressMessage ("ApiDesign", "RS0030:Do not used banned APIs", Justification = "This class provides wrapper methods around the banned Parameters property")]
+ internal static class MethodDefinitionExtensions
{
public static bool IsDefaultConstructor (this MethodDefinition method)
{
- return IsInstanceConstructor (method) && !method.HasParameters;
+ return IsInstanceConstructor (method) && !method.HasMetadataParameters ();
}
public static bool IsInstanceConstructor (this MethodDefinition method)
@@ -98,5 +101,50 @@ namespace Mono.Linker
di.Scope = null;
}
}
+
+ public static bool HasParameterOfType (this MethodDefinition method, ParameterIndex index, string typeName)
+ => method.TryGetParameter (index)?.ParameterType?.IsTypeOf (typeName) is true;
+
+ /// <summary>
+ /// Tries to get the <see cref="ParameterProxy"/> representing the parameter at index <paramref name="index"/> of method <paramref name="method"/>.
+ /// Returns null if <paramref name="index"/> is not a valid parameter index for <paramref name="method"/>.
+ /// <see cref="GetParameter(MethodDefinition, ParameterIndex)"/> for a non-nullable version if you know the index is valid.
+ /// </summary>
+ public static ParameterProxy? TryGetParameter (this MethodDefinition method, ParameterIndex index)
+ {
+ if (method.GetParametersCount () <= (int) index || (int) index < 0)
+ return null;
+ return new (new (method), index);
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ParameterProxy"/> representing the parameter at index <paramref name="index"/> of method <paramref name="method"/>.
+ /// Throws if <paramref name="index"/> is not a valid parameter index for <paramref name="method"/>.
+ /// <see cref="TryGetParameter(MethodDefinition, ParameterIndex)"/> for a non-throwing version if you're not sure the parameter exists on the method.
+ /// </summary>
+ public static ParameterProxy GetParameter (this MethodDefinition method, ParameterIndex index)
+ {
+ if (method.TryGetParameter (index) is not ParameterProxy param)
+ throw new InvalidOperationException ($"Cannot get parameter #{(int) index} of method {method.GetDisplayName ()} with {method.GetParametersCount ()} parameters");
+ return param;
+ }
+
+ /// <summary>
+ /// Returns a foreach-enumerable collection of the parameters pushed onto the stack before the method call (including the implicit 'this' parameter)
+ /// </summary>
+ public static ParameterProxyEnumerable GetParameters (this MethodDefinition method)
+ {
+ int implicitThisOffset = method.HasImplicitThis () ? 1 : 0;
+ return new ParameterProxyEnumerable (0, method.Parameters.Count + implicitThisOffset, method);
+ }
+
+ /// <summary>
+ /// Returns a list of ParameterProxy representing the parameters listed in the "Parameters" metadata section (i.e. not including the implicit 'this' parameter)
+ /// </summary>
+ public static ParameterProxyEnumerable GetMetadataParameters (this MethodDefinition method)
+ {
+ int implicitThisOffset = method.HasImplicitThis () ? 1 : 0;
+ return new ParameterProxyEnumerable (implicitThisOffset, method.Parameters.Count + implicitThisOffset, method);
+ }
}
}
diff --git a/src/linker/Linker/MethodReferenceExtensions.cs b/src/linker/Linker/MethodReferenceExtensions.cs
index 0911a84cd..740d5bbcc 100644
--- a/src/linker/Linker/MethodReferenceExtensions.cs
+++ b/src/linker/Linker/MethodReferenceExtensions.cs
@@ -2,13 +2,13 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
-using ILLink.Shared;
+using System.Collections.Generic;
using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
namespace Mono.Linker
{
- public static class MethodReferenceExtensions
+ internal static class MethodReferenceExtensions
{
public static string GetDisplayName (this MethodReference method)
{
@@ -43,11 +43,12 @@ namespace Mono.Linker
// Append parameters
sb.Append ("(");
- if (method.HasParameters) {
+ if (method.HasMetadataParameters ()) {
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- it's best to leave this as is for now
for (int i = 0; i < method.Parameters.Count - 1; i++)
sb.Append (method.Parameters[i].ParameterType.GetDisplayNameWithoutNamespace ()).Append (", ");
-
sb.Append (method.Parameters[method.Parameters.Count - 1].ParameterType.GetDisplayNameWithoutNamespace ());
+#pragma warning restore RS0030 // Do not used banned APIs
}
sb.Append (")");
@@ -83,51 +84,71 @@ namespace Mono.Linker
return method.ReturnType.WithoutModifiers ().MetadataType == MetadataType.Void;
}
- public static TypeReference? GetInflatedParameterType (this MethodReference method, int index, LinkContext context)
+ public static TypeReference? GetInflatedParameterType (this MethodReference method, int parameterIndex, LinkContext context)
{
- var uninflatedParameterType = method.GetParameterType ((SourceParameterIndex) index);
- if (method.DeclaringType is GenericInstanceType genericInstance) {
- return TypeReferenceExtensions.InflateGenericType (genericInstance, uninflatedParameterType, context);
- }
- return uninflatedParameterType;
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- it's best to leave this as is for now
+ if (method.DeclaringType is GenericInstanceType genericInstance)
+ return TypeReferenceExtensions.InflateGenericType (genericInstance, method.Parameters[parameterIndex].ParameterType, context);
+
+ return method.Parameters[parameterIndex].ParameterType;
+#pragma warning restore RS0030 // Do not used banned APIs
}
- public static TypeReference GetParameterType (this MethodReference method, SourceParameterIndex index)
- => method.Parameters[(int) index].ParameterType;
+ /// <summary>
+ /// Gets the number of entries in the 'Parameters' section of a method's metadata (i.e. excludes the implicit 'this' from the count)
+ /// </summary>
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- this provides a wrapper
+ public static int GetMetadataParametersCount (this MethodReference method)
+ => method.Parameters.Count;
+#pragma warning restore RS0030 // Do not used banned APIs
+
+ /// <summary>
+ /// Returns true if the method has any parameters in the .parameters section of the method's metadata
+ /// </summary>
+ public static bool HasMetadataParameters (this MethodReference method)
+ => method.GetMetadataParametersCount () != 0;
+
+ /// <summary>
+ /// Returns a list of the parameters in the method's 'parameters' metadata section (i.e. excluding the implicit 'this' parameter)
+ /// </summary>
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- this provides a wrapper
+ public static int GetParametersCount (this MethodReference method)
+ => method.Parameters.Count + (method.HasImplicitThis () ? 1 : 0);
+#pragma warning restore RS0030 // Do not used banned APIs
public static bool IsDeclaredOnType (this MethodReference method, string fullTypeName)
{
return method.DeclaringType.IsTypeOf (fullTypeName);
}
- public static bool HasParameterOfType (this MethodReference method, int parameterIndex, string fullTypeName)
- {
- return method.Parameters.Count > parameterIndex && method.Parameters[parameterIndex].ParameterType.IsTypeOf (fullTypeName);
- }
-
public static bool HasImplicitThis (this MethodReference method)
{
return method.HasThis && !method.ExplicitThis;
}
/// <summary>
- /// Returns the ReferenceKind of a parameter (in, out, ref, none) of a method. Uses the IL based index number (i.e. `this` is 0 if there is a `this`, then 1 is the first parameter)
+ /// Returns an IEnumerable of the ReferenceKind of each parameter, with the first being for the implicit 'this' parameter if it exists
+ /// Used for better performance when it's only necessary to get the ReferenceKind of all parameters and nothing else.
/// </summary>
- public static ReferenceKind ParameterReferenceKind (this MethodReference method, int index)
+ public static IEnumerable<ReferenceKind> GetParameterReferenceKinds (this MethodReference method)
{
- if (method.HasImplicitThis ()) {
- if (index == 0)
- return method.DeclaringType.IsValueType ? ReferenceKind.Ref : ReferenceKind.None;
- index--;
+ if (method.HasImplicitThis ())
+ yield return method.DeclaringType.IsValueType ? ReferenceKind.Ref : ReferenceKind.None;
+#pragma warning disable RS0030 // MethodReference.Parameters is banned -- this provides a wrapper
+ foreach (var parameter in method.Parameters)
+ yield return GetReferenceKind (parameter);
+#pragma warning restore RS0030 // Do not used banned APIs
+
+ static ReferenceKind GetReferenceKind (ParameterDefinition param)
+ {
+ if (!param.ParameterType.IsByReference)
+ return ReferenceKind.None;
+ if (param.IsIn)
+ return ReferenceKind.In;
+ if (param.IsOut)
+ return ReferenceKind.Out;
+ return ReferenceKind.Ref;
}
- var param = method.Parameters[index];
- if (!param.ParameterType.IsByReference)
- return ReferenceKind.None;
- if (param.IsIn)
- return ReferenceKind.In;
- if (param.IsOut)
- return ReferenceKind.Out;
- return ReferenceKind.Ref;
}
}
}
diff --git a/src/linker/Linker/ParameterHelpers.cs b/src/linker/Linker/ParameterHelpers.cs
index eeca9c28c..ba4bec06e 100644
--- a/src/linker/Linker/ParameterHelpers.cs
+++ b/src/linker/Linker/ParameterHelpers.cs
@@ -2,7 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
-using ILLink.Shared;
+using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -10,7 +10,7 @@ namespace Mono.Linker
{
public static class ParameterHelpers
{
- public static ILParameterIndex GetILParameterIndex (MethodDefinition thisMethod, Instruction operation)
+ public static ParameterIndex GetParameterIndex (MethodDefinition thisMethod, Instruction operation)
{
// Thank you Cecil, Operand being a ParameterDefinition instead of an integer,
// (except for Ldarg_0 - Ldarg_3, where it's null) makes all of this really convenient...
@@ -31,58 +31,18 @@ namespace Mono.Linker
or Code.Ldarga_S
=> GetParamSequence (),
- _ => throw new ArgumentException ($"{nameof (ILParameterIndex)} expected an ldarg or starg instruction, got {operation.OpCode.Name}")
+ _ => throw new ArgumentException ($"{nameof (GetParameterIndex)} expected an ldarg or starg instruction, got {operation.OpCode.Name}")
};
- ILParameterIndex GetLdargParamIndex ()
+ ParameterIndex GetLdargParamIndex ()
{
- return (ILParameterIndex) (code - Code.Ldarg_0);
+ return (ParameterIndex) (code - Code.Ldarg_0);
}
- ILParameterIndex GetParamSequence ()
+ ParameterIndex GetParamSequence ()
{
ParameterDefinition param = (ParameterDefinition) operation.Operand;
- return (ILParameterIndex) param.Sequence;
+ return (ParameterIndex) param.Sequence;
}
}
-
- /// <Summary>
- /// This enum is used when converting from an ILParameterIndex to a SourceParamterIndex to
- /// differentiate `This` parameters from other parameters.
- /// </Summary>
- public enum SourceParameterKind
- {
- This,
- Numbered
- }
-
- /// <summary>
- /// Used to get the SourceParameterIndex that an instruction refers to.
- /// If the return value is <see cref="SourceParameterKind.Numbered" />, the instruction refers to a numbered non-this parameter and <paramref name="sourceParameterIndex"/> will have a valid value.
- /// If the return value is <see cref="SourceParameterKind.This" />, the instruction refers to the `this` parameter, and <paramref name="sourceParameterIndex"/> will not have a valid value.
- /// </summary>
- public static SourceParameterKind GetSourceParameterIndex (MethodDefinition method, Instruction operation, out SourceParameterIndex sourceParameterIndex)
- => GetSourceParameterIndex (method, GetILParameterIndex (method, operation), out sourceParameterIndex);
-
- /// <summary>
- /// Used to get the SourceParameterIndex that an ILParameterIndex refers to.
- /// If the return value is <see cref="SourceParameterKind.Numbered" />, the instruction refers to a numbered non-this parameter and <paramref name="sourceParameterIndex"/> will have a valid value.
- /// If the return value is <see cref="SourceParameterKind.This" />, the instruction refers to the `this` parameter, and <paramref name="sourceParameterIndex"/> will not have a valid value.
- /// </summary>
- public static SourceParameterKind GetSourceParameterIndex (MethodReference method, ILParameterIndex ilIndex, out SourceParameterIndex sourceParameterIndex)
- {
- sourceParameterIndex = (SourceParameterIndex) (int) ilIndex;
- if (method.HasImplicitThis ()) {
- if (ilIndex == 0) {
- return SourceParameterKind.This;
- }
- sourceParameterIndex--;
- }
- return SourceParameterKind.Numbered;
- }
-
- public static ILParameterIndex GetILParameterIndex (MethodReference method, SourceParameterIndex sourceIndex)
- => method.HasImplicitThis ()
- ? (ILParameterIndex) (sourceIndex + 1)
- : (ILParameterIndex) sourceIndex;
}
}
diff --git a/src/linker/Linker/TypeMapInfo.cs b/src/linker/Linker/TypeMapInfo.cs
index 75613e2c0..c8ef8cc8f 100644
--- a/src/linker/Linker/TypeMapInfo.cs
+++ b/src/linker/Linker/TypeMapInfo.cs
@@ -30,6 +30,7 @@
//
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using Mono.Cecil;
namespace Mono.Linker
@@ -317,9 +318,10 @@ namespace Mono.Linker
return null;
}
+ [SuppressMessage ("ApiDesign", "RS0030:Do not used banned APIs", Justification = "It's best to leave working code alone.")]
bool MethodMatch (MethodReference candidate, MethodReference method)
{
- if (candidate.HasParameters != method.HasParameters)
+ if (candidate.HasParameters != method.HasMetadataParameters ())
return false;
if (candidate.Name != method.Name)
@@ -335,7 +337,7 @@ namespace Mono.Linker
!TypeMatch (candidateReturnType, methodReturnType))
return false;
- if (!candidate.HasParameters)
+ if (!candidate.HasMetadataParameters ())
return true;
var cp = candidate.Parameters;
diff --git a/src/linker/Linker/TypeReferenceExtensions.cs b/src/linker/Linker/TypeReferenceExtensions.cs
index 17fcc766b..d93a7578d 100644
--- a/src/linker/Linker/TypeReferenceExtensions.cs
+++ b/src/linker/Linker/TypeReferenceExtensions.cs
@@ -291,8 +291,10 @@ namespace Mono.Linker
CallingConvention = methodDef.CallingConvention
};
+#pragma warning disable RS0030 // MethodReference.Parameters is banned. It makes sense to use when needing to directly use Cecil's api.
foreach (var parameter in methodDef.Parameters)
method.Parameters.Add (new ParameterDefinition (parameter.Name, parameter.Attributes, parameter.ParameterType));
+#pragma warning restore RS0030
foreach (var gp in methodDef.GenericParameters)
method.GenericParameters.Add (new GenericParameter (gp.Name, method));
@@ -308,7 +310,7 @@ namespace Mono.Linker
public static bool HasDefaultConstructor (this TypeDefinition type, LinkContext context)
{
foreach (var m in type.Methods) {
- if (m.HasParameters)
+ if (m.HasMetadataParameters ())
continue;
var definition = context.Resolve (m);
@@ -322,7 +324,7 @@ namespace Mono.Linker
public static MethodReference GetDefaultInstanceConstructor (this TypeDefinition type, LinkContext context)
{
foreach (var m in type.Methods) {
- if (m.HasParameters)
+ if (m.HasMetadataParameters ())
continue;
var definition = context.Resolve (m);
diff --git a/src/linker/Linker/TypeReferenceWalker.cs b/src/linker/Linker/TypeReferenceWalker.cs
index c4ad8e58d..700e2c716 100644
--- a/src/linker/Linker/TypeReferenceWalker.cs
+++ b/src/linker/Linker/TypeReferenceWalker.cs
@@ -96,9 +96,10 @@ namespace Mono.Linker
foreach (var mo in m.Overrides)
WalkMethodReference (mo);
}
-
- if (m.HasParameters)
+#pragma warning disable RS0030 // MethodReference.Parameters is banned - It's best to leave this as is
+ if (m.HasMetadataParameters ())
WalkTypeScope (m.Parameters);
+#pragma warning restore RS0030
if (m.HasBody)
WalkTypeScope (m.Body);
@@ -216,8 +217,10 @@ namespace Mono.Linker
WalkScopeOfTypeReference (tr);
}
- if (mr.HasParameters) {
+ if (mr.HasMetadataParameters ()) {
+#pragma warning disable RS0030 // MethedReference.Parameters is banned. Best to leave working code as is.
WalkTypeScope (mr.Parameters);
+#pragma warning restore RS0030 // Do not used banned APIs
}
}