提交 47771e14 编写于 作者: K Kevin Halverson

Implement Dynamic View expansion...

上级 75dc71db
......@@ -72,6 +72,7 @@
<PlatformTarget>ARM</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Collections" />
<Reference Include="System.Collections.Immutable">
......@@ -96,6 +97,7 @@
<Compile Include="CSharpResultProviderTestBase.cs" />
<Compile Include="DynamicFlagsCustomTypeInfoTests.cs" />
<Compile Include="DynamicTests.cs" />
<Compile Include="DynamicViewTests.cs" />
<Compile Include="ExpansionTests.cs" />
<Compile Include="FormatSpecifierTests.cs" />
<Compile Include="FullNameTests.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Dynamic;
using System.Linq;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class DynamicViewTests : CSharpResultProviderTestBase
{
[Fact]
public void MultipleMembers()
{
var expression = "o";
dynamic o = new ExpandoObject();
o.Philosophers = new object[] { "Pythagoras", "Lucretius", "Zeno" };
o.WhatsForDinner = "Crab Cakes";
o.NumForks = 2;
var type = new DkmClrType((TypeImpl)o.GetType());
var value = CreateDkmClrValue((object)o, type);
var result = FormatResult(expression, value);
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable));
var dynamicView = GetChildren(result).Last();
Verify(dynamicView,
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", "o, dynamic", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
Verify(GetChildren(dynamicView),
EvalResult("NumForks", "2", "System.Int32", "new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items[0]", DkmEvaluationResultFlags.ReadOnly),
EvalResult("Philosophers", "{object[3]}", "System.Object[]", "new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items[1]", DkmEvaluationResultFlags.ReadOnly),
EvalResult("WhatsForDinner", "\"Crab Cakes\"", "System.String", "new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items[2]", DkmEvaluationResultFlags.ReadOnly));
}
[Fact]
public void MultipleExpansions()
{
var expression = "o";
dynamic o = new ExpandoObject();
o.Answer = 42;
var type = new DkmClrType((TypeImpl)o.GetType());
var value = CreateDkmClrValue((object)o, type);
// Dynamic View should appear after all other expansions.
var result = FormatResult(expression, value);
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable));
Verify(GetChildren(result),
EvalResult("Class", "{System.Dynamic.ExpandoClass}", "System.Dynamic.ExpandoClass", "o.Class", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Internal),
EvalResult("LockObject", "{object}", "object", "o.LockObject", DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Data, DkmEvaluationResultAccessType.Internal),
EvalResult("System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<string, object>>.Count", "1", "int", "((System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<string, object>>)o).Count", DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Private),
EvalResult("System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<string, object>>.IsReadOnly", "false", "bool", "((System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<string, object>>)o).IsReadOnly", DkmEvaluationResultFlags.Boolean | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Private),
EvalResult("System.Collections.Generic.IDictionary<string, object>.Keys", "Count = 1", "System.Collections.Generic.ICollection<string> {System.Dynamic.ExpandoObject.KeyCollection}", "((System.Collections.Generic.IDictionary<string, object>)o).Keys", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Private),
EvalResult("System.Collections.Generic.IDictionary<string, object>.Values", "Count = 1", "System.Collections.Generic.ICollection<object> {System.Dynamic.ExpandoObject.ValueCollection}", "((System.Collections.Generic.IDictionary<string, object>)o).Values", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Private),
EvalResult("_count", "1", "int", "o._count", category: DkmEvaluationResultCategory.Data, access: DkmEvaluationResultAccessType.Private),
EvalResult("_data", "{System.Dynamic.ExpandoObject.ExpandoData}", "System.Dynamic.ExpandoObject.ExpandoData", "o._data", DkmEvaluationResultFlags.Expandable, DkmEvaluationResultCategory.Data, DkmEvaluationResultAccessType.Private),
EvalResult("_propertyChanged", "null", "System.ComponentModel.PropertyChangedEventHandler", "o._propertyChanged", category: DkmEvaluationResultCategory.Data, access: DkmEvaluationResultAccessType.Private),
EvalResult(Resources.StaticMembers, null, "", "System.Dynamic.ExpandoObject", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Class),
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", "o, dynamic", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Method));
}
[Fact]
public void ExceptionTypeMember()
{
var expression = "o";
dynamic o = new ExpandoObject();
var exception = new NotImplementedException();
o.Member = exception;
var type = new DkmClrType((TypeImpl)o.GetType());
var value = CreateDkmClrValue((object)o, type);
var result = FormatResult(expression, value);
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable));
var dynamicView = GetChildren(result).Last();
Verify(dynamicView,
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", "o, dynamic", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
Verify(GetChildren(dynamicView),
EvalResult("Member", $"{{{exception.ToString()}}}", "System.NotImplementedException", "new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items[0]", DkmEvaluationResultFlags.ReadOnly));
}
[Fact]
public void DynamicTypeMember()
{
var expression = "o";
dynamic o = new ExpandoObject();
o.Pi = Math.PI;
o.OnAndOn = o;
var type = new DkmClrType((TypeImpl)o.GetType());
var value = CreateDkmClrValue((object)o, type);
var result = FormatResult(expression, value);
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable));
var members = GetChildren(result);
var fullNameOnAndOn = "o";
var fullNamePi = "o";
// Expand 3 levels...
for (var i = 0; i < 3; i++)
{
var dynamicView = members.Last();
Verify(dynamicView,
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", $"{fullNameOnAndOn}, dynamic", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
members = GetChildren(dynamicView);
fullNamePi = $"new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView({fullNameOnAndOn}).Items[1]";
fullNameOnAndOn = $"new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView({fullNameOnAndOn}).Items[0]";
Verify(members,
EvalResult("OnAndOn", "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", fullNameOnAndOn, DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly),
EvalResult("Pi", "3.1415926535897931", "System.Double", fullNamePi, DkmEvaluationResultFlags.ReadOnly));
members = GetChildren(members[0]);
}
}
[Fact]
public void NoMembers()
{
var expression = "o";
dynamic o = new ExpandoObject();
var type = new DkmClrType((TypeImpl)o.GetType());
var value = CreateDkmClrValue((object)o, type);
var result = FormatResult(expression, value);
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable));
var dynamicView = GetChildren(result).Last();
Verify(dynamicView,
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", "o, dynamic", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
Verify(GetChildren(dynamicView),
EvalFailedResult(Resources.ErrorName, "No further information on this object could be discovered"));
}
[Fact]
public void NullComObject()
{
var comObjectTypeName = "System.__ComObject";
var expression = $"({comObjectTypeName})null";
var type = new DkmClrType((TypeImpl)typeof(object).Assembly.GetType(comObjectTypeName));
var value = CreateDkmClrValue(null, type);
var result = FormatResult(expression, value);
Verify(result,
EvalResult(expression, "null", comObjectTypeName, expression));
result = FormatResult(expression, expression + ",dynamic", value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView));
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic));
}
[Fact]
public void NullIDynamicMetaObjectProvider()
{
var expression = "o";
var type = new DkmClrType((TypeImpl)typeof(IDynamicMetaObjectProvider));
var value = CreateDkmClrValue(null, type);
var result = FormatResult(expression, value);
Verify(result,
EvalResult(expression, "null", "System.Dynamic.IDynamicMetaObjectProvider", expression));
result = FormatResult(expression, expression + ",dynamic", value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView));
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic));
}
[Fact]
public void NullDynamicObject()
{
var expression = "o";
var type = new DkmClrType((TypeImpl)typeof(ExpandoObject));
var value = CreateDkmClrValue(null, type);
var result = FormatResult(expression, value);
Verify(result,
EvalResult(expression, "null", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable));
Verify(GetChildren(result),
EvalResult(Resources.StaticMembers, null, "", "System.Dynamic.ExpandoObject", DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Class));
result = FormatResult(expression, expression + ",dynamic", value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView));
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic));
}
[Fact]
public void DynamicTypeError()
{
var expression = "o";
var obj = new ExpandoObject();
// Verify that things *work* in this scenario if there was no error in member access.
var value = CreateDkmClrValue(obj);
var fullName = expression + ", dynamic";
var result = FormatResult(expression, fullName, value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView));
Verify(result,
EvalResult(expression, Resources.DynamicViewValueWarning, "", fullName, DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
// Verify no Dynamic View if member access is changed to result in an error.
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlibAndSystemCore());
value = CreateErrorValue(runtime.GetType(obj.GetType()), "Function evaluation timed out");
result = FormatResult(expression, fullName, value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView));
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic));
}
[Fact]
public void DynamicMetaObjectProviderDebugViewItemsError()
{
var expression = "o";
dynamic o = new ExpandoObject();
o.Answer = 42;
DkmClrRuntimeInstance runtime = null;
runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(),
getMemberValue: (_, m) => (m == "Items") ? CreateErrorValue(runtime.GetType(typeof(Array)), "Function evaluation timed out") : null);
var type = new DkmClrType(runtime, (TypeImpl)o.GetType());
var value = CreateDkmClrValue((object)o, type);
var fullName = expression + ", dynamic";
var result = FormatResult(expression, fullName, value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView));
Verify(result,
EvalResult(expression, Resources.DynamicViewValueWarning, "", fullName, DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
Verify(GetChildren(result),
EvalFailedResult(Resources.ErrorName, "Function evaluation timed out"));
}
[Fact]
public void DynamicFormatSpecifier()
{
var expression = "o";
dynamic o = new ExpandoObject();
o.Answer = 42;
var type = new DkmClrType((TypeImpl)o.GetType());
var value = CreateDkmClrValue((object)o, type);
var fullName = expression + ", dynamic";
var result = FormatResult(expression, fullName, value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView));
Verify(result,
EvalResult(expression, Resources.DynamicViewValueWarning, "", fullName, DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly));
Verify(GetChildren(result),
EvalResult("Answer", "42", "System.Int32", "new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items[0]", DkmEvaluationResultFlags.ReadOnly));
}
[Fact]
public void DynamicFormatSpecifierError()
{
var expression = "o";
var o = new Object();
var type = new DkmClrType((TypeImpl)o.GetType());
var value = CreateDkmClrValue(o, type);
var result = FormatResult(expression, expression + ",dynamic", value, inspectionContext: CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView));
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic));
}
}
}
......@@ -1302,7 +1302,7 @@ public void ImmutableArray()
evalFlags: DkmEvaluationResultFlags.None);
var evalResult = FormatResult("c", value);
Verify(evalResult,
EvalResult("c", "\"Length = 3\"", "System.Collections.Immutable.ImmutableArray<int>", "c", DkmEvaluationResultFlags.Expandable));
EvalResult("c", "Length = 3", "System.Collections.Immutable.ImmutableArray<int>", "c", DkmEvaluationResultFlags.Expandable));
var children = GetChildren(evalResult);
Verify(children,
EvalResult("[0]", "1", "int", "c.array[0]"),
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal sealed class DynamicViewExpansion : Expansion
{
private const string DynamicFormatSpecifier = "dynamic";
internal static DynamicViewExpansion CreateExpansion(DkmInspectionContext inspectionContext, DkmClrValue value, Formatter formatter)
{
if (value.IsError() || value.IsNull || value.HasExceptionThrown())
{
return null;
}
var type = value.Type.GetLmrType();
if (!(type.IsComObject() || type.IsIDynamicMetaObjectProvider()))
{
return null;
}
var proxyValue = value.InstantiateDynamicViewProxy(inspectionContext);
Debug.Assert((proxyValue == null) || (!proxyValue.IsNull && !proxyValue.IsError() && !proxyValue.HasExceptionThrown()));
// InstantiateDynamicViewProxy may return null (if required assembly is missing, for instance).
if (proxyValue == null)
{
return null;
}
// Expansion is based on the 'DynamicMetaObjectProviderDebugView.Items' property.
var proxyType = proxyValue.Type;
var itemsMemberExpansion = RootHiddenExpansion.CreateExpansion(
proxyType.GetMemberByName("Items"),
DynamicFlagsMap.Create(new TypeAndCustomInfo(proxyType)));
return new DynamicViewExpansion(proxyValue, itemsMemberExpansion);
}
internal static EvalResultDataItem CreateMembersOnlyRow(
DkmInspectionContext inspectionContext,
string name,
DkmClrValue value,
Formatter formatter)
{
var expansion = CreateExpansion(inspectionContext, value, formatter);
return (expansion != null) ?
expansion.CreateDynamicViewRow(inspectionContext, name, parent: null, formatter: formatter) :
new EvalResultDataItem(name, Resources.DynamicViewNotDynamic);
}
private readonly DkmClrValue _proxyValue;
private readonly Expansion _proxyMembers;
private DynamicViewExpansion(DkmClrValue proxyValue, Expansion proxyMembers)
{
Debug.Assert(proxyValue != null);
Debug.Assert(proxyMembers != null);
_proxyValue = proxyValue;
_proxyMembers = proxyMembers;
}
internal override void GetRows(
ResultProvider resultProvider,
ArrayBuilder<EvalResultDataItem> rows,
DkmInspectionContext inspectionContext,
EvalResultDataItem parent,
DkmClrValue value,
int startIndex,
int count,
bool visitAll,
ref int index)
{
if (InRange(startIndex, count, index))
{
rows.Add(CreateDynamicViewRow(inspectionContext, Resources.DynamicView, parent, resultProvider.Formatter));
}
index++;
}
private EvalResultDataItem CreateDynamicViewRow(DkmInspectionContext inspectionContext, string name, EvalResultDataItem parent, Formatter formatter)
{
var proxyTypeAndInfo = new TypeAndCustomInfo(_proxyValue.Type);
var isRootExpression = parent == null;
Debug.Assert(isRootExpression != (name == Resources.DynamicView));
var fullName = (!isRootExpression) ? parent.ChildFullNamePrefix : name;
var childFullNamePrefix = (fullName == null) ?
null :
formatter.GetObjectCreationExpression(formatter.GetTypeName(proxyTypeAndInfo, escapeKeywordIdentifiers: true), fullName);
var formatSpecifiers = (!isRootExpression) ? parent.FormatSpecifiers : Formatter.NoFormatSpecifiers;
return new EvalResultDataItem(
ExpansionKind.DynamicView,
name,
typeDeclaringMemberAndInfo: default(TypeAndCustomInfo),
declaredTypeAndInfo: proxyTypeAndInfo,
parent: null,
value: _proxyValue,
displayValue: Resources.DynamicViewValueWarning,
expansion: _proxyMembers,
childShouldParenthesize: false,
fullName: fullName,
childFullNamePrefixOpt: childFullNamePrefix,
formatSpecifiers: Formatter.AddFormatSpecifier(formatSpecifiers, DynamicFormatSpecifier),
category: DkmEvaluationResultCategory.Method,
flags: DkmEvaluationResultFlags.ReadOnly,
editableValue: null,
inspectionContext: inspectionContext);
}
}
}
......@@ -27,7 +27,17 @@ internal sealed class MemberExpansion : Expansion
Predicate<MemberInfo> predicate,
Formatter formatter)
{
var runtimeType = value.Type.GetLmrType();
// For members of type DynamicProperty (part of Dynamic View expansion), we want
// to expand the underlying value (not the members of the DynamicProperty type).
var type = value.Type;
var isDynamicProperty = type.GetLmrType().IsDynamicProperty();
if (isDynamicProperty)
{
Debug.Assert(!value.IsNull);
value = value.GetFieldValue("value", inspectionContext);
}
var runtimeType = type.GetLmrType();
// Primitives, enums and null values with a declared type that is an interface have no visible members.
Debug.Assert(!runtimeType.IsInterface || value.IsNull);
if (formatter.IsPredefinedType(runtimeType) || runtimeType.IsEnum || runtimeType.IsInterface)
......@@ -35,6 +45,13 @@ internal sealed class MemberExpansion : Expansion
return null;
}
// As in the old C# EE, DynamicProperty members are only expandable if they have a Dynamic View expansion.
var dynamicViewExpansion = DynamicViewExpansion.CreateExpansion(inspectionContext, value, formatter);
if (isDynamicProperty && (dynamicViewExpansion == null))
{
return null;
}
var dynamicFlagsMap = DynamicFlagsMap.Create(declaredTypeAndInfo);
var expansions = ArrayBuilder<Expansion>.GetInstance();
......@@ -132,6 +149,11 @@ internal sealed class MemberExpansion : Expansion
}
}
if (dynamicViewExpansion != null)
{
expansions.Add(dynamicViewExpansion);
}
var result = AggregateExpansion.CreateExpansion(expansions);
expansions.Free();
return result;
......@@ -237,7 +259,7 @@ private MemberExpansion(MemberAndDeclarationInfo[] members, DynamicFlagsMap dyna
EvalResultDataItem parent,
DynamicFlagsMap dynamicFlagsMap)
{
var memberValue = GetMemberValue(value, member, inspectionContext);
var memberValue = value.GetMemberValue(member, inspectionContext);
return CreateMemberDataItem(
resultProvider,
inspectionContext,
......@@ -248,64 +270,6 @@ private MemberExpansion(MemberAndDeclarationInfo[] members, DynamicFlagsMap dyna
ExpansionFlags.All);
}
private static DkmClrValue GetMemberValue(DkmClrValue container, MemberAndDeclarationInfo member, DkmInspectionContext inspectionContext)
{
// Note: GetMemberValue() may return special value
// when func-eval of properties is disabled.
return container.GetMemberValue(member.Name, (int)member.MemberType, member.DeclaringType.FullName, inspectionContext);
}
private sealed class RootHiddenExpansion : Expansion
{
private readonly MemberAndDeclarationInfo _member;
private readonly DynamicFlagsMap _dynamicFlagsMap;
internal RootHiddenExpansion(MemberAndDeclarationInfo member, DynamicFlagsMap dynamicFlagsMap)
{
_member = member;
_dynamicFlagsMap = dynamicFlagsMap;
}
internal override void GetRows(
ResultProvider resultProvider,
ArrayBuilder<EvalResultDataItem> rows,
DkmInspectionContext inspectionContext,
EvalResultDataItem parent,
DkmClrValue value,
int startIndex,
int count,
bool visitAll,
ref int index)
{
var memberValue = GetMemberValue(value, _member, inspectionContext);
if (memberValue.IsError())
{
if (InRange(startIndex, count, index))
{
var row = new EvalResultDataItem(Resources.ErrorName, errorMessage: (string)memberValue.HostObjectValue);
rows.Add(row);
}
index++;
}
else
{
parent = CreateMemberDataItem(
resultProvider,
inspectionContext,
_member,
memberValue,
parent,
_dynamicFlagsMap,
ExpansionFlags.IncludeBaseMembers | ExpansionFlags.IncludeResultsView);
var expansion = parent.Expansion;
if (expansion != null)
{
expansion.GetRows(resultProvider, rows, inspectionContext, parent, parent.Value, startIndex, count, visitAll, ref index);
}
}
}
}
/// <summary>
/// An explicit user request to bypass "Just My Code" and display
/// the inaccessible members of an instance of an imported type.
......@@ -439,7 +403,7 @@ internal StaticMembersExpansion(Type runtimeType, Expansion members)
}
}
private static EvalResultDataItem CreateMemberDataItem(
internal static EvalResultDataItem CreateMemberDataItem(
ResultProvider resultProvider,
DkmInspectionContext inspectionContext,
MemberAndDeclarationInfo member,
......
......@@ -160,8 +160,7 @@ private static DkmClrType GetEnumerableType(DkmClrValue value, DkmClrType valueT
private static ResultsViewExpansion CreateExpansion(DkmInspectionContext inspectionContext, DkmClrValue value, DkmClrType enumerableType, Formatter formatter)
{
var proxyValue = value.InstantiateResultsViewProxy(inspectionContext, enumerableType);
// InstantiateResultsViewProxy may return null
// (if assembly is missing for instance).
// InstantiateResultsViewProxy may return null (if required assembly is missing, for instance).
if (proxyValue == null)
{
return null;
......@@ -258,7 +257,7 @@ private EvalResultDataItem CreateResultsViewRow(DkmInspectionContext inspectionC
declaredTypeAndInfo: declaredTypeAndInfo,
parent: null,
value: value,
displayValue: name,
displayValue: null,
expansion: new IndirectExpansion(_proxyValue, _proxyMembers),
childShouldParenthesize: false,
fullName: fullName,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal sealed class RootHiddenExpansion : Expansion
{
internal static Expansion CreateExpansion(
MemberAndDeclarationInfo members,
DynamicFlagsMap dynamicFlagsMap)
{
return new RootHiddenExpansion(members, dynamicFlagsMap);
}
private readonly MemberAndDeclarationInfo _member;
private readonly DynamicFlagsMap _dynamicFlagsMap;
internal RootHiddenExpansion(MemberAndDeclarationInfo member, DynamicFlagsMap dynamicFlagsMap)
{
_member = member;
_dynamicFlagsMap = dynamicFlagsMap;
}
internal override void GetRows(
ResultProvider resultProvider,
ArrayBuilder<EvalResultDataItem> rows,
DkmInspectionContext inspectionContext,
EvalResultDataItem parent,
DkmClrValue value,
int startIndex,
int count,
bool visitAll,
ref int index)
{
var memberValue = value.GetMemberValue(_member, inspectionContext);
var isDynamicDebugViewEmptyException = memberValue.Type.GetLmrType().IsDynamicDebugViewEmptyException();
if (isDynamicDebugViewEmptyException || memberValue.IsError())
{
if (InRange(startIndex, count, index))
{
if (isDynamicDebugViewEmptyException)
{
var emptyMember = memberValue.Type.GetMemberByName("Empty");
memberValue = memberValue.GetMemberValue(emptyMember, inspectionContext);
}
var row = new EvalResultDataItem(Resources.ErrorName, (string)memberValue.HostObjectValue);
rows.Add(row);
}
index++;
}
else
{
parent = MemberExpansion.CreateMemberDataItem(
resultProvider,
inspectionContext,
_member,
memberValue,
parent,
_dynamicFlagsMap,
ExpansionFlags.IncludeBaseMembers | ExpansionFlags.IncludeResultsView);
var expansion = parent.Expansion;
if (expansion != null)
{
expansion.GetRows(resultProvider, rows, inspectionContext, parent, parent.Value, startIndex, count, visitAll, ref index);
}
}
}
}
}
......@@ -13,6 +13,7 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator
internal enum ExpansionKind
{
Default,
DynamicView,
Error,
NativeView,
NonPublicMembers,
......@@ -151,6 +152,12 @@ private static DkmEvaluationResultFlags GetFlags(DkmClrValue value, DkmInspectio
resultFlags |= DkmEvaluationResultFlags.RawString;
}
// As in the old EE, we won't allow editing members of a DynamicView expansion.
if (type.IsDynamicProperty())
{
resultFlags |= DkmEvaluationResultFlags.ReadOnly;
}
return resultFlags;
}
......
......@@ -270,6 +270,33 @@ internal static bool IsTypeVariables(this Type type)
return type.IsType(null, "<>c__TypeVariables");
}
internal static bool IsComObject(this Type type)
{
return type.IsType("System", "__ComObject");
}
internal static bool IsDynamicProperty(this Type type)
{
return type.IsType("Microsoft.CSharp.RuntimeBinder", "DynamicProperty");
}
internal static bool IsDynamicDebugViewEmptyException(this Type type)
{
return type.IsType("Microsoft.CSharp.RuntimeBinder", "DynamicDebugViewEmptyException");
}
internal static bool IsIDynamicMetaObjectProvider(this Type type)
{
foreach (var @interface in type.GetInterfaces())
{
if (@interface.IsType("System.Dynamic", "IDynamicMetaObjectProvider"))
{
return true;
}
}
return false;
}
/// <summary>
/// Returns type argument if the type is
/// Nullable&lt;T&gt;, otherwise null.
......@@ -669,5 +696,12 @@ internal static Type GetInterfaceListEntry(this Type interfaceType, Type declara
Debug.Assert(interfaceType.GetGenericTypeDefinition().Equals(result.GetGenericTypeDefinition()));
return result;
}
internal static MemberAndDeclarationInfo GetMemberByName(this DkmClrType type, string name)
{
var members = type.GetLmrType().GetMember(name, TypeHelpers.MemberBindingFlags);
Debug.Assert(members.Length == 1);
return new MemberAndDeclarationInfo(members[0], browsableState: null, info: DeclarationInfo.None, inheritanceLevel: 0);
}
}
}
......@@ -34,5 +34,11 @@ internal static string GetExceptionMessage(this DkmClrValue value, string fullNa
fullNameWithoutFormatSpecifiers,
formatter.GetTypeName(new TypeAndCustomInfo(value.Type)));
}
internal static DkmClrValue GetMemberValue(this DkmClrValue value, MemberAndDeclarationInfo member, DkmInspectionContext inspectionContext)
{
// Note: GetMemberValue() may return special value when func-eval of properties is disabled.
return value.GetMemberValue(member.Name, (int)member.MemberType, member.DeclaringType.FullName, inspectionContext);
}
}
}
......@@ -11,8 +11,8 @@
namespace Microsoft.CodeAnalysis.ExpressionEvaluator {
using System;
using System.Reflection;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
......@@ -61,6 +61,33 @@ internal class Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Dynamic View.
/// </summary>
internal static string DynamicView {
get {
return ResourceManager.GetString("DynamicView", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Only COM or Dynamic objects can have Dynamic View.
/// </summary>
internal static string DynamicViewNotDynamic {
get {
return ResourceManager.GetString("DynamicViewNotDynamic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Expanding the Dynamic View will get the dynamic members for the object.
/// </summary>
internal static string DynamicViewValueWarning {
get {
return ResourceManager.GetString("DynamicViewValueWarning", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error.
/// </summary>
......@@ -161,7 +188,7 @@ internal class Resources {
}
/// <summary>
/// Looks up a localized string similar to Shared Members.
/// Looks up a localized string similar to Shared members.
/// </summary>
internal static string SharedMembers {
get {
......@@ -170,7 +197,7 @@ internal class Resources {
}
/// <summary>
/// Looks up a localized string similar to Static Members.
/// Looks up a localized string similar to Static members.
/// </summary>
internal static string StaticMembers {
get {
......
......@@ -117,6 +117,18 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="DynamicView" xml:space="preserve">
<value>Dynamic View</value>
<comment>IDynamicMetaObjectProvider and System.__ComObject expansion</comment>
</data>
<data name="DynamicViewNotDynamic" xml:space="preserve">
<value>Only COM or Dynamic objects can have Dynamic View</value>
<comment>Cannot use "dynamic" format specifier on a non-dynamic type</comment>
</data>
<data name="DynamicViewValueWarning" xml:space="preserve">
<value>Expanding the Dynamic View will get the dynamic members for the object</value>
<comment>Warning reported in Dynamic View value</comment>
</data>
<data name="ErrorName" xml:space="preserve">
<value>Error</value>
<comment>Error result name</comment>
......@@ -161,14 +173,14 @@
<value>Expanding the Results View will enumerate the IEnumerable</value>
<comment>Warning reported in Results View value</comment>
</data>
<data name="SharedMembers" xml:space="preserve">
<value>Shared members</value>
<comment>Shared type members (VB only)</comment>
</data>
<data name="StaticMembers" xml:space="preserve">
<value>Static members</value>
<comment>Static type members (C# only)</comment>
</data>
<data name="SharedMembers" xml:space="preserve">
<value>Shared members</value>
<comment>Shared type members (VB only)</comment>
</data>
<data name="StaticMembers" xml:space="preserve">
<value>Static members</value>
<comment>Static type members (C# only)</comment>
</data>
<data name="TypeVariablesName" xml:space="preserve">
<value>Type variables</value>
<comment>Type variables result name</comment>
......
......@@ -229,14 +229,15 @@ private void CreateEvaluationResultAndContinue(EvalResultDataItem dataItem, Work
ExternalModules: null,
DataItem: dataItem));
break;
case ExpansionKind.DynamicView:
case ExpansionKind.ResultsView:
completionRoutine(DkmSuccessEvaluationResult.Create(
inspectionContext,
stackFrame,
Name: dataItem.Name,
FullName: dataItem.FullName,
Flags: dataItem.Flags,
Value: Resources.ResultsViewValueWarning,
dataItem.Name,
dataItem.FullName,
dataItem.Flags,
dataItem.DisplayValue,
EditableValue: null,
Type: string.Empty,
Category: DkmEvaluationResultCategory.Method,
......@@ -516,14 +517,28 @@ private static string GetTypeName(DkmInspectionContext inspectionContext, DkmClr
else if ((inspectionContext.EvaluationFlags & DkmEvaluationFlags.ResultsOnly) != 0)
{
var dataItem = ResultsViewExpansion.CreateResultsOnlyRow(
inspectionContext,
name,
declaredType,
declaredTypeInfo,
value,
inspectionContext,
name,
declaredType,
declaredTypeInfo,
value,
this.Formatter);
CreateEvaluationResultAndContinue(
dataItem,
workList,
inspectionContext,
value.StackFrame,
completionRoutine);
}
else if ((inspectionContext.EvaluationFlags & DkmEvaluationFlags.DynamicView) != 0)
{
var dataItem = DynamicViewExpansion.CreateMembersOnlyRow(
inspectionContext,
name,
value,
this.Formatter);
CreateEvaluationResultAndContinue(
dataItem,
dataItem,
workList,
inspectionContext,
value.StackFrame,
......@@ -532,11 +547,11 @@ private static string GetTypeName(DkmInspectionContext inspectionContext, DkmClr
else
{
var dataItem = ResultsViewExpansion.CreateResultsOnlyRowIfSynthesizedEnumerable(
inspectionContext,
name,
declaredType,
declaredTypeInfo,
value,
inspectionContext,
name,
declaredType,
declaredTypeInfo,
value,
this.Formatter);
if (dataItem != null)
{
......
......@@ -9,6 +9,7 @@
<Import_RootNamespace>ResultProvider</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Expansion\RootHiddenExpansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Formatter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Formatter.TypeNames.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Formatter.Values.cs" />
......@@ -21,6 +22,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Expansion\AggregateExpansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Expansion\ArrayExpansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Expansion\DebuggerTypeProxyExpansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Expansion\DynamicViewExpansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Expansion\Expansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Expansion\MemberExpansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Expansion\NativeViewExpansion.cs" />
......
......@@ -16,6 +16,7 @@
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.ComponentInterfaces;
using Microsoft.VisualStudio.Debugger.Metadata;
using Microsoft.VisualStudio.Debugger.Symbols;
using Roslyn.Utilities;
using Type = Microsoft.VisualStudio.Debugger.Metadata.Type;
using TypeCode = Microsoft.VisualStudio.Debugger.Metadata.TypeCode;
......@@ -240,18 +241,31 @@ public void EvaluateDebuggerDisplayString(DkmWorkList workList, DkmInspectionCon
string name = formatString.Substring(openPos + 1, i - openPos - 1);
openPos = -1;
// Ignore any format specifiers.
var formatSpecifers = Formatter.NoFormatSpecifiers;
int commaIndex = name.IndexOf(',');
if (commaIndex >= 0)
{
var rawFormatSpecifiers = name.Substring(commaIndex + 1).Split(',');
var trimmedFormatSpecifiers = ArrayBuilder<string>.GetInstance(rawFormatSpecifiers.Length);
trimmedFormatSpecifiers.AddRange(rawFormatSpecifiers.Select(fs => fs.Trim()));
formatSpecifers = trimmedFormatSpecifiers.ToImmutableAndFree();
foreach (var formatSpecifier in formatSpecifers)
{
if (formatSpecifier == "nq")
{
inspectionContext = new DkmInspectionContext(_formatter, inspectionContext.EvaluationFlags | DkmEvaluationFlags.NoQuotes, inspectionContext.Radix, inspectionContext.RuntimeInstance);
}
// If we need to support additional format specifiers, add them here...
}
name = name.Substring(0, commaIndex);
}
var type = ((TypeImpl)this.Type.GetLmrType()).Type;
const System.Reflection.BindingFlags bindingFlags =
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance |
const System.Reflection.BindingFlags bindingFlags =
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Static;
DkmClrValue exprValue;
......@@ -324,7 +338,7 @@ public void EvaluateDebuggerDisplayString(DkmWorkList workList, DkmInspectionCon
}
}
builder.Append(exprValue.GetValueString(inspectionContext, Formatter.NoFormatSpecifiers)); // Re-enter the formatter.
builder.Append(exprValue.GetValueString(inspectionContext, formatSpecifers)); // Re-enter the formatter.
}
else if (openPos < 0)
{
......@@ -607,6 +621,24 @@ public DkmClrValue InstantiateProxyType(DkmInspectionContext inspectionContext,
valueFlags: DkmClrValueFlags.None);
}
private static readonly ReadOnlyCollection<DkmClrType> s_noArguments = ArrayBuilder<DkmClrType>.GetInstance(0).ToImmutableAndFree();
public DkmClrValue InstantiateDynamicViewProxy(DkmInspectionContext inspectionContext)
{
if (inspectionContext == null)
{
throw new ArgumentNullException("inspectionContext");
}
var module = new DkmClrModuleInstance(
this.Type.AppDomain.RuntimeInstance,
typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly,
new DkmModule("Microsoft.CSharp.dll"));
var proxyType = module.ResolveTypeName(
"Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView",
s_noArguments);
return this.InstantiateProxyType(inspectionContext, proxyType);
}
public DkmClrValue InstantiateResultsViewProxy(DkmInspectionContext inspectionContext, DkmClrType enumerableType)
{
if (EvalFlags.Includes(DkmEvaluationResultFlags.ExceptionThrown))
......@@ -648,7 +680,6 @@ public DkmClrValue InstantiateResultsViewProxy(DkmInspectionContext inspectionCo
private static DkmClrModuleInstance GetModule(DkmClrAppDomain appDomain, string moduleName)
{
var modules = appDomain.GetClrModuleInstances();
Debug.Assert(modules.Length > 0);
foreach (var module in modules)
{
if (string.Equals(module.Name, moduleName, StringComparison.OrdinalIgnoreCase))
......
......@@ -17,6 +17,7 @@ public enum DkmEvaluationFlags
NoFormatting = 2048,
NoRawView = 4096, // Not used in managed debugging
NoQuotes = 8192,
DynamicView = 16384,
ResultsOnly = 32768,
NoExpansion = 65536,
}
......
......@@ -22,6 +22,7 @@
</PropertyGroup>
<ItemGroup Label="File References">
<Reference Include="$(OutDir)Microsoft.VisualStudio.Debugger.Metadata.dll" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Collections.Immutable">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.$(SystemCollectionsImmutableVersion)\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
......
......@@ -19,6 +19,8 @@
<RemoveIntegerChecks>true</RemoveIntegerChecks>
<RestorePackages>true</RestorePackages>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<VBRuntime>
</VBRuntime>
</PropertyGroup>
<ItemGroup Label="File References">
<Reference Include="$(OutDir)Microsoft.VisualStudio.Debugger.Metadata.dll" />
......@@ -80,6 +82,7 @@
</Compile>
<Compile Include="ArrayExpansionTests.vb" />
<Compile Include="DebuggerTypeProxyAttributeTests.vb" />
<Compile Include="DynamicViewTests.vb" />
<Compile Include="ExpansionTests.vb" />
<Compile Include="FormatSpecifierTests.vb" />
<Compile Include="FullNameTests.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Option Strict Off
Imports System.Dynamic
Imports Microsoft.CodeAnalysis.ExpressionEvaluator
Imports Microsoft.VisualStudio.Debugger.Clr
Imports Microsoft.VisualStudio.Debugger.Evaluation
Imports Xunit
Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Public Class DynamicViewTests : Inherits VisualBasicResultProviderTestBase
<Fact>
Public Sub MultipleMembers()
Dim expression = "o"
Dim o As Object = New ExpandoObject()
o.Philosophers = New Object() {"Pythagoras", "Lucretius", "Zeno"}
o.WhatsForDinner = "Crab Cakes"
o.NumForks = 2
Dim type = New DkmClrType(CType(o.GetType(), TypeImpl))
Dim value = CreateDkmClrValue(o, type)
Dim result = FormatResult(expression, value)
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable))
Dim dynamicView = GetChildren(result).Last()
Verify(dynamicView,
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", "o, dynamic", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly))
Verify(GetChildren(dynamicView),
EvalResult("NumForks", "2", "System.Int32", "New Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items(0)", DkmEvaluationResultFlags.ReadOnly),
EvalResult("Philosophers", "{Length=3}", "System.Object[]", "New Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items(1)", DkmEvaluationResultFlags.ReadOnly),
EvalResult("WhatsForDinner", """Crab Cakes""", "System.String", "New Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items(2)", DkmEvaluationResultFlags.ReadOnly))
End Sub
<Fact>
Public Sub MultipleExpansions()
Dim expression = "o"
Dim o As Object = New ExpandoObject()
o.Answer = 42
Dim type = New DkmClrType(CType(o.GetType(), TypeImpl))
Dim value = CreateDkmClrValue(o, type)
' Dynamic View should appear after all other expansions.
Dim result = FormatResult(expression, value)
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable))
Verify(GetChildren(result),
EvalResult("[Class]", "{System.Dynamic.ExpandoClass}", "System.Dynamic.ExpandoClass", "o.[Class]", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Internal),
EvalResult("LockObject", "{Object}", "Object", "o.LockObject", DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Data, DkmEvaluationResultAccessType.Internal),
EvalResult("System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of String, Object)).Count", "1", "Integer", "((System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of String, Object)))o).Count", DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Private),
EvalResult("System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of String, Object)).IsReadOnly", "False", "Boolean", "((System.Collections.Generic.ICollection(Of System.Collections.Generic.KeyValuePair(Of String, Object)))o).IsReadOnly", DkmEvaluationResultFlags.Boolean Or DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Private),
EvalResult("System.Collections.Generic.IDictionary(Of String, Object).Keys", "Count = 1", "System.Collections.Generic.ICollection(Of String) {System.Dynamic.ExpandoObject.KeyCollection}", "((System.Collections.Generic.IDictionary(Of String, Object))o).Keys", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Private),
EvalResult("System.Collections.Generic.IDictionary(Of String, Object).Values", "Count = 1", "System.Collections.Generic.ICollection(Of Object) {System.Dynamic.ExpandoObject.ValueCollection}", "((System.Collections.Generic.IDictionary(Of String, Object))o).Values", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Property, DkmEvaluationResultAccessType.Private),
EvalResult("_count", "1", "Integer", "o._count", category:=DkmEvaluationResultCategory.Data, access:=DkmEvaluationResultAccessType.Private),
EvalResult("_data", "{System.Dynamic.ExpandoObject.ExpandoData}", "System.Dynamic.ExpandoObject.ExpandoData", "o._data", DkmEvaluationResultFlags.Expandable, DkmEvaluationResultCategory.Data, DkmEvaluationResultAccessType.Private),
EvalResult("_propertyChanged", "Nothing", "System.ComponentModel.PropertyChangedEventHandler", "o._propertyChanged", category:=DkmEvaluationResultCategory.Data, access:=DkmEvaluationResultAccessType.Private),
EvalResult(Resources.SharedMembers, Nothing, "", "System.Dynamic.ExpandoObject", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Class),
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", "o, dynamic", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly))
End Sub
<Fact>
Public Sub ExceptionTypeMember()
Dim expression = "o"
Dim o As Object = New ExpandoObject()
Dim exception = New NotImplementedException()
o.Member = exception
Dim type = New DkmClrType(CType(o.GetType(), TypeImpl))
Dim value = CreateDkmClrValue(o, type)
Dim result = FormatResult(expression, value)
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable))
Dim dynamicView = GetChildren(result).Last()
Verify(dynamicView,
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", "o, dynamic", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly))
Verify(GetChildren(dynamicView),
EvalResult("Member", $"{{{exception.ToString()}}}", "System.NotImplementedException", "New Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items(0)", DkmEvaluationResultFlags.ReadOnly))
End Sub
<Fact>
Public Sub DynamicTypeMember()
Dim expression = "o"
Dim o As Object = New ExpandoObject()
o.Pi = Math.PI
o.OnAndOn = o
Dim type = New DkmClrType(CType(o.GetType(), TypeImpl))
Dim value = CreateDkmClrValue(o, type)
Dim result = FormatResult(expression, value)
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable))
Dim members = GetChildren(result)
Dim fullNameOnAndOn = "o"
Dim fullNamePi = "o"
' Expand 3 levels...
For i = 1 To 3
Dim dynamicView = members.Last()
Verify(dynamicView,
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", $"{fullNameOnAndOn}, dynamic", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly))
members = GetChildren(dynamicView)
fullNamePi = $"New Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView({fullNameOnAndOn}).Items(1)"
fullNameOnAndOn = $"New Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView({fullNameOnAndOn}).Items(0)"
Verify(members,
EvalResult("OnAndOn", "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", fullNameOnAndOn, DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly),
EvalResult("Pi", "3.1415926535897931", "System.Double", fullNamePi, DkmEvaluationResultFlags.ReadOnly))
members = GetChildren(members(0))
Next
End Sub
<Fact>
Public Sub NoMembers()
Dim expression = "o"
Dim o As Object = New ExpandoObject()
Dim type = New DkmClrType(CType(o.GetType(), TypeImpl))
Dim value = CreateDkmClrValue(o, type)
Dim result = FormatResult(expression, value)
Verify(result,
EvalResult(expression, "{System.Dynamic.ExpandoObject}", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable))
Dim dynamicView = GetChildren(result).Last()
Verify(dynamicView,
EvalResult(Resources.DynamicView, Resources.DynamicViewValueWarning, "", "o, dynamic", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly))
Verify(GetChildren(dynamicView),
EvalFailedResult(Resources.ErrorName, "No further information on this object could be discovered"))
End Sub
<Fact>
Public Sub NullComObject()
Dim comObjectTypeName = "System.__ComObject"
Dim expression = $"DirectCast(Nothing, {comObjectTypeName})"
Dim type = New DkmClrType(CType(GetType(Object).Assembly.GetType(comObjectTypeName), TypeImpl))
Dim value = CreateDkmClrValue(Nothing, type)
Dim result = FormatResult(expression, value)
Verify(result,
EvalResult(expression, "Nothing", comObjectTypeName, expression))
result = FormatResult(expression, expression + ",dynamic", value, inspectionContext:=CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView))
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic))
End Sub
<Fact>
Public Sub NullIDynamicMetaObjectProvider()
Dim expression = "o"
Dim type = New DkmClrType(CType(GetType(IDynamicMetaObjectProvider), TypeImpl))
Dim value = CreateDkmClrValue(Nothing, type)
Dim result = FormatResult(expression, value)
Verify(result,
EvalResult(expression, "Nothing", "System.Dynamic.IDynamicMetaObjectProvider", expression))
result = FormatResult(expression, expression + ",dynamic", value, inspectionContext:=CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView))
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic))
End Sub
<Fact>
Public Sub NullDynamicObject()
Dim expression = "o"
Dim type = New DkmClrType(CType(GetType(ExpandoObject), TypeImpl))
Dim value = CreateDkmClrValue(Nothing, type)
Dim result = FormatResult(expression, value)
Verify(result,
EvalResult(expression, "Nothing", "System.Dynamic.ExpandoObject", expression, DkmEvaluationResultFlags.Expandable))
Verify(GetChildren(result),
EvalResult(Resources.SharedMembers, Nothing, "", "System.Dynamic.ExpandoObject", DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Class))
result = FormatResult(expression, expression + ",dynamic", value, inspectionContext:=CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView))
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic))
End Sub
<Fact>
Public Sub DynamicTypeError()
Dim expression = "o"
Dim obj = New ExpandoObject()
' Verify that things *work* in this scenario if there was no error in member access.
Dim value = CreateDkmClrValue(obj)
Dim fullName = expression + ", dynamic"
Dim result = FormatResult(expression, fullName, value, inspectionContext:=CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView))
Verify(result,
EvalResult(expression, Resources.DynamicViewValueWarning, "", fullName, DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly))
' Verify no Dynamic View if member access is changed to result in an error.
Dim runtime = New DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlibAndSystemCore())
value = CreateErrorValue(runtime.GetType(obj.GetType()), "Function evaluation timed out")
result = FormatResult(expression, fullName, value, inspectionContext:=CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView))
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic))
End Sub
<Fact>
Public Sub DynamicMetaObjectProviderDebugViewItemsError()
Dim expression = "o"
Dim o As Object = New ExpandoObject()
o.Answer = 42
Dim runtime As DkmClrRuntimeInstance = Nothing
runtime = New DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(),
getMemberValue:=Function(v, m) If(m = "Items", CreateErrorValue(runtime.GetType(GetType(Array)), "Function evaluation timed out"), Nothing))
Dim type = New DkmClrType(runtime, CType(o.GetType(), TypeImpl))
Dim value = CreateDkmClrValue(o, type)
Dim fullName = expression + ", dynamic"
Dim result = FormatResult(expression, fullName, value, inspectionContext:=CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView))
Verify(result,
EvalResult(expression, Resources.DynamicViewValueWarning, "", fullName, DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly))
Verify(GetChildren(result),
EvalFailedResult(Resources.ErrorName, "Function evaluation timed out"))
End Sub
<Fact>
Public Sub DynamicFormatSpecifier()
Dim expression = "o"
Dim o As Object = New ExpandoObject()
o.Answer = 42
Dim type = New DkmClrType(CType(o.GetType(), TypeImpl))
Dim value = CreateDkmClrValue(o, type)
Dim fullName = expression + ", dynamic"
Dim result = FormatResult(expression, fullName, value, inspectionContext:=CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView))
Verify(result,
EvalResult(expression, Resources.DynamicViewValueWarning, "", fullName, DkmEvaluationResultFlags.Expandable Or DkmEvaluationResultFlags.ReadOnly))
Verify(GetChildren(result),
EvalResult("Answer", "42", "System.Int32", "New Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(o).Items(0)", DkmEvaluationResultFlags.ReadOnly))
End Sub
<Fact>
Public Sub DynamicFormatSpecifierError()
Dim expression = "o"
Dim o = New Object()
Dim type = New DkmClrType(CType(o.GetType(), TypeImpl))
Dim value = CreateDkmClrValue(o, type)
Dim result = FormatResult(expression, expression + ",dynamic", value, inspectionContext:=CreateDkmInspectionContext(DkmEvaluationFlags.DynamicView))
Verify(result,
EvalFailedResult(expression, Resources.DynamicViewNotDynamic))
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册