提交 69b40cea 编写于 作者: C Charles Stoner

Include all tuple elements when expanding in the EE

上级 54e58b99
......@@ -58,10 +58,15 @@ public void EncodeAndDecode()
var encoded = CustomTypeInfo.Encode(null, null);
Assert.Null(encoded);
var bytes = GetBytesInRange(0, 256);
ReadOnlyCollection<byte> bytes;
ReadOnlyCollection<string> names;
// Exceed max bytes.
bytes = GetBytesInRange(0, 256);
encoded = CustomTypeInfo.Encode(bytes, null);
Assert.Null(encoded);
// Max bytes.
bytes = GetBytesInRange(0, 255);
encoded = CustomTypeInfo.Encode(bytes, null);
Assert.Equal(256, encoded.Count);
......@@ -72,13 +77,59 @@ public void EncodeAndDecode()
Assert.Equal(bytes, dynamicFlags);
Assert.Null(tupleElementNames);
var names = new ReadOnlyCollection<string>(new[] { null, "A", null, "B" });
// Empty dynamic flags collection
bytes = new ReadOnlyCollection<byte>(new byte[0]);
// ... with names.
names = new ReadOnlyCollection<string>(new[] { "A" });
encoded = CustomTypeInfo.Encode(bytes, names);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Null(dynamicFlags);
Assert.Equal(names, tupleElementNames);
// ... without names.
encoded = CustomTypeInfo.Encode(bytes, null);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Null(dynamicFlags);
Assert.Null(tupleElementNames);
// Empty names collection
names = new ReadOnlyCollection<string>(new string[0]);
// ... with dynamic flags.
bytes = GetBytesInRange(0, 255);
encoded = CustomTypeInfo.Encode(bytes, names);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Equal(bytes, dynamicFlags);
Assert.Null(tupleElementNames);
// ... without dynamic flags.
encoded = CustomTypeInfo.Encode(null, names);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Null(dynamicFlags);
Assert.Null(tupleElementNames);
// Single null name
names = new ReadOnlyCollection<string>(new string[] { null });
// ... with dynamic flags.
bytes = GetBytesInRange(0, 255);
encoded = CustomTypeInfo.Encode(bytes, names);
Assert.Equal(255, encoded[0]);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Equal(bytes, dynamicFlags);
Assert.Equal(names, tupleElementNames);
// ... without dynamic flags.
encoded = CustomTypeInfo.Encode(null, names);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Null(dynamicFlags);
Assert.Equal(names, tupleElementNames);
// Multiple names
names = new ReadOnlyCollection<string>(new[] { null, "A", null, "B" });
// ... with dynamic flags.
bytes = GetBytesInRange(0, 255);
encoded = CustomTypeInfo.Encode(bytes, names);
Assert.Equal(255, encoded[0]);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Equal(bytes, dynamicFlags);
Assert.Equal(names, tupleElementNames);
// ... without dynamic flags.
encoded = CustomTypeInfo.Encode(null, names);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Null(dynamicFlags);
......
......@@ -4,6 +4,7 @@
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
......@@ -70,12 +71,14 @@ internal static DkmClrCustomTypeInfo SkipOne(DkmClrCustomTypeInfo customInfo)
internal static string GetTupleElementNameIfAny(ReadOnlyCollection<string> tupleElementNames, int index)
{
return tupleElementNames?[index];
return tupleElementNames != null && index < tupleElementNames.Count ?
tupleElementNames[index] :
null;
}
// Encode in payload as a sequence of bytes {count}{dynamicFlags}{tupleNames}
// where {count} is a byte of the number of bytes in {dynamicFlags} (max: 8*256 bits)
// and {tupleNames} is a UTF8 encoded string of the names separated by '|'.
// and {tupleNames} is a UTF8 encoded string of the names each preceded by '|'.
internal static ReadOnlyCollection<byte> Encode(
ReadOnlyCollection<byte> dynamicFlags,
ReadOnlyCollection<string> tupleElementNames)
......@@ -143,22 +146,7 @@ internal static string GetTupleElementNameIfAny(ReadOnlyCollection<string> tuple
private static ReadOnlyCollection<byte> EncodeNames(ReadOnlyCollection<string> names)
{
var pooledBuilder = PooledStringBuilder.GetInstance();
var builder = pooledBuilder.Builder;
bool any = false;
foreach (var name in names)
{
if (any)
{
builder.Append(NameSeparator);
}
if (name != null)
{
builder.Append(name);
}
any = true;
}
var str = pooledBuilder.ToStringAndFree();
var str = JoinNames(names);
return new ReadOnlyCollection<byte>(Encoding.UTF8.GetBytes(str));
}
......@@ -167,41 +155,54 @@ private static ReadOnlyCollection<string> DecodeNames(ReadOnlyCollection<byte> b
int length = bytes.Count - start;
var array = CopyBytes(bytes, start, length);
var str = Encoding.UTF8.GetString(array, 0, length);
return new ReadOnlyCollection<string>(NullNotEmpty(str.Split(NameSeparator)));
return SplitNames(str);
}
private static byte[] CopyBytes(ReadOnlyCollection<byte> bytes, int start, int length)
private static string JoinNames(ReadOnlyCollection<string> names)
{
var array = new byte[length];
for (int i = 0; i < length; i++)
var pooledBuilder = PooledStringBuilder.GetInstance();
var builder = pooledBuilder.Builder;
foreach (var name in names)
{
array[i] = bytes[start + i];
builder.Append(NameSeparator);
if (name != null)
{
builder.Append(name);
}
}
return array;
return pooledBuilder.ToStringAndFree();
}
private static string[] NullNotEmpty(string[] names)
private static ReadOnlyCollection<string> SplitNames(string str)
{
var builder = ArrayBuilder<string>.GetInstance(names.Length);
bool hasNull = false;
foreach (var name in names)
Debug.Assert(str != null);
Debug.Assert(str.Length > 0);
Debug.Assert(str[0] == NameSeparator);
var builder = ArrayBuilder<string>.GetInstance();
int offset = 1;
int n = str.Length;
while (true)
{
if (string.IsNullOrEmpty(name))
{
hasNull = true;
builder.Add(null);
}
else
int next = str.IndexOf(NameSeparator, offset);
var name = (next < 0) ? str.Substring(offset) : str.Substring(offset, next - offset);
builder.Add((name.Length == 0) ? null : name);
if (next < 0)
{
builder.Add(name);
break;
}
offset = next + 1;
}
if (hasNull)
return new ReadOnlyCollection<string>(builder.ToArrayAndFree());
}
private static byte[] CopyBytes(ReadOnlyCollection<byte> bytes, int start, int length)
{
var array = new byte[length];
for (int i = 0; i < length; i++)
{
names = builder.ToArray();
array[i] = bytes[start + i];
}
builder.Free();
return names;
return array;
}
}
}
......@@ -138,7 +138,7 @@ private static string GetFullName(DkmInspectionContext inspectionContext, EvalRe
if (parent.ChildShouldParenthesize)
{
parentFullName = $"({parentFullName})";
parentFullName = parentFullName.Parenthesize();
}
var parentRuntimeType = parent.Value.Type;
if (!parent.DeclaredTypeAndInfo.Type.Equals(parentRuntimeType.GetLmrType()))
......
......@@ -130,6 +130,9 @@ internal sealed class MemberExpansion : Expansion
expansions.Add(staticMembersExpansion);
}
instanceMembers.Free();
staticMembers.Free();
if (value.NativeComPointer != 0)
{
expansions.Add(NativeViewExpansion.Instance);
......@@ -478,7 +481,7 @@ internal StaticMembersExpansion(DkmClrType type, Expansion members)
if (parent.ChildShouldParenthesize)
{
parentFullName = $"({parentFullName})";
parentFullName = parentFullName.Parenthesize();
}
var typeDeclaringMember = typeDeclaringMemberAndInfo.Type;
......
// 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 Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.ComponentInterfaces;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using FieldInfo = Microsoft.VisualStudio.Debugger.Metadata.FieldInfo;
using Type = Microsoft.VisualStudio.Debugger.Metadata.Type;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal sealed class TupleExpansion : Expansion
{
internal static TupleExpansion CreateExpansion(DkmClrValue value, TypeAndCustomInfo declaredTypeAndInfo, int cardinality)
{
if (value.IsNull)
{
// No expansion.
return null;
}
return new TupleExpansion(new TypeAndCustomInfo(value.Type, declaredTypeAndInfo.Info), cardinality);
}
private readonly TypeAndCustomInfo _typeAndInfo;
private readonly int _cardinality;
private ReadOnlyCollection<Field> _lazyFields;
private TupleExpansion(TypeAndCustomInfo typeAndInfo, int cardinality)
{
_typeAndInfo = typeAndInfo;
_cardinality = cardinality;
}
internal override void GetRows(
ResultProvider resultProvider,
ArrayBuilder<EvalResult> rows,
DkmInspectionContext inspectionContext,
EvalResultDataItem parent,
DkmClrValue value,
int startIndex,
int count,
bool visitAll,
ref int index)
{
var fields = GetFields();
int startIndex2;
int count2;
GetIntersection(startIndex, count, index, fields.Count, out startIndex2, out count2);
int offset = startIndex2 - index;
for (int i = 0; i < count2; i++)
{
var row = GetMemberRow(resultProvider, inspectionContext, value, fields[i + offset], parent);
rows.Add(row);
}
index += fields.Count;
}
private static EvalResult GetMemberRow(
ResultProvider resultProvider,
DkmInspectionContext inspectionContext,
DkmClrValue value,
Field field,
EvalResultDataItem parent)
{
var fullNameProvider = resultProvider.FullNameProvider;
var parentFullName = parent.ChildFullNamePrefix;
if (parentFullName != null)
{
if (parent.ChildShouldParenthesize)
{
parentFullName = parentFullName.Parenthesize();
}
var parentRuntimeType = parent.Value.Type;
if (!parent.DeclaredTypeAndInfo.Type.Equals(parentRuntimeType.GetLmrType()))
{
parentFullName = fullNameProvider.GetClrCastExpression(inspectionContext, parentFullName, parentRuntimeType, customTypeInfo: null, parenthesizeArgument: false, parenthesizeEntireExpression: true);
}
}
// Ideally if the caller requests multiple items in a nested tuple
// we should only evaluate Rest once, and should only calculate
// the full name for Rest once.
string fullName;
var fieldValue = GetValueAndFullName(
fullNameProvider,
inspectionContext,
value,
field,
parentFullName,
out fullName);
return resultProvider.CreateDataItem(
inspectionContext,
field.Name,
typeDeclaringMemberAndInfo: default(TypeAndCustomInfo),
declaredTypeAndInfo: field.FieldTypeAndInfo,
value: fieldValue,
useDebuggerDisplay: false,
expansionFlags: ExpansionFlags.All,
childShouldParenthesize: false,
fullName: fullName,
formatSpecifiers: Formatter.NoFormatSpecifiers,
category: DkmEvaluationResultCategory.Other,
flags: fieldValue.EvalFlags,
evalFlags: DkmEvaluationFlags.None);
}
private static DkmClrValue GetValueAndFullName(
IDkmClrFullNameProvider fullNameProvider,
DkmInspectionContext inspectionContext,
DkmClrValue value,
Field field,
string parentFullName,
out string fullName)
{
var parent = field.Parent;
if (parent != null)
{
value = GetValueAndFullName(
fullNameProvider,
inspectionContext,
value,
parent,
parentFullName,
out parentFullName);
}
var fieldName = field.FieldInfo.Name;
fullName = (parentFullName == null) ?
null :
fullNameProvider.GetClrMemberName(
inspectionContext,
parentFullName,
declaringType: field.DeclaringTypeAndInfo.ClrType,
declaringTypeInfo: null,
memberName: fieldName,
memberAccessRequiresExplicitCast: false,
memberIsStatic: false);
return value.GetFieldValue(fieldName, inspectionContext);
}
private sealed class Field
{
internal readonly TypeAndCustomInfo DeclaringTypeAndInfo;
internal readonly TypeAndCustomInfo FieldTypeAndInfo;
internal readonly FieldInfo FieldInfo; // type field
internal readonly string Name;
internal readonly Field Parent; // parent Rest field, if any
internal Field(
TypeAndCustomInfo declaringTypeAndInfo,
TypeAndCustomInfo fieldTypeAndInfo,
FieldInfo fieldInfo,
string name,
Field parent)
{
Debug.Assert(declaringTypeAndInfo.ClrType != null);
Debug.Assert(fieldTypeAndInfo.ClrType != null);
Debug.Assert(fieldInfo != null);
Debug.Assert(name != null);
Debug.Assert(declaringTypeAndInfo.Type.Equals(fieldInfo.DeclaringType));
Debug.Assert(fieldTypeAndInfo.Type.Equals(fieldInfo.FieldType));
Debug.Assert(parent == null || parent.FieldInfo.FieldType.Equals(fieldInfo.DeclaringType));
DeclaringTypeAndInfo = declaringTypeAndInfo;
FieldTypeAndInfo = fieldTypeAndInfo;
FieldInfo = fieldInfo;
Name = name;
Parent = parent;
}
}
private ReadOnlyCollection<Field> GetFields()
{
if (_lazyFields == null)
{
_lazyFields = GetFields(_typeAndInfo, _cardinality);
}
return _lazyFields;
}
private static ReadOnlyCollection<Field> GetFields(TypeAndCustomInfo declaringTypeAndInfo, int cardinality)
{
Debug.Assert(declaringTypeAndInfo.Type.GetTupleCardinalityIfAny() == cardinality);
var appDomain = declaringTypeAndInfo.ClrType.AppDomain;
var customTypeInfoMap = CustomTypeInfoTypeArgumentMap.Create(declaringTypeAndInfo);
var tupleElementNames = customTypeInfoMap.TupleElementNames;
var builder = ArrayBuilder<Field>.GetInstance();
Field parent = null;
int offset = 0;
while (true)
{
var declaringType = declaringTypeAndInfo.Type;
int n = Math.Min(cardinality, TypeHelpers.TupleFieldRestPosition - 1);
for (int index = 0; index < n; index++)
{
var fieldName = TypeHelpers.GetTupleFieldName(index);
var field = declaringType.GetTupleField(fieldName);
if (field == null)
{
// Ignore missing fields.
continue;
}
var fieldTypeAndInfo = GetTupleFieldTypeAndInfo(appDomain, field, customTypeInfoMap);
var name = CustomTypeInfo.GetTupleElementNameIfAny(tupleElementNames, offset + index);
if (name != null)
{
builder.Add(new Field(declaringTypeAndInfo, fieldTypeAndInfo, field, name, parent));
}
builder.Add(new Field(
declaringTypeAndInfo,
fieldTypeAndInfo,
field,
(offset == 0) ? fieldName : TypeHelpers.GetTupleFieldName(offset + index),
parent));
}
cardinality -= n;
if (cardinality == 0)
{
break;
}
var rest = declaringType.GetTupleField(TypeHelpers.TupleFieldRestName);
if (rest == null)
{
// Ignore remaining fields.
break;
}
var restTypeAndInfo = GetTupleFieldTypeAndInfo(appDomain, rest, customTypeInfoMap);
parent = new Field(declaringTypeAndInfo, restTypeAndInfo, rest, TypeHelpers.TupleFieldRestName, parent);
declaringTypeAndInfo = restTypeAndInfo;
offset += TypeHelpers.TupleFieldRestPosition - 1;
}
// If there were any nested ValueTuples,
// add the Rest field of the outermost.
if (parent != null)
{
while (parent.Parent != null)
{
parent = parent.Parent;
}
builder.Add(parent);
}
return builder.ToImmutableAndFree();
}
private static TypeAndCustomInfo GetTupleFieldTypeAndInfo(
DkmClrAppDomain appDomain,
FieldInfo field,
CustomTypeInfoTypeArgumentMap customTypeInfoMap)
{
var declaringTypeDef = field.DeclaringType.GetGenericTypeDefinition();
var fieldDef = declaringTypeDef.GetTupleField(field.Name);
var fieldType = DkmClrType.Create(appDomain, field.FieldType);
var fieldTypeInfo = customTypeInfoMap.SubstituteCustomTypeInfo(fieldDef.FieldType, null);
return new TypeAndCustomInfo(fieldType, fieldTypeInfo);
}
}
}
......@@ -106,11 +106,14 @@ private string GetValueString(DkmClrValue value, DkmInspectionContext inspection
if (lmrType.IsTupleCompatible(out cardinality) && (cardinality > 1))
{
var values = ArrayBuilder<string>.GetInstance();
value.GetTupleFieldValues(cardinality, values, inspectionContext);
return IncludeObjectId(
value,
GetTupleExpression(values.ToArrayAndFree()),
flags);
if (value.TryGetTupleFieldValues(cardinality, values, inspectionContext))
{
return IncludeObjectId(
value,
GetTupleExpression(values.ToArrayAndFree()),
flags);
}
values.Free();
}
}
......
......@@ -81,6 +81,8 @@ internal static CustomTypeInfoTypeArgumentMap Create(TypeAndCustomInfo typeAndIn
tupleElementNameStartIndices);
}
internal ReadOnlyCollection<string> TupleElementNames => _tupleElementNames;
internal DkmClrCustomTypeInfo SubstituteCustomTypeInfo(Type type, DkmClrCustomTypeInfo customInfo)
{
if (_typeDefinition == null)
......@@ -181,7 +183,6 @@ private static int[] GetStartIndices(Type type, GetIndexCount getIndexCount)
}
}
Debug.Assert(pos > 1);
startsBuilder.Add(pos);
return startsBuilder.ToArrayAndFree();
}
......
......@@ -350,7 +350,7 @@ internal static DkmClrValue GetNullableValue(this DkmClrValue value, DkmInspecti
internal const int TupleFieldRestPosition = 8;
private const string TupleTypeNamePrefix = "ValueTuple`";
private const string TupleFieldItemNamePrefix = "Item";
private const string TupleFieldRestName = "Rest";
internal const string TupleFieldRestName = "Rest";
// See NamedTypeSymbol.IsTupleCompatible.
internal static bool IsTupleCompatible(this Type type, out int cardinality)
......@@ -397,23 +397,46 @@ internal static int GetTupleCardinalityIfAny(this Type type)
return cardinality;
}
internal static void GetTupleFieldValues(this DkmClrValue tuple, int cardinality, ArrayBuilder<string> values, DkmInspectionContext inspectionContext)
internal static FieldInfo GetTupleField(this Type type, string name)
{
return type.GetField(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
}
internal static string GetTupleFieldName(int index)
{
Debug.Assert(index >= 0);
return TupleFieldItemNamePrefix + (index + 1);
}
internal static bool TryGetTupleFieldValues(this DkmClrValue tuple, int cardinality, ArrayBuilder<string> values, DkmInspectionContext inspectionContext)
{
while (true)
{
var type = tuple.Type.GetLmrType();
int n = Math.Min(cardinality, TupleFieldRestPosition - 1);
for (int i = 0; i < n; i++)
for (int index = 0; index < n; index++)
{
var value = GetFieldValue(tuple, TupleFieldItemNamePrefix + (i + 1), inspectionContext);
var fieldName = GetTupleFieldName(index);
var fieldInfo = type.GetTupleField(fieldName);
if (fieldInfo == null)
{
return false;
}
var value = tuple.GetFieldValue(fieldName, inspectionContext);
var str = value.GetValueString(inspectionContext, Formatter.NoFormatSpecifiers);
values.Add(str);
}
cardinality -= n;
if (cardinality == 0)
{
return;
return true;
}
var restInfo = type.GetTupleField(TypeHelpers.TupleFieldRestName);
if (restInfo == null)
{
return false;
}
tuple = GetFieldValue(tuple, TupleFieldRestName, inspectionContext);
tuple = tuple.GetFieldValue(TupleFieldRestName, inspectionContext);
}
}
......
......@@ -38,5 +38,10 @@ internal static DkmClrValue GetMemberValue(this DkmClrValue value, MemberAndDecl
// 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);
}
internal static string Parenthesize(this string expr)
{
return $"({expr})";
}
}
}
......@@ -948,6 +948,12 @@ private static string GetTypeName(DkmInspectionContext inspectionContext, DkmClr
flags &= ~ExpansionFlags.IncludeBaseMembers;
}
int cardinality;
if (runtimeType.IsTupleCompatible(out cardinality))
{
return TupleExpansion.CreateExpansion(value, declaredTypeAndInfo, cardinality);
}
return MemberExpansion.CreateExpansion(inspectionContext, declaredTypeAndInfo, value, flags, TypeHelpers.IsVisibleMember, this);
}
......
......@@ -10,6 +10,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Expansion\RootHiddenExpansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Expansion\TupleExpansion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Formatter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Formatter.TypeNames.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Formatter.Values.cs" />
......
......@@ -161,7 +161,8 @@ public override EventInfo[] GetEvents(BindingFlags flags)
public override FieldInfo GetField(string name, BindingFlags bindingAttr)
{
return new FieldInfoImpl(Type.GetField(name, (System.Reflection.BindingFlags)bindingAttr));
var field = Type.GetField(name, (System.Reflection.BindingFlags)bindingAttr);
return (field == null) ? null : new FieldInfoImpl(field);
}
public override FieldInfo[] GetFields(BindingFlags flags)
......
......@@ -35,6 +35,10 @@
<Project>{2523d0e6-df32-4a3e-8ae0-a19bffae2ef6}</Project>
<Name>BasicCodeAnalysis</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Compilers\CSharp\Portable\CSharpCodeAnalysis.csproj">
<Project>{b501a547-c911-4a05-ac6e-274a50dff30e}</Project>
<Name>CSharpCodeAnalysis</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Test\Utilities\Desktop\TestUtilities.Desktop.csproj">
<Project>{76C6F005-C89D-4348-BB4A-391898DBEB52}</Project>
<Name>TestUtilities.Desktop</Name>
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.CSharp
Imports Microsoft.CodeAnalysis.ExpressionEvaluator
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests
......@@ -41,7 +42,7 @@ End Class"
"o._17",
DkmEvaluationResultFlags.Expandable))
children = GetChildren(children(0))
Assert.Equal(8, children.Length) ' Should be 18. https://github.com/dotnet/roslyn/issues/13421
Assert.Equal(18, children.Length)
Dim child = children(children.Length - 1)
Verify(child,
EvalResult(
......@@ -51,7 +52,7 @@ End Class"
"o._17.Rest",
DkmEvaluationResultFlags.Expandable))
children = GetChildren(child)
Assert.Equal(8, children.Length) ' Should be 11. https://github.com/dotnet/roslyn/issues/13421
Assert.Equal(11, children.Length)
child = children(children.Length - 1)
Verify(child,
EvalResult(
......@@ -64,16 +65,17 @@ End Class"
End Sub
<WorkItem(13625, "https://github.com/dotnet/roslyn/issues/13625")>
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/12347")>
<Fact>
Public Sub Names_LongTuple()
Const source =
"Class C
Private F As (K As (A As Integer, D As (B As Integer, C As Integer), E As Integer, F As Integer, G As Integer, H As Integer, I As Integer, J As Integer), O As (L As Integer, M As Integer, N As Integer)) =
((1, (2, 3), 4, 5, 6, 7, 8, 9), (10, 11, 12))
End Class"
"class C
{
((int A, (int B, int C) D, int E, int F, int G, int H, int I, int J) K, (int L, int M, int N) O) F =
((1, (2, 3), 4, 5, 6, 7, 8, 9), (10, 11, 12));
}"
Dim assembly0 = GenerateTupleAssembly()
Dim reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference()
Dim compilation1 = CreateCompilationWithMscorlib({source}, options:=TestOptions.ReleaseDll, references:={reference0}, assemblyName:=GetUniqueName())
Dim compilation1 = CreateCSharpCompilation(source, references:={TestBase.MscorlibRef, TestBase.SystemCoreRef, reference0})
Dim assembly1 = compilation1.EmitToArray()
Dim runtime = New DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)))
Using runtime.Load()
......@@ -93,25 +95,27 @@ End Class"
End Using
End Sub
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/12347")>
<Fact>
Public Sub NamesFromTypeArguments()
Const source =
"Class A(Of T, U)
Private F As T
Private G() As U = New U() { }
End Class
Class B(Of T)
Friend Structure S
End Structure
Private F As (X As Object, Y As T)
End Class
Class C
Private F As New A(Of (A As Object, B As Object)(), (C As Object, D As Object()))()
Private G As New B(Of (E As Object, H As B(Of (F As Object, G As Object)).S))()
End Class"
"class A<T, U>
{
T F;
U[] G = new U[0];
}
class B<T>
{
internal struct S { }
(dynamic X, T Y) F = (null, default(T));
}
class C
{
A<(dynamic A, object B)[], (object C, dynamic[] D)> F = new A<(dynamic A, object B)[], (object, dynamic[])>();
B<(object E, B<(object F, dynamic G)>.S H)> G = new B<(object E, B<(object F, dynamic G)>.S H)>();
}"
Dim assembly0 = GenerateTupleAssembly()
Dim reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference()
Dim compilation1 = CreateCompilationWithMscorlib({source}, options:=TestOptions.ReleaseDll, references:={reference0}, assemblyName:=GetUniqueName())
Dim compilation1 = CreateCSharpCompilation(source, references:={TestBase.MscorlibRef, TestBase.SystemCoreRef, reference0})
Dim assembly1 = compilation1.EmitToArray()
Dim runtime = New DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)))
Using runtime.Load()
......@@ -120,7 +124,7 @@ End Class"
Dim result = FormatResult("o", value)
Dim children = GetChildren(result)
Verify(children,
EvalResult("F", "{A(Of (Object, Object)(), (Object, Object()))}", "A(Of (A As Object, B As Object)(), (Object, Object()))", "o.F", DkmEvaluationResultFlags.Expandable),
EvalResult("F", "{A(Of (Object, Object)(), (Object, Object()))}", "A(Of (A As Object, B As Object)(), (C As Object, D As Object()))", "o.F", DkmEvaluationResultFlags.Expandable),
EvalResult("G", "{B(Of (Object, B(Of (Object, Object)).S))}", "B(Of (E As Object, H As B(Of (F As Object, G As Object)).S))", "o.G", DkmEvaluationResultFlags.Expandable))
Dim moreChildren = GetChildren(children(0))
Verify(moreChildren,
......@@ -131,8 +135,16 @@ End Class"
EvalResult("F", "(Nothing, (Nothing, {B(Of (Object, Object)).S}))", "(X As Object, Y As (E As Object, H As B(Of (F As Object, G As Object)).S))", "o.G.F", DkmEvaluationResultFlags.Expandable))
moreChildren = GetChildren(moreChildren(0))
Verify(moreChildren,
EvalResult("X", "Nothing", "Object", "o.G.F.Item1"),
EvalResult("Item1", "Nothing", "Object", "o.G.F.Item1"),
EvalResult("Y", "(Nothing, {B(Of (Object, Object)).S})", "(E As Object, H As B(Of (F As Object, G As Object)).S)", "o.G.F.Item2", DkmEvaluationResultFlags.Expandable),
EvalResult("Item2", "(Nothing, {B(Of (Object, Object)).S})", "(E As Object, H As B(Of (F As Object, G As Object)).S)", "o.G.F.Item2", DkmEvaluationResultFlags.Expandable))
moreChildren = GetChildren(moreChildren(3))
Verify(moreChildren,
EvalResult("E", "Nothing", "Object", "o.G.F.Item2.Item1"),
EvalResult("Item1", "Nothing", "Object", "o.G.F.Item2.Item1"),
EvalResult("H", "{B(Of (Object, Object)).S}", "B(Of (F As Object, G As Object)).S", "o.G.F.Item2.Item2"),
EvalResult("Item2", "{B(Of (Object, Object)).S}", "B(Of (F As Object, G As Object)).S", "o.G.F.Item2.Item2"))
End Using
End Sub
......@@ -170,6 +182,12 @@ End Class"
End Using
End Sub
Private Shared Function CreateCSharpCompilation(source As String, references As IEnumerable(Of MetadataReference)) As CSharpCompilation
Dim tree = CSharpSyntaxTree.ParseText(source)
Dim options = New CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, concurrentBuild:=False)
Return CSharpCompilation.Create(GetUniqueName(), {tree}, references, options)
End Function
Private Shared Function GenerateTupleAssembly() As ImmutableArray(Of Byte)
Const source =
"Namespace System
......@@ -281,7 +299,7 @@ End Namespace
Namespace System.Runtime.CompilerServices
Public Class TupleElementNamesAttribute
Inherits Attribute
Public Sub TupleElementNamesAttribute(names As String())
Public Sub New(names As String())
End Sub
End Class
End Namespace"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册