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:
authorMarek Safar <marek.safar@gmail.com>2021-05-08 09:26:38 +0300
committerGitHub <noreply@github.com>2021-05-08 09:26:38 +0300
commitfafb6cf6a385a8c753faa174b9ab7c3600a9d494 (patch)
tree15df162f348d2c147acc2e7b9afc8ecd525beb78
parenta5f4931bc577ca94d05cd6b64e810c5cc4f035bb (diff)
Trim parameter names metadata when they are not needed. (#1988)
Co-authored-by: Vitek Karas <vitek.karas@microsoft.com>
-rw-r--r--docs/error-codes.md2
-rw-r--r--src/ILLink.Tasks/LinkTask.cs10
-rw-r--r--src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs2
-rw-r--r--src/linker/Linker.Steps/MarkStep.cs10
-rw-r--r--src/linker/Linker.Steps/RootAssemblyInputStep.cs3
-rw-r--r--src/linker/Linker.Steps/SweepStep.cs13
-rw-r--r--src/linker/Linker/Annotations.cs11
-rw-r--r--src/linker/Linker/Driver.cs41
-rw-r--r--src/linker/Linker/FeatureSettings.cs2
-rw-r--r--src/linker/Linker/LinkContext.cs15
-rw-r--r--src/linker/Linker/MetadataTrimming.cs17
-rw-r--r--test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs13
-rw-r--r--test/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedNameValueAttribute.cs12
-rw-r--r--test/Mono.Linker.Tests.Cases.Expectations/Assertions/VerifyMetadataNamesAttribute.cs12
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs18
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs1
-rw-r--r--test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs1
-rw-r--r--test/Mono.Linker.Tests.Cases/Metadata/NamesAreKept.cs29
-rw-r--r--test/Mono.Linker.Tests.Cases/Metadata/NamesAreRemoved.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs4
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/ParametersUsedViaReflection.cs75
-rw-r--r--test/Mono.Linker.Tests/Extensions/CecilExtensions.cs7
-rw-r--r--test/Mono.Linker.Tests/TestCases/TestDatabase.cs5
-rw-r--r--test/Mono.Linker.Tests/TestCases/TestSuites.cs6
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs37
25 files changed, 340 insertions, 33 deletions
diff --git a/docs/error-codes.md b/docs/error-codes.md
index 8b24628e0..cb75e00e8 100644
--- a/docs/error-codes.md
+++ b/docs/error-codes.md
@@ -157,6 +157,8 @@ the error code. For example:
- The type name used with attribute type is not one of the supported types.
+#### `IL1046`: Invalid metadata '{name}' option
+
----
## Warning Codes
diff --git a/src/ILLink.Tasks/LinkTask.cs b/src/ILLink.Tasks/LinkTask.cs
index b3f369a0d..20adaf035 100644
--- a/src/ILLink.Tasks/LinkTask.cs
+++ b/src/ILLink.Tasks/LinkTask.cs
@@ -213,6 +213,11 @@ namespace ILLink.Tasks
/// </summary>
public ITaskItem[] CustomSteps { get; set; }
+ /// <summary>
+ /// A list selected metadata which should not be trimmed. It maps to 'keep-metadata' option
+ /// </summary>
+ public ITaskItem[] KeepMetadata { get; set; }
+
private const string DotNetHostPathEnvironmentName = "DOTNET_HOST_PATH";
private string _dotnetPath;
@@ -425,6 +430,11 @@ namespace ILLink.Tasks
}
}
+ if (KeepMetadata != null) {
+ foreach (var metadata in KeepMetadata)
+ args.Append ("--keep-metadata ").AppendLine (Quote (metadata.ItemSpec));
+ }
+
if (_removeSymbols == false)
args.AppendLine ("-b");
diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index ef3eaff02..ff63e562b 100644
--- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -2171,7 +2171,7 @@ namespace Mono.Linker.Dataflow
{
var source = reflectionContext.Source;
var offset = reflectionContext.Instruction?.Offset;
- reflectionContext.RecordRecognizedPattern (method, () => _markStep.MarkIndirectlyCalledMethod (method, new DependencyInfo (dependencyKind, source), new MessageOrigin (source, offset)));
+ reflectionContext.RecordRecognizedPattern (method, () => _markStep.MarkMethodVisibleToReflection (method, new DependencyInfo (dependencyKind, source), new MessageOrigin (source, offset)));
}
void MarkNestedType (ref ReflectionPatternContext reflectionContext, TypeDefinition nestedType, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index 7d549207b..1a5ae1bc8 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -1585,18 +1585,26 @@ namespace Mono.Linker.Steps
MarkMethodsIf (type.Methods, HasOnSerializeOrDeserializeAttribute, new DependencyInfo (DependencyKind.SerializationMethodForType, type), type);
}
- protected internal virtual TypeDefinition MarkTypeVisibleToReflection (TypeReference type, TypeDefinition definition, DependencyInfo reason, IMemberDefinition sourceLocationMember)
+ protected internal virtual TypeDefinition MarkTypeVisibleToReflection (TypeReference type, TypeDefinition definition, in DependencyInfo reason, IMemberDefinition sourceLocationMember)
{
// If a type is visible to reflection, we need to stop doing optimization that could cause observable difference
// in reflection APIs. This includes APIs like MakeGenericType (where variant castability of the produced type
// could be incorrect) or IsAssignableFrom (where assignability of unconstructed types might change).
Annotations.MarkRelevantToVariantCasting (definition);
+ Annotations.MarkReflectionUsed (definition);
+
MarkImplicitlyUsedFields (definition);
return MarkType (type, reason, sourceLocationMember);
}
+ internal void MarkMethodVisibleToReflection (MethodDefinition method, in DependencyInfo reason, in MessageOrigin origin)
+ {
+ MarkIndirectlyCalledMethod (method, reason, origin);
+ Annotations.MarkReflectionUsed (method);
+ }
+
/// <summary>
/// Marks the specified <paramref name="reference"/> as referenced.
/// </summary>
diff --git a/src/linker/Linker.Steps/RootAssemblyInputStep.cs b/src/linker/Linker.Steps/RootAssemblyInputStep.cs
index 317b32d1d..e2aa901b7 100644
--- a/src/linker/Linker.Steps/RootAssemblyInputStep.cs
+++ b/src/linker/Linker.Steps/RootAssemblyInputStep.cs
@@ -82,6 +82,9 @@ namespace Mono.Linker.Steps
CodeOptimizations.RemoveLinkAttributes |
CodeOptimizations.RemoveSubstitutions |
CodeOptimizations.RemoveDynamicDependencyAttribute, assembly.Name.Name);
+
+ // No metadata trimming
+ Context.MetadataTrimming = MetadataTrimming.None;
break;
case AssemblyRootMode.AllMembers:
Context.Annotations.SetAction (assembly, AssemblyAction.Copy);
diff --git a/src/linker/Linker.Steps/SweepStep.cs b/src/linker/Linker.Steps/SweepStep.cs
index e5139f458..babbf5657 100644
--- a/src/linker/Linker.Steps/SweepStep.cs
+++ b/src/linker/Linker.Steps/SweepStep.cs
@@ -277,6 +277,11 @@ namespace Mono.Linker.Steps
return Annotations.IsMarked (assembly.MainModule);
}
+ bool CanSweepNamesForMember (IMemberDefinition member, MetadataTrimming metadataTrimming)
+ {
+ return (Context.MetadataTrimming & metadataTrimming) != 0 && !Annotations.IsReflectionUsed (member);
+ }
+
protected virtual void RemoveAssembly (AssemblyDefinition assembly)
{
Annotations.SetAction (assembly, AssemblyAction.Delete);
@@ -451,8 +456,14 @@ namespace Mono.Linker.Steps
if (!method.HasParameters)
continue;
- foreach (var parameter in method.Parameters)
+ bool sweepNames = CanSweepNamesForMember (method, MetadataTrimming.ParameterName);
+
+ foreach (var parameter in method.Parameters) {
+ if (sweepNames)
+ parameter.Name = null;
+
SweepCustomAttributes (parameter);
+ }
}
}
diff --git a/src/linker/Linker/Annotations.cs b/src/linker/Linker/Annotations.cs
index ff3b6bc09..2bcbca3eb 100644
--- a/src/linker/Linker/Annotations.cs
+++ b/src/linker/Linker/Annotations.cs
@@ -66,6 +66,7 @@ namespace Mono.Linker
protected readonly HashSet<TypeDefinition> marked_instantiated = new HashSet<TypeDefinition> ();
protected readonly HashSet<MethodDefinition> indirectly_called = new HashSet<MethodDefinition> ();
protected readonly HashSet<TypeDefinition> types_relevant_to_variant_casting = new HashSet<TypeDefinition> ();
+ readonly HashSet<IMemberDefinition> reflection_used = new ();
public AnnotationStore (LinkContext context)
{
@@ -223,6 +224,16 @@ namespace Mono.Linker
return indirectly_called.Contains (method);
}
+ public void MarkReflectionUsed (IMemberDefinition member)
+ {
+ reflection_used.Add (member);
+ }
+
+ public bool IsReflectionUsed (IMemberDefinition method)
+ {
+ return reflection_used.Contains (method);
+ }
+
public void MarkInstantiated (TypeDefinition type)
{
marked_instantiated.Add (type);
diff --git a/src/linker/Linker/Driver.cs b/src/linker/Linker/Driver.cs
index d0456a604..4eb785200 100644
--- a/src/linker/Linker/Driver.cs
+++ b/src/linker/Linker/Driver.cs
@@ -171,6 +171,7 @@ namespace Mono.Linker
bool new_mvid_used = false;
bool deterministic_used = false;
bool keepCompilersResources = false;
+ MetadataTrimming metadataTrimming = MetadataTrimming.Any;
List<BaseStep> inputs = CreateDefaultResolvers ();
@@ -335,6 +336,18 @@ namespace Mono.Linker
continue;
+ case "--keep-metadata": {
+ string mname = null;
+ if (!GetStringParam (token, l => mname = l))
+ return -1;
+
+ if (!TryGetMetadataTrimming (mname, out var type))
+ return -1;
+
+ metadataTrimming &= ~type;
+ continue;
+ }
+
case "--disable-serialization-discovery":
if (!GetBoolParam (token, l => context.DisableSerializationDiscovery = l))
return -1;
@@ -650,7 +663,7 @@ namespace Mono.Linker
return -1;
}
-
+ context.MetadataTrimming = metadataTrimming;
// Default to deterministic output
if (!new_mvid_used && !deterministic_used) {
@@ -1088,6 +1101,25 @@ namespace Mono.Linker
return false;
}
+ bool TryGetMetadataTrimming (string text, out MetadataTrimming metadataTrimming)
+ {
+ switch (text.ToLowerInvariant ()) {
+ case "all":
+ metadataTrimming = MetadataTrimming.Any;
+ return true;
+ case "none":
+ metadataTrimming = MetadataTrimming.None;
+ return true;
+ case "parametername":
+ metadataTrimming = MetadataTrimming.ParameterName;
+ return true;
+ }
+
+ context.LogError ($"Invalid metadata value '{text}'", 1046);
+ metadataTrimming = 0;
+ return false;
+ }
+
protected static bool GetWarningSuppressionWriterFileOutputKind (string text, out WarningSuppressionWriter.FileOutputKind fileOutputKind)
{
switch (text.ToLowerInvariant ()) {
@@ -1248,8 +1280,12 @@ namespace Mono.Linker
Console.WriteLine (" --enable-opt NAME [ASM] Enable one of the additional optimizations globaly or for a specific assembly name");
Console.WriteLine (" sealer: Any method or type which does not have override is marked as sealed");
Console.WriteLine (" --explicit-reflection Adds to members never used through reflection DisablePrivateReflection attribute. Defaults to false");
- Console.WriteLine (" --keep-dep-attributes Keep attributes used for manual dependency tracking. Defaults to false");
Console.WriteLine (" --feature FEATURE VALUE Apply any optimizations defined when this feature setting is a constant known at link time");
+ Console.WriteLine (" --keep-compilers-resources Keep assembly resources used for F# compilation resources. Defaults to false");
+ Console.WriteLine (" --keep-dep-attributes Keep attributes used for manual dependency tracking. Defaults to false");
+ Console.WriteLine (" --keep-metadata NAME Keep metadata which would otherwise be removed if not used");
+ Console.WriteLine (" all: Metadata for any member are all kept");
+ Console.WriteLine (" parametername: All parameter names are kept");
Console.WriteLine (" --new-mvid Generate a new guid for each linked assembly (short -g). Defaults to true");
Console.WriteLine (" --strip-descriptors Remove XML descriptor resources for linked assemblies. Defaults to true");
Console.WriteLine (" --strip-security Remove metadata and code related to Code Access Security. Defaults to true");
@@ -1260,7 +1296,6 @@ namespace Mono.Linker
Console.WriteLine (" --link-attributes FILE Supplementary custom attribute definitions for attributes controlling the linker behavior.");
Console.WriteLine (" --ignore-link-attributes Skips reading embedded attributes. Defaults to false");
Console.WriteLine (" --strip-link-attributes Remove XML link attributes resources for linked assemblies. Defaults to true");
- Console.WriteLine (" --keep-compilers-resources Keep assembly resources used for F# compilation resources. Defaults to false");
Console.WriteLine ();
Console.WriteLine ("Analyzer");
diff --git a/src/linker/Linker/FeatureSettings.cs b/src/linker/Linker/FeatureSettings.cs
index 5e5fa4b14..fc99664f0 100644
--- a/src/linker/Linker/FeatureSettings.cs
+++ b/src/linker/Linker/FeatureSettings.cs
@@ -33,7 +33,7 @@ namespace Mono.Linker
return false;
}
- if (context.FeatureSettings == null || !context.FeatureSettings.TryGetValue (feature, out bool featureSetting))
+ if (!context.FeatureSettings.TryGetValue (feature, out bool featureSetting))
return bIsDefault;
return bValue == featureSetting;
diff --git a/src/linker/Linker/LinkContext.cs b/src/linker/Linker/LinkContext.cs
index 9a51d7392..fea6e82b3 100644
--- a/src/linker/Linker/LinkContext.cs
+++ b/src/linker/Linker/LinkContext.cs
@@ -94,6 +94,8 @@ namespace Mono.Linker
set { _outputDirectory = value; }
}
+ public MetadataTrimming MetadataTrimming { get; set; }
+
public AssemblyAction TrimAction { get; set; }
public AssemblyAction DefaultAction { get; set; }
@@ -127,7 +129,7 @@ namespace Mono.Linker
public bool IgnoreLinkAttributes { get; set; }
- public Dictionary<string, bool> FeatureSettings { get; private set; }
+ public Dictionary<string, bool> FeatureSettings { get; init; }
public List<string> AttributeDefinitions { get; private set; }
@@ -208,6 +210,7 @@ namespace Mono.Linker
_parameters = new Dictionary<string, string> (StringComparer.Ordinal);
_customAttributes = new CustomAttributeSource (this);
_cachedWarningMessageContainers = new List<MessageContainer> ();
+ FeatureSettings = new Dictionary<string, bool> (StringComparer.Ordinal);
SymbolReaderProvider = new DefaultSymbolReaderProvider (false);
@@ -247,14 +250,14 @@ namespace Mono.Linker
public void SetFeatureValue (string feature, bool value)
{
Debug.Assert (!String.IsNullOrEmpty (feature));
- if (FeatureSettings == null) {
- FeatureSettings = new Dictionary<string, bool> { { feature, value } };
- return;
- }
-
FeatureSettings[feature] = value;
}
+ public bool HasFeatureValue (string feature, bool value)
+ {
+ return FeatureSettings.TryGetValue (feature, out bool fvalue) && value == fvalue;
+ }
+
public void AddAttributeDefinitionFile (string file)
{
if (AttributeDefinitions == null) {
diff --git a/src/linker/Linker/MetadataTrimming.cs b/src/linker/Linker/MetadataTrimming.cs
new file mode 100644
index 000000000..c8240def4
--- /dev/null
+++ b/src/linker/Linker/MetadataTrimming.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Mono.Linker
+{
+ [Flags]
+ public enum MetadataTrimming
+ {
+ None = 0,
+ ParameterName = 1,
+
+ Any = ParameterName
+ }
+}
diff --git a/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs b/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs
index 3b70208fa..23544a538 100644
--- a/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs
+++ b/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs
@@ -522,6 +522,19 @@ namespace ILLink.Tasks.Tests
}
}
+
+ [Fact]
+ public void TestKeepCustomMetadata ()
+ {
+ var task = new MockTask () {
+ KeepMetadata = new ITaskItem[] { new TaskItem ("parametername") }
+ };
+
+ using (var driver = task.CreateDriver ()) {
+ Assert.Equal (MetadataTrimming.None, driver.Context.MetadataTrimming);
+ }
+ }
+
[Theory]
[InlineData ("copy")]
[InlineData ("link")]
diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedNameValueAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedNameValueAttribute.cs
new file mode 100644
index 000000000..1e25715fe
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedNameValueAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions
+{
+ /// <summary>
+ /// Verifies that name of the member is removed
+ /// </summary>
+ [AttributeUsage (AttributeTargets.All, AllowMultiple = false, Inherited = false)]
+ public class RemovedNameValueAttribute : BaseExpectedLinkedBehaviorAttribute
+ {
+ }
+}
diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/VerifyMetadataNamesAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/VerifyMetadataNamesAttribute.cs
new file mode 100644
index 000000000..8b8df3d33
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/VerifyMetadataNamesAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions
+{
+ [AttributeUsage (AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
+ public class VerifyMetadataNamesAttribute : BaseExpectedLinkedBehaviorAttribute
+ {
+ public VerifyMetadataNamesAttribute ()
+ {
+ }
+ }
+}
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs
index b56225c9b..3889225a2 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs
@@ -468,7 +468,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
typeof (T).RequiresNone ();
}
- [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "<T>()::T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "<#1>()::T", messageCode: "IL2091")]
static void MethodRequiresPublicFieldsPassThrough<
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> ()
{
@@ -477,8 +477,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
MethodRequiresNothing<T> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicFields) + "<T>()::T", messageCode: "IL2091")]
- [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "<T>()::T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicFields) + "<#1>()::T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "<#1>()::T", messageCode: "IL2091")]
static void MethodRequiresNothingPassThrough<T> ()
{
MethodRequiresPublicFields<T> ();
@@ -550,7 +550,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
class TypeWithInstantiatedGenericMethodViaGenericParameter<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TOuter>
: BaseTypeWithGenericMethod, IInterfaceWithGenericMethod
{
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "<T>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "<#1>()::T",
messageCode: "IL2091", message: new string[] {
"TInner",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>.StaticRequiresPublicFields<TInner>()",
@@ -562,7 +562,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
StaticRequiresPublicMethods<TInner> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "<T>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "<#1>()::T",
messageCode: "IL2091", message: new string[] {
"TOuter",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>",
@@ -580,7 +580,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
StaticRequiresMultipleGenericParams<TOuter, TestType> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams) + "<TFields,TMethods>()::TMethods",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams) + "<#2>()::TMethods",
messageCode: "IL2091", message: new string[] {
"TOuter",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>",
@@ -591,7 +591,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
StaticRequiresMultipleGenericParams<TestType, TOuter> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "<T>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "<#1>()::T",
messageCode: "IL2091", message: new string[] {
"TInner",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>.InstanceRequiresPublicFields<TInner>()",
@@ -603,7 +603,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
InstanceRequiresPublicMethods<TInner> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "<T>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "<#1>()::T",
messageCode: "IL2091", message: new string[] {
"TOuter",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>",
@@ -639,7 +639,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
typeof (T).RequiresPublicMethods ();
}
- [UnrecognizedReflectionAccessPattern (typeof (IInterfaceWithGenericMethod), nameof (IInterfaceWithGenericMethod.InterfaceRequiresPublicMethods) + "<T>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (IInterfaceWithGenericMethod), nameof (IInterfaceWithGenericMethod.InterfaceRequiresPublicMethods) + "<#1>()::T",
messageCode: "IL2091", message: new string[] {
"TOuter",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>",
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs
index fe11b6b03..01047bc7a 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs
@@ -14,6 +14,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
// Note: this test's goal is to validate that the product correctly reports unrecognized patterns
// - so the main validation is done by the UnrecognizedReflectionAccessPattern attributes.
[SkipKeptItemsValidation]
+ [SetupLinkerArgument ("--keep-metadata", "parametername")]
public class MethodParametersDataFlow
{
public static void Main ()
diff --git a/test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs b/test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs
index af105d086..e9e7ecf29 100644
--- a/test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs
+++ b/test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs
@@ -8,6 +8,7 @@ namespace Mono.Linker.Tests.Cases.Libraries
{
[SetupLinkerArgument ("-a", "test.exe", "library")]
[SetupLinkerArgument ("--enable-opt", "ipconstprop")]
+ [VerifyMetadataNames]
public class RootLibrary
{
private int field;
diff --git a/test/Mono.Linker.Tests.Cases/Metadata/NamesAreKept.cs b/test/Mono.Linker.Tests.Cases/Metadata/NamesAreKept.cs
new file mode 100644
index 000000000..5dabdf1f9
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Metadata/NamesAreKept.cs
@@ -0,0 +1,29 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Metadata
+{
+ [SetupLinkerArgument ("--keep-metadata", "parametername")]
+ [VerifyMetadataNames]
+ public class NamesAreKept
+ {
+ public static void Main ()
+ {
+ var n = new N (5);
+ N.Foo ("aa");
+ }
+
+ class N
+ {
+ [Kept]
+ public N (int arg)
+ {
+ }
+
+ [Kept]
+ public static void Foo (string str)
+ {
+ }
+ }
+ }
+}
diff --git a/test/Mono.Linker.Tests.Cases/Metadata/NamesAreRemoved.cs b/test/Mono.Linker.Tests.Cases/Metadata/NamesAreRemoved.cs
new file mode 100644
index 000000000..af793ee6c
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Metadata/NamesAreRemoved.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Metadata
+{
+ public class NamesAreRemoved
+ {
+ public static void Main ()
+ {
+ var n = new N (5);
+ N.Foo (null, 1);
+ }
+
+ class N
+ {
+ [Kept]
+ public N ([RemovedNameValueAttribute] int arg)
+ {
+ }
+
+ [Kept]
+ public static void Foo ([RemovedNameValueAttribute] string str, [RemovedNameValueAttribute] long _)
+ {
+ }
+ }
+ }
+}
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs b/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
index 6da378265..7b5f97803 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
@@ -454,10 +454,10 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[Kept]
- [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "<T>", new Type[0], messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "<#1>", new Type[0], messageCode: "IL2091")]
#if NETCOREAPP
// Warnings are currently duplicated in NETCORE (annotation and intrinsics) - but they're not identical in this case, so we have to list both cases
- [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "<T>()::T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "<#1>()::T", messageCode: "IL2091")]
#endif
private static void TestCreateInstanceOfTWithNoConstraint<T> ()
{
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ParametersUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/ParametersUsedViaReflection.cs
new file mode 100644
index 000000000..57b16569a
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Reflection/ParametersUsedViaReflection.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Reflection;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Reflection
+{
+ public class ParametersUsedViaReflection
+ {
+ public static void Main ()
+ {
+ TestMethodParameters ();
+ TestClassParameters ();
+ }
+
+ [Kept]
+ static void TestMethodParameters ()
+ {
+ var method = typeof (GetMethod_Name).GetMethod ("OnlyCalledViaReflection");
+ var name = method.GetParameters ()[0].Name;
+
+ GetMethod_Name.CalledDirectly (11);
+ GetMethod_Name.CalledDirectly2<string> (1);
+ }
+
+ [Kept]
+ static void TestClassParameters ()
+ {
+ var type = Type.GetType ("Mono.Linker.Tests.Cases.Reflection.ParametersUsedViaReflection/GenericClass1`1");
+
+ var type2 = new GenericClass2<int> ();
+ }
+
+ [Kept]
+ class GetMethod_Name
+ {
+ [Kept]
+ public static int OnlyCalledViaReflection (int firstName)
+ {
+ return 2;
+ }
+
+ [Kept]
+ public static int OnlyCalledViaReflection (int arg1, int arg2)
+ {
+ return 3;
+ }
+
+ [Kept]
+ public static void CalledDirectly ([RemovedNameValue] int firstArg)
+ {
+ }
+
+ [Kept]
+ public static void CalledDirectly2</*[RemovedNameValue]*/LongGenericName> ([RemovedNameValue] int firstArg)
+ {
+ }
+ }
+
+ [Kept]
+ public class GenericClass1<TKey>
+ {
+ }
+
+ [Kept]
+ public class GenericClass2</*[RemovedNameValue]*/TRKey>
+ {
+ [Kept]
+ public GenericClass2 ()
+ {
+ }
+ }
+ }
+
+}
diff --git a/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs b/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs
index f18803377..c6ed39935 100644
--- a/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs
+++ b/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs
@@ -126,12 +126,7 @@ namespace Mono.Linker.Tests.Extensions
var builder = new StringBuilder ();
builder.Append (method.Name);
if (method.HasGenericParameters) {
- builder.Append ('<');
-
- for (int i = 0; i < method.GenericParameters.Count - 1; i++)
- builder.Append ($"{method.GenericParameters[i]},");
-
- builder.Append ($"{method.GenericParameters[method.GenericParameters.Count - 1]}>");
+ builder.Append ($"<#{method.GenericParameters.Count}>");
}
builder.Append ("(");
diff --git a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
index 73e5ed671..fcab71eb7 100644
--- a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
+++ b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
@@ -212,6 +212,11 @@ namespace Mono.Linker.Tests.TestCases
return NUnitCasesBySuiteName ("LinkAttributes");
}
+ public static IEnumerable<TestCaseData> MetadataTests ()
+ {
+ return NUnitCasesBySuiteName ("Metadata");
+ }
+
public static TestCaseCollector CreateCollector ()
{
GetDirectoryPaths (out string rootSourceDirectory, out string testCaseAssemblyPath);
diff --git a/test/Mono.Linker.Tests/TestCases/TestSuites.cs b/test/Mono.Linker.Tests/TestCases/TestSuites.cs
index ae2d45090..3860cccbc 100644
--- a/test/Mono.Linker.Tests/TestCases/TestSuites.cs
+++ b/test/Mono.Linker.Tests/TestCases/TestSuites.cs
@@ -254,6 +254,12 @@ namespace Mono.Linker.Tests.TestCases
Run (testCase);
}
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.MetadataTests))]
+ public void MetadataTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
protected virtual void Run (TestCase testCase)
{
var runner = new TestRunner (new ObjectFactory ());
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
index 421e4ac1a..a4a4b1f64 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
@@ -18,11 +18,15 @@ namespace Mono.Linker.Tests.TestCasesRunner
readonly HashSet<string> verifiedGeneratedFields = new HashSet<string> ();
readonly HashSet<string> verifiedEventMethods = new HashSet<string> ();
readonly HashSet<string> verifiedGeneratedTypes = new HashSet<string> ();
+ bool checkNames;
public AssemblyChecker (AssemblyDefinition original, AssemblyDefinition linked)
{
this.originalAssembly = original;
this.linkedAssembly = linked;
+
+ checkNames = original.MainModule.GetTypeReferences ().Any (attr =>
+ attr.Name == nameof (RemovedNameValueAttribute));
}
public void Verify ()
@@ -107,8 +111,13 @@ namespace Mono.Linker.Tests.TestCasesRunner
return;
}
+ bool prev = checkNames;
+ checkNames |= original.HasAttribute (nameof (VerifyMetadataNamesAttribute));
+
VerifyTypeDefinitionKept (original, linked);
+ checkNames = prev;
+
if (original.HasAttribute (nameof (CreatedMemberAttribute))) {
foreach (var attr in original.CustomAttributes.Where (l => l.AttributeType.Name == nameof (CreatedMemberAttribute))) {
var newName = original.FullName + "::" + attr.ConstructorArguments[0].Value.ToString ();
@@ -163,7 +172,8 @@ namespace Mono.Linker.Tests.TestCasesRunner
foreach (var m in original.Methods) {
if (verifiedEventMethods.Contains (m.FullName))
continue;
- VerifyMethod (m, linked?.Methods.FirstOrDefault (l => m.GetSignature () == l.GetSignature ()));
+ var msign = m.GetSignature ();
+ VerifyMethod (m, linked?.Methods.FirstOrDefault (l => msign == l.GetSignature ()));
linkedMembers.Remove (m.FullName);
}
}
@@ -765,7 +775,18 @@ namespace Mono.Linker.Tests.TestCasesRunner
if (src.HasGenericParameters) {
for (int i = 0; i < src.GenericParameters.Count; ++i) {
// TODO: Verify constraints
- VerifyCustomAttributes (src.GenericParameters[i], linked.GenericParameters[i]);
+ var srcp = src.GenericParameters[i];
+ var lnkp = linked.GenericParameters[i];
+ VerifyCustomAttributes (srcp, lnkp);
+
+ if (checkNames) {
+ if (srcp.CustomAttributes.Any (attr => attr.AttributeType.Name == nameof (RemovedNameValueAttribute))) {
+ string name = (src.GenericParameterType == GenericParameterType.Method ? "!!" : "!") + srcp.Position;
+ Assert.AreEqual (name, lnkp.Name, "Expected empty generic parameter name");
+ } else {
+ Assert.AreEqual (srcp.Name, lnkp.Name, "Mismatch in generic parameter name");
+ }
+ }
}
}
}
@@ -775,7 +796,17 @@ namespace Mono.Linker.Tests.TestCasesRunner
Assert.AreEqual (src.HasParameters, linked.HasParameters);
if (src.HasParameters) {
for (int i = 0; i < src.Parameters.Count; ++i) {
- VerifyCustomAttributes (src.Parameters[i], linked.Parameters[i]);
+ var srcp = src.Parameters[i];
+ var lnkp = linked.Parameters[i];
+
+ VerifyCustomAttributes (srcp, lnkp);
+
+ if (checkNames) {
+ if (srcp.CustomAttributes.Any (attr => attr.AttributeType.Name == nameof (RemovedNameValueAttribute)))
+ Assert.IsEmpty (lnkp.Name, "Expected empty parameter name");
+ else
+ Assert.AreEqual (srcp.Name, lnkp.Name, "Mismatch in parameter name");
+ }
}
}
}