Skip to content
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
141 changes: 139 additions & 2 deletions src/libraries/System.Linq.Queryable/ref/System.Linq.Queryable.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<EnableAotAnalyzer>true</EnableAotAnalyzer>
</PropertyGroup>
<ItemGroup>
<Compile Include="System\Linq\CachedReflection.cs" />
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ namespace System.Linq
public abstract class EnumerableExecutor
{
[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
internal abstract object? ExecuteBoxed();

internal EnumerableExecutor() { }

[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
internal static EnumerableExecutor Create(Expression expression)
{
Type execType = typeof(EnumerableExecutor<>).MakeGenericType(expression.Type);
Expand All @@ -31,9 +33,11 @@ public EnumerableExecutor(Expression expression)
}

[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
internal override object? ExecuteBoxed() => Execute();

[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
internal T Execute()
{
EnumerableRewriter rewriter = new EnumerableRewriter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,37 @@ public abstract class EnumerableQuery
internal EnumerableQuery() { }

[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
internal static IQueryable Create(Type elementType, IEnumerable sequence)
{
Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType);
return (IQueryable)Activator.CreateInstance(seqType, sequence)!;
}

[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
internal static IQueryable Create(Type elementType, Expression expression)
{
Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType);
return (IQueryable)Activator.CreateInstance(seqType, expression)!;
}
}

[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
public class EnumerableQuery<T> : EnumerableQuery, IOrderedQueryable<T>, IQueryProvider
{
private readonly Expression _expression;
private IEnumerable<T>? _enumerable;

IQueryProvider IQueryable.Provider => this;

[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
public EnumerableQuery(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
_expression = Expression.Constant(this);
}

[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
public EnumerableQuery(Expression expression)
{
_expression = expression;
Expand All @@ -58,8 +60,6 @@ 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)
{
ArgumentNullException.ThrowIfNull(expression);
Expand All @@ -70,8 +70,6 @@ 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<TElement> IQueryProvider.CreateQuery<TElement>(Expression expression)
{
ArgumentNullException.ThrowIfNull(expression);
Expand All @@ -83,17 +81,13 @@ IQueryable<TElement> IQueryProvider.CreateQuery<TElement>(Expression expression)
return new EnumerableQuery<TElement>(expression);
}

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")]
object? IQueryProvider.Execute(Expression expression)
{
ArgumentNullException.ThrowIfNull(expression);

return EnumerableExecutor.Create(expression).ExecuteBoxed();
}

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")]
TElement IQueryProvider.Execute<TElement>(Expression expression)
{
ArgumentNullException.ThrowIfNull(expression);
Expand All @@ -107,8 +101,6 @@ TElement IQueryProvider.Execute<TElement>(Expression expression)

IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This class's ctor is annotated as RequiresUnreferencedCode.")]
private IEnumerator<T> GetEnumerator()
{
if (_enumerable == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace System.Linq
{
[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode("Requires MakeGenericType")]
internal sealed class EnumerableRewriter : ExpressionVisitor
{
// We must ensure that if a LabelTarget is rewritten that it is always rewritten to the same new target
Expand All @@ -19,13 +21,10 @@ internal sealed class EnumerableRewriter : ExpressionVisitor
// Finding equivalent types can be relatively expensive, and hitting with the same types repeatedly is quite likely.
private Dictionary<Type, Type>? _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);
Expand Down Expand Up @@ -196,38 +195,26 @@ private Type GetEquivalentType(Type type)
}
if (equiv == null)
{
equiv = GetEquivalentTypeToEnumerables(pubType);

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "The enumerable interface type (IOrderedQueryable<>, IOrderedEnumerable<>, IQueryable<> and IEnumerable<>) " +
"is kept since it's directly referenced here" +
"and so it will also be preserved in all places where it's implemented." +
"The GetInterfaces may return less after trimming but it will include" +
"the enumerable interface type if it was there before trimming, which is enough for this" +
"method to work.")]
static Type GetEquivalentTypeToEnumerables(Type sourceType)
var interfacesWithInfo = pubType.GetInterfaces();
var singleTypeGenInterfacesWithGetType = interfacesWithInfo
.Where(i => i.IsGenericType && i.GenericTypeArguments.Length == 1)
.Select(i => new { Info = i, GenType = i.GetGenericTypeDefinition() })
.ToArray();
Type? typeArg = singleTypeGenInterfacesWithGetType
.Where(i => i.GenType == typeof(IOrderedQueryable<>) || i.GenType == typeof(IOrderedEnumerable<>))
.Select(i => i.Info.GenericTypeArguments[0])
.Distinct()
.SingleOrDefault();
if (typeArg != null)
equiv = typeof(IOrderedEnumerable<>).MakeGenericType(typeArg);
else
{
var interfacesWithInfo = sourceType.GetInterfaces();
var singleTypeGenInterfacesWithGetType = interfacesWithInfo
.Where(i => i.IsGenericType && i.GenericTypeArguments.Length == 1)
.Select(i => new { Info = i, GenType = i.GetGenericTypeDefinition() })
.ToArray();
Type? typeArg = singleTypeGenInterfacesWithGetType
.Where(i => i.GenType == typeof(IOrderedQueryable<>) || i.GenType == typeof(IOrderedEnumerable<>))
typeArg = singleTypeGenInterfacesWithGetType
.Where(i => i.GenType == typeof(IQueryable<>) || i.GenType == typeof(IEnumerable<>))
.Select(i => i.Info.GenericTypeArguments[0])
.Distinct()
.SingleOrDefault();
if (typeArg != null)
return typeof(IOrderedEnumerable<>).MakeGenericType(typeArg);
else
{
typeArg = singleTypeGenInterfacesWithGetType
.Where(i => i.GenType == typeof(IQueryable<>) || i.GenType == typeof(IEnumerable<>))
.Select(i => i.Info.GenericTypeArguments[0])
.Distinct()
.Single();
return typeof(IEnumerable<>).MakeGenericType(typeArg);
}
.Single();
equiv = typeof(IEnumerable<>).MakeGenericType(typeArg);
}
}
_equivalentTypeCache.Add(type, equiv);
Expand Down Expand Up @@ -275,9 +262,7 @@ private static MethodInfo FindEnumerableMethodForQueryable(string name, ReadOnly
"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);

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
Justification = "Enumerable methods don't have trim annotations.")]
[RequiresDynamicCodeAttribute("Calls System.Reflection.MethodInfo.MakeGenericMethod(params Type[])")]
MethodInfo ApplyTypeArgs(MethodInfo methodInfo) => typeArgs == null ? methodInfo : methodInfo.MakeGenericMethod(typeArgs);

// In certain cases, there might be ambiguities when resolving matching overloads, for example between
Expand Down Expand Up @@ -335,6 +320,7 @@ static bool AreAssignableFromStrict(ParameterInfo[] left, ParameterInfo[] right)
}

[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode("Calls System.Reflection.MethodInfo.MakeGenericMethod(params Type[])")]
private static MethodInfo FindMethod(Type type, string name, ReadOnlyCollection<Expression> args, Type[]? typeArgs)
{
using (IEnumerator<MethodInfo> en = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).Where(m => m.Name == name).GetEnumerator())
Expand Down Expand Up @@ -372,9 +358,7 @@ private static bool ArgsMatch(MethodInfo m, ReadOnlyCollection<Expression> args,
return false;

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.")]
[RequiresDynamicCodeAttribute("Calls System.Reflection.MethodInfo.MakeGenericMethod(params Type[])")]
static ParameterInfo[] GetConstrutedGenericParameters(MethodInfo method, Type[] genericTypes) =>
method.MakeGenericMethod(genericTypes).GetParameters();
}
Expand Down Expand Up @@ -402,6 +386,7 @@ static ParameterInfo[] GetConstrutedGenericParameters(MethodInfo method, Type[]
return true;
}

[RequiresDynamicCode("Calls System.Type.MakeArrayType()")]
private static Type StripExpression(Type type)
{
bool isArray = type.IsArray;
Expand Down
Loading