diff --git a/eng/illink.targets b/eng/illink.targets index ecbe07e843837..5fefadd4b51b7 100644 --- a/eng/illink.targets +++ b/eng/illink.targets @@ -47,8 +47,6 @@ $(ILLinkDirectory)ILLink.Suppressions $(ILLinkSuppressionsXmlFilePrefix).xml $(ILLinkSuppressionsXmlFilePrefix).$(Configuration).xml - $(ILLinkSuppressionsXmlFilePrefix).$(TargetOS).xml - $(ILLinkSuppressionsXmlFilePrefix).NonWindows.xml true @@ -87,10 +85,6 @@ Include="$(ILLinkSuppressionsXmlFile)" /> - - diff --git a/src/libraries/System.Linq.Queryable/ref/System.Linq.Queryable.cs b/src/libraries/System.Linq.Queryable/ref/System.Linq.Queryable.cs index 55290e7106aa9..060cf4df2dc6d 100644 --- a/src/libraries/System.Linq.Queryable/ref/System.Linq.Queryable.cs +++ b/src/libraries/System.Linq.Queryable/ref/System.Linq.Queryable.cs @@ -20,7 +20,9 @@ internal EnumerableQuery() { } } public partial class EnumerableQuery : System.Linq.EnumerableQuery, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Linq.IOrderedQueryable, System.Linq.IOrderedQueryable, System.Linq.IQueryable, System.Linq.IQueryable, System.Linq.IQueryProvider { + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Enumerating in-memory collections as IQueryable can require unreferenced code because expressions referencing IQueryable extension methods can get rebound to IEnumerable extension methods. The IEnumerable extension methods could be trimmed causing the application to fail at runtime.")] public EnumerableQuery(System.Collections.Generic.IEnumerable enumerable) { } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Enumerating in-memory collections as IQueryable can require unreferenced code because expressions referencing IQueryable extension methods can get rebound to IEnumerable extension methods. The IEnumerable extension methods could be trimmed causing the application to fail at runtime.")] public EnumerableQuery(System.Linq.Expressions.Expression expression) { } System.Type System.Linq.IQueryable.ElementType { get { throw null; } } System.Linq.Expressions.Expression System.Linq.IQueryable.Expression { get { throw null; } } @@ -42,7 +44,9 @@ public static partial class Queryable public static bool Any(this System.Linq.IQueryable source) { throw null; } public static bool Any(this System.Linq.IQueryable source, System.Linq.Expressions.Expression> predicate) { throw null; } public static System.Linq.IQueryable Append(this System.Linq.IQueryable source, TSource element) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Enumerating in-memory collections as IQueryable can require unreferenced code because expressions referencing IQueryable extension methods can get rebound to IEnumerable extension methods. The IEnumerable extension methods could be trimmed causing the application to fail at runtime.")] public static System.Linq.IQueryable AsQueryable(this System.Collections.IEnumerable source) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Enumerating in-memory collections as IQueryable can require unreferenced code because expressions referencing IQueryable extension methods can get rebound to IEnumerable extension methods. The IEnumerable extension methods could be trimmed causing the application to fail at runtime.")] public static System.Linq.IQueryable AsQueryable(this System.Collections.Generic.IEnumerable source) { throw null; } public static decimal Average(this System.Linq.IQueryable source) { throw null; } public static double Average(this System.Linq.IQueryable source) { throw null; } diff --git a/src/libraries/System.Linq.Queryable/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Linq.Queryable/src/ILLink/ILLink.Suppressions.xml deleted file mode 100644 index 2393a6a50d10a..0000000000000 --- a/src/libraries/System.Linq.Queryable/src/ILLink/ILLink.Suppressions.xml +++ /dev/null @@ -1,677 +0,0 @@ - - - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Aggregate_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Aggregate_TSource_TAccumulate_3(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Aggregate_TSource_TAccumulate_TResult_4(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.All_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Any_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Any_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Append_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_Decimal_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_Double_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_Int32_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_Int64_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_NullableDecimal_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_NullableDouble_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_NullableInt32_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_NullableInt64_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_NullableSingle_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Average_Single_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Cast_TResult_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Chunk_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Concat_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Contains_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Contains_TSource_3(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Count_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Count_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.DefaultIfEmpty_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.DefaultIfEmpty_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Distinct_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Distinct_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.ElementAt_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.ElementAtOrDefault_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Except_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Except_TSource_3(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.First_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.First_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.FirstOrDefault_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.FirstOrDefault_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupBy_TSource_TKey_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupBy_TSource_TKey_3(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupBy_TSource_TKey_TElement_3(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupBy_TSource_TKey_TElement_4(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupBy_TSource_TKey_TElement_TResult_4(System.Type,System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupBy_TSource_TKey_TElement_TResult_5(System.Type,System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupBy_TSource_TKey_TResult_3(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupBy_TSource_TKey_TResult_4(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupJoin_TOuter_TInner_TKey_TResult_5(System.Type,System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.GroupJoin_TOuter_TInner_TKey_TResult_6(System.Type,System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Intersect_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Intersect_TSource_3(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Join_TOuter_TInner_TKey_TResult_5(System.Type,System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Join_TOuter_TInner_TKey_TResult_6(System.Type,System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Last_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Last_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.LastOrDefault_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.LastOrDefault_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.LongCount_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.LongCount_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Max_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Max_TSource_TResult_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Min_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Min_TSource_TResult_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.OfType_TResult_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.OrderBy_TSource_TKey_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.OrderBy_TSource_TKey_3(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.OrderByDescending_TSource_TKey_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.OrderByDescending_TSource_TKey_3(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Prepend_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Reverse_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Select_Index_TSource_TResult_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Select_TSource_TResult_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SelectMany_Index_TSource_TCollection_TResult_3(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SelectMany_Index_TSource_TResult_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SelectMany_TSource_TCollection_TResult_3(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SelectMany_TSource_TResult_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SequenceEqual_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SequenceEqual_TSource_3(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Single_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Single_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SingleOrDefault_TSource_1(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SingleOrDefault_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Skip_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SkipLast_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SkipWhile_Index_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.SkipWhile_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_Decimal_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_Double_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_Int32_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_Int64_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_NullableDecimal_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_NullableDouble_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_NullableInt32_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_NullableInt64_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_NullableSingle_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Sum_Single_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Take_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.TakeLast_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.TakeWhile_Index_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.TakeWhile_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.ThenBy_TSource_TKey_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.ThenBy_TSource_TKey_3(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.ThenByDescending_TSource_TKey_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.ThenByDescending_TSource_TKey_3(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Union_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Union_TSource_3(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Where_Index_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Where_TSource_2(System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Zip_TFirst_TSecond_2(System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Zip_TFirst_TSecond_TResult_3(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.CachedReflectionInfo.Zip_TFirst_TSecond_TThird_3(System.Type,System.Type,System.Type) - - - ILLink - IL2060 - member - M:System.Linq.EnumerableRewriter.ArgsMatch(System.Reflection.MethodInfo,System.Collections.ObjectModel.ReadOnlyCollection{System.Linq.Expressions.Expression},System.Type[]) - - - ILLink - IL2060 - member - M:System.Linq.EnumerableRewriter.FindEnumerableMethod(System.String,System.Collections.ObjectModel.ReadOnlyCollection{System.Linq.Expressions.Expression},System.Type[]) - - - ILLink - IL2060 - member - M:System.Linq.EnumerableRewriter.FindMethod(System.Type,System.String,System.Collections.ObjectModel.ReadOnlyCollection{System.Linq.Expressions.Expression},System.Type[]) - - - ILLink - IL2067 - member - M:System.Linq.TypeHelper.GetStaticMethods(System.Type) - - - diff --git a/src/libraries/System.Linq.Queryable/src/System/Linq/CachedReflection.cs b/src/libraries/System.Linq.Queryable/src/System/Linq/CachedReflection.cs index 11b615fd44b21..f7e9a83002de3 100644 --- a/src/libraries/System.Linq.Queryable/src/System/Linq/CachedReflection.cs +++ b/src/libraries/System.Linq.Queryable/src/System/Linq/CachedReflection.cs @@ -2,11 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; namespace System.Linq { + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod", + Justification = "The methods passed into MakeGenericMethod do not contain trim annotations.")] internal static class CachedReflectionInfo { private static MethodInfo? s_Aggregate_TSource_2; diff --git a/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableExecutor.cs b/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableExecutor.cs index d7185e70083bc..5ff04c6fdcc16 100644 --- a/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableExecutor.cs +++ b/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableExecutor.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace System.Linq { public abstract class EnumerableExecutor { + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] internal abstract object? ExecuteBoxed(); internal EnumerableExecutor() { } @@ -28,8 +30,10 @@ public EnumerableExecutor(Expression expression) _expression = expression; } + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] internal override object? ExecuteBoxed() => Execute(); + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] internal T Execute() { EnumerableRewriter rewriter = new EnumerableRewriter(); diff --git a/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableQuery.cs b/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableQuery.cs index 350ae38f1f30a..3bdd99ea15d07 100644 --- a/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableQuery.cs +++ b/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableQuery.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace System.Linq @@ -14,12 +15,14 @@ public abstract class EnumerableQuery internal EnumerableQuery() { } + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] internal static IQueryable Create(Type elementType, IEnumerable sequence) { Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType); return (IQueryable)Activator.CreateInstance(seqType, sequence)!; } + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] internal static IQueryable Create(Type elementType, Expression expression) { Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType); @@ -34,12 +37,14 @@ public class EnumerableQuery : EnumerableQuery, IOrderedQueryable, IQueryP IQueryProvider IQueryable.Provider => this; + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] public EnumerableQuery(IEnumerable enumerable) { _enumerable = enumerable; _expression = Expression.Constant(this); } + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] public EnumerableQuery(Expression expression) { _expression = expression; @@ -53,6 +58,8 @@ public EnumerableQuery(Expression expression) Type IQueryable.ElementType => typeof(T); + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")] IQueryable IQueryProvider.CreateQuery(Expression expression) { if (expression == null) @@ -63,6 +70,8 @@ IQueryable IQueryProvider.CreateQuery(Expression expression) return Create(iqType.GetGenericArguments()[0], expression); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")] IQueryable IQueryProvider.CreateQuery(Expression expression) { if (expression == null) @@ -74,6 +83,8 @@ IQueryable IQueryProvider.CreateQuery(Expression expression) return new EnumerableQuery(expression); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")] object? IQueryProvider.Execute(Expression expression) { if (expression == null) @@ -81,6 +92,8 @@ IQueryable IQueryProvider.CreateQuery(Expression expression) return EnumerableExecutor.Create(expression).ExecuteBoxed(); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")] TElement IQueryProvider.Execute(Expression expression) { if (expression == null) @@ -94,6 +107,8 @@ TElement IQueryProvider.Execute(Expression expression) IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")] private IEnumerator GetEnumerator() { if (_enumerable == null) diff --git a/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableRewriter.cs b/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableRewriter.cs index c7cd1e29ce0f3..d4448372c3167 100644 --- a/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableRewriter.cs +++ b/src/libraries/System.Linq.Queryable/src/System/Linq/EnumerableRewriter.cs @@ -19,6 +19,13 @@ internal class EnumerableRewriter : ExpressionVisitor // Finding equivalent types can be relatively expensive, and hitting with the same types repeatedly is quite likely. private Dictionary? _equivalentTypeCache; + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] + public EnumerableRewriter() + { + } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")] protected override Expression VisitMethodCall(MethodCallExpression m) { Expression? obj = Visit(m.Object); @@ -39,7 +46,7 @@ protected override Expression VisitMethodCall(MethodCallExpression m) else if (mInfo.DeclaringType == typeof(Queryable)) { // convert Queryable method to Enumerable method - MethodInfo seqMethod = FindEnumerableMethod(mInfo.Name, args, typeArgs); + MethodInfo seqMethod = FindEnumerableMethodForQueryable(mInfo.Name, args, typeArgs); args = FixupQuotedArgs(seqMethod, args); return Expression.Call(obj, seqMethod, args); } @@ -208,25 +215,32 @@ protected override Expression VisitConstant(ConstantExpression c) return c; } - - private static ILookup? s_seqMethods; - private static MethodInfo FindEnumerableMethod(string name, ReadOnlyCollection args, params Type[]? typeArgs) + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod", + Justification = "Enumerable methods don't have trim annotations.")] + private static MethodInfo FindEnumerableMethodForQueryable(string name, ReadOnlyCollection args, params Type[]? typeArgs) { if (s_seqMethods == null) { - s_seqMethods = typeof(Enumerable).GetStaticMethods().ToLookup(m => m.Name); + s_seqMethods = GetEnumerableStaticMethods(typeof(Enumerable)).ToLookup(m => m.Name); } MethodInfo? mi = s_seqMethods[name].FirstOrDefault(m => ArgsMatch(m, args, typeArgs)); Debug.Assert(mi != null, "All static methods with arguments on Queryable have equivalents on Enumerable."); if (typeArgs != null) return mi.MakeGenericMethod(typeArgs); return mi; + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", + Justification = "This method is intentionally hiding the Enumerable type from the trimmer so it doesn't preserve all Enumerable's methods. " + + "This is safe because all Queryable methods have a DynamicDependency to the corresponding Enumerable method.")] + static MethodInfo[] GetEnumerableStaticMethods(Type type) => + type.GetMethods(BindingFlags.Public | BindingFlags.Static); } + [RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] private static MethodInfo FindMethod(Type type, string name, ReadOnlyCollection args, Type[]? typeArgs) { - using (IEnumerator en = type.GetStaticMethods().Where(m => m.Name == name).GetEnumerator()) + using (IEnumerator en = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).Where(m => m.Name == name).GetEnumerator()) { if (!en.MoveNext()) throw Error.NoMethodOnType(name, type); @@ -259,8 +273,13 @@ private static bool ArgsMatch(MethodInfo m, ReadOnlyCollection args, return false; if (m.GetGenericArguments().Length != typeArgs.Length) return false; - m = m.MakeGenericMethod(typeArgs); - mParams = m.GetParameters(); + + mParams = GetConstrutedGenericParameters(m, typeArgs); + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod", + Justification = "MakeGenericMethod is only called to get the parameter types, which are only used to make a 'match' decision. The generic method is not invoked.")] + static ParameterInfo[] GetConstrutedGenericParameters(MethodInfo method, Type[] genericTypes) => + method.MakeGenericMethod(genericTypes).GetParameters(); } for (int i = 0, n = args.Count; i < n; i++) { diff --git a/src/libraries/System.Linq.Queryable/src/System/Linq/Queryable.cs b/src/libraries/System.Linq.Queryable/src/System/Linq/Queryable.cs index 16befe027e4d6..a4859f68608b8 100644 --- a/src/libraries/System.Linq.Queryable/src/System/Linq/Queryable.cs +++ b/src/libraries/System.Linq.Queryable/src/System/Linq/Queryable.cs @@ -10,6 +10,9 @@ namespace System.Linq { public static class Queryable { + internal const string InMemoryQueryableExtensionMethodsRequiresUnreferencedCode = "Enumerating in-memory collections as IQueryable can require unreferenced code because expressions referencing IQueryable extension methods can get rebound to IEnumerable extension methods. The IEnumerable extension methods could be trimmed causing the application to fail at runtime."; + + [RequiresUnreferencedCode(InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] public static IQueryable AsQueryable(this IEnumerable source) { if (source == null) @@ -17,6 +20,7 @@ public static IQueryable AsQueryable(this IEnumerable ?? new EnumerableQuery(source); } + [RequiresUnreferencedCode(InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)] public static IQueryable AsQueryable(this IEnumerable source) { if (source == null) diff --git a/src/libraries/System.Linq.Queryable/src/System/Linq/TypeHelper.cs b/src/libraries/System.Linq.Queryable/src/System/Linq/TypeHelper.cs index 7f2e0b50a6a07..64ef0c4201d67 100644 --- a/src/libraries/System.Linq.Queryable/src/System/Linq/TypeHelper.cs +++ b/src/libraries/System.Linq.Queryable/src/System/Linq/TypeHelper.cs @@ -1,10 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; - namespace System.Linq { internal static class TypeHelper @@ -31,10 +27,5 @@ internal static class TypeHelper } return null; } - - internal static IEnumerable GetStaticMethods(this Type type) - { - return type.GetRuntimeMethods().Where(m => m.IsStatic); - } } } diff --git a/src/libraries/System.Linq.Queryable/tests/Queryable.cs b/src/libraries/System.Linq.Queryable/tests/Queryable.cs index 9766b2581cbcb..5ccedaccacb64 100644 --- a/src/libraries/System.Linq.Queryable/tests/Queryable.cs +++ b/src/libraries/System.Linq.Queryable/tests/Queryable.cs @@ -78,40 +78,6 @@ public static void QueryableOfQueryable() Assert.Equal(2, i); } - /// - /// Verifies that all the Queryable methods contain a DynamicDependency - /// to the corresponding Enumerable method. This ensures the ILLinker will - /// preserve the corresponding Enumerable method when trimming. - /// - [Fact] - public static void QueryableMethodsContainCorrectDynamicDependency() - { - IEnumerable dependentMethods = - typeof(Queryable) - .GetMethods(BindingFlags.Public | BindingFlags.Static) - .Where(m => m.Name != "AsQueryable"); - - foreach (MethodInfo method in dependentMethods) - { - DynamicDependencyAttribute dependency = method.GetCustomAttribute(); - Assert.NotNull(dependency); - Assert.Equal(typeof(Enumerable), dependency.Type); - - int genericArgCount = 0; - string methodName = dependency.MemberSignature; - - int genericSeparator = methodName.IndexOf('`'); - if (genericSeparator != -1) - { - genericArgCount = int.Parse(methodName.Substring(genericSeparator + 1)); - methodName = methodName.Substring(0, genericSeparator); - } - - Assert.Equal(method.GetGenericArguments().Length, genericArgCount); - Assert.Equal(method.Name, methodName); - } - } - [Fact] public static void MatchSequencePattern() { diff --git a/src/libraries/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj b/src/libraries/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj index bceba421dbd45..a0124a904af1b 100644 --- a/src/libraries/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj +++ b/src/libraries/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj @@ -51,6 +51,7 @@ + diff --git a/src/libraries/System.Linq.Queryable/tests/TrimCompatibilityTests.cs b/src/libraries/System.Linq.Queryable/tests/TrimCompatibilityTests.cs new file mode 100644 index 0000000000000..76d7e864ca9b4 --- /dev/null +++ b/src/libraries/System.Linq.Queryable/tests/TrimCompatibilityTests.cs @@ -0,0 +1,116 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Xunit; + +namespace System.Linq.Tests +{ + public class TrimCompatibilityTests + { + /// + /// Verifies that all the Queryable methods contain a DynamicDependency + /// to the corresponding Enumerable method. This ensures the ILLinker will + /// preserve the corresponding Enumerable method when trimming. + /// + [Fact] + public static void QueryableMethodsContainCorrectDynamicDependency() + { + IEnumerable dependentMethods = + typeof(Queryable) + .GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(m => m.Name != "AsQueryable"); + + foreach (MethodInfo method in dependentMethods) + { + DynamicDependencyAttribute dependency = method.GetCustomAttribute(); + Assert.NotNull(dependency); + Assert.Equal(typeof(Enumerable), dependency.Type); + + int genericArgCount = 0; + string methodName = dependency.MemberSignature; + + int genericSeparator = methodName.IndexOf('`'); + if (genericSeparator != -1) + { + genericArgCount = int.Parse(methodName.Substring(genericSeparator + 1)); + methodName = methodName.Substring(0, genericSeparator); + } + + Assert.Equal(method.GetGenericArguments().Length, genericArgCount); + Assert.Equal(method.Name, methodName); + } + } + + /// + /// Verifies that all methods in CachedReflectionInfo that call MakeGenericMethod + /// call it on a method that doesn't contain any trimming annotations (i.e. DynamicallyAccessedMembers). + /// + /// + /// This ensures it is safe to suppress IL2060:MakeGenericMethod warnings in the CachedReflectionInfo class. + /// + [Fact] + public static void CachedReflectionInfoMethodsNoAnnotations() + { + IEnumerable methods = + typeof(Queryable).Assembly + .GetType("System.Linq.CachedReflectionInfo") + .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) + .Where(m => m.GetParameters().Length > 0); + + // If you are adding a new method to this class, ensure the method meets these requirements + Assert.Equal(108, methods.Count()); + foreach (MethodInfo method in methods) + { + ParameterInfo[] parameters = method.GetParameters(); + + Type[] args = new Type[parameters.Length]; + for (int i = 0; i < args.Length; i++) + { + args[i] = typeof(object); + } + + MethodInfo resultMethodInfo = (MethodInfo)method.Invoke(null, args); + Assert.True(resultMethodInfo.IsConstructedGenericMethod); + MethodInfo originalGenericDefinition = resultMethodInfo.GetGenericMethodDefinition(); + + EnsureNoTrimAnnotations(originalGenericDefinition); + } + } + + /// + /// Verifies that all methods in Enumerable don't contain any trimming annotations (i.e. DynamicallyAccessedMembers). + /// + /// + /// This ensures it is safe to suppress IL2060:MakeGenericMethod warnings in EnumerableRewriter.FindEnumerableMethodForQueryable. + /// + [Fact] + public static void EnumerableMethodsNoAnnotations() + { + IEnumerable methods = + typeof(Enumerable) + .GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(m => m.IsGenericMethodDefinition); + + foreach (MethodInfo method in methods) + { + EnsureNoTrimAnnotations(method); + } + } + + private static void EnsureNoTrimAnnotations(MethodInfo method) + { + Type[] genericTypes = method.GetGenericArguments(); + foreach (Type genericType in genericTypes) + { + // The generic type should not have DynamicallyAccessedMembersAttribute on it. + Assert.Null(genericType.GetCustomAttribute()); + + // The generic type should not have a 'where new()' constraint since that will tell the trimmer to keep the ctor + Assert.False(genericType.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint)); + } + } + } +} diff --git a/src/libraries/System.Resources.ResourceManager/tests/TrimCompatibilityTests.cs b/src/libraries/System.Resources.ResourceManager/tests/TrimCompatibilityTests.cs index 72333edcaa602..2767735a22d07 100644 --- a/src/libraries/System.Resources.ResourceManager/tests/TrimCompatibilityTests.cs +++ b/src/libraries/System.Resources.ResourceManager/tests/TrimCompatibilityTests.cs @@ -27,7 +27,11 @@ public static void VerifyMethodsCalledWithMakeGenericMethod() { foreach(Type genericType in genericTypes) { + // The generic type should not have DynamicallyAccessedMembersAttribute on it. Assert.Null(genericType.GetCustomAttribute()); + + // The generic type should not have a 'where new()' constraint since that will tell the trimmer to keep the ctor + Assert.False(genericType.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint)); } } }