Skip to content

Resolve ILLink warnings in System.Text.RegularExpressions #46687

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ public FieldBuilder DefineLiteral(string literalName, object? literalValue)
return fieldBuilder;
}

[return: DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes.All)]
public TypeInfo? CreateTypeInfo()
{
return m_typeBuilder.CreateTypeInfo();
}

// CreateType cause EnumBuilder to be baked.
[return: DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes.All)]
public Type? CreateType()
{
return m_typeBuilder.CreateType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1881,6 +1881,7 @@ private EventBuilder DefineEventNoLock(string name, EventAttributes attributes,

#region Create Type

[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public TypeInfo? CreateTypeInfo()
{
lock (SyncRoot)
Expand All @@ -1889,6 +1890,7 @@ private EventBuilder DefineEventNoLock(string name, EventAttributes attributes,
}
}

[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public Type? CreateType()
{
lock (SyncRoot)
Expand All @@ -1897,6 +1899,9 @@ private EventBuilder DefineEventNoLock(string name, EventAttributes attributes,
}
}

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2083:UnrecognizedReflectionPattern",
Justification = "Reflection.Emit is not subject to trimming")]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
private TypeInfo? CreateTypeNoLock()
{
if (IsCreated())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ internal EnumBuilder() { }
public override System.RuntimeTypeHandle TypeHandle { get { throw null; } }
public System.Reflection.Emit.FieldBuilder UnderlyingField { get { throw null; } }
public override System.Type UnderlyingSystemType { get { throw null; } }
[return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)]
public System.Reflection.TypeInfo? CreateTypeInfo() { throw null; }
public System.Reflection.Emit.FieldBuilder DefineLiteral(string literalName, object? literalValue) { throw null; }
protected override System.Reflection.TypeAttributes GetAttributeFlagsImpl() { throw null; }
Expand Down Expand Up @@ -460,7 +461,9 @@ internal TypeBuilder() { }
public override System.RuntimeTypeHandle TypeHandle { get { throw null; } }
public override System.Type UnderlyingSystemType { get { throw null; } }
public void AddInterfaceImplementation([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type interfaceType) { }
[return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)]
public System.Type? CreateType() { throw null; }
[return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)]
public System.Reflection.TypeInfo? CreateTypeInfo() { throw null; }
public System.Reflection.Emit.ConstructorBuilder DefineConstructor(System.Reflection.MethodAttributes attributes, System.Reflection.CallingConventions callingConvention, System.Type[]? parameterTypes) { throw null; }
public System.Reflection.Emit.ConstructorBuilder DefineConstructor(System.Reflection.MethodAttributes attributes, System.Reflection.CallingConventions callingConvention, System.Type[]? parameterTypes, System.Type[][]? requiredCustomModifiers, System.Type[][]? optionalCustomModifiers) { throw null; }
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Threading;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

#if DEBUG // until it can be fully implemented
namespace System.Text.RegularExpressions
Expand Down Expand Up @@ -97,14 +98,19 @@ private void GenerateInitTrackCount()
}

/// <summary>Generates a very simple factory method.</summary>
internal void GenerateCreateInstance(Type type)
private void GenerateCreateInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type)
{
// return new Type();
Newobj(type.GetConstructor(Type.EmptyTypes)!);
Ret();
}

private void GenerateRegexDefaultCtor(string pattern, RegexOptions options, Type regexRunnerFactoryType, RegexCode code, TimeSpan matchTimeout)
private void GenerateRegexDefaultCtor(
string pattern,
RegexOptions options,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type regexRunnerFactoryType,
RegexCode code,
TimeSpan matchTimeout)
{
// Call the base ctor and store pattern, options, and factory.
// base.ctor();
Expand Down Expand Up @@ -241,7 +247,12 @@ internal void Save()
}

/// <summary>Begins the definition of a new type with a specified base class</summary>
private static TypeBuilder DefineType(ModuleBuilder moduleBuilder, string typeName, bool isPublic, bool isSealed, Type inheritFromClass)
private static TypeBuilder DefineType(
ModuleBuilder moduleBuilder,
string typeName,
bool isPublic,
bool isSealed,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type inheritFromClass)
{
TypeAttributes attrs = TypeAttributes.Class | TypeAttributes.BeforeFieldInit | (isPublic ? TypeAttributes.Public : TypeAttributes.NotPublic);
if (isSealed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ namespace System.Text.RegularExpressions
/// RegexCompiler translates a block of RegexCode to MSIL, and creates a
/// subclass of the RegexRunner type.
/// </summary>
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
Target = "M:System.Text.RegularExpressions.RegexCompiler.#cctor",
Justification = "The referenced methods don't have any DynamicallyAccessedMembers annotations. See https://github.com/mono/linker/issues/1727")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated, are all of the patterns employed below recognized by the linker? i.e. it's able to see it must preserve the IsBoundary method, the runtrack field, the char.IsDigit method, etc?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ILLinker isn't warning for these methods:

        private static FieldInfo RegexRunnerField(string fieldname) => typeof(RegexRunner).GetField(fieldname, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)!;

        private static MethodInfo RegexRunnerMethod(string methname) => typeof(RegexRunner).GetMethod(methname, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)!;

My understanding is because it sees the specified typeof(RegexRunner) and thinks "I must preserve all Methods and Fields on the RegexRunner Type, since these methods try getting fields and methods on this Type".

But @vitek-karas and @MichalStrehovsky would know for sure if the above reasoning is correct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can validate by debugging the linker if needed, but @eerhardt is right - the call to GetField will fallback to basically mark all fields which fulfill the binding flags, if it can't figure out the name of the field statically (like in this case). Same goes for GetMethod.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info.

internal abstract class RegexCompiler
{
private static readonly FieldInfo s_runtextbegField = RegexRunnerField("runtextbeg");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,13 @@ public override Type UnderlyingSystemType
}
}

[return: DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes.All)]
public Type? CreateType()
{
return _tb.CreateType();
}

[return: DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes.All)]
public TypeInfo? CreateTypeInfo()
{
return _tb.CreateTypeInfo();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -796,10 +796,9 @@ private bool has_ctor_method()
// We require emitted types to have all members on their bases to be accessible.
// This is basically an identity function for `this`.
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2083:UnrecognizedReflectionPattern",
Justification = "Reflection emitted types have all of their members")]
Justification = "Reflection.Emit is not subject to trimming")]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public
TypeInfo? CreateTypeInfo()
public TypeInfo? CreateTypeInfo()
{
/* handle nesting_type */
if (createTypeCalled)
Expand Down