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:
authorMateo Torres-Ruiz <mateoatr@users.noreply.github.com>2021-09-08 21:10:56 +0300
committerGitHub <noreply@github.com>2021-09-08 21:10:56 +0300
commit8b7695af6debcbdaad531d521f8a8e10c553541a (patch)
treeebe54f6f1f85e817a5ec731363ea62c99a0f9079
parent4f28a6571fdf56b2c06dfb03fda41efb0ea4c9ed (diff)
Special case `MakeGenericMethod/Type` in RUC analyzer (#2209)
* Add MakeGenericMethod and MakeGenericType to the special incompatible members of the RUC analyzer. * Don't produce diagnostics for MakeGenericMethod/MakeGenericType * Add comment * Lint
-rw-r--r--src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs35
-rw-r--r--src/ILLink.Shared/DiagnosticId.cs2
-rw-r--r--src/ILLink.Shared/SharedStrings.resx6
-rw-r--r--src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs33
-rw-r--r--src/linker/Resources/Strings.Designer.cs9
-rw-r--r--src/linker/Resources/Strings.resx3
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs48
7 files changed, 102 insertions, 34 deletions
diff --git a/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs b/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs
index 052c560e0..441b846e4 100644
--- a/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs
+++ b/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs
@@ -24,6 +24,8 @@ namespace ILLink.RoslynAnalyzer
static readonly DiagnosticDescriptor s_dynamicTypeInvocationRule = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.RequiresUnreferencedCode,
new LocalizableResourceString (nameof (SharedStrings.DynamicTypeInvocationTitle), SharedStrings.ResourceManager, typeof (SharedStrings)),
new LocalizableResourceString (nameof (SharedStrings.DynamicTypeInvocationMessage), SharedStrings.ResourceManager, typeof (SharedStrings)));
+ static readonly DiagnosticDescriptor s_makeGenericTypeRule = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.MakeGenericType);
+ static readonly DiagnosticDescriptor s_makeGenericMethodRule = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.MakeGenericMethod);
static readonly Action<OperationAnalysisContext> s_dynamicTypeInvocation = operationContext => {
if (FindContainingSymbol (operationContext, DiagnosticTargets.All) is ISymbol containingSymbol &&
@@ -85,7 +87,7 @@ namespace ILLink.RoslynAnalyzer
};
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
- ImmutableArray.Create (s_dynamicTypeInvocationRule, s_requiresUnreferencedCodeRule, s_requiresUnreferencedCodeAttributeMismatch);
+ ImmutableArray.Create (s_dynamicTypeInvocationRule, s_makeGenericMethodRule, s_makeGenericTypeRule, s_requiresUnreferencedCodeRule, s_requiresUnreferencedCodeAttributeMismatch);
private protected override string RequiresAttributeName => RequiresUnreferencedCodeAttribute;
@@ -100,8 +102,37 @@ namespace ILLink.RoslynAnalyzer
protected override bool IsAnalyzerEnabled (AnalyzerOptions options, Compilation compilation) =>
options.IsMSBuildPropertyValueTrue (MSBuildPropertyOptionNames.EnableTrimAnalyzer, compilation);
+ protected override ImmutableArray<ISymbol> GetSpecialIncompatibleMembers (Compilation compilation)
+ {
+ var incompatibleMembers = ImmutableArray.CreateBuilder<ISymbol> ();
+ var typeType = compilation.GetTypeByMetadataName ("System.Type");
+ if (typeType != null) {
+ incompatibleMembers.AddRange (typeType.GetMembers ("MakeGenericType").OfType<IMethodSymbol> ());
+ }
+
+ var methodInfoType = compilation.GetTypeByMetadataName ("System.Reflection.MethodInfo");
+ if (methodInfoType != null) {
+ incompatibleMembers.AddRange (methodInfoType.GetMembers ("MakeGenericMethod").OfType<IMethodSymbol> ());
+ }
+
+ return incompatibleMembers.ToImmutable ();
+ }
+
+ protected override bool ReportSpecialIncompatibleMembersDiagnostic (OperationAnalysisContext operationContext, ImmutableArray<ISymbol> specialIncompatibleMembers, ISymbol member)
+ {
+ if (member is IMethodSymbol method && ImmutableArrayOperations.Contains (specialIncompatibleMembers, member, SymbolEqualityComparer.Default) &&
+ (method.Name == "MakeGenericMethod" || method.Name == "MakeGenericType")) {
+ // These two RUC-annotated APIs are intrinsically handled by the trimmer, which will not produce any
+ // RUC warning related to them. For unrecognized reflection patterns realted to generic type/method
+ // creation IL2055/IL2060 should be used instead.
+ return true;
+ }
+
+ return false;
+ }
+
private protected override ImmutableArray<(Action<OperationAnalysisContext> Action, OperationKind[] OperationKind)> ExtraOperationActions =>
- ImmutableArray.Create ((s_dynamicTypeInvocation, new OperationKind[] { OperationKind.DynamicInvocation }));
+ ImmutableArray.Create ((s_dynamicTypeInvocation, new OperationKind[] { OperationKind.DynamicInvocation }));
private protected override ImmutableArray<(Action<SyntaxNodeAnalysisContext> Action, SyntaxKind[] SyntaxKind)> ExtraSyntaxNodeActions =>
ImmutableArray.Create ((s_constructorConstraint, new SyntaxKind[] { SyntaxKind.GenericName }));
diff --git a/src/ILLink.Shared/DiagnosticId.cs b/src/ILLink.Shared/DiagnosticId.cs
index f586a6b43..c52dcc895 100644
--- a/src/ILLink.Shared/DiagnosticId.cs
+++ b/src/ILLink.Shared/DiagnosticId.cs
@@ -5,6 +5,8 @@
// Linker diagnostic ids.
RequiresUnreferencedCode = 2026,
RequiresUnreferencedCodeAttributeMismatch = 2046,
+ MakeGenericType = 2055,
+ MakeGenericMethod = 2060,
RequiresUnreferencedCodeOnStaticConstructor = 2116,
// Single-file diagnostic ids.
diff --git a/src/ILLink.Shared/SharedStrings.resx b/src/ILLink.Shared/SharedStrings.resx
index 70b50dbbf..c78c81ede 100644
--- a/src/ILLink.Shared/SharedStrings.resx
+++ b/src/ILLink.Shared/SharedStrings.resx
@@ -171,6 +171,12 @@
<data name="DynamicTypeInvocationTitle" xml:space="preserve">
<value>Using dynamic types might cause types or members to be removed by trimmer.</value>
</data>
+ <data name="MakeGenericMethodMessage" xml:space="preserve">
+ <value>Call to '{0}' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method.</value>
+ </data>
+ <data name="MakeGenericTypeMessage" xml:space="preserve">
+ <value>Call to '{0}' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type.</value>
+ </data>
<data name="RequiresUnreferencedCodeOnStaticConstructorMessage" xml:space="preserve">
<value>'RequiresUnreferencedCodeAttribute' cannot be placed directly on static constructor '{0}', consider placing 'RequiresUnreferencedCodeAttribute' on the type declaration instead.</value>
</data>
diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index 2b3d94095..c57a14b70 100644
--- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using ILLink.Shared;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Linker.Steps;
@@ -745,10 +746,8 @@ namespace Mono.Linker.Dataflow
}
}
if (hasUncheckedAnnotation) {
- reflectionContext.RecordUnrecognizedPattern (
- 2055,
- $"Call to '{calledMethodDefinition.GetDisplayName ()}' can not be statically analyzed. " +
- $"It's not possible to guarantee the availability of requirements of the generic type.");
+ reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericType,
+ new DiagnosticString (DiagnosticId.MakeGenericType).GetMessage (calledMethodDefinition.GetDisplayName ()));
}
}
@@ -758,10 +757,8 @@ namespace Mono.Linker.Dataflow
reflectionContext.RecordHandledPattern ();
else {
// We have no way to "include more" to fix this if we don't know, so we have to warn
- reflectionContext.RecordUnrecognizedPattern (
- 2055,
- $"Call to '{calledMethodDefinition.GetDisplayName ()}' can not be statically analyzed. " +
- $"It's not possible to guarantee the availability of requirements of the generic type.");
+ reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericType,
+ new DiagnosticString (DiagnosticId.MakeGenericType).GetMessage (calledMethodDefinition.GetDisplayName ()));
}
}
@@ -853,9 +850,8 @@ namespace Mono.Linker.Dataflow
if (hasTypeArguments) {
// We don't know what method the `MakeGenericMethod` was called on, so we have to assume
// that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern (
- 2060, string.Format (Resources.Strings.IL2060,
- DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
+ reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericMethod,
+ new DiagnosticString (DiagnosticId.MakeGenericMethod).GetMessage (DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
}
RequireDynamicallyAccessedMembers (
@@ -869,9 +865,8 @@ namespace Mono.Linker.Dataflow
if (hasTypeArguments) {
// We don't know what method the `MakeGenericMethod` was called on, so we have to assume
// that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern (
- 2060, string.Format (Resources.Strings.IL2060,
- DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
+ reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericMethod,
+ new DiagnosticString (DiagnosticId.MakeGenericMethod).GetMessage (DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
}
RequireDynamicallyAccessedMembers (
@@ -1718,9 +1713,8 @@ namespace Mono.Linker.Dataflow
} else {
// We don't know what method the `MakeGenericMethod` was called on, so we have to assume
// that the method may have requirements which we can't fullfil -> warn.
- reflectionContext.RecordUnrecognizedPattern (
- 2060, string.Format (Resources.Strings.IL2060,
- DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
+ reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericMethod,
+ new DiagnosticString (DiagnosticId.MakeGenericMethod).GetMessage (DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethod)));
}
}
@@ -2403,9 +2397,8 @@ namespace Mono.Linker.Dataflow
}
if (!AnalyzeGenericInstatiationTypeArray (genericParametersArray, ref reflectionContext, reflectionMethod, genericMethod.GenericParameters)) {
- reflectionContext.RecordUnrecognizedPattern (
- 2060,
- string.Format (Resources.Strings.IL2060, DiagnosticUtilities.GetMethodSignatureDisplayName (reflectionMethod)));
+ reflectionContext.RecordUnrecognizedPattern ((int) DiagnosticId.MakeGenericMethod,
+ new DiagnosticString (DiagnosticId.MakeGenericMethod).GetMessage (DiagnosticUtilities.GetMethodSignatureDisplayName (reflectionMethod)));
} else {
reflectionContext.RecordHandledPattern ();
}
diff --git a/src/linker/Resources/Strings.Designer.cs b/src/linker/Resources/Strings.Designer.cs
index 6211cd6c6..df64816a2 100644
--- a/src/linker/Resources/Strings.Designer.cs
+++ b/src/linker/Resources/Strings.Designer.cs
@@ -61,15 +61,6 @@ namespace Mono.Linker.Resources {
}
/// <summary>
- /// Looks up a localized string similar to Call to &apos;{0}&apos; can not be statically analyzed. It&apos;s not possible to guarantee the availability of requirements of the generic method..
- /// </summary>
- internal static string IL2060 {
- get {
- return ResourceManager.GetString("IL2060", resourceCulture);
- }
- }
-
- /// <summary>
/// Looks up a localized string similar to &apos;{0}&apos; argument does not satisfy {4} in call to &apos;{1}&apos;. The parameter &apos;{2}&apos; of method &apos;{3}&apos; does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to..
/// </summary>
internal static string IL2067 {
diff --git a/src/linker/Resources/Strings.resx b/src/linker/Resources/Strings.resx
index 4a8297ed6..0ffbe886a 100644
--- a/src/linker/Resources/Strings.resx
+++ b/src/linker/Resources/Strings.resx
@@ -117,9 +117,6 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
- <data name="IL2060" xml:space="preserve">
- <value>Call to '{0}' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method.</value>
- </data>
<data name="IL2067" xml:space="preserve">
<value>'{0}' argument does not satisfy {4} in call to '{1}'. The parameter '{2}' of method '{3}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.</value>
</data>
diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs
index 9b448970e..345b6d7c0 100644
--- a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs
+++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs
@@ -920,5 +920,53 @@ class C
return VerifyRequiresUnreferencedCodeAnalyzer (source);
}
+
+ [Fact]
+ public Task TestMakeGenericMethodUsage ()
+ {
+ var source = @"
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+class C
+{
+ static void M1 (MethodInfo methodInfo)
+ {
+ methodInfo.MakeGenericMethod (typeof (C));
+ }
+
+ [RequiresUnreferencedCode (""Message from RUC"")]
+ static void M2 (MethodInfo methodInfo)
+ {
+ methodInfo.MakeGenericMethod (typeof (C));
+ }
+}";
+
+ return VerifyRequiresUnreferencedCodeAnalyzer (source);
+ }
+
+ [Fact]
+ public Task TestMakeGenericTypeUsage ()
+ {
+ var source = @"
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+class C
+{
+ static void M1 (Type t)
+ {
+ typeof (Nullable<>).MakeGenericType (typeof (C));
+ }
+
+ [RequiresUnreferencedCode (""Message from RUC"")]
+ static void M2 (Type t)
+ {
+ typeof (Nullable<>).MakeGenericType (typeof (C));
+ }
+}";
+
+ return VerifyRequiresUnreferencedCodeAnalyzer (source);
+ }
}
}