Skip to content
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

Move ILLink.LinkAttributes to shared and support NullabilityInfoContext with trimming nullability attributes #56475

Merged
merged 7 commits into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions docs/workflow/trimming/feature-switches.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ configurations but their defaults might vary as any SDK can set the defaults dif
| EnableCppCLIHostActivation | System.Runtime.InteropServices.EnableCppCLIHostActivation | C++/CLI host activation code is disabled when set to false and related functionality can be trimmed. |
| MetadataUpdaterSupport | System.Reflection.Metadata.MetadataUpdater.IsSupported | Metadata update related code to be trimmed when set to false |
| _EnableConsumingManagedCodeFromNativeHosting | System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting | Getting a managed function from native hosting is disabled when set to false and related functionality can be trimmed. |
| NullabilityInfoContextSupport | System.Reflection.NullabilityInfoContext.IsSupported | Nullable attributes can be trimmed when set to false |
| _AggressiveAttributeTrimming | System.AggressiveAttributeTrimming | When set to true, aggressively trims attributes to allow for the most size savings possible, even if it could result in runtime behavior changes |
Copy link
Member

Choose a reason for hiding this comment

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

Why does the name have the _ prefix?

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 same reason _EnableConsumingManagedCodeFromNativeHosting has a _ prefix. This isn't intended to be a "public" setting, but only exists for Blazor WASM to trim these attributes, and an escape hatch for developers in case we got it wrong.


Any feature-switch which defines property can be set in csproj file or
on the command line as any other MSBuild property. Those without predefined property name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<linker>
<!-- The following attributes are only necessary when debugging is supported -->
<assembly fullname="System.Private.CoreLib" feature="System.Diagnostics.Debugger.IsSupported" featurevalue="false">
<!-- Debugger specific attributes -->
<type fullname="System.Diagnostics.DebuggableAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
Expand Down Expand Up @@ -57,4 +56,254 @@
<attribute internal="RemoveAttributeInstances" />
</type>
</assembly>

<!--
The following attributes are necessary when NullabilityInfoContext is supported.
Note these attributes are allowed to be in any assembly.
-->
<assembly fullname="*" feature="System.Reflection.NullabilityInfoContext.IsSupported" featurevalue="false">
<type fullname="System.Diagnostics.CodeAnalysis.AllowNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.DisallowNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.MaybeNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.NotNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.NullableAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.NullableContextAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.NullablePublicOnlyAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
</assembly>

<!--
Attributes listed below here should be behind the 'System.AggressiveAttributeTrimming' feature switch, which
is only enabled by default on app models that need as much size savings as possible.
-->

<assembly fullname="System.Private.CoreLib" feature="System.AggressiveAttributeTrimming" featurevalue="true">
<!-- System -->
<type fullname="System.CLSCompliantAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.ObsoleteAttribute">
<!--
Note that removing this attribute can change runtime behavior. For example,
System.Xml.Serialization will behave differently if a ctor is Obsolete.
This is low enough risk on when 'System.AggressiveAttributeTrimming' is enabled to justify
removing the attribute for size savings. The app developer can override this setting
to keep all ObsoleteAttributes.
-->
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- System.Diagnostics.CodeAnalysis -->
<type fullname="System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- System.Reflection -->
<type fullname="System.Reflection.AssemblyCompanyAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Reflection.AssemblyConfigurationAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Reflection.AssemblyCopyrightAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Reflection.AssemblyDefaultAliasAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Reflection.AssemblyDescriptionAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Reflection.AssemblyProductAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Reflection.AssemblyTitleAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- System.Runtime.CompilerServices -->
<type fullname="System.Runtime.CompilerServices.AsyncMethodBuilderAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.CallerArgumentExpressionAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.CallerMemberNameAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.CallerFilePathAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.CallerLineNumberAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.CallerMemberNameAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.CompilerGlobalScopeAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.IsReadOnlyAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.EnumeratorCancellationAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.ExtensionAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.SkipLocalsInitAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.TupleElementNamesAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- System.Runtime.Versioning -->
<type fullname="System.Runtime.Versioning.SupportedOSPlatformAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.Versioning.UnsupportedOSPlatformAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.Versioning.SupportedOSPlatformGuardAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.Versioning.UnsupportedOSPlatformGuardAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.Versioning.TargetPlatformAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- System.ComponentModel -->
<type fullname="System.ComponentModel.EditorBrowsableAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
</assembly>

<!-- Attributes that are allowed to be in any assembly -->
<assembly fullname="*" feature="System.AggressiveAttributeTrimming" featurevalue="true">
<!-- Internal attributes shared as implementation, so they could be in any assembly -->
<type fullname="System.Runtime.Versioning.NonVersionableAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- Attributes that tooling allows to be in any assembly to support earlier TFMs -->
<type fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.RequiresAssemblyFilesAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.SuppressMessageAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.NotNullWhenAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.MemberNotNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- The following attributes are generated by the compiler, so they could be in any assembly -->

<!-- System.Runtime.CompilerServices -->
<type fullname="System.Runtime.CompilerServices.IsUnmanagedAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.NativeIntegerAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- Microsoft.CodeAnalysis -->
<type fullname="Microsoft.CodeAnalysis.EmbeddedAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- Metadata attributes present in most core SDKs assemblies -->
<type fullname="System.Reflection.AssemblyMetadataAttribute">
<attribute internal="RemoveAttributeInstances">
<argument type="System.Object">
<argument>Serviceable</argument>
</argument>
</attribute>
</type>
<type fullname="System.Reflection.AssemblyMetadataAttribute">
<attribute internal="RemoveAttributeInstances">
<argument type="System.Object">
<argument>PreferInbox</argument>
</argument>
</attribute>
</type>
<type fullname="System.Reflection.AssemblyMetadataAttribute">
<attribute internal="RemoveAttributeInstances">
<argument type="System.Object">
<argument>.NETFrameworkAssembly</argument>
</argument>
</attribute>
</type>
<type fullname="System.Reflection.AssemblyMetadataAttribute">
<attribute internal="RemoveAttributeInstances">
<argument type="System.Object">
<argument>RepositoryUrl</argument>
</argument>
</attribute>
</type>
<type fullname="System.Reflection.AssemblyMetadataAttribute">
<attribute internal="RemoveAttributeInstances">
<argument type="System.Object">
<argument>SourceCommitUrl</argument>
</argument>
</attribute>
</type>
<type fullname="System.Reflection.AssemblyMetadataAttribute">
<attribute internal="RemoveAttributeInstances">
<argument type="System.Object">
<argument>CommitHash</argument>
</argument>
</attribute>
</type>
<type fullname="System.Reflection.AssemblyMetadataAttribute">
<attribute internal="RemoveAttributeInstances">
<argument type="System.Object">
<argument>IsTrimmable</argument>
</argument>
</attribute>
</type>
</assembly>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,8 @@
<type fullname="System.Reflection.Metadata.MetadataUpdater" feature="System.Reflection.Metadata.MetadataUpdater.IsSupported" featurevalue="false">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
<type fullname="System.Reflection.NullabilityInfoContext" feature="System.Reflection.NullabilityInfoContext.IsSupported" featurevalue="false">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
</assembly>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -3814,4 +3814,7 @@
<data name="TimeZoneNotFound_ValidTimeZoneFileMissing" xml:space="preserve">
<value>Unable to properly load any time zone data files.</value>
</data>
<data name="NullabilityInfoContext_NotSupported" xml:space="preserve">
<value>NullabilityInfoContext is not supported in the current application because 'System.Reflection.NullabilityInfoContext.IsSupported' is set to false. Set the MSBuild Property 'NullabilityInfoContextSupport' to true in order to enable it.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;

namespace System.Reflection
{
Expand All @@ -17,6 +16,9 @@ public sealed class NullabilityInfoContext
private readonly Dictionary<Module, NotAnnotatedStatus> _publicOnlyModules = new();
private readonly Dictionary<MemberInfo, NullabilityState> _context = new();

internal static bool IsSupported { get; } =
AppContext.TryGetSwitch("System.Reflection.NullabilityInfoContext.IsSupported", out bool isSupported) ? isSupported : true;

[Flags]
private enum NotAnnotatedStatus
{
Expand Down Expand Up @@ -60,14 +62,15 @@ private NullabilityState GetNullableContext(MemberInfo? memberInfo)
/// <param name="parameterInfo">The parameter which nullability info gets populated</param>
/// <exception cref="ArgumentNullException">If the parameterInfo parameter is null</exception>
/// <returns><see cref="NullabilityInfo" /></returns>
[RequiresUnreferencedCode("By default nullability attributes are trimmed by the trimmer")]
public NullabilityInfo Create(ParameterInfo parameterInfo)
{
if (parameterInfo is null)
{
throw new ArgumentNullException(nameof(parameterInfo));
}

EnsureIsSupported();

if (parameterInfo.Member is MethodInfo method && IsPrivateOrInternalMethodAndAnnotationDisabled(method))
{
return new NullabilityInfo(parameterInfo.ParameterType, NullabilityState.Unknown, NullabilityState.Unknown, null, Array.Empty<NullabilityInfo>());
Expand Down Expand Up @@ -172,14 +175,15 @@ private void CheckNullabilityAttributes(NullabilityInfo nullability, IList<Custo
/// <param name="propertyInfo">The parameter which nullability info gets populated</param>
/// <exception cref="ArgumentNullException">If the propertyInfo parameter is null</exception>
/// <returns><see cref="NullabilityInfo" /></returns>
[RequiresUnreferencedCode("By default nullability attributes are trimmed by the trimmer")]
public NullabilityInfo Create(PropertyInfo propertyInfo)
{
if (propertyInfo is null)
{
throw new ArgumentNullException(nameof(propertyInfo));
}

EnsureIsSupported();

NullabilityInfo nullability = GetNullabilityInfo(propertyInfo, propertyInfo.PropertyType, propertyInfo.GetCustomAttributesData());
MethodInfo? getter = propertyInfo.GetGetMethod(true);
MethodInfo? setter = propertyInfo.GetSetMethod(true);
Expand Down Expand Up @@ -234,14 +238,15 @@ private bool IsPrivateOrInternalMethodAndAnnotationDisabled(MethodInfo method)
/// <param name="eventInfo">The parameter which nullability info gets populated</param>
/// <exception cref="ArgumentNullException">If the eventInfo parameter is null</exception>
/// <returns><see cref="NullabilityInfo" /></returns>
[RequiresUnreferencedCode("By default nullability attributes are trimmed by the trimmer")]
public NullabilityInfo Create(EventInfo eventInfo)
{
if (eventInfo is null)
{
throw new ArgumentNullException(nameof(eventInfo));
}

EnsureIsSupported();

return GetNullabilityInfo(eventInfo, eventInfo.EventHandlerType!, eventInfo.GetCustomAttributesData());
}

Expand All @@ -253,14 +258,15 @@ public NullabilityInfo Create(EventInfo eventInfo)
/// <param name="fieldInfo">The parameter which nullability info gets populated</param>
/// <exception cref="ArgumentNullException">If the fieldInfo parameter is null</exception>
/// <returns><see cref="NullabilityInfo" /></returns>
[RequiresUnreferencedCode("By default nullability attributes are trimmed by the trimmer")]
public NullabilityInfo Create(FieldInfo fieldInfo)
{
if (fieldInfo is null)
{
throw new ArgumentNullException(nameof(fieldInfo));
}

EnsureIsSupported();

if (IsPrivateOrInternalFieldAndAnnotationDisabled(fieldInfo))
{
return new NullabilityInfo(fieldInfo.FieldType, NullabilityState.Unknown, NullabilityState.Unknown, null, Array.Empty<NullabilityInfo>());
Expand All @@ -272,6 +278,14 @@ public NullabilityInfo Create(FieldInfo fieldInfo)
return nullability;
}

private static void EnsureIsSupported()
{
if (!IsSupported)
{
throw new InvalidOperationException(SR.NullabilityInfoContext_NotSupported);
}
}

private bool IsPrivateOrInternalFieldAndAnnotationDisabled(FieldInfo fieldInfo)
{
if ((fieldInfo.IsPrivate || fieldInfo.IsFamilyAndAssembly || fieldInfo.IsAssembly) &&
Expand Down
Loading