Skip to content

Commit 0e0f51d

Browse files
committed
Don't keep members of pointer or byref element types
1 parent 4cb6f78 commit 0e0f51d

File tree

6 files changed

+32
-42
lines changed

6 files changed

+32
-42
lines changed

src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,8 @@ private partial bool TryResolveTypeNameForCreateInstanceAndMark (in MethodProxy
242242
return false;
243243
}
244244

245-
if (!_reflectionMarker.TryResolveTypeNameAndMark (resolvedAssembly, typeName, _diagnosticContext, out TypeDefinition? resolvedTypeDefinition)
246-
|| resolvedTypeDefinition.IsTypeOf (WellKnownType.System_Array)) {
245+
if (!_reflectionMarker.TryResolveTypeNameAndMark (resolvedAssembly, typeName, _diagnosticContext, out TypeReference? foundType)
246+
|| foundType.IsTypeOf (WellKnownType.System_Array)) {
247247
// It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case
248248
// Note that we did find the assembly, so it's not a ILLink config problem, it's either intentional, or wrong versions of assemblies
249249
// but ILLink can't know that. In case a user tries to create an array using System.Activator we should simply ignore it, the user
@@ -252,7 +252,7 @@ private partial bool TryResolveTypeNameForCreateInstanceAndMark (in MethodProxy
252252
return false;
253253
}
254254

255-
resolvedType = new TypeProxy (resolvedTypeDefinition);
255+
resolvedType = new TypeProxy (foundType);
256256
return true;
257257
}
258258

src/tools/illink/src/linker/Linker.Dataflow/ReflectionMarker.cs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,39 +58,32 @@ internal void MarkTypeForDynamicallyAccessedMembers (in MessageOrigin origin, Ty
5858

5959
// Resolve a (potentially assembly qualified) type name based on the current context (taken from DiagnosticContext) and mark the type for reflection.
6060
// This method will probe the current context assembly and if that fails CoreLib for the specified type. Emulates behavior of Type.GetType.
61-
internal bool TryResolveTypeNameAndMark (string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, [NotNullWhen (true)] out TypeDefinition? type)
61+
internal bool TryResolveTypeNameAndMark (string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, [NotNullWhen (true)] out TypeReference? type)
6262
{
63-
if (!_context.TypeNameResolver.TryResolveTypeName (typeName, diagnosticContext, out TypeReference? typeRef, out var typeResolutionRecords, needsAssemblyName)
64-
|| typeRef.ResolveToTypeDefinition (_context) is not TypeDefinition foundType) {
63+
if (!_context.TypeNameResolver.TryResolveTypeName (typeName, diagnosticContext, out type, out var typeResolutionRecords, needsAssemblyName)) {
6564
type = default;
6665
return false;
6766
}
6867

69-
MarkResolvedType (diagnosticContext, typeRef, foundType, typeResolutionRecords);
70-
71-
type = foundType;
68+
MarkType (diagnosticContext, type, typeResolutionRecords);
7269
return true;
7370
}
7471

7572
// Resolve a type from the specified assembly and mark it for reflection.
76-
internal bool TryResolveTypeNameAndMark (AssemblyDefinition assembly, string typeName, in DiagnosticContext diagnosticContext, [NotNullWhen (true)] out TypeDefinition? type)
73+
internal bool TryResolveTypeNameAndMark (AssemblyDefinition assembly, string typeName, in DiagnosticContext diagnosticContext, [NotNullWhen (true)] out TypeReference? type)
7774
{
78-
if (!_context.TypeNameResolver.TryResolveTypeName (assembly, typeName, out TypeReference? typeRef, out var typeResolutionRecords)
79-
|| typeRef.ResolveToTypeDefinition (_context) is not TypeDefinition foundType) {
75+
if (!_context.TypeNameResolver.TryResolveTypeName (assembly, typeName, out type, out var typeResolutionRecords)) {
8076
type = default;
8177
return false;
8278
}
8379

84-
MarkResolvedType (diagnosticContext, typeRef, foundType, typeResolutionRecords);
85-
86-
type = foundType;
80+
MarkType (diagnosticContext, type, typeResolutionRecords);
8781
return true;
8882
}
8983

90-
void MarkResolvedType (
84+
void MarkType (
9185
in DiagnosticContext diagnosticContext,
9286
TypeReference typeReference,
93-
TypeDefinition typeDefinition,
9487
List<TypeNameResolver.TypeResolutionRecord> typeResolutionRecords)
9588
{
9689
if (_enabled) {
@@ -100,9 +93,9 @@ void MarkResolvedType (
10093
// This is necessary because if the app's code contains the input string as literal (which is pretty much always the case)
10194
// that string has to work at runtime, and if it relies on type forwarders we need to preserve those as well.
10295
var origin = diagnosticContext.Origin;
103-
_markStep.MarkTypeVisibleToReflection (typeReference, typeDefinition, new DependencyInfo (DependencyKind.AccessedViaReflection, origin.Provider), origin);
96+
_markStep.MarkTypeVisibleToReflection (typeReference, new DependencyInfo (DependencyKind.AccessedViaReflection, origin.Provider), origin);
10497
foreach (var typeResolutionRecord in typeResolutionRecords) {
105-
_context.MarkingHelpers.MarkMatchingExportedType (typeResolutionRecord.ResolvedType, typeResolutionRecord.ReferringAssembly, new DependencyInfo (DependencyKind.DynamicallyAccessedMember, typeDefinition), origin);
98+
_context.MarkingHelpers.MarkMatchingExportedType (typeResolutionRecord.ResolvedType, typeResolutionRecord.ReferringAssembly, new DependencyInfo (DependencyKind.DynamicallyAccessedMember, typeReference), origin);
10699
}
107100
}
108101
}
@@ -115,7 +108,7 @@ internal void MarkType (in MessageOrigin origin, TypeReference typeRef, Dependen
115108
if (typeRef.ResolveToTypeDefinition (_context) is not TypeDefinition type)
116109
return;
117110

118-
_markStep.MarkTypeVisibleToReflection (type, type, new DependencyInfo (dependencyKind, origin.Provider), origin);
111+
_markStep.MarkTypeVisibleToReflection (type, new DependencyInfo (dependencyKind, origin.Provider), origin);
119112
}
120113

121114
internal void MarkMethod (in MessageOrigin origin, MethodDefinition method, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)

src/tools/illink/src/linker/Linker.Dataflow/RequireDynamicallyAccessedMembersAction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public RequireDynamicallyAccessedMembersAction (
2323

2424
public partial bool TryResolveTypeNameAndMark (string typeName, bool needsAssemblyName, out TypeProxy type)
2525
{
26-
if (_reflectionMarker.TryResolveTypeNameAndMark (typeName, _diagnosticContext, needsAssemblyName, out TypeDefinition? foundType)) {
26+
if (_reflectionMarker.TryResolveTypeNameAndMark (typeName, _diagnosticContext, needsAssemblyName, out TypeReference? foundType)) {
2727
type = new (foundType);
2828
return true;
2929
} else {

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

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ internal void MarkEntireType (TypeDefinition type, in DependencyInfo reason, Mes
325325
MarkEntireType (nested, new DependencyInfo (DependencyKind.NestedType, type), origin);
326326
}
327327

328-
MarkTypeVisibleToReflection (type, type, reason, origin);
328+
MarkTypeVisibleToReflection (type, reason, origin);
329329
MarkCustomAttributes (type, new DependencyInfo (DependencyKind.CustomAttribute, type), origin);
330330
MarkTypeSpecialCustomAttributes (type, origin);
331331

@@ -914,7 +914,7 @@ void MarkMembersVisibleToReflection (IEnumerable<IMetadataTokenProvider> members
914914
foreach (var member in members) {
915915
switch (member) {
916916
case TypeDefinition type:
917-
MarkTypeVisibleToReflection (type, type, reason, origin);
917+
MarkTypeVisibleToReflection (type, reason, origin);
918918
break;
919919
case MethodDefinition method:
920920
MarkMethodVisibleToReflection (method, reason, origin);
@@ -1795,18 +1795,17 @@ protected virtual void MarkSerializable (TypeDefinition type, MessageOrigin orig
17951795
MarkMethodsIf (type.Methods, HasOnSerializeOrDeserializeAttribute, new DependencyInfo (DependencyKind.SerializationMethodForType, type), origin);
17961796
}
17971797

1798-
protected internal virtual TypeDefinition? MarkTypeVisibleToReflection (TypeReference type, TypeDefinition definition, in DependencyInfo reason, in MessageOrigin origin)
1798+
protected internal virtual void MarkTypeVisibleToReflection (TypeReference type, in DependencyInfo reason, in MessageOrigin origin)
17991799
{
1800-
// If a type is visible to reflection, we need to stop doing optimization that could cause observable difference
1801-
// in reflection APIs. This includes APIs like MakeGenericType (where variant castability of the produced type
1802-
// could be incorrect) or IsAssignableFrom (where assignability of unconstructed types might change).
1803-
Annotations.MarkRelevantToVariantCasting (definition);
1804-
1805-
Annotations.MarkReflectionUsed (definition);
1806-
1807-
MarkImplicitlyUsedFields (definition, origin);
1808-
1809-
return MarkType (type, reason, origin);
1800+
TypeDefinition? definition = MarkType (type, reason, origin);
1801+
if (definition is not null) {
1802+
// If a type is visible to reflection, we need to stop doing optimization that could cause observable difference
1803+
// in reflection APIs. This includes APIs like MakeGenericType (where variant castability of the produced type
1804+
// could be incorrect) or IsAssignableFrom (where assignability of unconstructed types might change).
1805+
Annotations.MarkRelevantToVariantCasting (definition);
1806+
Annotations.MarkReflectionUsed (definition);
1807+
MarkImplicitlyUsedFields (definition, origin);
1808+
}
18101809
}
18111810

18121811
internal void MarkMethodVisibleToReflection (MethodReference method, in DependencyInfo reason, in MessageOrigin origin)
@@ -3640,9 +3639,7 @@ protected virtual void MarkInstruction (Instruction instruction, MethodDefinitio
36403639
origin = new MessageOrigin (origin, instruction.Offset);
36413640

36423641
if (token is TypeReference typeReference) {
3643-
// Error will be reported as part of MarkType
3644-
if (Context.TryResolve (typeReference) is TypeDefinition type)
3645-
MarkTypeVisibleToReflection (typeReference, type, reason, origin);
3642+
MarkTypeVisibleToReflection (typeReference, reason, origin);
36463643
} else if (token is MethodReference methodReference) {
36473644
MarkMethodVisibleToReflection (methodReference, reason, origin);
36483645
} else {

src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,9 @@ public static bool IsNamedType (this TypeReference typeReference) {
435435
public static TypeDefinition? ResolveToTypeDefinition (this TypeReference typeReference, LinkContext context)
436436
=> typeReference is ArrayType
437437
? BCL.FindPredefinedType (WellKnownType.System_Array, context)
438-
: context.TryResolve (typeReference);
438+
: typeReference.IsNamedType ()
439+
? context.TryResolve (typeReference)
440+
: null;
439441

440442
public static bool IsByRefOrPointer (this TypeReference typeReference)
441443
{

src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,12 @@ public static void TestType ()
213213
}
214214

215215
[Kept]
216-
[KeptMember (".ctor()")]
217216
[KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]
218217
[RequiresUnreferencedCode (nameof (Pointer))]
219218
public class Pointer { }
220219

221220
[Kept]
222-
[ExpectedWarning ("IL2026", nameof (Pointer), Tool.Trimmer | Tool.NativeAot, "Analyzer doesn't treat members of pointer element type as reflected")]
221+
// Applying DynamicallyAccessedMembers annotations to a pointer type doesn't keep members of the underlying type.
223222
public static void TestPointer ()
224223
{
225224
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Pointer*";
@@ -228,13 +227,12 @@ public static void TestPointer ()
228227
}
229228

230229
[Kept]
231-
[KeptMember (".ctor()")]
232230
[KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]
233231
[RequiresUnreferencedCode (nameof (Reference))]
234232
public class Reference { }
235233

236234
[Kept]
237-
[ExpectedWarning ("IL2026", nameof (Reference), Tool.Trimmer | Tool.NativeAot, "Analyzer doesn't treat members of reference element type as reflected")]
235+
// Applying DynamicallyAccessedMembers annotations to a byref type doesn't keep members of the underlying type.
238236
public static void TestReference ()
239237
{
240238
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Reference&";

0 commit comments

Comments
 (0)