| #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member | 
|   | 
| using System; | 
| using System.Collections.Generic; | 
| using System.Diagnostics; | 
| using System.Globalization; | 
| using System.IO; | 
| using System.Linq; | 
| using System.Reflection; | 
| using System.Runtime.CompilerServices; | 
| using System.Security; | 
| using System.Text; | 
| using System.Text.RegularExpressions; | 
| using System.Threading.Tasks; | 
| using UnityEngine; | 
|   | 
| namespace Cysharp.Threading.Tasks.Internal | 
| { | 
|     internal static class DiagnosticsExtensions | 
|     { | 
|         static bool displayFilenames = true; | 
|   | 
|         static readonly Regex typeBeautifyRegex = new Regex("`.+$", RegexOptions.Compiled); | 
|   | 
|         static readonly Dictionary<Type, string> builtInTypeNames = new Dictionary<Type, string> | 
|         { | 
|             { typeof(void), "void" }, | 
|             { typeof(bool), "bool" }, | 
|             { typeof(byte), "byte" }, | 
|             { typeof(char), "char" }, | 
|             { typeof(decimal), "decimal" }, | 
|             { typeof(double), "double" }, | 
|             { typeof(float), "float" }, | 
|             { typeof(int), "int" }, | 
|             { typeof(long), "long" }, | 
|             { typeof(object), "object" }, | 
|             { typeof(sbyte), "sbyte" }, | 
|             { typeof(short), "short" }, | 
|             { typeof(string), "string" }, | 
|             { typeof(uint), "uint" }, | 
|             { typeof(ulong), "ulong" }, | 
|             { typeof(ushort), "ushort" }, | 
|             { typeof(Task), "Task" }, | 
|             { typeof(UniTask), "UniTask" }, | 
|             { typeof(UniTaskVoid), "UniTaskVoid" } | 
|         }; | 
|   | 
|         public static string CleanupAsyncStackTrace(this StackTrace stackTrace) | 
|         { | 
|             if (stackTrace == null) return ""; | 
|   | 
|             var sb = new StringBuilder(); | 
|             for (int i = 0; i < stackTrace.FrameCount; i++) | 
|             { | 
|                 var sf = stackTrace.GetFrame(i); | 
|   | 
|                 var mb = sf.GetMethod(); | 
|   | 
|                 if (IgnoreLine(mb)) continue; | 
|                 if (IsAsync(mb)) | 
|                 { | 
|                     sb.Append("async "); | 
|                     TryResolveStateMachineMethod(ref mb, out var decType); | 
|                 } | 
|   | 
|                 // return type | 
|                 if (mb is MethodInfo mi) | 
|                 { | 
|                     sb.Append(BeautifyType(mi.ReturnType, false)); | 
|                     sb.Append(" "); | 
|                 } | 
|   | 
|                 // method name | 
|                 sb.Append(BeautifyType(mb.DeclaringType, false)); | 
|                 if (!mb.IsConstructor) | 
|                 { | 
|                     sb.Append("."); | 
|                 } | 
|                 sb.Append(mb.Name); | 
|                 if (mb.IsGenericMethod) | 
|                 { | 
|                     sb.Append("<"); | 
|                     foreach (var item in mb.GetGenericArguments()) | 
|                     { | 
|                         sb.Append(BeautifyType(item, true)); | 
|                     } | 
|                     sb.Append(">"); | 
|                 } | 
|   | 
|                 // parameter | 
|                 sb.Append("("); | 
|                 sb.Append(string.Join(", ", mb.GetParameters().Select(p => BeautifyType(p.ParameterType, true) + " " + p.Name))); | 
|                 sb.Append(")"); | 
|   | 
|                 // file name | 
|                 if (displayFilenames && (sf.GetILOffset() != -1)) | 
|                 { | 
|                     String fileName = null; | 
|   | 
|                     try | 
|                     { | 
|                         fileName = sf.GetFileName(); | 
|                     } | 
|                     catch (NotSupportedException) | 
|                     { | 
|                         displayFilenames = false; | 
|                     } | 
|                     catch (SecurityException) | 
|                     { | 
|                         displayFilenames = false; | 
|                     } | 
|   | 
|                     if (fileName != null) | 
|                     { | 
|                         sb.Append(' '); | 
|                         sb.AppendFormat(CultureInfo.InvariantCulture, "(at {0})", AppendHyperLink(fileName, sf.GetFileLineNumber().ToString())); | 
|                     } | 
|                 } | 
|   | 
|                 sb.AppendLine(); | 
|             } | 
|             return sb.ToString(); | 
|         } | 
|   | 
|   | 
|         static bool IsAsync(MethodBase methodInfo) | 
|         { | 
|             var declareType = methodInfo.DeclaringType; | 
|             return typeof(IAsyncStateMachine).IsAssignableFrom(declareType); | 
|         } | 
|   | 
|         // code from Ben.Demystifier/EnhancedStackTrace.Frame.cs | 
|         static bool TryResolveStateMachineMethod(ref MethodBase method, out Type declaringType) | 
|         { | 
|             declaringType = method.DeclaringType; | 
|   | 
|             var parentType = declaringType.DeclaringType; | 
|             if (parentType == null) | 
|             { | 
|                 return false; | 
|             } | 
|   | 
|             var methods = parentType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); | 
|             if (methods == null) | 
|             { | 
|                 return false; | 
|             } | 
|   | 
|             foreach (var candidateMethod in methods) | 
|             { | 
|                 var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>(false); | 
|                 if (attributes == null) | 
|                 { | 
|                     continue; | 
|                 } | 
|   | 
|                 foreach (var asma in attributes) | 
|                 { | 
|                     if (asma.StateMachineType == declaringType) | 
|                     { | 
|                         method = candidateMethod; | 
|                         declaringType = candidateMethod.DeclaringType; | 
|                         // Mark the iterator as changed; so it gets the + annotation of the original method | 
|                         // async statemachines resolve directly to their builder methods so aren't marked as changed | 
|                         return asma is IteratorStateMachineAttribute; | 
|                     } | 
|                 } | 
|             } | 
|   | 
|             return false; | 
|         } | 
|   | 
|         static string BeautifyType(Type t, bool shortName) | 
|         { | 
|             if (builtInTypeNames.TryGetValue(t, out var builtin)) | 
|             { | 
|                 return builtin; | 
|             } | 
|             if (t.IsGenericParameter) return t.Name; | 
|             if (t.IsArray) return BeautifyType(t.GetElementType(), shortName) + "[]"; | 
|             if (t.FullName?.StartsWith("System.ValueTuple") ?? false) | 
|             { | 
|                 return "(" + string.Join(", ", t.GetGenericArguments().Select(x => BeautifyType(x, true))) + ")"; | 
|             } | 
|             if (!t.IsGenericType) return shortName ? t.Name : t.FullName.Replace("Cysharp.Threading.Tasks.Triggers.", "").Replace("Cysharp.Threading.Tasks.Internal.", "").Replace("Cysharp.Threading.Tasks.", "") ?? t.Name; | 
|   | 
|             var innerFormat = string.Join(", ", t.GetGenericArguments().Select(x => BeautifyType(x, true))); | 
|   | 
|             var genericType = t.GetGenericTypeDefinition().FullName; | 
|             if (genericType == "System.Threading.Tasks.Task`1") | 
|             { | 
|                 genericType = "Task"; | 
|             } | 
|   | 
|             return typeBeautifyRegex.Replace(genericType, "").Replace("Cysharp.Threading.Tasks.Triggers.", "").Replace("Cysharp.Threading.Tasks.Internal.", "").Replace("Cysharp.Threading.Tasks.", "") + "<" + innerFormat + ">"; | 
|         } | 
|   | 
|         static bool IgnoreLine(MethodBase methodInfo) | 
|         { | 
|             var declareType = methodInfo.DeclaringType.FullName; | 
|             if (declareType == "System.Threading.ExecutionContext") | 
|             { | 
|                 return true; | 
|             } | 
|             else if (declareType.StartsWith("System.Runtime.CompilerServices")) | 
|             { | 
|                 return true; | 
|             } | 
|             else if (declareType.StartsWith("Cysharp.Threading.Tasks.CompilerServices")) | 
|             { | 
|                 return true; | 
|             } | 
|             else if (declareType == "System.Threading.Tasks.AwaitTaskContinuation") | 
|             { | 
|                 return true; | 
|             } | 
|             else if (declareType.StartsWith("System.Threading.Tasks.Task")) | 
|             { | 
|                 return true; | 
|             } | 
|             else if (declareType.StartsWith("Cysharp.Threading.Tasks.UniTaskCompletionSourceCore")) | 
|             { | 
|                 return true; | 
|             } | 
|             else if (declareType.StartsWith("Cysharp.Threading.Tasks.AwaiterActions")) | 
|             { | 
|                 return true; | 
|             } | 
|   | 
|             return false; | 
|         } | 
|   | 
|         static string AppendHyperLink(string path, string line) | 
|         { | 
|             var fi = new FileInfo(path); | 
|             if (fi.Directory == null) | 
|             { | 
|                 return fi.Name; | 
|             } | 
|             else | 
|             { | 
|                 var fname = fi.FullName.Replace(Path.DirectorySeparatorChar, '/').Replace(PlayerLoopHelper.ApplicationDataPath, ""); | 
|                 var withAssetsPath = "Assets/" + fname; | 
|                 return "<a href=\"" + withAssetsPath + "\" line=\"" + line + "\">" + withAssetsPath + ":" + line + "</a>"; | 
|             } | 
|         } | 
|     } | 
| } |