Skip to content

Commit

Permalink
First round of trimming annotation work
Browse files Browse the repository at this point in the history
To make basic save/query scenarios work with aggressive trimming, as
long as user types are properly preserved.

Closes dotnet#29092
  • Loading branch information
roji committed Sep 14, 2022
1 parent b8d4c14 commit 45ea21d
Show file tree
Hide file tree
Showing 91 changed files with 1,263 additions and 541 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore.Utilities;

namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
Expand All @@ -12,6 +13,8 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[RequiresUnreferencedCode(
"BindingList raises ListChanged events with PropertyDescriptors. PropertyDescriptors require unreferenced code.")]
public class ObservableBackedBindingList<T> : SortableBindingList<T>
{
private bool _addingNewInstance;
Expand All @@ -28,6 +31,8 @@ public class ObservableBackedBindingList<T> : SortableBindingList<T>
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[RequiresUnreferencedCode(
"BindingList raises ListChanged events with PropertyDescriptors. PropertyDescriptors require unreferenced code.")]
public ObservableBackedBindingList(ICollection<T> observableCollection)
: base(observableCollection.ToList())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;

Expand All @@ -12,6 +13,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[RequiresUnreferencedCode("Raises ListChanged events with PropertyDescriptors. PropertyDescriptors require unreferenced code.")]
public class SortableBindingList<T> : BindingList<T>
{
private bool _isSorted;
Expand All @@ -24,6 +26,7 @@ public class SortableBindingList<T> : BindingList<T>
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[RequiresUnreferencedCode("Raises ListChanged events with PropertyDescriptors. PropertyDescriptors require unreferenced code.")]
public SortableBindingList(List<T> list)
: base(list)
{
Expand All @@ -35,6 +38,13 @@ public SortableBindingList(List<T> list)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[RequiresUnreferencedCode("Requires accessing property 'Default' on the property descriptor's type")]
[UnconditionalSuppressMessage(
"ReflectionAnalysis",
"IL2046",
Justification =
"This method is an override, and the base method isn't annotated with RequiresUnreferencedCode. " +
"The entire type is marked with RequiresUnreferencedCode.")]
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
if (PropertyComparer.CanSort(prop.PropertyType))
Expand Down Expand Up @@ -101,6 +111,7 @@ private sealed class PropertyComparer : Comparer<T>
private readonly ListSortDirection _direction;
private readonly PropertyDescriptor _prop;

[RequiresUnreferencedCode("Requires accessing property 'Default' on the property descriptor's type")]
public PropertyComparer(PropertyDescriptor prop, ListSortDirection direction)
{
if (!prop.ComponentType.IsAssignableFrom(typeof(T)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.EntityFrameworkCore.ChangeTracking;

Expand All @@ -25,6 +26,8 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking;
/// </para>
/// </remarks>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
[RequiresUnreferencedCode(
"BindingList raises ListChanged events with PropertyDescriptors. PropertyDescriptors require unreferenced code.")]
public class ObservableCollectionListSource<T> : ObservableCollection<T>, IListSource
where T : class
{
Expand Down Expand Up @@ -71,6 +74,14 @@ bool IListSource.ContainsListCollection
/// <returns>
/// An <see cref="IBindingList" /> in sync with the ObservableCollection.
/// </returns>
[RequiresUnreferencedCode(
"BindingList raises ListChanged events with PropertyDescriptors. PropertyDescriptors require unreferenced code.")]
[UnconditionalSuppressMessage(
"ReflectionAnalysis",
"IL2046",
Justification =
"This method is an interface implementation, and the interface method isn't annotated with RequiresUnreferencedCode. " +
"The entire type is marked with RequiresUnreferencedCode.")]
IList IListSource.GetList()
=> _bindingList ??= this.ToBindingList();
}
2 changes: 2 additions & 0 deletions src/EFCore.Abstractions/EntityTypeConfigurationAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore.Utilities;

namespace Microsoft.EntityFrameworkCore;
Expand Down Expand Up @@ -28,5 +29,6 @@ public EntityTypeConfigurationAttribute(Type entityConfigurationType)
/// <summary>
/// Type of the entity type configuration.
/// </summary>
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.Interfaces)]
public Type EntityTypeConfigurationType { get; }
}
3 changes: 3 additions & 0 deletions src/EFCore.Abstractions/ObservableCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;

namespace Microsoft.EntityFrameworkCore;
Expand All @@ -23,6 +24,8 @@ public static class ObservableCollectionExtensions
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The collection that the binding list will stay in sync with.</param>
/// <returns>The binding list.</returns>
[RequiresUnreferencedCode(
"BindingList raises ListChanged events with PropertyDescriptors. PropertyDescriptors require unreferenced code.")]
public static BindingList<T> ToBindingList<T>(this ObservableCollection<T> source)
where T : class
=> new ObservableBackedBindingList<T>(source);
Expand Down
5 changes: 5 additions & 0 deletions src/EFCore.Relational/Migrations/IMigrator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.EntityFrameworkCore.Migrations;

/// <summary>
Expand Down Expand Up @@ -30,6 +32,7 @@ public interface IMigrator
/// <param name="targetMigration">
/// The target migration to migrate the database to, or <see langword="null" /> to migrate to the latest.
/// </param>
[RequiresUnreferencedCode("Migration generation currently isn't compatible with trimming")]
void Migrate(string? targetMigration = null);

/// <summary>
Expand All @@ -45,6 +48,7 @@ public interface IMigrator
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>A task that represents the asynchronous operation</returns>
/// <exception cref="OperationCanceledException">If the <see cref="CancellationToken" /> is canceled.</exception>
[RequiresUnreferencedCode("Migration generation currently isn't compatible with trimming")]
Task MigrateAsync(
string? targetMigration = null,
CancellationToken cancellationToken = default);
Expand All @@ -66,6 +70,7 @@ public interface IMigrator
/// The options to use when generating SQL for migrations.
/// </param>
/// <returns>The generated script.</returns>
[RequiresUnreferencedCode("Migration generation currently isn't compatible with trimming")]
string GenerateScript(
string? fromMigration = null,
string? toMigration = null,
Expand Down
5 changes: 4 additions & 1 deletion src/EFCore/ChangeTracking/GeometryValueComparer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.EntityFrameworkCore.ChangeTracking;

/// <summary>
Expand All @@ -9,7 +11,8 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking;
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-comparers">EF Core value comparers</see> for more information and examples.
/// </remarks>
public class GeometryValueComparer<TGeometry> : ValueComparer<TGeometry>
public class GeometryValueComparer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TGeometry>
: ValueComparer<TGeometry>
{
/// <summary>
/// Initializes a new instance of the <see cref="GeometryValueComparer{TGeometry}" /> class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public class IdentityMapFactoryFactory
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual Func<bool, IIdentityMap> Create(IKey key)
=> (Func<bool, IIdentityMap>)typeof(IdentityMapFactoryFactory).GetTypeInfo()
.GetDeclaredMethod(nameof(CreateFactory))!
=> (Func<bool, IIdentityMap>)typeof(IdentityMapFactoryFactory)
.GetMethod(nameof(CreateFactory), BindingFlags.NonPublic | BindingFlags.Static)!
.MakeGenericMethod(key.GetKeyType())
.Invoke(null, new object[] { key })!;

Expand Down
41 changes: 34 additions & 7 deletions src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Internal;
Expand Down Expand Up @@ -829,8 +830,9 @@ private void MarkShadowPropertiesNotSet(IEntityType entityType)
public void MarkUnknown(IProperty property)
=> _stateData.FlagProperty(property.GetIndex(), PropertyFlag.Unknown, true);

internal static readonly MethodInfo ReadShadowValueMethod
= typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadShadowValue))!;
internal static MethodInfo MakeReadShadowValueMethod(Type type)
=> typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadShadowValue))!
.MakeGenericMethod(type);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -841,38 +843,63 @@ public void MarkUnknown(IProperty property)
private T ReadShadowValue<T>(int shadowIndex)
=> _shadowValues.GetValue<T>(shadowIndex);

internal static readonly MethodInfo ReadOriginalValueMethod
private static readonly MethodInfo ReadOriginalValueMethod
= typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadOriginalValue))!;

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060",
Justification = "MakeGenericMethod wrapper, see https://github.com/dotnet/linker/issues/2482")]
internal static MethodInfo MakeReadOriginalValueMethod(Type type)
=> ReadOriginalValueMethod.MakeGenericMethod(type);

[UsedImplicitly]
private T ReadOriginalValue<T>(IProperty property, int originalValueIndex)
=> _originalValues.GetValue<T>(this, property, originalValueIndex);

internal static readonly MethodInfo ReadRelationshipSnapshotValueMethod
private static readonly MethodInfo ReadRelationshipSnapshotValueMethod
= typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadRelationshipSnapshotValue))!;

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060",
Justification = "MakeGenericMethod wrapper, see https://github.com/dotnet/linker/issues/2482")]
internal static MethodInfo MakeReadRelationshipSnapshotValueMethod(Type type)
=> ReadRelationshipSnapshotValueMethod.MakeGenericMethod(type);

[UsedImplicitly]
private T ReadRelationshipSnapshotValue<T>(IPropertyBase propertyBase, int relationshipSnapshotIndex)
=> _relationshipsSnapshot.GetValue<T>(this, propertyBase, relationshipSnapshotIndex);

internal static readonly MethodInfo ReadStoreGeneratedValueMethod
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060",
Justification = "MakeGenericMethod wrapper, see https://github.com/dotnet/linker/issues/2482")]
internal static MethodInfo MakeReadStoreGeneratedValueMethod(Type type)
=> ReadStoreGeneratedValueMethod.MakeGenericMethod(type);

private static readonly MethodInfo ReadStoreGeneratedValueMethod
= typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadStoreGeneratedValue))!;

[UsedImplicitly]
private T ReadStoreGeneratedValue<T>(int storeGeneratedIndex)
=> _storeGeneratedValues.GetValue<T>(storeGeneratedIndex);

internal static readonly MethodInfo ReadTemporaryValueMethod
private static readonly MethodInfo ReadTemporaryValueMethod
= typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadTemporaryValue))!;

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060",
Justification = "MakeGenericMethod wrapper, see https://github.com/dotnet/linker/issues/2482")]
internal static MethodInfo MakeReadTemporaryValueMethod(Type type)
=> ReadTemporaryValueMethod.MakeGenericMethod(type);

[UsedImplicitly]
private T ReadTemporaryValue<T>(int storeGeneratedIndex)
=> _temporaryValues.GetValue<T>(storeGeneratedIndex);

internal static readonly MethodInfo GetCurrentValueMethod
private static readonly MethodInfo GetCurrentValueMethod
= typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethods(nameof(GetCurrentValue)).Single(
m => m.IsGenericMethod);

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060",
Justification = "MakeGenericMethod wrapper, see https://github.com/dotnet/linker/issues/2482")]
internal static MethodInfo MakeGetCurrentValueMethod(Type type)
=> GetCurrentValueMethod.MakeGenericMethod(type);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
3 changes: 3 additions & 0 deletions src/EFCore/ChangeTracking/Internal/Snapshot.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;

/// <summary>
Expand Down Expand Up @@ -82,6 +84,7 @@ public static Delegate[] CreateReaders<TSnapshot>()
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
public static Type CreateSnapshotType(Type[] types)
=> types.Length switch
{
Expand Down
4 changes: 2 additions & 2 deletions src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ private Expression CreateSnapshotValueExpression(Expression expression, IPropert
IPropertyBase property)
=> Expression.Call(
parameter,
InternalEntityEntry.ReadShadowValueMethod.MakeGenericMethod((property as IProperty)?.ClrType ?? typeof(object)),
InternalEntityEntry.MakeReadShadowValueMethod((property as IProperty)?.ClrType ?? typeof(object)),
Expression.Constant(property.GetShadowIndex()));

/// <summary>
Expand All @@ -233,7 +233,7 @@ private Expression CreateSnapshotValueExpression(Expression expression, IPropert
IPropertyBase property)
=> Expression.Call(
parameter,
InternalEntityEntry.GetCurrentValueMethod.MakeGenericMethod(property.ClrType),
InternalEntityEntry.MakeGetCurrentValueMethod(property.ClrType),
Expression.Constant(property, typeof(IProperty)));

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;

/// <summary>
Expand All @@ -18,7 +20,7 @@ public class TemporaryValuesFactoryFactory : SidecarValuesFactoryFactory
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override Expression CreateSnapshotExpression(
Type? entityType,
[DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] Type? entityType,
ParameterExpression parameter,
Type[] types,
IList<IPropertyBase> propertyBases)
Expand Down
5 changes: 4 additions & 1 deletion src/EFCore/ChangeTracking/LocalView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Internal;

Expand Down Expand Up @@ -45,7 +46,7 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking;
/// </para>
/// </remarks>
/// <typeparam name="TEntity">The type of the entity in the local view.</typeparam>
public class LocalView<TEntity> :
public class LocalView<[DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] TEntity> :
ICollection<TEntity>,
INotifyCollectionChanged,
INotifyPropertyChanged,
Expand Down Expand Up @@ -473,6 +474,8 @@ private void OnCollectionChanged(NotifyCollectionChangedAction action, object it
/// examples.
/// </remarks>
/// <returns>The binding list.</returns>
[RequiresUnreferencedCode(
"BindingList raises ListChanged events with PropertyDescriptors. PropertyDescriptors require unreferenced code.")]
public virtual BindingList<TEntity> ToBindingList()
=> _bindingList ??= new ObservableBackedBindingList<TEntity>(ToObservableCollection());

Expand Down
Loading

0 comments on commit 45ea21d

Please sign in to comment.