|
// 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.Immutable;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.VisualStudio.Debugger.Clr;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class CSharpInstructionDecoder : InstructionDecoder<CSharpCompilation, MethodSymbol, PEModuleSymbol, TypeSymbol, TypeParameterSymbol>
{
// This string was not localized in the old EE. We'll keep it that way
// so as not to break consumers who may have been parsing frame names...
private const string AnonymousMethodName = "AnonymousMethod";
/// <summary>
/// Singleton instance of <see cref="CSharpInstructionDecoder"/> (created using default constructor).
/// </summary>
internal static readonly CSharpInstructionDecoder Instance = new CSharpInstructionDecoder();
private CSharpInstructionDecoder()
{
}
private static readonly SymbolDisplayFormat s_propertyDisplayFormat = DisplayFormat.
AddMemberOptions(SymbolDisplayMemberOptions.IncludeParameters).
WithParameterOptions(SymbolDisplayParameterOptions.IncludeType);
internal override void AppendFullName(StringBuilder builder, MethodSymbol method)
{
var displayFormat = (method.MethodKind == MethodKind.PropertyGet || method.MethodKind == MethodKind.PropertySet)
? s_propertyDisplayFormat
: DisplayFormat;
var parts = method.ToDisplayParts(displayFormat);
var numParts = parts.Length;
for (int i = 0; i < numParts; i++)
{
var part = parts[i];
var displayString = part.ToString();
switch (part.Kind)
{
case SymbolDisplayPartKind.ClassName:
if (GeneratedNameParser.GetKind(displayString) != GeneratedNameKind.LambdaDisplayClass)
{
builder.Append(displayString);
}
else
{
// Drop any remaining display class name parts and the subsequent dot...
do
{
i++;
}
while (i < numParts && parts[i].Kind != SymbolDisplayPartKind.MethodName);
i--;
}
break;
case SymbolDisplayPartKind.MethodName:
GeneratedNameKind kind;
int openBracketOffset, closeBracketOffset;
if (GeneratedNameParser.TryParseGeneratedName(displayString, out kind, out openBracketOffset, out closeBracketOffset) &&
(kind == GeneratedNameKind.LambdaMethod || kind == GeneratedNameKind.LocalFunction))
{
builder.Append(displayString, openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1); // source method name
builder.Append('.');
if (kind == GeneratedNameKind.LambdaMethod)
{
builder.Append(AnonymousMethodName);
}
// NOTE: Local functions include the local function name inside the suffix ("<Main>__Local1_1")
// NOTE: The old implementation only appended the first ordinal number. Since this is not useful
// in uniquely identifying the lambda, we'll append the entire ordinal suffix (which may contain
// multiple numbers, as well as '-' or '_').
builder.Append(displayString.Substring(closeBracketOffset + 2)); // ordinal suffix (e.g. "__1")
}
else
{
builder.Append(displayString);
}
break;
default:
builder.Append(displayString);
break;
}
}
}
internal override void AppendParameterTypeName(StringBuilder builder, IParameterSymbol parameter)
{
// The old EE only displayed "ref" and "out" modifiers in C# and only when displaying parameter
// types. We will do the same here for compatibility with the old behavior.
switch (parameter.RefKind)
{
case RefKind.Out:
builder.Append("out ");
break;
case RefKind.Ref:
builder.Append("ref ");
break;
}
base.AppendParameterTypeName(builder, parameter);
}
internal override MethodSymbol ConstructMethod(MethodSymbol method, ImmutableArray<TypeParameterSymbol> typeParameters, ImmutableArray<TypeSymbol> typeArguments)
{
var methodArity = method.Arity;
var methodArgumentStartIndex = typeParameters.Length - methodArity;
var typeMap = new TypeMap(
ImmutableArray.Create(typeParameters, 0, methodArgumentStartIndex),
ImmutableArray.CreateRange(typeArguments, 0, methodArgumentStartIndex, t => TypeWithAnnotations.Create(t)));
var substitutedType = typeMap.SubstituteNamedType(method.ContainingType);
method = method.AsMember(substitutedType);
if (methodArity > 0)
{
method = method.Construct(ImmutableArray.Create(typeArguments, methodArgumentStartIndex, methodArity));
}
return method;
}
internal override ImmutableArray<TypeParameterSymbol> GetAllTypeParameters(MethodSymbol method)
{
return method.GetAllTypeParameters();
}
internal override CSharpCompilation GetCompilation(DkmClrModuleInstance moduleInstance)
{
var appDomain = moduleInstance.AppDomain;
var moduleVersionId = moduleInstance.Mvid;
var previous = appDomain.GetMetadataContext<CSharpMetadataContext>();
var metadataBlocks = moduleInstance.RuntimeInstance.GetMetadataBlocks(appDomain, previous.MetadataBlocks);
var kind = GetMakeAssemblyReferencesKind();
var contextId = MetadataContextId.GetContextId(moduleVersionId, kind);
var assemblyContexts = previous.Matches(metadataBlocks) ? previous.AssemblyContexts : ImmutableDictionary<MetadataContextId, CSharpMetadataContext>.Empty;
CSharpMetadataContext previousContext;
assemblyContexts.TryGetValue(contextId, out previousContext);
var compilation = previousContext.Compilation;
if (compilation == null)
{
compilation = metadataBlocks.ToCompilation(moduleVersionId, kind);
appDomain.SetMetadataContext(
new MetadataContext<CSharpMetadataContext>(
metadataBlocks,
assemblyContexts.SetItem(contextId, new CSharpMetadataContext(compilation))),
report: kind == MakeAssemblyReferencesKind.AllReferences);
}
return compilation;
}
internal override MethodSymbol GetMethod(CSharpCompilation compilation, DkmClrInstructionAddress instructionAddress)
{
var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(instructionAddress.MethodId.Token);
return compilation.GetSourceMethod(instructionAddress.ModuleInstance.Mvid, methodHandle);
}
internal override TypeNameDecoder<PEModuleSymbol, TypeSymbol> GetTypeNameDecoder(CSharpCompilation compilation, MethodSymbol method)
{
Debug.Assert(method is PEMethodSymbol);
return new EETypeNameDecoder(compilation, (PEModuleSymbol)method.ContainingModule);
}
}
}
|