|
// 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.
#nullable disable
using Microsoft.CodeAnalysis.CSharp.Symbols;
using System;
using System.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal abstract class DisplayClassInstance
{
internal abstract Symbol ContainingSymbol { get; }
internal abstract TypeSymbol Type { get; }
internal abstract DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap);
internal abstract BoundExpression ToBoundExpression(SyntaxNode syntax);
internal string GetDebuggerDisplay(ConsList<FieldSymbol> fields)
{
return GetDebuggerDisplay(GetInstanceName(), fields);
}
private static string GetDebuggerDisplay(string expr, ConsList<FieldSymbol> fields)
{
return fields.Any()
? $"{GetDebuggerDisplay(expr, fields.Tail)}.{fields.Head.Name}"
: expr;
}
protected abstract string GetInstanceName();
}
internal sealed class DisplayClassInstanceFromLocal : DisplayClassInstance
{
internal readonly EELocalSymbol Local;
internal DisplayClassInstanceFromLocal(EELocalSymbol local)
{
Debug.Assert(!local.IsPinned);
Debug.Assert(local.RefKind == RefKind.None);
Debug.Assert(local.DeclarationKind == LocalDeclarationKind.RegularVariable);
this.Local = local;
}
internal override Symbol ContainingSymbol
{
get { return this.Local.ContainingSymbol; }
}
internal override TypeSymbol Type
{
get { return this.Local.Type; }
}
internal override DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap)
{
var otherInstance = (EELocalSymbol)this.Local.ToOtherMethod(method, typeMap);
return new DisplayClassInstanceFromLocal(otherInstance);
}
internal override BoundExpression ToBoundExpression(SyntaxNode syntax)
{
return new BoundLocal(syntax, this.Local, constantValueOpt: null, type: this.Local.Type) { WasCompilerGenerated = true };
}
protected override string GetInstanceName() => Local.Name;
}
internal sealed class DisplayClassInstanceFromParameter : DisplayClassInstance
{
internal readonly ParameterSymbol Parameter;
internal DisplayClassInstanceFromParameter(ParameterSymbol parameter)
{
Debug.Assert((object)parameter != null);
Debug.Assert(parameter.Name.EndsWith("this", StringComparison.Ordinal) ||
parameter.Name.Length == 0 || // unnamed
parameter.Name.Equals("value", StringComparison.Ordinal) || // display class instance passed to local function as parameter
GeneratedNameParser.GetKind(parameter.Name) == GeneratedNameKind.TransparentIdentifier);
this.Parameter = parameter;
}
internal override Symbol ContainingSymbol
{
get { return this.Parameter.ContainingSymbol; }
}
internal override TypeSymbol Type
{
get { return this.Parameter.Type; }
}
internal override DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap)
{
Debug.Assert(method.IsStatic);
var otherOrdinal = this.ContainingSymbol.IsStatic
? this.Parameter.Ordinal
: (this.Parameter.Ordinal + 1);
var otherParameter = method.Parameters[otherOrdinal];
return new DisplayClassInstanceFromParameter(otherParameter);
}
internal override BoundExpression ToBoundExpression(SyntaxNode syntax)
{
return new BoundParameter(syntax, this.Parameter) { WasCompilerGenerated = true };
}
protected override string GetInstanceName() => Parameter.Name;
}
}
|