From f5e446fb5a03d3819c0faecaf381e28db3bf3b0a Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 3 Apr 2023 17:18:25 -0700 Subject: [PATCH] Switch CustomAttributeTypeNameParser to use common type name parser --- .../Reflection/TypeNameParser.CoreCLR.cs | 2 +- .../Reflection/TypeNameParser.NativeAot.cs | 2 +- .../CustomAttributeTypeNameParser.cs | 475 +++--------------- .../ILVerification/ILVerification.projitems | 6 + .../TypeNameParser.Dataflow.cs} | 26 +- .../ILCompiler.Compiler.csproj | 14 +- .../Compiler/CallChainProfile.cs | 7 +- .../ILCompiler.TypeSystem.csproj | 6 + src/coreclr/tools/aot/ILCompiler/Program.cs | 8 +- src/coreclr/tools/aot/crossgen2/Program.cs | 8 +- .../src/System/Reflection/TypeNameParser.cs | 35 +- 11 files changed, 136 insertions(+), 453 deletions(-) rename src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/{DependencyAnalysis/TypeNameParser.cs => Dataflow/TypeNameParser.Dataflow.cs} (84%) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs index 4776a1a81dfe9..2af4bb792d458 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs @@ -13,7 +13,7 @@ namespace System.Reflection { - internal unsafe ref partial struct TypeNameParser + internal partial struct TypeNameParser { private Func? _assemblyResolver; private Func? _typeResolver; 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/TypeNameParser.NativeAot.cs index ea3c7f89b7104..e370cb4eed0a8 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs @@ -13,7 +13,7 @@ namespace System.Reflection // // Parser for type names passed to GetType() apis. // - internal ref partial struct TypeNameParser + internal partial struct TypeNameParser { private Func? _assemblyResolver; private Func? _typeResolver; diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs index 8089f6585d498..42744c7fead6e 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs @@ -5,15 +5,10 @@ using System.Collections.Generic; using System.Text; -using AssemblyName = System.Reflection.AssemblyName; -using Debug = System.Diagnostics.Debug; +using Internal.TypeSystem; namespace Internal.TypeSystem { - // TODO: This file is pretty much a line-by-line port of C++ code to parse CA type name strings from NUTC. - // It's a stopgap solution. - // This should be replaced with type name parser in System.Reflection.Metadata once it starts shipping. - public static class CustomAttributeTypeNameParser { /// @@ -21,441 +16,107 @@ public static class CustomAttributeTypeNameParser /// The type name string should be in the 'SerString' format as defined by the ECMA-335 standard. /// This is the inverse of what does. /// - public static TypeDesc GetTypeByCustomAttributeTypeName(this ModuleDesc module, string name, bool throwIfNotFound = true, Func resolver = null) + public static TypeDesc GetTypeByCustomAttributeTypeName(this ModuleDesc module, string name, bool throwIfNotFound = true, + Func canonResolver = null) { - TypeDesc loadedType; - - StringBuilder genericTypeDefName = new StringBuilder(name.Length); - - var ch = name.Begin(); - var nameEnd = name.End(); - - for (; ch < nameEnd; ++ch) - { - // Always pass escaped characters through. - if (ch.Current == '\\') - { - genericTypeDefName.Append(ch.Current); - ++ch; - if (ch < nameEnd) - { - genericTypeDefName.Append(ch.Current); - } - continue; - } - - // The type def name ends if - - // The start of a generic argument list - if (ch.Current == '[') - break; - - // Indication that the type is a pointer - if (ch.Current == '*') - break; - - // Indication that the type is a reference - if (ch.Current == '&') - break; - - // A comma that indicates that the rest of the name is an assembly reference - if (ch.Current == ',') - break; - - genericTypeDefName.Append(ch.Current); - } - - ModuleDesc homeModule = module; - AssemblyName homeAssembly = FindAssemblyIfNamePresent(name); - if (homeAssembly != null) - { - homeModule = module.Context.ResolveAssembly(homeAssembly, throwIfNotFound); - if (homeModule == null) - return null; - } - MetadataType typeDef = resolver != null ? resolver(genericTypeDefName.ToString(), homeModule, throwIfNotFound) : - ResolveCustomAttributeTypeDefinitionName(genericTypeDefName.ToString(), homeModule, throwIfNotFound); - if (typeDef == null) - return null; - - ArrayBuilder genericArgs = default(ArrayBuilder); - - // Followed by generic instantiation parameters (but check for the array case) - if (ch < nameEnd && ch.Current == '[' && (ch + 1) < nameEnd && (ch + 1).Current != ']' && (ch + 1).Current != ',') - { - ch++; // truncate the '[' - var genericInstantiationEnd = ch + ReadTypeArgument(ch, nameEnd, true); // find the end of the instantiation list - while (ch < genericInstantiationEnd) - { - if (ch.Current == ',') - ch++; - - int argLen = ReadTypeArgument(ch, name.End(), false); - string typeArgName; - if (ch.Current == '[') - { - // This type argument name is stringified, - // we need to remove the [] from around it - ch++; - typeArgName = StringIterator.Substring(ch, ch + (argLen - 2)); - ch += argLen - 1; - } - else - { - typeArgName = StringIterator.Substring(ch, ch + argLen); - ch += argLen; - } - - TypeDesc argType = module.GetTypeByCustomAttributeTypeName(typeArgName, throwIfNotFound, resolver); - if (argType == null) - return null; - genericArgs.Add(argType); - } - - Debug.Assert(ch == genericInstantiationEnd); - ch++; - - loadedType = typeDef.MakeInstantiatedType(genericArgs.ToArray()); - } - else - { - // Non-generic type - loadedType = typeDef; - } - - // At this point the characters following may be any number of * characters to indicate pointer depth - while (ch < nameEnd) - { - if (ch.Current == '*') - { - loadedType = loadedType.MakePointerType(); - } - else - { - break; - } - ch++; - } - - // Followed by any number of "[]" or "[,*]" pairs to indicate arrays - int commasSeen = 0; - bool bracketSeen = false; - while (ch < nameEnd) - { - if (ch.Current == '[') - { - ch++; - commasSeen = 0; - bracketSeen = true; - } - else if (ch.Current == ']') - { - if (!bracketSeen) - break; - - ch++; - if (commasSeen == 0) - { - loadedType = loadedType.MakeArrayType(); - } - else - { - loadedType = loadedType.MakeArrayType(commasSeen + 1); - } - - bracketSeen = false; - } - else if (ch.Current == ',') - { - if (!bracketSeen) - break; - ch++; - commasSeen++; - } - else - { - break; - } - } - - // Followed by at most one & character to indicate a byref. - if (ch < nameEnd) - { - if (ch.Current == '&') - { - loadedType = loadedType.MakeByRefType(); -#pragma warning disable IDE0059 // Unnecessary assignment of a value - ch++; -#pragma warning restore IDE0059 // Unnecessary assignment of a value - } - } - - return loadedType; + return System.Reflection.TypeNameParser.ResolveType(module, name, throwIfNotFound, canonResolver); } + } +} +namespace System.Reflection +{ + internal partial struct TypeNameParser + { + private ModuleDesc _module; + private bool _throwIfNotFound; + private Func _canonResolver; - public static MetadataType ResolveCustomAttributeTypeDefinitionName(string name, ModuleDesc module, bool throwIfNotFound) - { - MetadataType containingType = null; - StringBuilder typeName = new StringBuilder(name.Length); - bool escaped = false; - for (var c = name.Begin(); c < name.End(); c++) - { - if (c.Current == '\\' && !escaped) - { - escaped = true; - continue; - } - - if (escaped) - { - escaped = false; - typeName.Append(c.Current); - continue; - } - - if (c.Current == ',') - { - break; - } - - if (c.Current == '[' || c.Current == '*' || c.Current == '&') - { - break; - } - - if (c.Current == '+') - { - if (containingType != null) - { - MetadataType outerType = containingType; - containingType = outerType.GetNestedType(typeName.ToString()); - if (containingType == null) - { - if (throwIfNotFound) - ThrowHelper.ThrowTypeLoadException(typeName.ToString(), outerType.Module); - - return null; - } - } - else - { - containingType = module.GetType(typeName.ToString(), throwIfNotFound); - if (containingType == null) - return null; - } - typeName.Length = 0; - continue; - } - - typeName.Append(c.Current); - } - - if (containingType != null) - { - MetadataType type = containingType.GetNestedType(typeName.ToString()); - if ((type == null) && throwIfNotFound) - ThrowHelper.ThrowTypeLoadException(typeName.ToString(), containingType.Module); - - return type; - } - - return module.GetType(typeName.ToString(), throwIfNotFound); - } - - private static MetadataType GetType(this ModuleDesc module, string fullName, bool throwIfNotFound = true) + public static TypeDesc ResolveType(ModuleDesc module, string name, bool throwIfNotFound, + Func canonResolver) { - string namespaceName; - string typeName; - int split = fullName.LastIndexOf('.'); - if (split < 0) + return new TypeNameParser(name.AsSpan()) { - namespaceName = ""; - typeName = fullName; - } - else - { - namespaceName = fullName.Substring(0, split); - typeName = fullName.Substring(split + 1); - } - return module.GetType(namespaceName, typeName, throwIfNotFound); + _module = module, + _throwIfNotFound = throwIfNotFound, + _canonResolver = canonResolver + }.Parse()?.Value; } - private static AssemblyName FindAssemblyIfNamePresent(string name) + private sealed class Type { - AssemblyName result = null; - var endOfType = name.Begin() + ReadTypeArgument(name.Begin(), name.End(), false); - if (endOfType < name.End() && endOfType.Current == ',') - { - // There is an assembly name here - int foundCommas = 0; - var endOfAssemblyName = endOfType; - for (var ch = endOfType + 1; ch < name.End(); ch++) - { - if (foundCommas == 3) - { - // We're now eating the public key token, looking for the end of the name, - // or a right bracket - if (ch.Current == ']' || ch.Current == ',') - { - endOfAssemblyName = ch - 1; - break; - } - } - - if (ch.Current == ',') - { - foundCommas++; - } - } - if (endOfAssemblyName == endOfType) - { - endOfAssemblyName = name.End(); - } + public Type(TypeDesc type) => Value = type; + public TypeDesc Value { get; } - // eat the comma - endOfType++; - for (; endOfType < endOfAssemblyName; ++endOfType) - { - // trim off spaces - if (endOfType.Current != ' ') - break; - } - result = new AssemblyName(StringIterator.Substring(endOfType, endOfAssemblyName)); - } - return result; - } + 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()); - private static int ReadTypeArgument(StringIterator strBegin, StringIterator strEnd, bool ignoreComma) - { - int level = 0; - int length = 0; - for (var c = strBegin; c < strEnd; c++) + public Type MakeGenericType(Type[] typeArguments) { - if (c.Current == '\\') - { - length++; - if ((c + 1) < strEnd) - { - c++; - length++; - } - continue; - } - if (c.Current == '[') - { - level++; - } - else if (c.Current == ']') - { - if (level == 0) - break; - level--; - } - else if (!ignoreComma && (c.Current == ',')) - { - if (level == 0) - break; - } - - length++; + 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)); } - - return length; } - #region C++ string iterator compatibility shim - - private static StringIterator Begin(this string s) - { - return new StringIterator(s, 0); - } + private static bool CheckTopLevelAssemblyQualifiedName() => true; - private static StringIterator End(this string s) + private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, string assemblyNameIfAny) { - return new StringIterator(s, s.Length); - } - - private struct StringIterator : IEquatable - { - private string _string; - private int _index; - - public char Current - { - get - { - return _string[_index]; - } - } + ModuleDesc module = (assemblyNameIfAny == null) ? _module : + _module.Context.ResolveAssembly(new AssemblyName(assemblyNameIfAny), throwIfNotFound: _throwIfNotFound); - public StringIterator(string s, int index) + if (_canonResolver != null && nestedTypeNames.IsEmpty) { - Debug.Assert(index <= s.Length); - _string = s; - _index = index; + MetadataType canonType = _canonResolver(module, typeName); + if (canonType != null) + return new Type(canonType); } - public static string Substring(StringIterator it1, StringIterator it2) + if (module != null) { - Debug.Assert(ReferenceEquals(it1._string, it2._string)); - return it1._string.Substring(it1._index, it2._index - it1._index); + Type type = GetTypeCore(module, typeName, nestedTypeNames); + if (type != null) + return type; } - public static StringIterator operator ++(StringIterator it) + // If it didn't resolve and wasn't assembly-qualified, we also try core library + if (assemblyNameIfAny == null) { - return new StringIterator(it._string, ++it._index); + Type type = GetTypeCore(module.Context.SystemModule, typeName, nestedTypeNames); + if (type != null) + return type; } - public static bool operator <(StringIterator it1, StringIterator it2) - { - Debug.Assert(ReferenceEquals(it1._string, it2._string)); - return it1._index < it2._index; - } - - public static bool operator >(StringIterator it1, StringIterator it2) - { - Debug.Assert(ReferenceEquals(it1._string, it2._string)); - return it1._index > it2._index; - } - - public static StringIterator operator +(StringIterator it, int val) - { - return new StringIterator(it._string, it._index + val); - } - - public static StringIterator operator -(StringIterator it, int val) - { - return new StringIterator(it._string, it._index - val); - } + if (_throwIfNotFound) + ThrowHelper.ThrowTypeLoadException(EscapeTypeName(typeName, nestedTypeNames), module); + return null; + } - public static bool operator ==(StringIterator it1, StringIterator it2) - { - Debug.Assert(ReferenceEquals(it1._string, it2._string)); - return it1._index == it2._index; - } + private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan nestedTypeNames) + { + (string typeNamespace, string name) = SplitFullTypeName(typeName); - public static bool operator !=(StringIterator it1, StringIterator it2) - { - Debug.Assert(ReferenceEquals(it1._string, it2._string)); - return it1._index != it2._index; - } + MetadataType type = module.GetType(typeNamespace, name, throwIfNotFound: false); + if (type == null) + return null; - public override bool Equals(object obj) + for (int i = 0; i < nestedTypeNames.Length; i++) { - throw new NotImplementedException(); + type = type.GetNestedType(nestedTypeNames[i]); + if (type == null) + return null; } - public override int GetHashCode() - { - throw new NotImplementedException(); - } + return new Type(type); + } - public bool Equals(StringIterator other) - { - throw new NotImplementedException(); - } + private void ParseError() + { + ThrowHelper.ThrowTypeLoadException(_input.ToString(), _module); } - #endregion } } diff --git a/src/coreclr/tools/ILVerification/ILVerification.projitems b/src/coreclr/tools/ILVerification/ILVerification.projitems index 55b8d20304d00..61a4a8c280df0 100644 --- a/src/coreclr/tools/ILVerification/ILVerification.projitems +++ b/src/coreclr/tools/ILVerification/ILVerification.projitems @@ -64,6 +64,12 @@ Utilities\CustomAttributeTypeNameParser.cs + + Utilities\TypeNameParser.cs + + + Utilities\ValueStringBuilder.cs + Utilities\LockFreeReaderHashtable.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeNameParser.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs similarity index 84% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeNameParser.cs rename to src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs index b41b0aac06b01..90b63f39c9f02 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeNameParser.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs @@ -10,7 +10,7 @@ namespace System.Reflection { - internal unsafe ref partial struct TypeNameParser + internal partial struct TypeNameParser { private TypeSystemContext _context; private ModuleDesc _callingModule; @@ -20,7 +20,7 @@ internal unsafe ref partial struct TypeNameParser public static TypeDesc ResolveType(string name, ModuleDesc callingModule, TypeSystemContext context, List referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary) { - var parser = new System.Reflection.TypeNameParser(name) + var parser = new TypeNameParser(name) { _context = context, _callingModule = callingModule, @@ -68,11 +68,9 @@ private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, stri module = _callingModule; } - Type type; - if (module != null) { - type = GetTypeCore(module, typeName, nestedTypeNames); + Type type = GetTypeCore(module, typeName, nestedTypeNames); if (type != null) { _referencedModules?.Add(module); @@ -83,7 +81,7 @@ private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, stri // If it didn't resolve and wasn't assembly-qualified, we also try core library if (assemblyNameIfAny == null) { - type = GetTypeCore(_context.SystemModule, typeName, nestedTypeNames); + Type type = GetTypeCore(_context.SystemModule, typeName, nestedTypeNames); if (type != null) { _referencedModules?.Add(_context.SystemModule); @@ -114,21 +112,7 @@ private static AssemblyName TryParseAssemblyName(string assemblyName) private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan nestedTypeNames) { - string typeNamespace, name; - - 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); - } + (string typeNamespace, string name) = SplitFullTypeName(typeName); MetadataType type = module.GetType(typeNamespace, name, throwIfNotFound: false); if (type == null) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 4578500923ef8..a18341218ed06 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -30,12 +30,6 @@ - - TypeNameParser.cs - - - ValueStringBuilder.cs - IL\DelegateInfo.cs @@ -390,6 +384,13 @@ + + + Compiler\Dataflow\TypeNameParser.cs + + + Utilities\ValueStringBuilder.cs + @@ -421,7 +422,6 @@ - diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CallChainProfile.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CallChainProfile.cs index b8f05a9c3bf52..bc79c183257bc 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CallChainProfile.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CallChainProfile.cs @@ -226,11 +226,8 @@ private MethodDesc ResolveMethodName(CompilerTypeSystemContext context, string m /// MethodDesc if found, null otherwise private MethodDesc ResolveMethodName(CompilerTypeSystemContext context, ModuleDesc module, string namespaceAndTypeName, string methodName) { - TypeDesc resolvedType = module.GetTypeByCustomAttributeTypeName(namespaceAndTypeName, false, (typeDefName, module, throwIfNotFound) => - { - return (MetadataType)context.GetCanonType(typeDefName) - ?? CustomAttributeTypeNameParser.ResolveCustomAttributeTypeDefinitionName(typeDefName, module, throwIfNotFound); - }); + TypeDesc resolvedType = module.GetTypeByCustomAttributeTypeName(namespaceAndTypeName, false, + (module, typeDefName) => (MetadataType)module.Context.GetCanonType(typeDefName)); if (resolvedType != null) { diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj index 45b684243e8d4..4e5d5b1d1baea 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj @@ -177,6 +177,12 @@ Utilities\CustomAttributeTypeNameParser.cs + + Utilities\TypeNameParser.cs + + + Utilities\ValueStringBuilder.cs + Utilities\GCPointerMap.Algorithm.cs diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs index 2abe0367c42b3..56689af570bf0 100644 --- a/src/coreclr/tools/aot/ILCompiler/Program.cs +++ b/src/coreclr/tools/aot/ILCompiler/Program.cs @@ -630,11 +630,9 @@ private static TypeDesc FindType(CompilerTypeSystemContext context, string typeN { ModuleDesc systemModule = context.SystemModule; - TypeDesc foundType = systemModule.GetTypeByCustomAttributeTypeName(typeName, false, (typeDefName, module, throwIfNotFound) => - { - return (MetadataType)context.GetCanonType(typeDefName) - ?? CustomAttributeTypeNameParser.ResolveCustomAttributeTypeDefinitionName(typeDefName, module, throwIfNotFound); - }); + TypeDesc foundType = systemModule.GetTypeByCustomAttributeTypeName(typeName, false, + (module, typeDefName) => (MetadataType)module.Context.GetCanonType(typeDefName)); + if (foundType == null) throw new CommandLineException($"Type '{typeName}' not found"); diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs index f9f6b8b86317b..b044eea0b4743 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -638,11 +638,9 @@ private TypeDesc FindType(CompilerTypeSystemContext context, string typeName) { ModuleDesc systemModule = context.SystemModule; - TypeDesc foundType = systemModule.GetTypeByCustomAttributeTypeName(typeName, false, (typeDefName, module, throwIfNotFound) => - { - return (MetadataType)context.GetCanonType(typeDefName) - ?? CustomAttributeTypeNameParser.ResolveCustomAttributeTypeDefinitionName(typeDefName, module, throwIfNotFound); - }); + TypeDesc foundType = systemModule.GetTypeByCustomAttributeTypeName(typeName, false, + (module, typeDefName) => (MetadataType)module.Context.GetCanonType(typeDefName)); + if (foundType == null) throw new CommandLineException(string.Format(SR.TypeNotFound, typeName)); diff --git a/src/libraries/Common/src/System/Reflection/TypeNameParser.cs b/src/libraries/Common/src/System/Reflection/TypeNameParser.cs index 3cc111f5fea4c..93a9f30468c42 100644 --- a/src/libraries/Common/src/System/Reflection/TypeNameParser.cs +++ b/src/libraries/Common/src/System/Reflection/TypeNameParser.cs @@ -337,7 +337,7 @@ private TokenType GetNextToken() if (!StartAssemblyName()) return null; - string assemblyName = new string(_input.Slice(_index)); + string assemblyName = _input.Slice(_index).ToString(); _index = _input.Length; return assemblyName; } @@ -542,8 +542,10 @@ public ModifierTypeName(TypeName elementTypeName, int rankOrModifier) _rankOrModifier = rankOrModifier; } +#if NETCOREAPP [UnconditionalSuppressMessage("AotAnalysis", "IL3050:AotUnfriendlyApi", Justification = "Used to implement resolving types from strings.")] +#endif public override Type? ResolveType(ref TypeNameParser parser, string? containingAssemblyIfAny) { Type? elementType = _elementTypeName.ResolveType(ref parser, containingAssemblyIfAny); @@ -576,10 +578,12 @@ public GenericTypeName(TypeName genericTypeDefinition, TypeName[] typeArguments, _typeArgumentsCount = typeArgumentsCount; } +#if NETCOREAPP [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:UnrecognizedReflectionPattern", Justification = "Used to implement resolving types from strings.")] [UnconditionalSuppressMessage("AotAnalysis", "IL3050:AotUnfriendlyApi", Justification = "Used to implement resolving types from strings.")] +#endif public override Type? ResolveType(ref TypeNameParser parser, string? containingAssemblyIfAny) { Type? typeDefinition = _typeDefinition.ResolveType(ref parser, containingAssemblyIfAny); @@ -603,10 +607,17 @@ public GenericTypeName(TypeName genericTypeDefinition, TypeName[] typeArguments, // Type name escaping helpers // +#if NETCOREAPP private static ReadOnlySpan CharsToEscape => "\\[]+*&,"; private static bool NeedsEscapingInTypeName(char c) => CharsToEscape.Contains(c); +#else + private static char[] CharsToEscape { get; } = "\\[]+*&,".ToCharArray(); + + private static bool NeedsEscapingInTypeName(char c) + => Array.IndexOf(CharsToEscape, c) >= 0; +#endif private static string EscapeTypeName(string name) { @@ -640,6 +651,28 @@ private static string EscapeTypeName(string typeName, ReadOnlySpan neste return fullName; } + private static (string typeNamespace, string name) SplitFullTypeName(string typeName) + { + string typeNamespace, name; + + // Matches algorithm from ns::FindSep in src\coreclr\utilcode\namespaceutil.cpp + 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); + } + #if SYSTEM_PRIVATE_CORELIB private void ParseError() {