diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index fdd395fe520a0..a37abf7a0c116 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -192,7 +192,7 @@ - + diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs index 6f74dde91fe7e..c95e1630a04a1 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs @@ -270,12 +270,12 @@ internal static unsafe MarshalAsAttribute GetMarshalAs(ConstArray nativeType, Ru : Text.Encoding.UTF8.GetString(MemoryMarshal.CreateReadOnlySpanFromNullTerminated(marshalCookieRaw)); RuntimeType? safeArrayUserDefinedType = string.IsNullOrEmpty(safeArrayUserDefinedTypeName) ? null : - TypeNameParser.GetTypeReferencedByCustomAttribute(safeArrayUserDefinedTypeName, scope); + TypeNameResolver.GetTypeReferencedByCustomAttribute(safeArrayUserDefinedTypeName, scope); RuntimeType? marshalTypeRef = null; try { - marshalTypeRef = marshalTypeName is null ? null : TypeNameParser.GetTypeReferencedByCustomAttribute(marshalTypeName, scope); + marshalTypeRef = marshalTypeName is null ? null : TypeNameResolver.GetTypeReferencedByCustomAttribute(marshalTypeName, scope); } catch (TypeLoadException) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index 53f2690948df4..3af48057a870e 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -249,7 +249,7 @@ private static partial void GetTypeCoreIgnoreCase(QCallAssembly assembly, { ArgumentException.ThrowIfNullOrEmpty(name); - return TypeNameParser.GetType(name, topLevelAssembly: this, + return TypeNameResolver.GetType(name, topLevelAssembly: this, throwOnError: throwOnError, ignoreCase: ignoreCase); } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index 38663e57cde24..e00b0b1854a36 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -543,7 +543,7 @@ private static object EncodedValueToRawValue(PrimitiveValue val, CustomAttribute } private static RuntimeType ResolveType(RuntimeModule scope, string typeName) { - RuntimeType type = TypeNameParser.GetTypeReferencedByCustomAttribute(typeName, scope); + RuntimeType type = TypeNameResolver.GetTypeReferencedByCustomAttribute(typeName, scope); Debug.Assert(type is not null); return type; } @@ -899,7 +899,7 @@ private static CustomAttributeType ParseCustomAttributeType(ref CustomAttributeD throw new BadImageFormatException(); } - enumType = TypeNameParser.GetTypeReferencedByCustomAttribute(enumTypeMaybe, module); + enumType = TypeNameResolver.GetTypeReferencedByCustomAttribute(enumTypeMaybe, module); if (!enumType.IsEnum) { throw new BadImageFormatException(); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs index 4e9a4dffeb209..43760e17b4d98 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs @@ -403,7 +403,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont { ArgumentException.ThrowIfNullOrEmpty(className); - return TypeNameParser.GetType(className, topLevelAssembly: Assembly, + return TypeNameResolver.GetType(className, topLevelAssembly: Assembly, throwOnError: throwOnError, ignoreCase: ignoreCase); } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.CoreCLR.cs similarity index 89% rename from src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs rename to src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.CoreCLR.cs index 35fa0b5718e38..78e2422b34104 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.CoreCLR.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Loader; @@ -11,7 +12,7 @@ namespace System.Reflection { - internal partial struct TypeNameParser + internal partial struct TypeNameResolver { private Func? _assemblyResolver; private Func? _typeResolver; @@ -55,13 +56,13 @@ internal partial struct TypeNameParser return null; } - Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError: throwOnError); + TypeName? parsed = TypeNameParser.Parse(typeName, throwOnError); if (parsed is null) { return null; } - return new TypeNameParser() + return new TypeNameResolver() { _assemblyResolver = assemblyResolver, _typeResolver = typeResolver, @@ -79,7 +80,7 @@ internal partial struct TypeNameParser bool ignoreCase, Assembly topLevelAssembly) { - Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError); + TypeName? parsed = TypeNameParser.Parse(typeName, throwOnError); if (parsed is null) { @@ -90,7 +91,7 @@ internal partial struct TypeNameParser return throwOnError ? throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly) : null; } - return new TypeNameParser() + return new TypeNameResolver() { _throwOnError = throwOnError, _ignoreCase = ignoreCase, @@ -110,8 +111,8 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, RuntimeAssembly requestingAssembly = scope.GetRuntimeAssembly(); - Metadata.TypeName parsed = Metadata.TypeName.Parse(typeName); - RuntimeType? type = (RuntimeType?)new TypeNameParser() + TypeName parsed = TypeName.Parse(typeName); + RuntimeType? type = (RuntimeType?)new TypeNameResolver() { _throwOnError = true, _suppressContextualReflectionContext = true, @@ -140,13 +141,13 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, return null; } - Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError); + TypeName? parsed = TypeNameParser.Parse(typeName, throwOnError); if (parsed is null) { return null; } - RuntimeType? type = (RuntimeType?)new TypeNameParser() + RuntimeType? type = (RuntimeType?)new TypeNameResolver() { _requestingAssembly = requestingAssembly, _throwOnError = throwOnError, @@ -181,11 +182,10 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", - Justification = "TypeNameParser.GetType is marked as RequiresUnreferencedCode.")] + Justification = "TypeNameResolver.GetType is marked as RequiresUnreferencedCode.")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", - Justification = "TypeNameParser.GetType is marked as RequiresUnreferencedCode.")] - private Type? GetType(string escapedTypeName, // For nested types, it's Name. For other types it's FullName - ReadOnlySpan nestedTypeNames, Metadata.TypeName parsedName) + Justification = "TypeNameResolver.GetType is marked as RequiresUnreferencedCode.")] + private Type? GetType(string escapedTypeName, ReadOnlySpan nestedTypeNames, TypeName parsedName) { Assembly? assembly; @@ -230,12 +230,12 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, } return null; } - return GetTypeFromDefaultAssemblies(UnescapeTypeName(escapedTypeName), nestedTypeNames, parsedName); + return GetTypeFromDefaultAssemblies(TypeNameHelpers.Unescape(escapedTypeName), nestedTypeNames, parsedName); } if (assembly is RuntimeAssembly runtimeAssembly) { - string unescapedTypeName = UnescapeTypeName(escapedTypeName); + string unescapedTypeName = TypeNameHelpers.Unescape(escapedTypeName); // Compat: Non-extensible parser allows ambiguous matches with ignore case lookup if (!_extensibleParser || !_ignoreCase) { @@ -268,7 +268,7 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, if (_throwOnError) { throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveNestedType, - nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : escapedTypeName)); + nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : TypeNameHelpers.Unescape(escapedTypeName))); } return null; } @@ -277,7 +277,7 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, return type; } - private Type? GetTypeFromDefaultAssemblies(string typeName, ReadOnlySpan nestedTypeNames, Metadata.TypeName parsedName) + private Type? GetTypeFromDefaultAssemblies(string typeName, ReadOnlySpan nestedTypeNames, TypeName parsedName) { RuntimeAssembly? requestingAssembly = (RuntimeAssembly?)_requestingAssembly; if (requestingAssembly is not null) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs index 81caecb09c99a..8707db0cf7f6f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs @@ -16,7 +16,7 @@ public abstract partial class Type : MemberInfo, IReflect public static Type? GetType(string typeName, bool throwOnError, bool ignoreCase) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return TypeNameParser.GetType(typeName, Assembly.GetExecutingAssembly(ref stackMark), + return TypeNameResolver.GetType(typeName, Assembly.GetExecutingAssembly(ref stackMark), throwOnError: throwOnError, ignoreCase: ignoreCase); } @@ -25,7 +25,7 @@ public abstract partial class Type : MemberInfo, IReflect public static Type? GetType(string typeName, bool throwOnError) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return TypeNameParser.GetType(typeName, Assembly.GetExecutingAssembly(ref stackMark), + return TypeNameResolver.GetType(typeName, Assembly.GetExecutingAssembly(ref stackMark), throwOnError: throwOnError); } @@ -34,7 +34,7 @@ public abstract partial class Type : MemberInfo, IReflect public static Type? GetType(string typeName) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return TypeNameParser.GetType(typeName, Assembly.GetExecutingAssembly(ref stackMark)); + return TypeNameResolver.GetType(typeName, Assembly.GetExecutingAssembly(ref stackMark)); } [RequiresUnreferencedCode("The type might be removed")] @@ -45,7 +45,7 @@ public abstract partial class Type : MemberInfo, IReflect Func? typeResolver) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return TypeNameParser.GetType(typeName, assemblyResolver, typeResolver, + return TypeNameResolver.GetType(typeName, assemblyResolver, typeResolver, ((assemblyResolver != null) && (typeResolver != null)) ? null : Assembly.GetExecutingAssembly(ref stackMark)); } @@ -58,7 +58,7 @@ public abstract partial class Type : MemberInfo, IReflect bool throwOnError) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return TypeNameParser.GetType(typeName, assemblyResolver, typeResolver, + return TypeNameResolver.GetType(typeName, assemblyResolver, typeResolver, ((assemblyResolver != null) && (typeResolver != null)) ? null : Assembly.GetExecutingAssembly(ref stackMark), throwOnError: throwOnError); } @@ -73,7 +73,7 @@ public abstract partial class Type : MemberInfo, IReflect bool ignoreCase) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return TypeNameParser.GetType(typeName, assemblyResolver, typeResolver, + return TypeNameResolver.GetType(typeName, assemblyResolver, typeResolver, ((assemblyResolver != null) && (typeResolver != null)) ? null : Assembly.GetExecutingAssembly(ref stackMark), throwOnError: throwOnError, ignoreCase: ignoreCase); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ReflectionHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ReflectionHelpers.cs index 1defad0d10f95..dbdc93b93bac7 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ReflectionHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ReflectionHelpers.cs @@ -17,14 +17,14 @@ internal static class ReflectionHelpers // a default assembly name. public static Type GetType(string typeName, string callingAssemblyName, bool throwOnError, bool ignoreCase) { - return TypeNameParser.GetType(typeName, throwOnError: throwOnError, ignoreCase: ignoreCase, defaultAssemblyName: callingAssemblyName); + return TypeNameResolver.GetType(typeName, throwOnError: throwOnError, ignoreCase: ignoreCase, defaultAssemblyName: callingAssemblyName); } // This entry is used to implement Type.GetType()'s ability to detect the calling assembly and use it as // a default assembly name. public static Type ExtensibleGetType(string typeName, string callingAssemblyName, Func assemblyResolver, Func? typeResolver, bool throwOnError, bool ignoreCase) { - return TypeNameParser.GetType(typeName, assemblyResolver, typeResolver, throwOnError: throwOnError, ignoreCase: ignoreCase, defaultAssemblyName: callingAssemblyName); + return TypeNameResolver.GetType(typeName, assemblyResolver, typeResolver, throwOnError: throwOnError, ignoreCase: ignoreCase, defaultAssemblyName: callingAssemblyName); } // This supports Assembly.GetExecutingAssembly() intrinsic expansion in the compiler diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index c7bfa7ff2215e..faf1eb8fc3de1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -493,7 +493,7 @@ - + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs index 9fb1ebe030827..99292670fa8aa 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs @@ -68,7 +68,7 @@ public sealed override Type GetType(string name, bool throwOnError, bool ignoreC { ArgumentException.ThrowIfNullOrEmpty(name); - return TypeNameParser.GetType(name, + return TypeNameResolver.GetType(name, throwOnError: throwOnError, ignoreCase: ignoreCase, topLevelAssembly: this); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.NativeAot.cs similarity index 92% rename from src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.NativeAot.cs index 2149003ddcfb4..51129f0fda74d 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.NativeAot.cs @@ -3,15 +3,16 @@ using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Reflection.Metadata; using System.Reflection.Runtime.Assemblies; using System.Reflection.Runtime.General; namespace System.Reflection { // - // Parser for type names passed to GetType() apis. + // Resolver for type names passed to GetType() apis. // - internal partial struct TypeNameParser + internal partial struct TypeNameResolver { private Func? _assemblyResolver; private Func? _typeResolver; @@ -51,13 +52,13 @@ internal partial struct TypeNameParser return null; } - Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError); + TypeName? parsed = TypeNameParser.Parse(typeName, throwOnError); if (parsed is null) { return null; } - return new TypeNameParser() + return new TypeNameResolver() { _assemblyResolver = assemblyResolver, _typeResolver = typeResolver, @@ -74,7 +75,7 @@ internal partial struct TypeNameParser bool ignoreCase, Assembly topLevelAssembly) { - Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError); + TypeName? parsed = TypeNameParser.Parse(typeName, throwOnError); if (parsed is null) { @@ -85,7 +86,7 @@ internal partial struct TypeNameParser return throwOnError ? throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly) : null; } - return new TypeNameParser() + return new TypeNameResolver() { _throwOnError = throwOnError, _ignoreCase = ignoreCase, @@ -117,7 +118,7 @@ internal partial struct TypeNameParser Justification = "GetType APIs are marked as RequiresUnreferencedCode.")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "GetType APIs are marked as RequiresUnreferencedCode.")] - private Type? GetType(string escapedTypeName, ReadOnlySpan nestedTypeNames, Metadata.TypeName parsedName) + private Type? GetType(string escapedTypeName, ReadOnlySpan nestedTypeNames, TypeName parsedName) { Assembly? assembly; @@ -156,7 +157,7 @@ internal partial struct TypeNameParser { if (assembly is RuntimeAssemblyInfo runtimeAssembly) { - type = runtimeAssembly.GetTypeCore(UnescapeTypeName(escapedTypeName), throwOnError: _throwOnError, ignoreCase: _ignoreCase); + type = runtimeAssembly.GetTypeCore(TypeNameHelpers.Unescape(escapedTypeName), throwOnError: _throwOnError, ignoreCase: _ignoreCase); } else { @@ -171,7 +172,7 @@ internal partial struct TypeNameParser } else { - string? unescapedTypeName = UnescapeTypeName(escapedTypeName); + string? unescapedTypeName = TypeNameHelpers.Unescape(escapedTypeName); RuntimeAssemblyInfo? defaultAssembly = null; if (_defaultAssemblyName != null) @@ -233,7 +234,7 @@ internal partial struct TypeNameParser if (_throwOnError) { throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveNestedType, - nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : escapedTypeName)); + nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : TypeNameHelpers.Unescape(escapedTypeName))); } return null; } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs index 7db1728b3128e..d5b3c54e1fc27 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs @@ -95,7 +95,7 @@ internal string FormatTypeNameForReflection() [RequiresUnreferencedCode("The type might be removed")] public static Type GetType(string typeName, bool throwOnError, bool ignoreCase) { - return TypeNameParser.GetType(typeName, throwOnError: throwOnError, ignoreCase: ignoreCase); + return TypeNameResolver.GetType(typeName, throwOnError: throwOnError, ignoreCase: ignoreCase); } [Intrinsic] @@ -108,7 +108,7 @@ public static Type GetType(string typeName, bool throwOnError, bool ignoreCase) [RequiresUnreferencedCode("The type might be removed")] public static Type GetType(string typeName, Func? assemblyResolver, Func? typeResolver, bool throwOnError, bool ignoreCase) { - return TypeNameParser.GetType(typeName, assemblyResolver, typeResolver, throwOnError: throwOnError, ignoreCase: ignoreCase); + return TypeNameResolver.GetType(typeName, assemblyResolver, typeResolver, throwOnError: throwOnError, ignoreCase: ignoreCase); } } } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs index 33a86023ced27..cda882d7b730f 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs @@ -2,16 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; using System.Reflection.Metadata; using Internal.TypeSystem; -#nullable disable - namespace Internal.TypeSystem { public static class CustomAttributeTypeNameParser { + private static readonly TypeNameParseOptions s_typeNameParseOptions = new() { MaxNodes = int.MaxValue }; + /// /// Parses the string '' and returns the type corresponding to the parsed type name. /// The type name string should be in the 'SerString' format as defined by the ECMA-335 standard. @@ -19,105 +22,170 @@ public static class CustomAttributeTypeNameParser /// public static TypeDesc GetTypeByCustomAttributeTypeName(this ModuleDesc module, string name, bool throwIfNotFound = true, Func canonResolver = null) - { - return System.Reflection.TypeNameParser.ResolveType(module, name, throwIfNotFound, canonResolver); - } - } -} - -namespace System.Reflection -{ - internal partial struct TypeNameParser - { - private static readonly TypeNameParseOptions s_typeNameParseOptions = new() { MaxNodes = int.MaxValue }; - - private ModuleDesc _module; - private bool _throwIfNotFound; - private Func _canonResolver; - - public static TypeDesc ResolveType(ModuleDesc module, string name, bool throwIfNotFound, - Func canonResolver) { if (!TypeName.TryParse(name.AsSpan(), out TypeName parsed, s_typeNameParseOptions)) - { ThrowHelper.ThrowTypeLoadException(name, module); - } - return new TypeNameParser() + return new TypeNameResolver() { + _context = module.Context, _module = module, _throwIfNotFound = throwIfNotFound, _canonResolver = canonResolver - }.Resolve(parsed)?.Value; + }.Resolve(parsed); } - private sealed class Type + public static TypeDesc GetTypeByCustomAttributeTypeNameForDataFlow(string name, ModuleDesc callingModule, + TypeSystemContext context, List referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary) { - public Type(TypeDesc type) => Value = type; - public TypeDesc Value { get; } + typeWasNotFoundInAssemblyNorBaseLibrary = false; - public Type MakeArrayType() => new Type(Value.MakeArrayType()); - public Type MakeArrayType(int rank) => new Type(Value.MakeArrayType(rank)); - public Type MakePointerType() => new Type(Value.MakePointerType()); - public Type MakeByRefType() => new Type(Value.MakeByRefType()); + if (!TypeName.TryParse(name.AsSpan(), out TypeName parsed, s_typeNameParseOptions)) + return null; - public Type MakeGenericType(Type[] typeArguments) + TypeNameResolver resolver = new() { - TypeDesc[] instantiation = new TypeDesc[typeArguments.Length]; - for (int i = 0; i < typeArguments.Length; i++) - instantiation[i] = typeArguments[i].Value; - return new Type(((MetadataType)Value).MakeInstantiatedType(instantiation)); - } + _context = context, + _module = callingModule, + _referencedModules = referencedModules + }; + + TypeDesc type = resolver.Resolve(parsed); + + typeWasNotFoundInAssemblyNorBaseLibrary = resolver._typeWasNotFoundInAssemblyNorBaseLibrary; + return type; } - private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, TypeName parsedName) + private struct TypeNameResolver { - ModuleDesc module = (parsedName.AssemblyName == null) ? _module : - _module.Context.ResolveAssembly(parsedName.AssemblyName.ToAssemblyName(), throwIfNotFound: _throwIfNotFound); + internal TypeSystemContext _context; + internal ModuleDesc _module; + internal bool _throwIfNotFound; + internal Func _canonResolver; + + internal List _referencedModules; + internal bool _typeWasNotFoundInAssemblyNorBaseLibrary; - if (_canonResolver != null && nestedTypeNames.IsEmpty) + internal TypeDesc Resolve(TypeName typeName) { - MetadataType canonType = _canonResolver(module, typeName); - if (canonType != null) - return new Type(canonType); + if (typeName.IsSimple) + { + return GetSimpleType(typeName); + } + + if (typeName.IsConstructedGenericType) + { + return GetGenericType(typeName); + } + + if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef) + { + TypeDesc type = Resolve(typeName.GetElementType()); + if (type == null) + return null; + + if (typeName.IsArray) + return typeName.IsSZArray ? type.MakeArrayType() : type.MakeArrayType(rank: typeName.GetArrayRank()); + + if (typeName.IsPointer) + return type.MakePointerType(); + + if (typeName.IsByRef) + return type.MakeByRefType(); + } + + Debug.Fail("Expected to be unreachable"); + return null; } - if (module != null) + private TypeDesc GetSimpleType(TypeName typeName) { - Type type = GetTypeCore(module, typeName, nestedTypeNames); - if (type != null) - return type; + TypeName topLevelTypeName = typeName; + while (topLevelTypeName.IsNested) + { + topLevelTypeName = topLevelTypeName.DeclaringType; + } + + ModuleDesc module = _module; + if (topLevelTypeName.AssemblyName != null) + { + module = _context.ResolveAssembly(typeName.AssemblyName.ToAssemblyName(), throwIfNotFound: _throwIfNotFound); + if (module == null) + return null; + } + + if (module != null) + { + TypeDesc type = GetSimpleTypeFromModule(typeName, module); + if (type != null) + { + _referencedModules?.Add(module); + return type; + } + } + + // If it didn't resolve and wasn't assembly-qualified, we also try core library + if (topLevelTypeName.AssemblyName == null) + { + if (module != _context.SystemModule) + { + TypeDesc type = GetSimpleTypeFromModule(typeName, _context.SystemModule); + if (type != null) + { + _referencedModules?.Add(_context.SystemModule); + return type; + } + } + + _typeWasNotFoundInAssemblyNorBaseLibrary = true; + } + + if (_throwIfNotFound) + ThrowHelper.ThrowTypeLoadException(typeName.FullName, module); + return null; } - // If it didn't resolve and wasn't assembly-qualified, we also try core library - if (parsedName.AssemblyName == null) + private TypeDesc GetSimpleTypeFromModule(TypeName typeName, ModuleDesc module) { - Type type = GetTypeCore(module.Context.SystemModule, typeName, nestedTypeNames); - if (type != null) - return type; + if (typeName.IsNested) + { + TypeDesc type = GetSimpleTypeFromModule(typeName.DeclaringType, module); + if (type == null) + return null; + return ((MetadataType)type).GetNestedType(TypeNameHelpers.Unescape(typeName.Name)); + } + + string fullName = TypeNameHelpers.Unescape(typeName.FullName); + + if (_canonResolver != null) + { + MetadataType canonType = _canonResolver(module, fullName); + if (canonType != null) + return canonType; + } + + (string typeNamespace, string name) = TypeNameHelpers.Split(fullName); + + return module.GetType(typeNamespace, name, throwIfNotFound: false); } - if (_throwIfNotFound) - ThrowHelper.ThrowTypeLoadException(parsedName.FullName, module); - return null; - } - - private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan nestedTypeNames) - { - (string typeNamespace, string name) = SplitFullTypeName(typeName); - - MetadataType type = module.GetType(typeNamespace, name, throwIfNotFound: false); - if (type == null) - return null; - - for (int i = 0; i < nestedTypeNames.Length; i++) + private TypeDesc GetGenericType(TypeName typeName) { - type = type.GetNestedType(nestedTypeNames[i]); - if (type == null) + TypeDesc typeDefinition = Resolve(typeName.GetGenericTypeDefinition()); + if (typeDefinition == null) return null; - } - return new Type(type); + ImmutableArray typeArguments = typeName.GetGenericArguments(); + TypeDesc[] instantiation = new TypeDesc[typeArguments.Length]; + for (int i = 0; i < typeArguments.Length; i++) + { + TypeDesc type = Resolve(typeArguments[i]); + if (type == null) + return null; + instantiation[i] = type; + } + return ((MetadataType)typeDefinition).MakeInstantiatedType(instantiation); + } } } } diff --git a/src/coreclr/tools/ILVerification/ILVerification.projitems b/src/coreclr/tools/ILVerification/ILVerification.projitems index c0f3644b1ab34..fc02753d60104 100644 --- a/src/coreclr/tools/ILVerification/ILVerification.projitems +++ b/src/coreclr/tools/ILVerification/ILVerification.projitems @@ -66,21 +66,12 @@ Utilities\CustomAttributeTypeNameParser.cs - - System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs - - - System\Diagnostics\CodeAnalysis\NullableAttributes.cs - - - Utilities\CustomAttributeTypeNameParser.Helpers + + Utilities\TypeNameHelpers.cs Utilities\ValueStringBuilder.cs - - Utilities\ValueStringBuilder.AppendSpanFormattable.cs - Utilities\LockFreeReaderHashtable.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs index 279418b2fac3c..f297a7cb73927 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs @@ -88,7 +88,7 @@ internal bool TryResolveTypeNameAndMark(string typeName, in DiagnosticContext di ModuleDesc? callingModule = (diagnosticContext.Origin.MemberDefinition.GetOwningType() as MetadataType)?.Module; List referencedModules = new(); - TypeDesc foundType = System.Reflection.TypeNameParser.ResolveType(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context, + TypeDesc foundType = CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeNameForDataFlow(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context, referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary); if (foundType == null) { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs deleted file mode 100644 index 278b6c4735afc..0000000000000 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs +++ /dev/null @@ -1,117 +0,0 @@ -// 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.Reflection.Metadata; -using Internal.TypeSystem; - -namespace System.Reflection -{ - internal partial struct TypeNameParser - { - private static readonly TypeNameParseOptions s_typeNameParseOptions = new() { MaxNodes = int.MaxValue }; - - private TypeSystemContext _context; - private ModuleDesc _callingModule; - private List _referencedModules; - private bool _typeWasNotFoundInAssemblyNorBaseLibrary; - - public static TypeDesc ResolveType(string name, ModuleDesc callingModule, - TypeSystemContext context, List referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary) - { - if (!TypeName.TryParse(name, out TypeName parsed, s_typeNameParseOptions)) - { - typeWasNotFoundInAssemblyNorBaseLibrary = false; - return null; - } - - var parser = new TypeNameParser() - { - _context = context, - _callingModule = callingModule, - _referencedModules = referencedModules - }; - - TypeDesc result = parser.Resolve(parsed)?.Value; - - typeWasNotFoundInAssemblyNorBaseLibrary = parser._typeWasNotFoundInAssemblyNorBaseLibrary; - return result; - } - - private sealed class Type - { - public Type(TypeDesc type) => Value = type; - public TypeDesc Value { get; } - - public Type MakeArrayType() => new Type(Value.MakeArrayType()); - public Type MakeArrayType(int rank) => new Type(Value.MakeArrayType(rank)); - public Type MakePointerType() => new Type(Value.MakePointerType()); - public Type MakeByRefType() => new Type(Value.MakeByRefType()); - - public Type MakeGenericType(Type[] typeArguments) - { - TypeDesc[] instantiation = new TypeDesc[typeArguments.Length]; - for (int i = 0; i < typeArguments.Length; i++) - instantiation[i] = typeArguments[i].Value; - return new Type(((MetadataType)Value).MakeInstantiatedType(instantiation)); - } - } - - private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, TypeName parsedName) - { - ModuleDesc module; - - if (parsedName.AssemblyName != null) - { - module = _context.ResolveAssembly(parsedName.AssemblyName.ToAssemblyName(), throwIfNotFound: false); - } - else - { - module = _callingModule; - } - - if (module != null) - { - Type type = GetTypeCore(module, typeName, nestedTypeNames); - if (type != null) - { - _referencedModules?.Add(module); - return type; - } - } - - // If it didn't resolve and wasn't assembly-qualified, we also try core library - if (parsedName.AssemblyName == null) - { - Type type = GetTypeCore(_context.SystemModule, typeName, nestedTypeNames); - if (type != null) - { - _referencedModules?.Add(_context.SystemModule); - return type; - } - - _typeWasNotFoundInAssemblyNorBaseLibrary = true; - } - - return null; - } - - private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan nestedTypeNames) - { - (string typeNamespace, string name) = SplitFullTypeName(typeName); - - MetadataType type = module.GetType(typeNamespace, name, throwIfNotFound: false); - if (type == null) - return null; - - for (int i = 0; i < nestedTypeNames.Length; i++) - { - type = type.GetNestedType(nestedTypeNames[i]); - if (type == null) - return null; - } - - return new Type(type); - } - } -} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index a895dbe1726fa..eb9db7165be26 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -396,9 +396,8 @@ - - - Compiler\Dataflow\TypeNameParser.Helpers.cs + + Utilities\TypeNameHelpers.cs Utilities\ValueStringBuilder.cs diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj index 1a5db3b44445d..d287e10e97d5f 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj @@ -198,8 +198,8 @@ Utilities\CustomAttributeTypeNameParser.cs - - Utilities\CustomAttributeTypeNameParser.Helpers + + Utilities\TypeNameHelpers.cs Utilities\ValueStringBuilder.cs diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 2f9049aea8d71..081325545827e 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -337,8 +337,8 @@ DEFINE_METHOD(RT_TYPE_HANDLE, ALLOCATECOMOBJECT, AllocateComObject, #endif DEFINE_FIELD(RT_TYPE_HANDLE, M_TYPE, m_type) -DEFINE_CLASS(TYPE_NAME_PARSER, Reflection, TypeNameParser) -DEFINE_METHOD(TYPE_NAME_PARSER, GET_TYPE_HELPER, GetTypeHelper, SM_Type_CharPtr_RuntimeAssembly_Bool_Bool_RetRuntimeType) +DEFINE_CLASS(TYPE_NAME_RESOLVER, Reflection, TypeNameResolver) +DEFINE_METHOD(TYPE_NAME_RESOLVER, GET_TYPE_HELPER, GetTypeHelper, SM_Type_CharPtr_RuntimeAssembly_Bool_Bool_RetRuntimeType) DEFINE_CLASS_U(Reflection, RtFieldInfo, NoClass) DEFINE_FIELD_U(m_fieldHandle, ReflectFieldObject, m_pFD) diff --git a/src/coreclr/vm/typeparse.cpp b/src/coreclr/vm/typeparse.cpp index 3f6acfafdf471..5a9947042928c 100644 --- a/src/coreclr/vm/typeparse.cpp +++ b/src/coreclr/vm/typeparse.cpp @@ -31,7 +31,7 @@ static TypeHandle GetTypeHelper(LPCWSTR szTypeName, Assembly* pRequestingAssembl OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED); - PREPARE_NONVIRTUAL_CALLSITE(METHOD__TYPE_NAME_PARSER__GET_TYPE_HELPER); + PREPARE_NONVIRTUAL_CALLSITE(METHOD__TYPE_NAME_RESOLVER__GET_TYPE_HELPER); DECLARE_ARGHOLDER_ARRAY(args, 4); args[ARGNUM_0] = PTR_TO_ARGHOLDER(szTypeName); args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(objRequestingAssembly); diff --git a/src/libraries/Common/src/System/Reflection/AssemblyNameFormatter.cs b/src/libraries/Common/src/System/Reflection/AssemblyNameFormatter.cs index b4fbdca1e9091..41598ddc5310c 100644 --- a/src/libraries/Common/src/System/Reflection/AssemblyNameFormatter.cs +++ b/src/libraries/Common/src/System/Reflection/AssemblyNameFormatter.cs @@ -6,8 +6,6 @@ using System.Globalization; using System.Text; -#nullable enable - namespace System.Reflection { internal static class AssemblyNameFormatter diff --git a/src/libraries/Common/src/System/Reflection/AssemblyNameParser.cs b/src/libraries/Common/src/System/Reflection/AssemblyNameParser.cs index bfd91d781a4ec..1c9f55d4087f7 100644 --- a/src/libraries/Common/src/System/Reflection/AssemblyNameParser.cs +++ b/src/libraries/Common/src/System/Reflection/AssemblyNameParser.cs @@ -8,8 +8,6 @@ using System.Runtime.CompilerServices; using System.Text; -#nullable enable - namespace System.Reflection { /// diff --git a/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs b/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs index cb4de9467f660..35e12bdd81527 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable enable - using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text; diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs index 1464f0248280b..3f1ea8394393c 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable enable - using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -390,7 +388,7 @@ public int GetArrayRank() /// public #if SYSTEM_PRIVATE_CORELIB - IReadOnlyList GetGenericArguments() => _genericArguments is null ? Array.Empty() : _genericArguments; + ReadOnlySpan GetGenericArguments() => CollectionsMarshal.AsSpan(_genericArguments); #else ImmutableArray GetGenericArguments() => _genericArguments; #endif diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameHelpers.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameHelpers.cs new file mode 100644 index 0000000000000..f43a04fadfd59 --- /dev/null +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameHelpers.cs @@ -0,0 +1,79 @@ +// 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; +using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata; +using System.Text; + +namespace System.Reflection.Metadata +{ + internal static class TypeNameHelpers + { + private const char EscapeCharacter = '\\'; + + /// + /// Removes escape characters from the string (if there were any found). + /// + internal static string Unescape(string name) + { + int indexOfEscapeCharacter = name.IndexOf(EscapeCharacter); + if (indexOfEscapeCharacter < 0) + { + return name; + } + + return Unescape(name, indexOfEscapeCharacter); + + static string Unescape(string name, int indexOfEscapeCharacter) + { + // this code path is executed very rarely (IL Emit or pure IL with chars not allowed in C# or F#) + var sb = new ValueStringBuilder(stackalloc char[64]); + sb.EnsureCapacity(name.Length); + sb.Append(name.AsSpan(0, indexOfEscapeCharacter)); + + for (int i = indexOfEscapeCharacter; i < name.Length;) + { + char c = name[i++]; + + if (c != EscapeCharacter) + { + sb.Append(c); + } + else if (i < name.Length && name[i] == EscapeCharacter) // escaped escape character ;) + { + sb.Append(c); + // Consume the escaped escape character, it's important for edge cases + // like escaped escape character followed by another escaped char (example: "\\\\\\+") + i++; + } + } + + return sb.ToString(); + } + } + + internal static (string typeNamespace, string name) Split(string typeName) + { + string typeNamespace, name; + + // Matches algorithm from ns::FindSep in src\coreclr\utilcode\namespaceutil.cpp + // This could result in the type name beginning with a '.' character. + int separator = typeName.LastIndexOf('.'); + if (separator <= 0) + { + typeNamespace = ""; + name = typeName; + } + else + { + if (typeName[separator - 1] == '.') + separator--; + typeNamespace = typeName.Substring(0, separator); + name = typeName.Substring(separator + 1); + } + + return (typeNamespace, name); + } + } +} diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs index dcba442054a5d..5a5bbe04a0c18 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs @@ -10,8 +10,6 @@ using static System.Reflection.Metadata.TypeNameParserHelpers; -#nullable enable - namespace System.Reflection.Metadata { [DebuggerDisplay("{_inputString}")] diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs index 1cdc5e230ad96..2fa33ea1dfe3b 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs @@ -7,8 +7,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -#nullable enable - namespace System.Reflection.Metadata { internal static class TypeNameParserHelpers diff --git a/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs b/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs deleted file mode 100644 index 84ef2137fb095..0000000000000 --- a/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs +++ /dev/null @@ -1,214 +0,0 @@ -// 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; -using System.Diagnostics.CodeAnalysis; -using System.Reflection.Metadata; -using System.Text; - -#nullable enable - -#if SYSTEM_PRIVATE_CORELIB -namespace System.Reflection.Metadata -{ - internal struct TypeNameParseOptions - { - public TypeNameParseOptions() { } -#pragma warning disable CA1822 // Mark members as static - // CoreLib does not enforce any limits - public bool IsMaxDepthExceeded(int _) => false; - public int MaxNodes - { - get - { - Debug.Fail("Expected to be unreachable"); - return 0; - } - } -#pragma warning restore CA1822 - } -} -#endif - -namespace System.Reflection -{ - internal partial struct TypeNameParser - { -#if !MONO // Mono never needs unescaped names - private const char EscapeCharacter = '\\'; - - /// - /// Removes escape characters from the string (if there were any found). - /// - private static string UnescapeTypeName(string name) - { - int indexOfEscapeCharacter = name.IndexOf(EscapeCharacter); - if (indexOfEscapeCharacter < 0) - { - return name; - } - - return Unescape(name, indexOfEscapeCharacter); - - static string Unescape(string name, int indexOfEscapeCharacter) - { - // this code path is executed very rarely (IL Emit or pure IL with chars not allowed in C# or F#) - var sb = new ValueStringBuilder(stackalloc char[64]); - sb.EnsureCapacity(name.Length); - sb.Append(name.AsSpan(0, indexOfEscapeCharacter)); - - for (int i = indexOfEscapeCharacter; i < name.Length;) - { - char c = name[i++]; - - if (c != EscapeCharacter) - { - sb.Append(c); - } - else if (i < name.Length && name[i] == EscapeCharacter) // escaped escape character ;) - { - sb.Append(c); - // Consume the escaped escape character, it's important for edge cases - // like escaped escape character followed by another escaped char (example: "\\\\\\+") - i++; - } - } - - return sb.ToString(); - } - } -#endif - - private static (string typeNamespace, string name) SplitFullTypeName(string typeName) - { - string typeNamespace, name; - - // Matches algorithm from ns::FindSep in src\coreclr\utilcode\namespaceutil.cpp - // This could result in the type name beginning with a '.' character. - int separator = typeName.LastIndexOf('.'); - if (separator <= 0) - { - typeNamespace = ""; - name = typeName; - } - else - { - if (typeName[separator - 1] == '.') - separator--; - typeNamespace = typeName.Substring(0, separator); - name = typeName.Substring(separator + 1); - } - - return (typeNamespace, name); - } - - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL3050:RequiresDynamicCode", - Justification = "Used to implement resolving types from strings.")] - private Type? Resolve(TypeName typeName) - { - if (typeName.IsNested) - { - TypeName? current = typeName; - int nestingDepth = 0; - while (current is not null && current.IsNested) - { - nestingDepth++; - current = current.DeclaringType; - } - - // We're performing real type resolution, it is assumed that the caller has already validated the correctness - // of this TypeName object against their own policies, so there is no need for this method to perform any further checks. - string[] nestedTypeNames = new string[nestingDepth]; - current = typeName; - while (current is not null && current.IsNested) - { -#if MONO - nestedTypeNames[--nestingDepth] = current.Name; -#else // CLR, NativeAOT and tools require unescaped nested type names - nestedTypeNames[--nestingDepth] = UnescapeTypeName(current.Name); -#endif - current = current.DeclaringType; - } -#if SYSTEM_PRIVATE_CORELIB - string nonNestedParentName = current!.FullName; -#else // the tools require unescaped names - string nonNestedParentName = UnescapeTypeName(current!.FullName); -#endif - Type? type = GetType(nonNestedParentName, nestedTypeNames, typeName); - return type is null || !typeName.IsConstructedGenericType ? type : MakeGenericType(type, typeName); - } - else if (typeName.IsConstructedGenericType) - { - Type? type = Resolve(typeName.GetGenericTypeDefinition()); - return type is null ? null : MakeGenericType(type, typeName); - } - else if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef) - { - Type? type = Resolve(typeName.GetElementType()); - if (type is null) - { - return null; - } - - if (typeName.IsByRef) - { - return type.MakeByRefType(); - } - else if (typeName.IsPointer) - { - return type.MakePointerType(); - } - else if (typeName.IsSZArray) - { - return type.MakeArrayType(); - } - else - { - Debug.Assert(typeName.IsVariableBoundArrayType); - - return type.MakeArrayType(rank: typeName.GetArrayRank()); - } - } - else - { - Debug.Assert(typeName.IsSimple); - - Type? type = GetType( -#if SYSTEM_PRIVATE_CORELIB - typeName.FullName, -#else // the tools require unescaped names - UnescapeTypeName(typeName.FullName), -#endif - nestedTypeNames: ReadOnlySpan.Empty, typeName); - - return type; - } - } - - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:UnrecognizedReflectionPattern", - Justification = "Used to implement resolving types from strings.")] - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL3050:RequiresDynamicCode", - Justification = "Used to implement resolving types from strings.")] - private Type? MakeGenericType(Type type, TypeName typeName) - { - var genericArgs = typeName.GetGenericArguments(); -#if SYSTEM_PRIVATE_CORELIB - int size = genericArgs.Count; -#else - int size = genericArgs.Length; -#endif - Type[] genericTypes = new Type[size]; - for (int i = 0; i < size; i++) - { - Type? genericArg = Resolve(genericArgs[i]); - if (genericArg is null) - { - return null; - } - genericTypes[i] = genericArg; - } - - return type.MakeGenericType(genericTypes); - } - } -} diff --git a/src/libraries/Common/src/System/Text/ValueStringBuilder.AppendSpanFormattable.cs b/src/libraries/Common/src/System/Text/ValueStringBuilder.AppendSpanFormattable.cs index 3e9cf2c56d3ea..04e9fcbdb5524 100644 --- a/src/libraries/Common/src/System/Text/ValueStringBuilder.AppendSpanFormattable.cs +++ b/src/libraries/Common/src/System/Text/ValueStringBuilder.AppendSpanFormattable.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable enable - namespace System.Text { internal ref partial struct ValueStringBuilder diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index f1b61a1ea67c4..99e354aa32d3a 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -778,6 +778,7 @@ + @@ -1475,9 +1476,6 @@ Common\System\IO\PathInternal.CaseSensitivity.cs - - Common\System\Reflection\TypeNameParser.Helpers - Common\System\Reflection\AssemblyNameParser.cs @@ -1490,6 +1488,9 @@ Common\System\Reflection\Metadata\TypeName.cs + + Common\System\Reflection\Metadata\TypeNameHelpers.cs + Common\System\Reflection\Metadata\TypeNameParser.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs index 5ee6c949bc97e..2d82ed0c0e7f5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable enable - namespace System.Diagnostics.CodeAnalysis { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.cs new file mode 100644 index 0000000000000..9e36505b390ea --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.cs @@ -0,0 +1,122 @@ +// 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; +using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata; +using System.Text; + +namespace System.Reflection.Metadata +{ + internal struct TypeNameParseOptions + { + public TypeNameParseOptions() { } +#pragma warning disable CA1822 // Mark members as static + // CoreLib does not enforce any limits + public bool IsMaxDepthExceeded(int _) => false; + public int MaxNodes + { + get + { + Debug.Fail("Expected to be unreachable"); + return 0; + } + } +#pragma warning restore CA1822 + } +} + +namespace System.Reflection +{ + internal partial struct TypeNameResolver + { + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL3050:RequiresDynamicCode", + Justification = "Used to implement resolving types from strings.")] + private Type? Resolve(TypeName typeName) + { + if (typeName.IsSimple) + { + return GetSimpleType(typeName); + } + else if (typeName.IsConstructedGenericType) + { + return GetGenericType(typeName); + } + else if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef) + { + Type? type = Resolve(typeName.GetElementType()); + if (type is null) + return null; + + if (typeName.IsArray) + { + return typeName.IsSZArray ? type.MakeArrayType() : type.MakeArrayType(rank: typeName.GetArrayRank()); + } + if (typeName.IsByRef) + { + return type.MakeByRefType(); + } + else if (typeName.IsPointer) + { + return type.MakePointerType(); + } + } + + Debug.Fail("Expected to be unreachable"); + return null; + } + + private Type? GetSimpleType(TypeName typeName) + { + if (typeName.IsNested) + { + TypeName current = typeName; + int nestingDepth = 0; + do + { + nestingDepth++; + current = current.DeclaringType!; + } + while (current.IsNested); + + string[] nestedTypeNames = new string[nestingDepth]; + current = typeName; + while (current.IsNested) + { + nestedTypeNames[--nestingDepth] = TypeNameHelpers.Unescape(current.Name); + current = current.DeclaringType!; + } + + return GetType(current.FullName, nestedTypeNames, typeName); + } + else + { + return GetType(typeName.FullName, default, typeName); + } + + } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:UnrecognizedReflectionPattern", + Justification = "Used to implement resolving types from strings.")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL3050:RequiresDynamicCode", + Justification = "Used to implement resolving types from strings.")] + private Type? GetGenericType(TypeName typeName) + { + Type? type = Resolve(typeName.GetGenericTypeDefinition()); + if (type is null) + return null; + + ReadOnlySpan genericArgs = typeName.GetGenericArguments(); + Type[] genericTypes = new Type[genericArgs.Length]; + for (int i = 0; i < genericArgs.Length; i++) + { + Type? genericArg = Resolve(genericArgs[i]); + if (genericArg is null) + return null; + genericTypes[i] = genericArg; + } + + return type.MakeGenericType(genericTypes); + } + } +} diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 076fc42815c65..9137c694aa4ab 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -235,7 +235,7 @@ - + diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameParser.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.Mono.cs similarity index 91% rename from src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameParser.Mono.cs rename to src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.Mono.cs index 22a7361d9814e..ef5d63ec28074 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameParser.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.Mono.cs @@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; +using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Runtime.Loader; using System.Text; @@ -11,7 +12,7 @@ namespace System.Reflection { - internal unsafe ref partial struct TypeNameParser + internal unsafe ref partial struct TypeNameResolver { private Func? _assemblyResolver; private Func? _typeResolver; @@ -39,13 +40,13 @@ internal unsafe ref partial struct TypeNameParser return null; } - Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError: throwOnError); + TypeName? parsed = TypeNameParser.Parse(typeName, throwOnError); if (parsed is null) { return null; } - return new TypeNameParser() + return new TypeNameResolver() { _assemblyResolver = assemblyResolver, _typeResolver = typeResolver, @@ -92,10 +93,10 @@ internal unsafe ref partial struct TypeNameParser } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", - Justification = "TypeNameParser.GetType is marked as RequiresUnreferencedCode.")] + Justification = "TypeNameResolver.GetType is marked as RequiresUnreferencedCode.")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", - Justification = "TypeNameParser.GetType is marked as RequiresUnreferencedCode.")] - private Type? GetType(string escapedTypeName, ReadOnlySpan nestedTypeNames, Metadata.TypeName parsedName) + Justification = "TypeNameResolver.GetType is marked as RequiresUnreferencedCode.")] + private Type? GetType(string escapedTypeName, ReadOnlySpan nestedTypeNames, TypeName parsedName) { Assembly? assembly = (parsedName.AssemblyName is not null) ? ResolveAssembly(parsedName.AssemblyName.ToAssemblyName()) : null; @@ -150,7 +151,7 @@ internal unsafe ref partial struct TypeNameParser if (_throwOnError) { throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveNestedType, - nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : escapedTypeName)); + nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : TypeNameHelpers.Unescape(escapedTypeName))); } return null; } diff --git a/src/mono/System.Private.CoreLib/src/System/Type.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Type.Mono.cs index 851cc8f92c551..3fc4f6082c9b2 100644 --- a/src/mono/System.Private.CoreLib/src/System/Type.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Type.Mono.cs @@ -76,7 +76,7 @@ internal IntPtr GetUnderlyingNativeHandle() [RequiresUnreferencedCode("The type might be removed")] private static Type? GetType(string typeName, Func? assemblyResolver, Func? typeResolver, bool throwOnError, bool ignoreCase, ref StackCrawlMark stackMark) { - return TypeNameParser.GetType(typeName, assemblyResolver, typeResolver, throwOnError, ignoreCase, ref stackMark); + return TypeNameResolver.GetType(typeName, assemblyResolver, typeResolver, throwOnError, ignoreCase, ref stackMark); } public static Type? GetTypeFromHandle(RuntimeTypeHandle handle)