/*
Copyright (C) 2014-2019 de4dot@gmail.com
This file is part of dnSpy
dnSpy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
dnSpy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with dnSpy. If not, see .
*/
using System;
using System.ComponentModel.Composition;
using System.Text;
using dnSpy.Contracts.Debugger;
using dnSpy.Contracts.Debugger.DotNet.Evaluation;
using dnSpy.Contracts.Debugger.DotNet.Evaluation.ExpressionCompiler;
using dnSpy.Contracts.Debugger.Evaluation;
using dnSpy.Contracts.Debugger.Text;
using dnSpy.Debugger.DotNet.Metadata;
namespace dnSpy.Debugger.DotNet.Evaluation.Engine {
abstract class DbgAliasProvider {
public abstract (DbgDotNetAlias[] aliases, DmdType[] typeReferences) GetAliases(DbgEvaluationInfo evalInfo);
}
[Export(typeof(DbgAliasProvider))]
sealed class DbgAliasProviderImpl : DbgAliasProvider {
readonly DbgObjectIdService objectIdService;
[ImportingConstructor]
DbgAliasProviderImpl(DbgObjectIdService objectIdService) => this.objectIdService = objectIdService;
public override (DbgDotNetAlias[] aliases, DmdType[] typeReferences) GetAliases(DbgEvaluationInfo evalInfo) {
var runtime = evalInfo.Runtime.GetDotNetRuntime();
var objectIds = objectIdService.GetObjectIds(evalInfo.Runtime);
var aliases = runtime.GetAliases(evalInfo);
if (objectIds.Length == 0 && aliases.Length == 0)
return (Array.Empty(), Array.Empty());
var res = new DbgDotNetAlias[objectIds.Length + aliases.Length];
var typeReferences = new DmdType[res.Length];
StringBuilder? sb = ObjectCache.AllocStringBuilder();
var output = new DbgStringBuilderTextWriter(sb);
int w = 0;
foreach (var alias in aliases) {
output.Reset();
DbgDotNetAliasKind dnAliasKind;
string aliasName;
switch (alias.Kind) {
case DbgDotNetAliasInfoKind.Exception:
dnAliasKind = DbgDotNetAliasKind.Exception;
evalInfo.Context.Language.Formatter.FormatExceptionName(evalInfo.Context, output, alias.Id);
aliasName = sb.ToString();
break;
case DbgDotNetAliasInfoKind.StowedException:
dnAliasKind = DbgDotNetAliasKind.StowedException;
evalInfo.Context.Language.Formatter.FormatStowedExceptionName(evalInfo.Context, output, alias.Id);
aliasName = sb.ToString();
break;
case DbgDotNetAliasInfoKind.ReturnValue:
dnAliasKind = DbgDotNetAliasKind.ReturnValue;
evalInfo.Context.Language.Formatter.FormatReturnValueName(evalInfo.Context, output, alias.Id);
aliasName = sb.ToString();
break;
default:
throw new InvalidOperationException();
}
res[w] = new DbgDotNetAlias(dnAliasKind, alias.Type.AssemblyQualifiedName ?? string.Empty, aliasName, alias.CustomTypeInfoId, alias.CustomTypeInfo);
typeReferences[w] = alias.Type;
w++;
}
foreach (var objectId in objectIds) {
output.Reset();
var value = objectId.GetValue(evalInfo);
var dnValue = (DbgDotNetValue)value.InternalValue;
evalInfo.Context.Language.Formatter.FormatObjectIdName(evalInfo.Context, output, objectId.Id);
res[w] = new DbgDotNetAlias(DbgDotNetAliasKind.ObjectId, dnValue.Type.AssemblyQualifiedName ?? string.Empty, sb.ToString(), Guid.Empty, null);
typeReferences[w] = dnValue.Type;
w++;
value.Close();
}
if (w != res.Length || w != typeReferences.Length)
throw new InvalidOperationException();
ObjectCache.Free(ref sb);
return (res, typeReferences);
}
}
}