Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Fix tests
  • Loading branch information
layomia committed Jul 15, 2021
commit b0f2019d87ff07c5970e982beb5819258fcbc8ad
131 changes: 109 additions & 22 deletions src/libraries/System.Text.Json/Common/ReflectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,37 @@ namespace System.Text.Json.Reflection
internal static partial class ReflectionExtensions
{
// Immutable collection types.
public const string ImmutableArrayGenericTypeName = "System.Collections.Immutable.ImmutableArray`1";
public const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1";
public const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1";
public const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1";
public const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1";
public const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1";
public const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1";
public const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1";
public const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1";
public const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1";
public const string ImmutableDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableDictionary`2";
public const string ImmutableDictionaryGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableDictionary`2";
public const string ImmutableSortedDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableSortedDictionary`2";

public static Type? GetCompatibleGenericBaseClass(this Type type, Type baseType, Type? objectType = null)
private const string ImmutableArrayGenericTypeName = "System.Collections.Immutable.ImmutableArray`1";
private const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1";
private const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1";
private const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1";
private const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1";
private const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1";
private const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1";
private const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1";
private const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1";
private const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1";
private const string ImmutableDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableDictionary`2";
private const string ImmutableDictionaryGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableDictionary`2";
private const string ImmutableSortedDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableSortedDictionary`2";

// Immutable collection builder types.
private const string ImmutableArrayTypeName = "System.Collections.Immutable.ImmutableArray";
private const string ImmutableListTypeName = "System.Collections.Immutable.ImmutableList";
private const string ImmutableStackTypeName = "System.Collections.Immutable.ImmutableStack";
private const string ImmutableQueueTypeName = "System.Collections.Immutable.ImmutableQueue";
private const string ImmutableSortedSetTypeName = "System.Collections.Immutable.ImmutableSortedSet";
private const string ImmutableHashSetTypeName = "System.Collections.Immutable.ImmutableHashSet";
private const string ImmutableDictionaryTypeName = "System.Collections.Immutable.ImmutableDictionary";
private const string ImmutableSortedDictionaryTypeName = "System.Collections.Immutable.ImmutableSortedDictionary";

public const string CreateRangeMethodName = "CreateRange";

public static Type? GetCompatibleGenericBaseClass(
this Type type,
Type baseType,
Type? objectType = null,
bool sourceGenType = false)
{
Debug.Assert(baseType.IsGenericType);
Debug.Assert(!baseType.IsInterface);
Expand All @@ -42,7 +58,8 @@ internal static partial class ReflectionExtensions
if (baseTypeToCheck.IsGenericType)
{
Type genericTypeToCheck = baseTypeToCheck.GetGenericTypeDefinition();
if (genericTypeToCheck == baseType)
if (genericTypeToCheck == baseType ||
(sourceGenType && (OpenGenericTypesHaveSamePrefix(baseType, genericTypeToCheck))))
{
return baseTypeToCheck;
}
Expand Down Expand Up @@ -94,14 +111,14 @@ internal static partial class ReflectionExtensions
return null;
}

public static bool IsImmutableDictionaryType(this Type type)
public static bool IsImmutableDictionaryType(this Type type, bool sourceGenType = false)
{
if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable,", StringComparison.Ordinal))
if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable", StringComparison.Ordinal))
{
return false;
}

switch (type.GetGenericTypeDefinition().FullName)
switch (GetBaseNameFromGenericType(type, sourceGenType))
{
case ImmutableDictionaryGenericTypeName:
case ImmutableDictionaryGenericInterfaceTypeName:
Expand All @@ -112,14 +129,14 @@ public static bool IsImmutableDictionaryType(this Type type)
}
}

public static bool IsImmutableEnumerableType(this Type type)
public static bool IsImmutableEnumerableType(this Type type, bool sourceGenType = false)
{
if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable,", StringComparison.Ordinal))
if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable", StringComparison.Ordinal))
{
return false;
}

switch (type.GetGenericTypeDefinition().FullName)
switch (GetBaseNameFromGenericType(type, sourceGenType))
{
case ImmutableArrayGenericTypeName:
case ImmutableListGenericTypeName:
Expand All @@ -137,6 +154,76 @@ public static bool IsImmutableEnumerableType(this Type type)
}
}

public static string? GetImmutableDictionaryConstructingTypeName(this Type type, bool sourceGenType = false)
{
Debug.Assert(type.IsImmutableDictionaryType(sourceGenType));

// Use the generic type definition of the immutable collection to determine
// an appropriate constructing type, i.e. a type that we can invoke the
// `CreateRange<T>` method on, which returns the desired immutable collection.
switch (GetBaseNameFromGenericType(type, sourceGenType))
{
case ImmutableDictionaryGenericTypeName:
case ImmutableDictionaryGenericInterfaceTypeName:
return ImmutableDictionaryTypeName;
case ImmutableSortedDictionaryGenericTypeName:
return ImmutableSortedDictionaryTypeName;
default:
// We verified that the type is an immutable collection, so the
// generic definition is one of the above.
return null;
}
}

public static string? GetImmutableEnumerableConstructingTypeName(this Type type, bool sourceGenType = false)
{
Debug.Assert(type.IsImmutableEnumerableType(sourceGenType));

// Use the generic type definition of the immutable collection to determine
// an appropriate constructing type, i.e. a type that we can invoke the
// `CreateRange<T>` method on, which returns the desired immutable collection.
switch (GetBaseNameFromGenericType(type, sourceGenType))
{
case ImmutableArrayGenericTypeName:
return ImmutableArrayTypeName;
case ImmutableListGenericTypeName:
case ImmutableListGenericInterfaceTypeName:
return ImmutableListTypeName;
case ImmutableStackGenericTypeName:
case ImmutableStackGenericInterfaceTypeName:
return ImmutableStackTypeName;
case ImmutableQueueGenericTypeName:
case ImmutableQueueGenericInterfaceTypeName:
return ImmutableQueueTypeName;
case ImmutableSortedSetGenericTypeName:
return ImmutableSortedSetTypeName;
case ImmutableHashSetGenericTypeName:
case ImmutableSetGenericInterfaceTypeName:
return ImmutableHashSetTypeName;
default:
// We verified that the type is an immutable collection, so the
// generic definition is one of the above.
return null;
}
}

private static bool OpenGenericTypesHaveSamePrefix(Type t1, Type t2)
=> t1.FullName == GetBaseNameFromGenericTypeDef(t2);

private static string GetBaseNameFromGenericType(Type genericType, bool sourceGenType)
{
Type genericTypeDef = genericType.GetGenericTypeDefinition();
return sourceGenType ? GetBaseNameFromGenericTypeDef(genericTypeDef) : genericTypeDef.FullName!;
}

private static string GetBaseNameFromGenericTypeDef(Type genericTypeDef)
{
Debug.Assert(genericTypeDef.IsGenericType);
string fullName = genericTypeDef.FullName!;
int length = fullName.IndexOf("`") + 2;
return fullName.Substring(0, length);
}

public static bool IsVirtual(this PropertyInfo? propertyInfo)
{
Debug.Assert(propertyInfo != null);
Expand Down
27 changes: 15 additions & 12 deletions src/libraries/System.Text.Json/gen/CollectionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,27 @@ namespace System.Text.Json.SourceGeneration
internal enum CollectionType
{
NotApplicable,
// Dictionary types
IDictionary,
Dictionary,
ImmutableDictionary,
IDictionaryOfTKeyTValue,
IReadOnlyDictionary,
// Non-dictionary types
Array,
List,
IEnumerable,
IList,
GenericIList,
IListOfT,
ISet,
GenericICollection,
GenericStack,
GenericQueue,
ICollectionOfT,
StackOfT,
QueueOfT,
ConcurrentStack,
ConcurrentQueue,
GenericIEnumerable,
StackOrQueue,
ImmutableCollection,
IDictionary,
Dictionary,
ImmutableDictionary,
GenericIDictionary,
IReadOnlyDictionary
IEnumerableOfT,
Stack,
Queue,
ImmutableEnumerable
}
}
4 changes: 3 additions & 1 deletion src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Text.Json.Reflection;
using System.Diagnostics;

namespace System.Text.Json.SourceGeneration
{
/// <summary>
/// Represents the set of input types and options needed to provide an
/// implementation for a user-provided JsonSerializerContext-derived type.
/// </summary>
[DebuggerDisplay("ContextTypeRef={ContextTypeRef}")]
internal sealed class ContextGenerationSpec
{
public JsonSourceGenerationOptionsAttribute GenerationOptions { get; init; }
Expand All @@ -34,6 +36,6 @@ internal sealed class ContextGenerationSpec
/// </summary>
public HashSet<string> RuntimePropertyNames { get; } = new();

public string ContextTypeRef => $"global::{ContextType.GetUniqueCompilableTypeName()}";
public string ContextTypeRef => ContextType.GetCompilableName();
}
}
Loading