Make ToString reslient to metadata loading failures
authorDavid Wrighton <davidwr@microsoft.com>
Fri, 20 Sep 2019 19:23:36 +0000 (12:23 -0700)
committerDavid Wrighton <davidwr@microsoft.com>
Fri, 20 Sep 2019 20:24:57 +0000 (13:24 -0700)
- Add a DiagnosticName property to type system constructs that have a Name property that may fail
- Workaround issue where Category cannot be reliably computed, and so instead use switch on type (as that is sufficient for this need)

Commit migrated from https://github.com/dotnet/coreclr/commit/76c8097ddef6b87c0a1e62b05bacc98c6969bacf

21 files changed:
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.ToString.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.ToString.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/TypeDesc.ToString.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/DebugNameFormatter.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/DebugNameFormatter.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/TypeNameFormatter.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj

diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Canon/CanonTypes.Diagnostic.cs
new file mode 100644 (file)
index 0000000..728eea9
--- /dev/null
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+
+using Internal.NativeFormat;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace Internal.TypeSystem
+{
+    internal sealed partial class CanonType
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                return FullName;
+            }
+        }
+    }
+
+    internal sealed partial class UniversalCanonType
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                return FullName;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/ArrayMethod.Diagnostic.cs
new file mode 100644 (file)
index 0000000..4da118c
--- /dev/null
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.TypeSystem
+{
+    public partial class ArrayMethod
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                // The ArrayMethod.Name property is gauranteed to not throw
+                return Name;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/DefType.Diagnostic.cs
new file mode 100644 (file)
index 0000000..c7a10bc
--- /dev/null
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+
+namespace Internal.TypeSystem
+{
+    /// <summary>
+    /// Type with metadata available that is equivalent to a TypeDef record in an ECMA 335 metadata stream.
+    /// A class, an interface, or a value type.
+    /// </summary>
+    abstract partial class DefType
+    {
+        public abstract string DiagnosticName { get; }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/GenericParameterDesc.Diagnostic.cs
new file mode 100644 (file)
index 0000000..0a49801
--- /dev/null
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+
+namespace Internal.TypeSystem
+{
+    public abstract partial class GenericParameterDesc
+    {
+        /// <summary>
+        /// Gets the name of the generic parameter as defined in the metadata.
+        /// </summary>
+        public abstract string DiagnosticName { get; }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedMethod.Diagnostic.cs
new file mode 100644 (file)
index 0000000..c33020e
--- /dev/null
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.TypeSystem
+{
+    public sealed partial class InstantiatedMethod
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                return _methodDef.DiagnosticName;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/InstantiatedType.Diagnostic.cs
new file mode 100644 (file)
index 0000000..342a401
--- /dev/null
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.TypeSystem
+{
+    public sealed partial class InstantiatedType
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                return _typeDef.DiagnosticName;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDelegator.Diagnostic.cs
new file mode 100644 (file)
index 0000000..e4e47f9
--- /dev/null
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.TypeSystem
+{
+    partial class MethodDelegator
+    {
+        public override string DiagnosticName => _wrappedMethod.Name;
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.Diagnostic.cs
new file mode 100644 (file)
index 0000000..5811259
--- /dev/null
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Text;
+
+namespace Internal.TypeSystem
+{
+    partial class MethodDesc
+    {
+        public abstract string DiagnosticName { get; }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.ToString.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodDesc.ToString.Diagnostic.cs
new file mode 100644 (file)
index 0000000..d1bb25d
--- /dev/null
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Text;
+
+namespace Internal.TypeSystem
+{
+    partial class MethodDesc
+    {
+        partial void GetDiagnosticName(ref string diagnosticName)
+        {
+            diagnosticName = DiagnosticName;
+        }
+    }
+}
index 2c87071..3f7c8b3 100644 (file)
@@ -19,7 +19,7 @@ namespace Internal.TypeSystem
 
             if (includeReturnType)
             {
-                DebugNameFormatter.Instance.AppendName(sb, ReturnType, DebugNameFormatter.FormatOptions.None);
+                DebugNameFormatter.Instance.AppendName(sb, ReturnType, DebugNameFormatter.FormatOptions.None | DebugNameFormatter.FormatOptions.UseDiagnosticName);
                 sb.Append('(');
             }
 
@@ -30,7 +30,7 @@ namespace Internal.TypeSystem
                     first = false;
                 else
                     sb.Append(',');
-                DebugNameFormatter.Instance.AppendName(sb, param, DebugNameFormatter.FormatOptions.None);
+                DebugNameFormatter.Instance.AppendName(sb, param, DebugNameFormatter.FormatOptions.None | DebugNameFormatter.FormatOptions.UseDiagnosticName);
             }
 
             if (includeReturnType)
@@ -49,7 +49,18 @@ namespace Internal.TypeSystem
             // (Skipping return type to keep things short)
             sb.Append(OwningType);
             sb.Append('.');
-            sb.Append(Name);
+            try
+            {
+                sb.Append(Name);
+            }
+            catch
+            {
+                string diagName = null;
+                GetDiagnosticName(ref diagName);
+                if (diagName == null)
+                    throw;
+                sb.Append(diagName);
+            }
 
             bool first = true;
             for (int i = 0; i < Instantiation.Length; i++)
@@ -63,16 +74,25 @@ namespace Internal.TypeSystem
                 {
                     sb.Append(',');
                 }
-                DebugNameFormatter.Instance.AppendName(sb, Instantiation[i], DebugNameFormatter.FormatOptions.None);
+                DebugNameFormatter.Instance.AppendName(sb, Instantiation[i], DebugNameFormatter.FormatOptions.None | DebugNameFormatter.FormatOptions.UseDiagnosticName);
             }
             if (!first)
                 sb.Append('>');
 
             sb.Append('(');
-            sb.Append(Signature.ToString(includeReturnType: false));
+            try
+            {
+                sb.Append(Signature.ToString(includeReturnType: false));
+            }
+            catch
+            {
+                sb.Append("Unknown");
+            }
             sb.Append(')');
 
             return sb.ToString();
         }
+
+        partial void GetDiagnosticName(ref string diagnosticName);
     }
 }
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/MethodForInstantiatedType.Diagnostic.cs
new file mode 100644 (file)
index 0000000..e1e18c7
--- /dev/null
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.TypeSystem
+{
+    public sealed partial class MethodForInstantiatedType
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                return _typicalMethodDef.DiagnosticName;
+            }
+        }
+    }
+}
index 34e616f..6fe094a 100644 (file)
@@ -8,7 +8,7 @@ namespace Internal.TypeSystem
     {
         public override string ToString()
         {
-            return DebugNameFormatter.Instance.FormatName(this, DebugNameFormatter.FormatOptions.Default);
+            return DebugNameFormatter.Instance.FormatName(this, DebugNameFormatter.FormatOptions.Default | DebugNameFormatter.FormatOptions.UseDiagnosticName);
         }
     }
 }
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/DebugNameFormatter.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Common/Utilities/DebugNameFormatter.Diagnostic.cs
new file mode 100644 (file)
index 0000000..e362b9d
--- /dev/null
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace Internal.TypeSystem
+{
+    partial class DebugNameFormatter
+    {
+        partial void GetDiagnosticName(GenericParameterDesc type, ref string diagnosticName)
+        {
+            try
+            {
+                diagnosticName = type.DiagnosticName;
+            }
+            catch {}
+        }
+
+        partial void GetDiagnosticName(DefType type, ref string diagnosticName)
+        {
+            try
+            {
+                diagnosticName = type.DiagnosticName;
+            }
+            catch {}
+        }
+    }
+}
index 9a5b5a1..187a97b 100644 (file)
@@ -9,8 +9,11 @@ using Debug = System.Diagnostics.Debug;
 
 namespace Internal.TypeSystem
 {
-    public class DebugNameFormatter : TypeNameFormatter<DebugNameFormatter.Void, DebugNameFormatter.FormatOptions>
+    public partial class DebugNameFormatter : TypeNameFormatter<DebugNameFormatter.Void, DebugNameFormatter.FormatOptions>
     {
+        partial void GetDiagnosticName(GenericParameterDesc type, ref string diagnosticName);
+        partial void GetDiagnosticName(DefType type, ref string diagnosticName);
+
         public static readonly DebugNameFormatter Instance = new DebugNameFormatter();
 
         public override Void AppendName(StringBuilder sb, ArrayType type, FormatOptions options)
@@ -67,7 +70,16 @@ namespace Internal.TypeSystem
 
         public override Void AppendName(StringBuilder sb, GenericParameterDesc type, FormatOptions options)
         {
-            sb.Append(type.Name);
+            try
+            {
+                sb.Append(type.Name);
+            }
+            catch when ((options & FormatOptions.UseDiagnosticName) != 0)
+            {
+                string diagnosticName = "Unknown";
+                GetDiagnosticName(type, ref diagnosticName);
+                sb.Append(diagnosticName);
+            }
 
             return Void.Value;
         }
@@ -96,75 +108,116 @@ namespace Internal.TypeSystem
                 sb.Append('+');
             }
 
-            sb.Append(nestedType.Name);
+            try
+            {
+                sb.Append(nestedType.Name);
+            }
+            catch when ((options & FormatOptions.UseDiagnosticName) != 0)
+            {
+                string diagnosticName = "Unknown";
+                GetDiagnosticName(nestedType, ref diagnosticName);
+                sb.Append(diagnosticName);
+            }
 
             return Void.Value;
         }
 
         protected override Void AppendNameForNamespaceType(StringBuilder sb, DefType type, FormatOptions options)
         {
-            // Shortcut some of the well known types
-            switch (type.Category)
+            int initialLen = sb.Length;
+            try
             {
-                case TypeFlags.Void:
-                    sb.Append("void");
-                    return Void.Value;
-                case TypeFlags.Boolean:
-                    sb.Append("bool");
-                    return Void.Value;
-                case TypeFlags.Char:
-                    sb.Append("char");
-                    return Void.Value;
-                case TypeFlags.SByte:
-                    sb.Append("int8");
-                    return Void.Value;
-                case TypeFlags.Byte:
-                    sb.Append("uint8");
-                    return Void.Value;
-                case TypeFlags.Int16:
-                    sb.Append("int16");
-                    return Void.Value;
-                case TypeFlags.UInt16:
-                    sb.Append("uint16");
-                    return Void.Value;
-                case TypeFlags.Int32:
-                    sb.Append("int32");
-                    return Void.Value;
-                case TypeFlags.UInt32:
-                    sb.Append("uint32");
-                    return Void.Value;
-                case TypeFlags.Int64:
-                    sb.Append("int64");
-                    return Void.Value;
-                case TypeFlags.UInt64:
-                    sb.Append("uint64");
-                    return Void.Value;
-                case TypeFlags.IntPtr:
-                    sb.Append("native int");
-                    return Void.Value;
-                case TypeFlags.UIntPtr:
-                    sb.Append("native uint");
-                    return Void.Value;
-                case TypeFlags.Single:
-                    sb.Append("float32");
+                // Shortcut some of the well known types
+                switch (type.Category)
+                {
+                    case TypeFlags.Void:
+                        sb.Append("void");
+                        return Void.Value;
+                    case TypeFlags.Boolean:
+                        sb.Append("bool");
+                        return Void.Value;
+                    case TypeFlags.Char:
+                        sb.Append("char");
+                        return Void.Value;
+                    case TypeFlags.SByte:
+                        sb.Append("int8");
+                        return Void.Value;
+                    case TypeFlags.Byte:
+                        sb.Append("uint8");
+                        return Void.Value;
+                    case TypeFlags.Int16:
+                        sb.Append("int16");
+                        return Void.Value;
+                    case TypeFlags.UInt16:
+                        sb.Append("uint16");
+                        return Void.Value;
+                    case TypeFlags.Int32:
+                        sb.Append("int32");
+                        return Void.Value;
+                    case TypeFlags.UInt32:
+                        sb.Append("uint32");
+                        return Void.Value;
+                    case TypeFlags.Int64:
+                        sb.Append("int64");
+                        return Void.Value;
+                    case TypeFlags.UInt64:
+                        sb.Append("uint64");
+                        return Void.Value;
+                    case TypeFlags.IntPtr:
+                        sb.Append("native int");
+                        return Void.Value;
+                    case TypeFlags.UIntPtr:
+                        sb.Append("native uint");
+                        return Void.Value;
+                    case TypeFlags.Single:
+                        sb.Append("float32");
+                        return Void.Value;
+                    case TypeFlags.Double:
+                        sb.Append("float64");
+                        return Void.Value;
+                }
+
+                if (type.IsString)
+                {
+                    sb.Append("string");
                     return Void.Value;
-                case TypeFlags.Double:
-                    sb.Append("float64");
+                }
+
+                if (type.IsObject)
+                {
+                    sb.Append("object");
                     return Void.Value;
-            }
+                }
 
-            if (type.IsString)
-            {
-                sb.Append("string");
-                return Void.Value;
-            }
+                AssemblyQualify(sb, type, options);
+
+                if ((options & FormatOptions.NamespaceQualify) != 0)
+                {
+                    string ns = type.Namespace;
+                    if (!string.IsNullOrEmpty(ns))
+                    {
+                        sb.Append(ns);
+                        sb.Append('.');
+                    }
+                }
 
-            if (type.IsObject)
+                sb.Append(type.Name);
+            }
+            catch when ((options & FormatOptions.UseDiagnosticName) != 0)
             {
-                sb.Append("object");
-                return Void.Value;
+                sb.Length = initialLen;
+
+                string diagnosticName = "Unknown";
+                AssemblyQualify(sb, type, options);
+                GetDiagnosticName(type, ref diagnosticName);
+                sb.Append(diagnosticName);
             }
 
+            return Void.Value;
+        }
+
+        private void AssemblyQualify(StringBuilder sb, DefType type, FormatOptions options)
+        {
             if (((options & FormatOptions.AssemblyQualify) != 0)
                 && type is MetadataType mdType
                 && mdType.Module is IAssemblyDesc)
@@ -172,27 +225,22 @@ namespace Internal.TypeSystem
                 sb.Append('[');
 
                 // Trim the "System.Private." prefix
-                string assemblyName = ((IAssemblyDesc)mdType.Module).GetName().Name;
+                string assemblyName;
+                try
+                {
+                    assemblyName = ((IAssemblyDesc)mdType.Module).GetName().Name;
+                }
+                catch when ((options & FormatOptions.UseDiagnosticName) != 0)
+                {
+                    assemblyName = "Unknown";
+                }
+
                 if (assemblyName.StartsWith("System.Private", StringComparison.Ordinal))
                     assemblyName = "S.P" + assemblyName.Substring(14);
 
                 sb.Append(assemblyName);
                 sb.Append(']');
             }
-
-            if ((options & FormatOptions.NamespaceQualify) != 0)
-            {
-                string ns = type.Namespace;
-                if (!string.IsNullOrEmpty(ns))
-                {
-                    sb.Append(ns);
-                    sb.Append('.');
-                }
-            }
-
-            sb.Append(type.Name);
-
-            return Void.Value;
         }
 
         protected override Void AppendNameForInstantiatedType(StringBuilder sb, DefType type, FormatOptions options)
@@ -216,6 +264,18 @@ namespace Internal.TypeSystem
             return Void.Value;
         }
 
+        protected override DefType GetContainingType(DefType possibleInnerType, FormatOptions options)
+        {
+            try
+            {
+                return possibleInnerType.ContainingType;
+            }
+            catch when ((options & FormatOptions.UseDiagnosticName) != 0)
+            {
+                return null;
+            }
+        }
+
         public struct Void
         {
             public static Void Value => default(Void);
@@ -227,6 +287,7 @@ namespace Internal.TypeSystem
             None = 0,
             AssemblyQualify = 0x1,
             NamespaceQualify = 0x2,
+            UseDiagnosticName = 0x4,
 
             Default = AssemblyQualify | NamespaceQualify,
         }
index 4653331..19b45fe 100644 (file)
@@ -87,7 +87,29 @@ namespace Internal.TypeSystem
     {
         public TState AppendName(StringBuilder sb, TypeDesc type, TOptions options)
         {
-            switch (type.Category)
+            TypeFlags category;
+            bool normalCategoryComputation = false;
+            try
+            {
+                category = type.Category;
+                normalCategoryComputation = true;
+            }
+            catch
+            {
+                category = type switch
+                {
+                    ArrayType t => TypeFlags.Array, // This will get us into the path that works with an ArrayType below
+                    ByRefType t => TypeFlags.ByRef,
+                    PointerType t => TypeFlags.Pointer,
+                    FunctionPointerType t => TypeFlags.FunctionPointer,
+                    GenericParameterDesc t => TypeFlags.GenericParameter,
+                    SignatureTypeVariable t => TypeFlags.SignatureTypeVariable,
+                    SignatureMethodVariable t => TypeFlags.SignatureMethodVariable,
+                    _ => TypeFlags.Class, // This will get us into the DefType path below
+                };
+            }
+
+            switch (category)
             {
                 case TypeFlags.Array:
                 case TypeFlags.SzArray:
@@ -105,7 +127,7 @@ namespace Internal.TypeSystem
                 case TypeFlags.SignatureMethodVariable:
                     return AppendName(sb, (SignatureMethodVariable)type, options);
                 default:
-                    Debug.Assert(type.IsDefType);
+                    Debug.Assert(normalCategoryComputation && type.IsDefType); // Don't call type.IsDefType if Category computation failed
                     return AppendName(sb, (DefType)type, options);
             }
         }
@@ -118,7 +140,8 @@ namespace Internal.TypeSystem
             }
             else
             {
-                DefType containingType = type.ContainingType;
+                DefType containingType = GetContainingType(type, options);
+
                 if (containingType != null)
                     return AppendNameForNestedType(sb, type, containingType, options);
                 else
@@ -138,6 +161,11 @@ namespace Internal.TypeSystem
         protected abstract TState AppendNameForNamespaceType(StringBuilder sb, DefType type, TOptions options);
         protected abstract TState AppendNameForInstantiatedType(StringBuilder sb, DefType type, TOptions options);
 
+        protected virtual DefType GetContainingType(DefType possibleInnerType, TOptions options)
+        {
+            return possibleInnerType.ContainingType;
+        }
+
         public string FormatName(TypeDesc type, TOptions options)
         {
             StringBuilder sb = new StringBuilder();
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaGenericParameter.Diagnostic.cs
new file mode 100644 (file)
index 0000000..aeddc44
--- /dev/null
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection.Metadata.Ecma335;
+
+namespace Internal.TypeSystem.Ecma
+{
+    public sealed partial class EcmaGenericParameter
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                return $"GenericParam({MetadataReader.GetToken(Handle):x8})";
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaMethod.Diagnostic.cs
new file mode 100644 (file)
index 0000000..b0db281
--- /dev/null
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection.Metadata.Ecma335;
+
+namespace Internal.TypeSystem.Ecma
+{
+    public sealed partial class EcmaMethod
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                return $"MethodDef({MetadataReader.GetToken(Handle):x8})";
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.Diagnostic.cs
new file mode 100644 (file)
index 0000000..635bb6e
--- /dev/null
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+using System.Threading;
+using Debug = System.Diagnostics.Debug;
+
+using Internal.NativeFormat;
+
+namespace Internal.TypeSystem.Ecma
+{
+    /// <summary>
+    /// Override of MetadataType that uses actual Ecma335 metadata.
+    /// </summary>
+    public sealed partial class EcmaType
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                if (_typeName == null)
+                    return InitializeName();
+                return _typeName;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/MethodForRuntimeDeterminedType.Diagnostic.cs
new file mode 100644 (file)
index 0000000..3aa3b44
--- /dev/null
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.TypeSystem
+{
+    partial class MethodForRuntimeDeterminedType
+    {
+        public override string DiagnosticName => _typicalMethodDef.DiagnosticName;
+    }
+}
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.Diagnostic.cs
new file mode 100644 (file)
index 0000000..e4df8ce
--- /dev/null
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.TypeSystem
+{
+    partial class RuntimeDeterminedType
+    {
+        public override string DiagnosticName
+        {
+            get
+            {
+                return _rawCanonType.DiagnosticName;
+            }
+        }
+    }
+}
index 2d3d69c..c6cd57e 100644 (file)
@@ -24,6 +24,9 @@
     </PackageReference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Common\TypeSystem\Common\ArrayMethod.Diagnostic.cs">
+      <Link>TypeSystem\Common\ArrayMethod.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Canon\ArrayType.Canon.cs">
       <Link>TypeSystem\Canon\ArrayType.Canon.cs</Link>
     </Compile>
@@ -33,6 +36,9 @@
     <Compile Include="..\Common\TypeSystem\Canon\CanonTypes.cs">
       <Link>TypeSystem\Canon\CanonTypes.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Canon\CanonTypes.Diagnostic.cs">
+      <Link>TypeSystem\Canon\CanonTypes.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Canon\CanonTypes.Interop.cs">
       <Link>TypeSystem\Canon\CanonTypes.Interop.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Common\Utilities\DebugNameFormatter.cs">
       <Link>Utilities\DebugNameFormatter.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\Utilities\DebugNameFormatter.Diagnostic.cs">
+      <Link>Utilities\DebugNameFormatter.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\Utilities\LockFreeReaderHashtable.cs">
       <Link>Utilities\LockFreeReaderHashtable.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Common\GenericParameterDesc.cs">
       <Link>TypeSystem\Common\GenericParameterDesc.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\GenericParameterDesc.Diagnostic.cs">
+      <Link>TypeSystem\Common\GenericParameterDesc.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\ExceptionStringID.cs">
       <Link>TypeSystem\Common\ExceptionStringID.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Common\InstantiatedMethod.cs">
       <Link>TypeSystem\Common\InstantiatedMethod.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\InstantiatedMethod.Diagnostic.cs">
+      <Link>TypeSystem\Common\InstantiatedMethod.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\InstantiatedType.cs">
       <Link>TypeSystem\Common\InstantiatedType.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\InstantiatedType.Diagnostic.cs">
+      <Link>TypeSystem\Common\InstantiatedType.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\InstantiatedType.Interfaces.cs">
       <Link>TypeSystem\Common\InstantiatedType.Interfaces.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Common\MetadataType.cs">
       <Link>TypeSystem\Common\MetadataType.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\DefType.Diagnostic.cs">
+      <Link>TypeSystem\Common\DefType.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\MetadataType.Interfaces.cs">
       <Link>TypeSystem\Common\MetadataType.Interfaces.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Common\MethodForInstantiatedType.cs">
       <Link>TypeSystem\Common\MethodForInstantiatedType.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\MethodForInstantiatedType.Diagnostic.cs">
+      <Link>TypeSystem\Common\MethodForInstantiatedType.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\ParameterizedType.cs">
       <Link>TypeSystem\Common\ParameterizedType.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Common\MethodDelegator.cs">
       <Link>TypeSystem\Common\MethodDelegator.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\MethodDelegator.Diagnostic.cs">
+      <Link>TypeSystem\Common\MethodDelegator.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\MethodDesc.cs">
       <Link>TypeSystem\Common\MethodDesc.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\MethodDesc.Diagnostic.cs">
+      <Link>TypeSystem\Common\MethodDesc.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\MethodDesc.ToString.cs">
       <Link>TypeSystem\Common\MethodDesc.ToString.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Common\MethodDesc.ToString.Diagnostic.cs">
+      <Link>TypeSystem\Common\MethodDesc.ToString.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Common\MetadataVirtualMethodAlgorithm.cs">
       <Link>TypeSystem\Common\StandardVirtualMethodAlgorithm.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Ecma\EcmaGenericParameter.cs">
       <Link>Ecma\EcmaGenericParameter.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Ecma\EcmaGenericParameter.Diagnostic.cs">
+      <Link>Ecma\EcmaGenericParameter.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Ecma\EcmaMethod.cs">
       <Link>Ecma\EcmaMethod.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Ecma\EcmaMethod.Diagnostic.cs">
+      <Link>Ecma\EcmaMethod.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Ecma\EcmaModule.cs">
       <Link>Ecma\EcmaModule.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Ecma\EcmaType.cs">
       <Link>Ecma\EcmaType.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Ecma\EcmaType.Diagnostic.cs">
+      <Link>Ecma\EcmaType.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Ecma\EcmaType.MethodImpls.cs">
       <Link>Ecma\EcmaType.MethodImpls.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.cs">
       <Link>TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.Diagnostic.cs">
+      <Link>TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.Sorting.cs">
       <Link>TypeSystem\RuntimeDetermined\MethodForRuntimeDeterminedType.Sorting.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\RuntimeDetermined\RuntimeDeterminedType.cs">
       <Link>TypeSystem\RuntimeDetermined\RuntimeDeterminedType.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\RuntimeDetermined\RuntimeDeterminedType.Diagnostic.cs">
+      <Link>TypeSystem\RuntimeDetermined\RuntimeDeterminedType.Diagnostic.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\RuntimeDetermined\RuntimeDeterminedType.Sorting.cs">
       <Link>TypeSystem\RuntimeDetermined\RuntimeDeterminedType.Sorting.cs</Link>
     </Compile>