From 82804300a7969f7f8f4e20c60153eac09ddb41b3 Mon Sep 17 00:00:00 2001
From: ElektroKill <elektrokilldev@protonmail.com>
Date: Wed, 27 Sep 2023 21:31:27 +0200
Subject: [PATCH] Provide custom type info for return values in Mono debugger

---
 .../Evaluation/DbgMonoDebugInternalRuntimeImpl.cs | 15 +++++++++++++--
 .../Evaluation/Engine/DbgEngineLanguageImpl.cs    |  3 ++-
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Impl/Evaluation/DbgMonoDebugInternalRuntimeImpl.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Impl/Evaluation/DbgMonoDebugInternalRuntimeImpl.cs
index ddfb8941d7..69b9e6e557 100644
--- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Impl/Evaluation/DbgMonoDebugInternalRuntimeImpl.cs
+++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet.Mono/Impl/Evaluation/DbgMonoDebugInternalRuntimeImpl.cs
@@ -27,6 +27,7 @@ You should have received a copy of the GNU General Public License
 using dnSpy.Contracts.Debugger.CallStack;
 using dnSpy.Contracts.Debugger.DotNet.Disassembly;
 using dnSpy.Contracts.Debugger.DotNet.Evaluation;
+using dnSpy.Contracts.Debugger.DotNet.Evaluation.ExpressionCompiler;
 using dnSpy.Contracts.Debugger.DotNet.Mono;
 using dnSpy.Contracts.Debugger.Engine.Evaluation;
 using dnSpy.Contracts.Debugger.Evaluation;
@@ -626,6 +627,7 @@ DbgDotNetAliasInfo[] GetAliasesCore(DbgEvaluationInfo evalInfo) {
 				exception = GetExceptionCore(evalInfo, DbgDotNetRuntimeConstants.ExceptionId);
 				stowedException = GetStowedExceptionCore(evalInfo, DbgDotNetRuntimeConstants.StowedExceptionId);
 				returnValues = GetReturnValuesCore(evalInfo);
+				evalInfo.Context.TryGetData(out DbgDotNetExpressionCompiler? expressionCompiler);
 
 				int count = (exception is not null ? 1 : 0) + (stowedException is not null ? 1 : 0) + returnValues.Length + (returnValues.Length != 0 ? 1 : 0);
 				if (count == 0)
@@ -638,10 +640,19 @@ DbgDotNetAliasInfo[] GetAliasesCore(DbgEvaluationInfo evalInfo) {
 				if (stowedException is not null)
 					res[w++] = new DbgDotNetAliasInfo(DbgDotNetAliasInfoKind.StowedException, stowedException.Type, DbgDotNetRuntimeConstants.StowedExceptionId, null);
 				if (returnValues.Length != 0) {
-					res[w++] = new DbgDotNetAliasInfo(DbgDotNetAliasInfoKind.ReturnValue, returnValues[returnValues.Length - 1].Value.Type, DbgDotNetRuntimeConstants.LastReturnValueId, null);
+					var lastReturnVal = returnValues[returnValues.Length - 1];
+					res[w++] = new DbgDotNetAliasInfo(DbgDotNetAliasInfoKind.ReturnValue, lastReturnVal.Value.Type, DbgDotNetRuntimeConstants.LastReturnValueId, CreateCustomTypeInfo(lastReturnVal));
+
 					foreach (var returnValue in returnValues) {
 						Debug.Assert(returnValue.Id != DbgDotNetRuntimeConstants.LastReturnValueId);
-						res[w++] = new DbgDotNetAliasInfo(DbgDotNetAliasInfoKind.ReturnValue, returnValue.Value.Type, returnValue.Id, null);
+						res[w++] = new DbgDotNetAliasInfo(DbgDotNetAliasInfoKind.ReturnValue, returnValue.Value.Type, returnValue.Id, CreateCustomTypeInfo(returnValue));
+					}
+
+					DbgDotNetCustomTypeInfo? CreateCustomTypeInfo(DbgDotNetReturnValueInfo returnVal) {
+						var method = returnVal.Method as DmdMethodInfo;
+						if (method?.ReturnType.Equals(returnVal.Value.Type) == true)
+							return expressionCompiler?.CreateCustomTypeInfo(method.ReturnParameter);
+						return null;
 					}
 				}
 				if (w != res.Length)
diff --git a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet/Evaluation/Engine/DbgEngineLanguageImpl.cs b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet/Evaluation/Engine/DbgEngineLanguageImpl.cs
index 779ca65563..c01f509759 100644
--- a/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet/Evaluation/Engine/DbgEngineLanguageImpl.cs
+++ b/Extensions/dnSpy.Debugger/dnSpy.Debugger.DotNet/Evaluation/Engine/DbgEngineLanguageImpl.cs
@@ -123,7 +123,8 @@ public override void InitializeContext(DbgEvaluationContext context, DbgCodeLoca
 			Debug2.Assert(context.Runtime.GetDotNetRuntime() is not null);
 
 			IDebuggerDisplayAttributeEvaluatorUtils.Initialize(context, debuggerDisplayAttributeEvaluator);
-			// Needed by DebuggerRuntimeImpl (calls expressionCompiler.TryGetAliasInfo()), DbgCorDebugInternalRuntimeImpl and DbgEngineStaticFieldsProviderImpl (calls expressionCompiler.CreateCustomTypeInfo())
+			// Needed by DebuggerRuntimeImpl (calls expressionCompiler.TryGetAliasInfo()), DbgCorDebugInternalRuntimeImpl,
+			// DbgMonoDebugInternalRuntimeImpl and DbgEngineStaticFieldsProviderImpl (calls expressionCompiler.CreateCustomTypeInfo())
 			context.GetOrCreateData(() => expressionCompiler);
 
 			if ((context.Options & DbgEvaluationContextOptions.NoMethodBody) == 0 && location is IDbgDotNetCodeLocation loc) {