Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
86595de
new TypeName methods
adamsitnik Jun 18, 2024
d906606
do not join the type and library name strings when UndoTruncatedTypeN…
adamsitnik Jun 19, 2024
448f01e
cache known primitive type names (and SZArrays of these)
adamsitnik Jun 19, 2024
b37b8da
add more tests and finish WithAssemblyName implementation
adamsitnik Jun 19, 2024
6b933d9
finish the implementation
adamsitnik Jun 28, 2024
f707dfd
Merge remote-tracking branch 'upstream/main' into extendTypeName
adamsitnik Jun 28, 2024
1736b24
add missing IntPtr and UIntPtr support (discovered once I've re-enabl…
adamsitnik Jun 28, 2024
a54e55f
use TypeNameMatches in more places
adamsitnik Jun 28, 2024
7d2d0d6
Merge remote-tracking branch 'upstream/main' into extendTypeName
adamsitnik Aug 2, 2024
9a0cd58
address API review feedback
adamsitnik Aug 2, 2024
aabe51b
remove CreateSimpleTypeName, introduce MakeSimpleTypeNameThrowsForNon…
adamsitnik Aug 2, 2024
e207e0f
handle nested names properly
adamsitnik Aug 6, 2024
19f1e82
update the code after reading it again on GH
adamsitnik Aug 6, 2024
6d03c00
Merge remote-tracking branch 'upstream/main' into extendTypeName
adamsitnik Aug 12, 2024
3abda02
address code review feedback
adamsitnik Aug 12, 2024
50a58fb
address code review feedback
adamsitnik Aug 12, 2024
ebfc35e
address code review feedback
adamsitnik Aug 13, 2024
f50ae19
rename MakeSimpleTypeName to WithAssemblyName
adamsitnik Aug 13, 2024
69cd1fa
Apply suggestions from code review
adamsitnik Aug 14, 2024
aa0870f
don't use sbyte to store array rank, the limit of 32 can be changed i…
adamsitnik Aug 14, 2024
30be71e
fix the build
adamsitnik Aug 14, 2024
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
address API review feedback
  • Loading branch information
adamsitnik committed Aug 2, 2024
commit 9a0cd5819f8d5367e94aeb0da9d98e6fb5ea51f3
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ internal TypeName GetArrayTypeName(ArrayInfo arrayInfo)
// Custom offset arrays are not supported by design, so in our case it's always SZArray.
// That is why we don't call TypeName.MakeArrayTypeName(1) because it would create [*] instead of [] name.
return arrayInfo.Rank == 1
? elementTypeName.MakeArrayTypeName()
? elementTypeName.MakeSZArrayTypeName()
: elementTypeName.MakeArrayTypeName(arrayInfo.Rank);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ internal static void ThrowInvalidValue(object value)
internal static void ThrowInvalidReference()
=> throw new SerializationException(SR.Serialization_InvalidReference);

internal static void ThrowInvalidTypeName(string name)
=> throw new SerializationException(SR.Format(SR.Serialization_InvalidTypeName, name));

internal static void ThrowUnexpectedNullRecordCount()
=> throw new SerializationException(SR.Serialization_UnexpectedNullRecordCount);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ internal static class TypeNameHelpers
private static readonly TypeName?[] s_PrimitiveSZArrayTypeNames = new TypeName?[(int)UIntPtrPrimitiveType + 1];
private static AssemblyNameInfo? s_CoreLibAssemblyName;

internal static AssemblyNameInfo CoreLibAssemblyName
=> s_CoreLibAssemblyName ??= AssemblyNameInfo.Parse("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".AsSpan());

internal static TypeName GetPrimitiveTypeName(PrimitiveType primitiveType)
{
Debug.Assert(primitiveType is not (PrimitiveType.None or PrimitiveType.Null));
Expand Down Expand Up @@ -50,7 +53,7 @@ internal static TypeName GetPrimitiveTypeName(PrimitiveType primitiveType)
_ => "System.UInt64",
};

s_PrimitiveTypeNames[(int)primitiveType] = typeName = TypeName.Parse(fullName.AsSpan()).WithCoreLibAssemblyName();
s_PrimitiveTypeNames[(int)primitiveType] = typeName = TypeName.CreateSimpleTypeName(fullName, assemblyName: CoreLibAssemblyName);
}
return typeName;
}
Expand All @@ -60,7 +63,7 @@ internal static TypeName GetPrimitiveSZArrayTypeName(PrimitiveType primitiveType
TypeName? typeName = s_PrimitiveSZArrayTypeNames[(int)primitiveType];
if (typeName is null)
{
s_PrimitiveSZArrayTypeNames[(int)primitiveType] = typeName = GetPrimitiveTypeName(primitiveType).MakeArrayTypeName();
s_PrimitiveSZArrayTypeNames[(int)primitiveType] = typeName = GetPrimitiveTypeName(primitiveType).MakeSZArrayTypeName();
}
return typeName;
}
Expand Down Expand Up @@ -128,7 +131,38 @@ internal static TypeName ParseSystemRecordTypeName(this string rawName, PayloadO
.WithCoreLibAssemblyName(); // We know it's a System Record, so we set the LibraryName to CoreLib

internal static TypeName WithCoreLibAssemblyName(this TypeName systemType)
=> systemType.WithAssemblyName(s_CoreLibAssemblyName ??= AssemblyNameInfo.Parse("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".AsSpan()));
=> systemType.WithAssemblyName(CoreLibAssemblyName);

private static TypeName WithAssemblyName(this TypeName typeName, AssemblyNameInfo assemblyName)
{
if (!typeName.IsSimple)
{
if (typeName.IsArray)
{
TypeName newElementType = typeName.GetElementType().WithAssemblyName(assemblyName);

return typeName.IsSZArray
? newElementType.MakeSZArrayTypeName()
: newElementType.MakeArrayTypeName(typeName.GetArrayRank());
}
else if (typeName.IsConstructedGenericType)
{
TypeName newGenericTypeDefinition = typeName.GetGenericTypeDefinition().WithAssemblyName(assemblyName);

// We don't change the assembly name of generic arguments on purpose.
return newGenericTypeDefinition.MakeGenericTypeName(typeName.GetGenericArguments());
}
else
{
// BinaryFormatter can not serialize pointers or references.
ThrowHelper.ThrowInvalidTypeName(typeName.FullName);
}
}

TypeName? newDeclaringType = typeName.IsNested ? typeName.DeclaringType.WithAssemblyName(assemblyName) : null;

return TypeName.CreateSimpleTypeName(typeName.FullName, newDeclaringType, assemblyName);
}

private static TypeName ParseWithoutAssemblyName(string rawName, PayloadOptions payloadOptions)
{
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/System.Formats.Nrbf/tests/TypeMatchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,12 @@ private static void Verify<T>(T input) where T : notnull

Assert.True(one.TypeNameMatches(typeof(T)));

Assert.Equal(typeof(T).GetTypeFullNameIncludingTypeForwards(), one.TypeName.FullName);
if (typeof(T) != typeof(TimeSpan)) // TimeSpan is missing type forwards
{
Assert.Equal(typeof(T).GetAssemblyNameIncludingTypeForwards(), one.TypeName.AssemblyName!.FullName);
}

foreach (Type type in PrimitiveTypes)
{
Assert.Equal(typeof(T) == type, one.TypeNameMatches(type));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2427,7 +2427,7 @@ public sealed partial class TypeName
internal TypeName() { }
public string AssemblyQualifiedName { get { throw null; } }
public AssemblyNameInfo? AssemblyName { get { throw null; } }
public System.Reflection.Metadata.TypeName? DeclaringType { get { throw null; } }
public System.Reflection.Metadata.TypeName DeclaringType { get { throw null; } }
public string FullName { get { throw null; } }
public bool IsArray { get { throw null; } }
public bool IsByRef { get { throw null; } }
Expand All @@ -2438,19 +2438,19 @@ internal TypeName() { }
public bool IsSZArray { get { throw null; } }
public bool IsVariableBoundArrayType { get { throw null; } }
public string Name { get { throw null; } }
public static System.Reflection.Metadata.TypeName CreateSimpleTypeName(string metadataName, System.Reflection.Metadata.TypeName? declaringType = null, AssemblyNameInfo? assemblyName = null) { throw null; }
public static System.Reflection.Metadata.TypeName Parse(System.ReadOnlySpan<char> typeName, System.Reflection.Metadata.TypeNameParseOptions? options = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> typeName, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Reflection.Metadata.TypeName? result, System.Reflection.Metadata.TypeNameParseOptions? options = null) { throw null; }
public int GetArrayRank() { throw null; }
public System.Collections.Immutable.ImmutableArray<System.Reflection.Metadata.TypeName> GetGenericArguments() { throw null; }
public System.Reflection.Metadata.TypeName GetGenericTypeDefinition() { throw null; }
public System.Reflection.Metadata.TypeName GetElementType() { throw null; }
public int GetNodeCount() { throw null; }
public System.Reflection.Metadata.TypeName MakeArrayTypeName() { throw null; }
public System.Reflection.Metadata.TypeName MakeSZArrayTypeName() { throw null; }
public System.Reflection.Metadata.TypeName MakeArrayTypeName(int rank) { throw null; }
public System.Reflection.Metadata.TypeName MakeByRefTypeName() { throw null; }
public System.Reflection.Metadata.TypeName MakeGenericTypeName(System.Collections.Immutable.ImmutableArray<System.Reflection.Metadata.TypeName> typeArguments) { throw null; }
public System.Reflection.Metadata.TypeName MakePointerTypeName() { throw null; }
public System.Reflection.Metadata.TypeName WithAssemblyName(AssemblyNameInfo assemblyName) { throw null; }
}
public sealed partial class TypeNameParseOptions
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,4 +435,7 @@
<data name="Arg_NotSimpleTypeName" xml:space="preserve">
<value>MakeGenericTypeName may only be called on a type name for which TypeName.IsSimple is true, for '{0}' it's not.</value>
</data>
<data name="Argument_EmptyString" xml:space="preserve">
<value>The value cannot be an empty string.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,41 @@ public int GetArrayRank()
#endif

#if SYSTEM_REFLECTION_METADATA
/// <summary>
/// Creates a new <see cref="TypeName" /> object that represents given name with provided assembly name.
/// </summary>
/// <param name="metadataName">Unescaped full name.</param>
/// <param name="declaringType">Declaring type name.</param>
/// <param name="assemblyName">Assembly name.</param>
/// <returns>Created simple name.</returns>
/// <exception cref="ArgumentNullException"><paramref name="metadataName"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException">Provided type name was invalid. For example, it was empty or escaped.</exception>
public static TypeName CreateSimpleTypeName(string metadataName, TypeName? declaringType = null, AssemblyNameInfo? assemblyName = null)
{
#if NET
ArgumentNullException.ThrowIfNullOrEmpty(nameof(metadataName));
bool containsEscapeCharacter = metadataName.Contains(TypeNameParserHelpers.EscapeCharacter);
#else
if (string.IsNullOrEmpty(metadataName))
{
throw metadataName is null
? throw new ArgumentNullException(nameof(metadataName))
: throw new ArgumentException(SR.Argument_EmptyString, nameof(metadataName));
}
bool containsEscapeCharacter = metadataName.IndexOf(TypeNameParserHelpers.EscapeCharacter) >= 0;
#endif
if (containsEscapeCharacter)
{
throw new ArgumentException(SR.Argument_InvalidTypeName);
}

return new TypeName(fullName: metadataName,
assemblyName: assemblyName,
elementOrGenericType: null,
declaringType: declaringType,
genericTypeArguments: ImmutableArray<TypeName>.Empty);
}

/// <summary>
/// Returns a <see cref="TypeName" /> object representing a one-dimensional array
/// of the current type, with a lower bound of zero.
Expand All @@ -421,7 +456,7 @@ public int GetArrayRank()
/// A <see cref="TypeName" /> object representing a one-dimensional array
/// of the current type, with a lower bound of zero.
/// </returns>
public TypeName MakeArrayTypeName() => MakeElementTypeName(TypeNameParserHelpers.SZArray);
public TypeName MakeSZArrayTypeName() => MakeElementTypeName(TypeNameParserHelpers.SZArray);

/// <summary>
/// Returns a <see cref="TypeName" /> object representing an array of the current type,
Expand Down Expand Up @@ -465,40 +500,9 @@ public TypeName MakeArrayTypeName(int rank)
/// <exception cref="InvalidOperationException">The current type name is not simple.</exception>
public TypeName MakeGenericTypeName(ImmutableArray<TypeName> typeArguments)
=> IsSimple
? new TypeName(fullName: null, AssemblyName, elementOrGenericType: this, genericTypeArguments: typeArguments)
? new TypeName(fullName: null, AssemblyName, elementOrGenericType: this, declaringType: _declaringType, genericTypeArguments: typeArguments)
: throw new InvalidOperationException(SR.Format(SR.Arg_NotSimpleTypeName, FullName));

/// <summary>
/// Returns a <see cref="TypeName" /> object that represents the current type name with provided assembly name.
/// </summary>
/// <returns>
/// A <see cref="TypeName" /> object that represents the current type name with provided assembly name.
/// </returns>
public TypeName WithAssemblyName(AssemblyNameInfo? assemblyName)
=> WithAssemblyName(this, AssemblyName, assemblyName)!;

private static TypeName? WithAssemblyName(TypeName? typeName, AssemblyNameInfo? oldName, AssemblyNameInfo? newName)
{
if (typeName is null)
{
return null;
}
else if (!ReferenceEquals(typeName.AssemblyName, oldName))
{
return typeName; // There is nothing to update.
}

return new TypeName(
fullName: typeName._fullName,
newName,
elementOrGenericType: WithAssemblyName(typeName._elementOrGenericType, oldName, newName),
declaringType: WithAssemblyName(typeName._declaringType, oldName, newName),
// We don't update the assembly names of generic arguments on purpose!
genericTypeArguments: typeName._genericArguments,
rankOrModifier: typeName._rankOrModifier,
nestedNameLength: typeName._nestedNameLength);
}

private TypeName MakeElementTypeName(sbyte rankOrModifier)
=> new TypeName(
fullName: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal static class TypeNameParserHelpers
internal const sbyte SZArray = -1;
internal const sbyte Pointer = -2;
internal const sbyte ByRef = -3;
private const char EscapeCharacter = '\\';
internal const char EscapeCharacter = '\\';
#if NET8_0_OR_GREATER
private static readonly SearchValues<char> s_endOfFullTypeNameDelimitersSearchValues = SearchValues.Create("[]&*,+\\");
#endif
Expand Down
Loading