File: CustomResultProviderTests.cs
Web Access
Project: ..\..\..\src\ExpressionEvaluator\CSharp\Test\ResultProvider\Microsoft.CodeAnalysis.CSharp.ResultProvider.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.ResultProvider.UnitTests)
// 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 System;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator;
using Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Debugger;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.ComponentInterfaces;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using Microsoft.VisualStudio.Debugger.Metadata;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    /// <summary>
    /// A custom IDkmClrResultProvider implementation
    /// re-using C# implementation.
    /// </summary>
    public class CustomResultProviderTests : CSharpResultProviderTestBase
    {
        public CustomResultProviderTests() :
            base(
                new DkmInspectionSession(
                    ImmutableArray.Create<IDkmClrFormatter>(new CustomFormatter(new CSharpFormatter()), new CSharpFormatter()),
                    ImmutableArray.Create<IDkmClrResultProvider>(new CustomResultProvider(), new CSharpResultProvider())))
        {
        }
 
        [Fact]
        public void Root()
        {
            var source =
@".field static assembly int32 s_val
.class public C
{
  .method public hidebysig specialname rtspecialname instance void .ctor() { ret }
  .method public instance int32* modopt([mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) get_P()
  {
    ldsflda int32 s_val
    ret
  }
  .property instance int32* modopt([mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) P()
  {
    .get instance int32* modopt([mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) C::get_P()
  }
}";
            ImmutableArray<byte> assemblyBytes;
            ImmutableArray<byte> pdbBytes;
            CommonTestBase.EmitILToArray(source, appendDefaultHeader: true, includePdb: false, assemblyBytes: out assemblyBytes, pdbBytes: out pdbBytes);
            var assembly = ReflectionUtilities.Load(assemblyBytes);
            var type = assembly.GetType("C");
            var value = CreateDkmClrValue(type.Instantiate()).GetMemberValue("P", (int)MemberTypes.Property, "C", DefaultInspectionContext);
            var evalResult = FormatResult("P", value);
            Verify(evalResult,
                EvalResult("P", "0", "int*", "P", DkmEvaluationResultFlags.None, DkmEvaluationResultCategory.Property));
        }
 
        [Fact]
        public void Member()
        {
            var source =
@".field static assembly int32 s_val
.class public C
{
  .method public hidebysig specialname rtspecialname instance void .ctor() { ret }
  .method public instance int32* modopt([mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) get_P()
  {
    ldsflda int32 s_val
    ret
  }
  .property instance int32* modopt([mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) P()
  {
    .get instance int32* modopt([mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) C::get_P()
  }
}";
            ImmutableArray<byte> assemblyBytes;
            ImmutableArray<byte> pdbBytes;
            CommonTestBase.EmitILToArray(source, appendDefaultHeader: true, includePdb: false, assemblyBytes: out assemblyBytes, pdbBytes: out pdbBytes);
            var assembly = ReflectionUtilities.Load(assemblyBytes);
            var type = assembly.GetType("C");
            var value = CreateDkmClrValue(type.Instantiate(), type);
            var evalResult = FormatResult("o", value);
            Verify(evalResult,
                EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable, DkmEvaluationResultCategory.Other));
            var children = GetChildren(evalResult);
            Verify(children,
                EvalResult("P", "0", "int*", "o.P", DkmEvaluationResultFlags.None, DkmEvaluationResultCategory.Property));
        }
 
        private sealed class CustomResultProvider : IDkmClrResultProvider
        {
            void IDkmClrResultProvider.GetResult(DkmClrValue clrValue, DkmWorkList workList, DkmClrType declaredType, DkmClrCustomTypeInfo customTypeInfo, DkmInspectionContext inspectionContext, ReadOnlyCollection<string> formatSpecifiers, string resultName, string resultFullName, DkmCompletionRoutine<DkmEvaluationAsyncResult> completionRoutine)
            {
                clrValue.GetResult(
                    workList,
                    declaredType,
                    customTypeInfo,
                    inspectionContext,
                    formatSpecifiers,
                    resultName,
                    resultFullName,
                    result =>
                    {
                        var type = declaredType.GetLmrType();
                        if (type.IsPointer)
                        {
                            var r = (DkmSuccessEvaluationResult)result.Result;
                            // TODO: Why aren't modopts for & properties included?
                            r.GetChildren(
                                workList,
                                1,
                                inspectionContext,
                                children =>
                                {
                                    var c = (DkmSuccessEvaluationResult)children.InitialChildren[0];
                                    r = DkmSuccessEvaluationResult.Create(
                                        c.InspectionContext,
                                        c.StackFrame,
                                        r.Name,
                                        r.FullName,
                                        c.Flags,
                                        c.Value,
                                        r.EditableValue,
                                        r.Type,
                                        r.Category,
                                        r.Access,
                                        r.StorageType,
                                        r.TypeModifierFlags,
                                        null,
                                        r.CustomUIVisualizers,
                                        null,
                                        null);
                                    completionRoutine(new DkmEvaluationAsyncResult(r));
                                });
                        }
                        else
                        {
                            completionRoutine(result);
                        }
                    });
            }
 
            DkmClrValue IDkmClrResultProvider.GetClrValue(DkmSuccessEvaluationResult successResult)
            {
                return successResult.GetClrValue();
            }
 
            void IDkmClrResultProvider.GetChildren(DkmEvaluationResult evaluationResult, DkmWorkList workList, int initialRequestSize, DkmInspectionContext inspectionContext, DkmCompletionRoutine<DkmGetChildrenAsyncResult> completionRoutine)
            {
                evaluationResult.GetChildren(workList, initialRequestSize, inspectionContext, completionRoutine);
            }
 
            void IDkmClrResultProvider.GetItems(DkmEvaluationResultEnumContext enumContext, DkmWorkList workList, int startIndex, int count, DkmCompletionRoutine<DkmEvaluationEnumAsyncResult> completionRoutine)
            {
                enumContext.GetItems(workList, startIndex, count, completionRoutine);
            }
 
            string IDkmClrResultProvider.GetUnderlyingString(DkmEvaluationResult result)
            {
                return result.GetUnderlyingString();
            }
        }
 
        private sealed class CustomFormatter : IDkmClrFormatter, IDkmClrFormatter2, IDkmClrFullNameProvider
        {
            private readonly IDkmClrFormatter _fallback; // Remove and dispatch calls through DkmInspectionContext.
 
            internal CustomFormatter(IDkmClrFormatter2 fallback)
            {
                _fallback = (IDkmClrFormatter)fallback;
            }
 
            string IDkmClrFormatter.GetTypeName(DkmInspectionContext inspectionContext, DkmClrType clrType, DkmClrCustomTypeInfo customTypeInfo, ReadOnlyCollection<string> formatSpecifiers)
            {
                return inspectionContext.GetTypeName(clrType, customTypeInfo, formatSpecifiers);
            }
 
            string IDkmClrFormatter.GetUnderlyingString(DkmClrValue clrValue, DkmInspectionContext inspectionContext)
            {
                return clrValue.GetUnderlyingString(inspectionContext);
            }
 
            string IDkmClrFormatter.GetValueString(DkmClrValue clrValue, DkmInspectionContext inspectionContext, ReadOnlyCollection<string> formatSpecifiers)
            {
                return clrValue.GetValueString(inspectionContext, formatSpecifiers);
            }
 
            bool IDkmClrFormatter.HasUnderlyingString(DkmClrValue clrValue, DkmInspectionContext inspectionContext)
            {
                return clrValue.HasUnderlyingString(inspectionContext);
            }
 
            string IDkmClrFormatter2.GetValueString(DkmClrValue value, DkmClrCustomTypeInfo customTypeInfo, DkmInspectionContext inspectionContext, ReadOnlyCollection<string> formatSpecifiers)
            {
                return ((IDkmClrFormatter2)_fallback).GetValueString(value, customTypeInfo, inspectionContext, formatSpecifiers);
            }
 
            string IDkmClrFormatter2.GetEditableValueString(DkmClrValue value, DkmInspectionContext inspectionContext, DkmClrCustomTypeInfo customTypeInfo)
            {
                return ((IDkmClrFormatter2)_fallback).GetEditableValueString(value, inspectionContext, customTypeInfo);
            }
 
            string IDkmClrFullNameProvider.GetClrTypeName(DkmInspectionContext inspectionContext, DkmClrType clrType, DkmClrCustomTypeInfo customTypeInfo)
            {
                throw new NotImplementedException();
            }
 
            string IDkmClrFullNameProvider.GetClrArrayIndexExpression(DkmInspectionContext inspectionContext, string[] indices)
            {
                throw new NotImplementedException();
            }
 
            string IDkmClrFullNameProvider.GetClrCastExpression(DkmInspectionContext inspectionContext, string argument, DkmClrType type, DkmClrCustomTypeInfo customTypeInfo, DkmClrCastExpressionOptions castExpressionOptions)
            {
                throw new NotImplementedException();
            }
 
            string IDkmClrFullNameProvider.GetClrObjectCreationExpression(DkmInspectionContext inspectionContext, DkmClrType type, DkmClrCustomTypeInfo customTypeInfo, string[] arguments)
            {
                throw new NotImplementedException();
            }
 
            string IDkmClrFullNameProvider.GetClrValidIdentifier(DkmInspectionContext inspectionContext, string identifier)
            {
                return ((IDkmClrFullNameProvider)_fallback).GetClrValidIdentifier(inspectionContext, identifier);
            }
 
            string IDkmClrFullNameProvider.GetClrExpressionAndFormatSpecifiers(DkmInspectionContext inspectionContext, string expression, out ReadOnlyCollection<string> formatSpecifiers)
            {
                return ((IDkmClrFullNameProvider)_fallback).GetClrExpressionAndFormatSpecifiers(inspectionContext, expression, out formatSpecifiers);
            }
 
            bool IDkmClrFullNameProvider.ClrExpressionMayRequireParentheses(DkmInspectionContext inspectionContext, string expression)
            {
                return ((IDkmClrFullNameProvider)_fallback).ClrExpressionMayRequireParentheses(inspectionContext, expression);
            }
 
            string IDkmClrFullNameProvider.GetClrMemberName(
                DkmInspectionContext inspectionContext,
                string parentFullName,
                DkmClrType declaringType,
                DkmClrCustomTypeInfo declaringTypeInfo,
                string memberName,
                bool memberAccessRequiresExplicitCast,
                bool memberIsStatic)
            {
                return ((IDkmClrFullNameProvider)_fallback).GetClrMemberName(inspectionContext, parentFullName, declaringType, declaringTypeInfo, memberName, memberAccessRequiresExplicitCast, memberIsStatic);
            }
 
            string IDkmClrFullNameProvider.GetClrExpressionForNull(DkmInspectionContext inspectionContext)
            {
                throw new NotImplementedException();
            }
 
            string IDkmClrFullNameProvider.GetClrExpressionForThis(DkmInspectionContext inspectionContext)
            {
                throw new NotImplementedException();
            }
        }
    }
}