Switch CustomAttributeTypeNameParser to use common type name parser (#84281)
authorJan Kotas <jkotas@microsoft.com>
Wed, 5 Apr 2023 17:36:38 +0000 (10:36 -0700)
committerGitHub <noreply@github.com>
Wed, 5 Apr 2023 17:36:38 +0000 (10:36 -0700)
src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs
src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs
src/coreclr/tools/ILVerification/ILVerification.projitems
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs [moved from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeNameParser.cs with 84% similarity]
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CallChainProfile.cs
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj
src/coreclr/tools/aot/ILCompiler/Program.cs
src/coreclr/tools/aot/crossgen2/Program.cs
src/libraries/Common/src/System/Reflection/TypeNameParser.cs

index 4776a1a..2af4bb7 100644 (file)
@@ -13,7 +13,7 @@ using System.Threading;
 
 namespace System.Reflection
 {
-    internal unsafe ref partial struct TypeNameParser
+    internal partial struct TypeNameParser
     {
         private Func<AssemblyName, Assembly?>? _assemblyResolver;
         private Func<Assembly?, string, bool, Type?>? _typeResolver;
index ea3c7f8..e370cb4 100644 (file)
@@ -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<AssemblyName, Assembly?>? _assemblyResolver;
         private Func<Assembly?, string, bool, Type?>? _typeResolver;
index 8089f65..42744c7 100644 (file)
@@ -5,15 +5,10 @@ using System;
 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
     {
         /// <summary>
@@ -21,441 +16,107 @@ namespace Internal.TypeSystem
         /// The type name string should be in the 'SerString' format as defined by the ECMA-335 standard.
         /// This is the inverse of what <see cref="CustomAttributeTypeNameFormatter"/> does.
         /// </summary>
-        public static TypeDesc GetTypeByCustomAttributeTypeName(this ModuleDesc module, string name, bool throwIfNotFound = true, Func<string, ModuleDesc, bool, MetadataType> resolver = null)
+        public static TypeDesc GetTypeByCustomAttributeTypeName(this ModuleDesc module, string name, bool throwIfNotFound = true,
+            Func<ModuleDesc, string, MetadataType> 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<TypeDesc> genericArgs = default(ArrayBuilder<TypeDesc>);
-
-            // 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<ModuleDesc, string, MetadataType> _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<ModuleDesc, string, MetadataType> 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<string> nestedTypeNames, string assemblyNameIfAny)
         {
-            return new StringIterator(s, s.Length);
-        }
-
-        private struct StringIterator : IEquatable<StringIterator>
-        {
-            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<string> 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
     }
 }
index 55b8d20..61a4a8c 100644 (file)
     <Compile Include="$(ToolsCommonPath)TypeSystem\Common\Utilities\CustomAttributeTypeNameParser.cs">
       <Link>Utilities\CustomAttributeTypeNameParser.cs</Link>
     </Compile>
+    <Compile Include="$(LibrariesProjectRoot)\Common\src\System\Reflection\TypeNameParser.cs">
+      <Link>Utilities\TypeNameParser.cs</Link>
+    </Compile>
+    <Compile Include="$(LibrariesProjectRoot)\Common\src\System\Text\ValueStringBuilder.cs">
+      <Link>Utilities\ValueStringBuilder.cs</Link>
+    </Compile>
     <Compile Include="$(ToolsCommonPath)TypeSystem\Common\Utilities\LockFreeReaderHashtable.cs">
       <Link>Utilities\LockFreeReaderHashtable.cs</Link>
     </Compile>
@@ -10,7 +10,7 @@ using Internal.TypeSystem;
 
 namespace System.Reflection
 {
-    internal unsafe ref partial struct TypeNameParser
+    internal partial struct TypeNameParser
     {
         private TypeSystemContext _context;
         private ModuleDesc _callingModule;
@@ -20,7 +20,7 @@ namespace System.Reflection
         public static TypeDesc ResolveType(string name, ModuleDesc callingModule,
             TypeSystemContext context, List<ModuleDesc> referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary)
         {
-            var parser = new System.Reflection.TypeNameParser(name)
+            var parser = new TypeNameParser(name)
             {
                 _context = context,
                 _callingModule = callingModule,
@@ -68,11 +68,9 @@ namespace System.Reflection
                 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 @@ namespace System.Reflection
             // 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 @@ namespace System.Reflection
 
         private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan<string> 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)
index 4578500..a183412 100644 (file)
   </ItemGroup>
 
   <ItemGroup>
-    <Compile Include="..\..\..\..\libraries\Common\src\System\Reflection\TypeNameParser.cs">
-      <Link>TypeNameParser.cs</Link>
-    </Compile>
-    <Compile Include="..\..\..\..\libraries\Common\src\System\Text\ValueStringBuilder.cs">
-      <Link>ValueStringBuilder.cs</Link>
-    </Compile>
     <Compile Include="..\..\Common\TypeSystem\IL\DelegateInfo.cs">
       <Link>IL\DelegateInfo.cs</Link>
     </Compile>
     <Compile Include="Compiler\Dataflow\TrimAnalysisMethodCallPattern.cs" />
     <Compile Include="Compiler\Dataflow\TrimAnalysisPatternStore.cs" />
     <Compile Include="Compiler\Dataflow\TrimAnalysisReflectionAccessPattern.cs" />
+    <Compile Include="Compiler\Dataflow\TypeNameParser.Dataflow.cs" />
+    <Compile Include="$(LibrariesProjectRoot)\Common\src\System\Reflection\TypeNameParser.cs">
+      <Link>Compiler\Dataflow\TypeNameParser.cs</Link>
+    </Compile>
+    <Compile Include="$(LibrariesProjectRoot)\Common\src\System\Text\ValueStringBuilder.cs">
+      <Link>Utilities\ValueStringBuilder.cs</Link>
+    </Compile>
     <Compile Include="Compiler\Dataflow\ValueNode.cs" />
     <Compile Include="Compiler\DebugInformationProvider.cs" />
     <Compile Include="Compiler\DependencyAnalysis\CustomAttributeMetadataNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\TentativeInstanceMethodNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\TentativeMethodNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\TrimmingDescriptorNode.cs" />
-    <Compile Include="Compiler\DependencyAnalysis\TypeNameParser.cs" />
     <Compile Include="Compiler\DependencyAnalysis\VariantInterfaceMethodUseNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\CustomAttributeBasedDependencyAlgorithm.cs" />
     <Compile Include="Compiler\DependencyAnalysis\FieldMetadataNode.cs" />
index b8f05a9..bc79c18 100644 (file)
@@ -226,11 +226,8 @@ namespace ILCompiler
         /// <returns>MethodDesc if found, null otherwise</returns>
         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)
             {
index 45b6842..4e5d5b1 100644 (file)
     <Compile Include="..\..\Common\TypeSystem\Common\Utilities\CustomAttributeTypeNameParser.cs">
       <Link>Utilities\CustomAttributeTypeNameParser.cs</Link>
     </Compile>
+    <Compile Include="$(LibrariesProjectRoot)\Common\src\System\Reflection\TypeNameParser.cs">
+      <Link>Utilities\TypeNameParser.cs</Link>
+    </Compile>
+    <Compile Include="$(LibrariesProjectRoot)\Common\src\System\Text\ValueStringBuilder.cs">
+      <Link>Utilities\ValueStringBuilder.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\Utilities\GCPointerMap.Algorithm.cs">
       <Link>Utilities\GCPointerMap.Algorithm.cs</Link>
     </Compile>
index 2abe036..56689af 100644 (file)
@@ -630,11 +630,9 @@ namespace ILCompiler
         {
             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");
 
index f9f6b8b..b044eea 100644 (file)
@@ -638,11 +638,9 @@ namespace ILCompiler
         {
             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));
 
index 3cc111f..93a9f30 100644 (file)
@@ -337,7 +337,7 @@ namespace System.Reflection
             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 @@ namespace System.Reflection
                 _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 @@ namespace System.Reflection
                 _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 @@ namespace System.Reflection
         // Type name escaping helpers
         //
 
+#if NETCOREAPP
         private static ReadOnlySpan<char> 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 @@ namespace System.Reflection
             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()
         {