提交 bb8d4482 编写于 作者: C Charles Stoner

Display non-default Tuple names in EE

上级 4d6eb4fc
......@@ -4,7 +4,6 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE
......@@ -272,7 +271,6 @@ private ArrayTypeSymbol DecodeArrayType(ArrayTypeSymbol type)
type.Sizes,
type.LowerBounds,
type.CustomModifiers);
}
private ImmutableArray<string> EatElementNamesIfAvailable(int numberOfElements)
......@@ -293,6 +291,7 @@ private ImmutableArray<string> EatElementNamesIfAvailable(int numberOfElements)
// Check to see if all the elements are null
var start = _namesIndex - numberOfElements;
_namesIndex = start;
bool allNull = true;
for (int i = 0; i < numberOfElements; i++)
......@@ -300,12 +299,12 @@ private ImmutableArray<string> EatElementNamesIfAvailable(int numberOfElements)
if (_elementNames[start + i] != null)
{
allNull = false;
break;
}
}
if (allNull)
{
_namesIndex = start;
return default(ImmutableArray<string>);
}
......@@ -316,7 +315,6 @@ private ImmutableArray<string> EatElementNamesIfAvailable(int numberOfElements)
builder.Add(_elementNames[start + i]);
}
_namesIndex = start;
return builder.ToImmutableAndFree();
}
}
......
// 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.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
......@@ -21,7 +22,10 @@ internal sealed class CSharpCompileResult : CompileResult
_method = method;
}
public override CustomTypeInfo GetCustomTypeInfo() =>
new CustomTypeInfo(DynamicFlagsCustomTypeInfo.PayloadTypeId, _method.GetCustomTypeInfoPayload());
public override Guid GetCustomTypeInfo(out ReadOnlyCollection<byte> payload)
{
payload = _method.GetCustomTypeInfoPayload();
return (payload == null) ? default(Guid) : CustomTypeInfo.PayloadTypeId;
}
}
}
// 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.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
......@@ -22,7 +24,10 @@ public CSharpLocalAndMethod(string name, string displayName, MethodSymbol method
/// The custom type info payload depends on the return type, which is not available when
/// <see cref="CSharpLocalAndMethod"/> is created.
/// </remarks>
public override CustomTypeInfo GetCustomTypeInfo() =>
new CustomTypeInfo(DynamicFlagsCustomTypeInfo.PayloadTypeId, _method.GetCustomTypeInfoPayload());
public override Guid GetCustomTypeInfo(out ReadOnlyCollection<byte> payload)
{
payload = _method.GetCustomTypeInfoPayload();
return (payload == null) ? default(Guid) : CustomTypeInfo.PayloadTypeId;
}
}
}
......@@ -2,11 +2,9 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
......@@ -107,7 +105,7 @@ private static BoundExpression GetCustomTypeInfoPayloadId(SyntaxNode syntax, Met
return new BoundDefaultOperator(syntax, guidConstructor.ContainingType);
}
var value = ConstantValue.Create(DynamicFlagsCustomTypeInfo.PayloadTypeId.ToString());
var value = ConstantValue.Create(CustomTypeInfo.PayloadTypeId.ToString());
return new BoundObjectCreationExpression(
syntax,
guidConstructor,
......@@ -120,8 +118,7 @@ private static BoundExpression GetCustomTypeInfoPayload(LocalSymbol local, Synta
compilation.Assembly,
compilation.GetSpecialType(SpecialType.System_Byte));
var flags = CSharpCompilation.DynamicTransformsEncoder.Encode(local.Type, customModifiersCount: 0, refKind: RefKind.None);
var bytes = DynamicFlagsCustomTypeInfo.Create(flags).GetCustomTypeInfoPayload();
var bytes = CSharpCompilation.DynamicTransformsEncoder.Encode(local.Type, customModifiersCount: 0, refKind: RefKind.None).ToBytes();
hasCustomTypeInfoPayload = bytes != null;
if (!hasCustomTypeInfoPayload)
{
......
......@@ -2,6 +2,7 @@
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
......@@ -19,9 +20,19 @@ internal static ImmutableArray<TypeParameterSymbol> GetAllTypeParameters(this Me
internal static ReadOnlyCollection<byte> GetCustomTypeInfoPayload(this MethodSymbol method)
{
var dynamicFlags = CSharpCompilation.DynamicTransformsEncoder.Encode(method.ReturnType, method.ReturnTypeCustomModifiers.Length, RefKind.None);
var dynamicFlagsInfo = DynamicFlagsCustomTypeInfo.Create(dynamicFlags);
return dynamicFlagsInfo.GetCustomTypeInfoPayload();
return CSharpCompilation.DynamicTransformsEncoder.Encode(method.ReturnType, method.ReturnTypeCustomModifiers.Length, RefKind.None).ToBytes();
}
internal static ReadOnlyCollection<byte> ToBytes(this ImmutableArray<bool> dynamicFlags)
{
Debug.Assert(!dynamicFlags.IsDefaultOrEmpty);
var builder = ArrayBuilder<bool>.GetInstance(dynamicFlags.Length);
builder.AddRange(dynamicFlags);
var bytes = DynamicFlagsCustomTypeInfo.ToBytes(builder);
builder.Free();
return CustomTypeInfo.Encode(bytes, null);
}
}
}
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
......@@ -40,11 +41,15 @@ internal PlaceholderLocalSymbol(MethodSymbol method, string name, string display
var type = typeNameDecoder.GetTypeSymbolForSerializedType(typeName);
Debug.Assert((object)type != null);
var dynamicFlagsInfo = alias.CustomTypeInfo.ToDynamicFlagsCustomTypeInfo();
if (dynamicFlagsInfo.Any())
ReadOnlyCollection<byte> dynamicFlags;
ReadOnlyCollection<string> tupleElementNames;
CustomTypeInfo.Decode(alias.CustomTypeInfoId, alias.CustomTypeInfo, out dynamicFlags, out tupleElementNames);
// Preserve tuple element names. See https://github.com/dotnet/roslyn/issues/13589.
if (dynamicFlags != null)
{
var flagsBuilder = ArrayBuilder<bool>.GetInstance();
dynamicFlagsInfo.CopyTo(flagsBuilder);
DynamicFlagsCustomTypeInfo.CopyTo(dynamicFlags, flagsBuilder);
var dynamicType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(
type,
sourceAssembly,
......
// 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.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
......@@ -29,8 +29,10 @@ protected override void AppendIdentifierEscapingPotentialKeywords(StringBuilder
StringBuilder builder,
Type[] typeArguments,
int typeArgumentOffset,
DynamicFlagsCustomTypeInfo dynamicFlags,
ref int index,
ReadOnlyCollection<byte> dynamicFlags,
ref int dynamicFlagIndex,
ReadOnlyCollection<string> tupleElementNames,
ref int tupleElementIndex,
int arity,
bool escapeKeywordIdentifiers,
out bool sawInvalidIdentifier)
......@@ -46,12 +48,51 @@ protected override void AppendIdentifierEscapingPotentialKeywords(StringBuilder
Type typeArgument = typeArguments[typeArgumentOffset + i];
bool sawSingleInvalidIdentifier;
AppendQualifiedTypeName(builder, typeArgument, dynamicFlags, ref index, escapeKeywordIdentifiers, out sawSingleInvalidIdentifier);
AppendQualifiedTypeName(
builder,
typeArgument,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
escapeKeywordIdentifiers,
out sawSingleInvalidIdentifier);
sawInvalidIdentifier |= sawSingleInvalidIdentifier;
}
builder.Append('>');
}
protected override void AppendTupleElement(
StringBuilder builder,
Type type,
string nameOpt,
ReadOnlyCollection<byte> dynamicFlags,
ref int dynamicFlagIndex,
ReadOnlyCollection<string> tupleElementNames,
ref int tupleElementIndex,
bool escapeKeywordIdentifiers,
out bool sawInvalidIdentifier)
{
sawInvalidIdentifier = false;
bool sawSingleInvalidIdentifier;
AppendQualifiedTypeName(
builder,
type,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
escapeKeywordIdentifiers,
sawInvalidIdentifier: out sawSingleInvalidIdentifier);
Debug.Assert(!sawSingleInvalidIdentifier);
if (!string.IsNullOrEmpty(nameOpt))
{
builder.Append(' ');
AppendIdentifier(builder, escapeKeywordIdentifiers, nameOpt, out sawSingleInvalidIdentifier);
sawInvalidIdentifier |= sawSingleInvalidIdentifier;
}
}
protected override void AppendRankSpecifier(StringBuilder builder, int rank)
{
Debug.Assert(rank > 0);
......
......@@ -20,8 +20,17 @@ private void AppendEnumTypeAndName(StringBuilder builder, Type typeToDisplayOpt,
{
// We're showing the type of a value, so "dynamic" does not apply.
bool unused;
int index = 0;
AppendQualifiedTypeName(builder, typeToDisplayOpt, default(DynamicFlagsCustomTypeInfo), ref index, escapeKeywordIdentifiers: true, sawInvalidIdentifier: out unused);
int index1 = 0;
int index2 = 0;
AppendQualifiedTypeName(
builder,
typeToDisplayOpt,
null,
ref index1,
null,
ref index2,
escapeKeywordIdentifiers: true,
sawInvalidIdentifier: out unused);
builder.Append('.');
AppendIdentifierEscapingPotentialKeywords(builder, name, sawInvalidIdentifier: out unused);
}
......
......@@ -604,27 +604,31 @@ static void M()
CompileDeclaration(context, "dynamic d = 1;", out flags, out testData);
Assert.Equal(flags, DkmClrCompilationResultFlags.PotentialSideEffect | DkmClrCompilationResultFlags.ReadOnlyResult);
testData.GetMethodData("<>x.<>m0").VerifyIL(
@"{
// Code size 58 (0x3a)
@"{
// Code size 62 (0x3e)
.maxstack 7
IL_0000: ldtoken ""object""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""d""
IL_000f: ldstr ""826d6ec1-dc4b-46af-be05-cd3f1a1fd4ac""
IL_000f: ldstr ""108766ce-df68-46ee-b761-0dcb7ac805f1""
IL_0014: newobj ""System.Guid..ctor(string)""
IL_0019: ldc.i4.1
IL_0019: ldc.i4.2
IL_001a: newarr ""byte""
IL_001f: dup
IL_0020: ldc.i4.0
IL_0021: ldc.i4.1
IL_0022: stelem.i1
IL_0023: call ""void Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, string, System.Guid, byte[])""
IL_0028: ldstr ""d""
IL_002d: call ""dynamic Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress<dynamic>(string)""
IL_0032: ldc.i4.1
IL_0033: box ""int""
IL_0038: stind.ref
IL_0039: ret
IL_0023: dup
IL_0024: ldc.i4.1
IL_0025: ldc.i4.1
IL_0026: stelem.i1
IL_0027: call ""void Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, string, System.Guid, byte[])""
IL_002c: ldstr ""d""
IL_0031: call ""dynamic Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress<dynamic>(string)""
IL_0036: ldc.i4.1
IL_0037: box ""int""
IL_003c: stind.ref
IL_003d: ret
}");
});
}
......
// 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.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
......@@ -789,29 +791,24 @@ .maxstack 1
Assert.Equal(resultProperties.Flags, DkmClrCompilationResultFlags.PotentialSideEffect | DkmClrCompilationResultFlags.ReadOnlyResult);
testData.GetMethodData("<>x.<>m0").VerifyIL(
@"{
// Code size 57 (0x39)
.maxstack 7
// Code size 60 (0x3c)
.maxstack 6
IL_0000: ldtoken ""Outer<dynamic[], object[]>.Inner<Outer<object, dynamic>[], dynamic>""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""dd""
IL_000f: ldstr ""826d6ec1-dc4b-46af-be05-cd3f1a1fd4ac""
IL_000f: ldstr ""108766ce-df68-46ee-b761-0dcb7ac805f1""
IL_0014: newobj ""System.Guid..ctor(string)""
IL_0019: ldc.i4.2
IL_0019: ldc.i4.3
IL_001a: newarr ""byte""
IL_001f: dup
IL_0020: ldc.i4.0
IL_0021: ldc.i4.4
IL_0022: stelem.i1
IL_0023: dup
IL_0024: ldc.i4.1
IL_0025: ldc.i4.3
IL_0026: stelem.i1
IL_0027: call ""void Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, string, System.Guid, byte[])""
IL_002c: ldstr ""dd""
IL_0031: call ""Outer<dynamic[], object[]>.Inner<Outer<object, dynamic>[], dynamic> Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress<Outer<dynamic[], object[]>.Inner<Outer<object, dynamic>[], dynamic>>(string)""
IL_0036: ldarg.0
IL_0037: stind.ref
IL_0038: ret
IL_0020: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=3 <PrivateImplementationDetails>.A4E591DA7617172655FE45FC3878ECC8CC0D44B3""
IL_0025: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)""
IL_002a: call ""void Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, string, System.Guid, byte[])""
IL_002f: ldstr ""dd""
IL_0034: call ""Outer<dynamic[], object[]>.Inner<Outer<object, dynamic>[], dynamic> Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress<Outer<dynamic[], object[]>.Inner<Outer<object, dynamic>[], dynamic>>(string)""
IL_0039: ldarg.0
IL_003a: stind.ref
IL_003b: ret
}");
locals.Free();
});
......@@ -831,8 +828,8 @@ static void M()
WithRuntimeInstance(comp, runtime =>
{
var context = CreateMethodContext(
runtime,
"C.M");
runtime,
"C.M");
var aliases = ImmutableArray.Create(
Alias(
DkmClrAliasKind.Variable,
......@@ -885,11 +882,14 @@ .maxstack 1
});
}
private static CustomTypeInfo MakeCustomTypeInfo(params bool[] flags)
private static ReadOnlyCollection<byte> MakeCustomTypeInfo(params bool[] flags)
{
Assert.NotNull(flags);
var dynamicFlagsInfo = DynamicFlagsCustomTypeInfo.Create(ImmutableArray.CreateRange(flags));
return new CustomTypeInfo(DynamicFlagsCustomTypeInfo.PayloadTypeId, dynamicFlagsInfo.GetCustomTypeInfoPayload());
var builder = ArrayBuilder<bool>.GetInstance();
builder.AddRange(flags);
var bytes = DynamicFlagsCustomTypeInfo.ToBytes(builder);
builder.Free();
return CustomTypeInfo.Encode(bytes, null);
}
[Fact]
......@@ -1446,18 +1446,35 @@ .maxstack 9
private static void VerifyCustomTypeInfo(LocalAndMethod localAndMethod, string expectedName, params byte[] expectedBytes)
{
Assert.Equal(localAndMethod.LocalName, expectedName);
VerifyCustomTypeInfo(localAndMethod.GetCustomTypeInfo(), expectedBytes);
ReadOnlyCollection<byte> customTypeInfo;
Guid customTypeInfoId = localAndMethod.GetCustomTypeInfo(out customTypeInfo);
VerifyCustomTypeInfo(customTypeInfoId, customTypeInfo, expectedBytes);
}
private static void VerifyCustomTypeInfo(CompileResult compileResult, params byte[] expectedBytes)
{
VerifyCustomTypeInfo(compileResult.GetCustomTypeInfo(), expectedBytes);
ReadOnlyCollection<byte> customTypeInfo;
Guid customTypeInfoId = compileResult.GetCustomTypeInfo(out customTypeInfo);
VerifyCustomTypeInfo(customTypeInfoId, customTypeInfo, expectedBytes);
}
private static void VerifyCustomTypeInfo(CustomTypeInfo customTypeInfo, byte[] expectedBytes)
private static void VerifyCustomTypeInfo(Guid customTypeInfoId, ReadOnlyCollection<byte> customTypeInfo, params byte[] expectedBytes)
{
Assert.Equal(DynamicFlagsCustomTypeInfo.PayloadTypeId, customTypeInfo.PayloadTypeId);
Assert.Equal(expectedBytes, customTypeInfo.Payload);
if (expectedBytes == null)
{
Assert.Equal(Guid.Empty, customTypeInfoId);
Assert.Null(customTypeInfo);
}
else
{
Assert.Equal(CustomTypeInfo.PayloadTypeId, customTypeInfoId);
// Include leading count byte.
var builder = ArrayBuilder<byte>.GetInstance();
builder.Add((byte)expectedBytes.Length);
builder.AddRange(expectedBytes);
expectedBytes = builder.ToArrayAndFree();
Assert.Equal(expectedBytes, customTypeInfo);
}
}
}
}
......@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
......@@ -300,7 +301,7 @@ internal static Alias VariableAlias(string name, Type type = null)
internal static Alias VariableAlias(string name, string typeAssemblyQualifiedName)
{
return new Alias(DkmClrAliasKind.Variable, name, name, typeAssemblyQualifiedName, default(CustomTypeInfo));
return new Alias(DkmClrAliasKind.Variable, name, name, typeAssemblyQualifiedName, default(Guid), null);
}
internal static Alias ObjectIdAlias(uint id, Type type = null)
......@@ -312,7 +313,7 @@ internal static Alias ObjectIdAlias(uint id, string typeAssemblyQualifiedName)
{
Assert.NotEqual(0u, id); // Not a valid id.
var name = $"${id}";
return new Alias(DkmClrAliasKind.ObjectId, name, name, typeAssemblyQualifiedName, default(CustomTypeInfo));
return new Alias(DkmClrAliasKind.ObjectId, name, name, typeAssemblyQualifiedName, default(Guid), null);
}
internal static Alias ReturnValueAlias(int id = -1, Type type = null)
......@@ -324,7 +325,7 @@ internal static Alias ReturnValueAlias(int id, string typeAssemblyQualifiedName)
{
var name = $"Method M{(id < 0 ? "" : id.ToString())} returned";
var fullName = id < 0 ? "$ReturnValue" : $"$ReturnValue{id}";
return new Alias(DkmClrAliasKind.ReturnValue, name, fullName, typeAssemblyQualifiedName, default(CustomTypeInfo));
return new Alias(DkmClrAliasKind.ReturnValue, name, fullName, typeAssemblyQualifiedName, default(Guid), null);
}
internal static Alias ExceptionAlias(Type type = null, bool stowed = false)
......@@ -337,12 +338,12 @@ internal static Alias ExceptionAlias(string typeAssemblyQualifiedName, bool stow
var name = "Error";
var fullName = stowed ? "$stowedexception" : "$exception";
var kind = stowed ? DkmClrAliasKind.StowedException : DkmClrAliasKind.Exception;
return new Alias(kind, name, fullName, typeAssemblyQualifiedName, default(CustomTypeInfo));
return new Alias(kind, name, fullName, typeAssemblyQualifiedName, default(Guid), null);
}
internal static Alias Alias(DkmClrAliasKind kind, string name, string fullName, string type, CustomTypeInfo customTypeInfo)
internal static Alias Alias(DkmClrAliasKind kind, string name, string fullName, string type, ReadOnlyCollection<byte> payload)
{
return new Alias(kind, name, fullName, type, customTypeInfo);
return new Alias(kind, name, fullName, type, (payload == null) ? default(Guid) : CustomTypeInfo.PayloadTypeId, payload);
}
internal static MethodDebugInfo<TypeSymbol, LocalSymbol> GetMethodDebugInfo(RuntimeInstance runtime, string qualifiedMethodName, int ilOffset = 0)
......
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis.CodeGen;
......@@ -762,7 +763,7 @@ private TestCompileResult()
{
}
public override CustomTypeInfo GetCustomTypeInfo()
public override Guid GetCustomTypeInfo(out ReadOnlyCollection<byte> payload)
{
throw new NotImplementedException();
}
......
// 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.Collections;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
......@@ -14,24 +13,81 @@ namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests
public class DynamicFlagsCustomTypeInfoTests : CSharpResultProviderTestBase
{
[Fact]
public void BoolArrayConstructor()
public void ToBytes()
{
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(new bool[0]));
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false), 0x00);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(true), 0x01);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, false), 0x00);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(true, false), 0x01);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, true), 0x02);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(true, true), 0x03);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, false, true), 0x04);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, false, false, true), 0x08);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, false, false, false, true), 0x10);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, false, false, false, false, true), 0x20);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, false, false, false, false, false, true), 0x40);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, false, false, false, false, false, false, true), 0x80);
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(false, false, false, false, false, false, false, false, true), 0x00, 0x01);
ValidateToBytes(new bool[0]);
ValidateToBytes(new bool[] { false });
ValidateToBytes(new bool[] { true }, 0x01);
ValidateToBytes(new bool[] { false, false });
ValidateToBytes(new bool[] { true, false }, 0x01);
ValidateToBytes(new bool[] { false, true }, 0x02);
ValidateToBytes(new bool[] { true, true }, 0x03);
ValidateToBytes(new bool[] { false, false, true }, 0x04);
ValidateToBytes(new bool[] { false, false, false, true }, 0x08);
ValidateToBytes(new bool[] { false, false, false, false, true }, 0x10);
ValidateToBytes(new bool[] { false, false, false, false, false, true }, 0x20);
ValidateToBytes(new bool[] { false, false, false, false, false, false, true }, 0x40);
ValidateToBytes(new bool[] { false, false, false, false, false, false, false, true }, 0x80);
ValidateToBytes(new bool[] { false, false, false, false, false, false, false, false, true }, 0x00, 0x01);
}
[Fact]
public void CopyTo()
{
ValidateCopyTo(new byte[0]);
ValidateCopyTo(new byte[] { 0x00 }, false, false, false, false, false, false, false, false);
ValidateCopyTo(new byte[] { 0x01 }, true, false, false, false, false, false, false, false);
ValidateCopyTo(new byte[] { 0x02 }, false, true, false, false, false, false, false, false);
ValidateCopyTo(new byte[] { 0x03 }, true, true, false, false, false, false, false, false);
ValidateCopyTo(new byte[] { 0x04 }, false, false, true, false, false, false, false, false);
ValidateCopyTo(new byte[] { 0x08 }, false, false, false, true, false, false, false, false);
ValidateCopyTo(new byte[] { 0x10 }, false, false, false, false, true, false, false, false);
ValidateCopyTo(new byte[] { 0x20 }, false, false, false, false, false, true, false, false);
ValidateCopyTo(new byte[] { 0x40 }, false, false, false, false, false, false, true, false);
ValidateCopyTo(new byte[] { 0x80 }, false, false, false, false, false, false, false, true);
ValidateCopyTo(new byte[] { 0x00, 0x01 }, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false);
}
[Fact]
public void EncodeAndDecode()
{
var encoded = CustomTypeInfo.Encode(null, null);
Assert.Null(encoded);
var bytes = GetBytesInRange(0, 256);
encoded = CustomTypeInfo.Encode(bytes, null);
Assert.Null(encoded);
bytes = GetBytesInRange(0, 255);
encoded = CustomTypeInfo.Encode(bytes, null);
Assert.Equal(256, encoded.Count);
Assert.Equal(255, encoded[0]);
ReadOnlyCollection<byte> dynamicFlags;
ReadOnlyCollection<string> tupleElementNames;
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Equal(bytes, dynamicFlags);
Assert.Null(tupleElementNames);
var names = new ReadOnlyCollection<string>(new[] { null, "A", null, "B" });
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);
encoded = CustomTypeInfo.Encode(null, names);
CustomTypeInfo.Decode(CustomTypeInfo.PayloadTypeId, encoded, out dynamicFlags, out tupleElementNames);
Assert.Null(dynamicFlags);
Assert.Equal(names, tupleElementNames);
}
private static ReadOnlyCollection<byte> GetBytesInRange(int start, int length)
{
return new ReadOnlyCollection<byte>(Enumerable.Range(start, length).Select(i => (byte)(i % 256)).ToArray());
}
[Fact]
......@@ -56,7 +112,16 @@ public void CustomTypeInfoConstructor()
[Fact]
public void CustomTypeInfoConstructor_OtherGuid()
{
ValidateBytes(DynamicFlagsCustomTypeInfo.Create(DkmClrCustomTypeInfo.Create(Guid.NewGuid(), new ReadOnlyCollection<byte>(new byte[] { 0x01 }))));
var customTypeInfo = DkmClrCustomTypeInfo.Create(Guid.NewGuid(), new ReadOnlyCollection<byte>(new byte[] { 0x01 }));
ReadOnlyCollection<byte> dynamicFlags;
ReadOnlyCollection<string> tupleElementNames;
CustomTypeInfo.Decode(
customTypeInfo.PayloadTypeId,
customTypeInfo.Payload,
out dynamicFlags,
out tupleElementNames);
Assert.Null(dynamicFlags);
Assert.Null(tupleElementNames);
}
[Fact]
......@@ -79,61 +144,37 @@ public void Indexer()
ValidateIndexer(false, false, false, false, false, false, false, false, true);
}
[Fact]
public void Any()
{
ValidateAny(null);
ValidateAny(false);
ValidateAny(true);
ValidateAny(false, false);
ValidateAny(false, true);
ValidateAny(true, false);
ValidateAny(true, true);
ValidateAny(false, false, true);
ValidateAny(false, false, false, true);
ValidateAny(false, false, false, false, true);
ValidateAny(false, false, false, false, false, true);
ValidateAny(false, false, false, false, false, false, true);
ValidateAny(false, false, false, false, false, false, false, true);
ValidateAny(false, false, false, false, false, false, false, false, true);
}
[Fact]
public void SkipOne()
{
var dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.Create((bool[])null);
ValidateBytes(dynamicFlagsCustomTypeInfo.SkipOne());
ValidateBytes(DynamicFlagsCustomTypeInfo.SkipOne(null));
var dkmClrCustomTypeInfo = DkmClrCustomTypeInfo.Create(DynamicFlagsCustomTypeInfo.PayloadTypeId, new ReadOnlyCollection<byte>(new byte[] { 0x80 }));
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.Create(dkmClrCustomTypeInfo);
var dynamicFlagsCustomTypeInfo = new ReadOnlyCollection<byte>(new byte[] { 0x80 });
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x40);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x20);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x10);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x08);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x04);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x02);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x01);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x00);
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo);
dkmClrCustomTypeInfo = DkmClrCustomTypeInfo.Create(DynamicFlagsCustomTypeInfo.PayloadTypeId, new ReadOnlyCollection<byte>(new byte[] { 0x00, 0x02 }));
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.Create(dkmClrCustomTypeInfo);
dynamicFlagsCustomTypeInfo = new ReadOnlyCollection<byte>(new byte[] { 0x00, 0x02 });
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x00, 0x01);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x80, 0x00);
dynamicFlagsCustomTypeInfo = dynamicFlagsCustomTypeInfo.SkipOne();
dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlagsCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, 0x40, 0x00);
}
......@@ -141,64 +182,71 @@ private static void ValidateCustomTypeInfo(params byte[] payload)
{
Assert.NotNull(payload);
var dkmClrCustomTypeInfo = DkmClrCustomTypeInfo.Create(DynamicFlagsCustomTypeInfo.PayloadTypeId, new ReadOnlyCollection<byte>(payload));
var dynamicFlagsCustomTypeInfo = DynamicFlagsCustomTypeInfo.Create(dkmClrCustomTypeInfo);
ValidateBytes(dynamicFlagsCustomTypeInfo, payload);
var dkmClrCustomTypeInfo = CustomTypeInfo.Create(new ReadOnlyCollection<byte>(payload), null);
Assert.Equal(CustomTypeInfo.PayloadTypeId, dkmClrCustomTypeInfo.PayloadTypeId);
Assert.NotNull(dkmClrCustomTypeInfo.Payload);
var dkmClrCustomTypeInfo2 = dynamicFlagsCustomTypeInfo.GetCustomTypeInfo();
if (dynamicFlagsCustomTypeInfo.Any())
{
Assert.Equal(dkmClrCustomTypeInfo.PayloadTypeId, dkmClrCustomTypeInfo2.PayloadTypeId);
Assert.Equal(dkmClrCustomTypeInfo.Payload, dkmClrCustomTypeInfo2.Payload);
}
else
{
Assert.Null(dkmClrCustomTypeInfo2);
}
ReadOnlyCollection<byte> dynamicFlags;
ReadOnlyCollection<string> tupleElementNames;
CustomTypeInfo.Decode(
dkmClrCustomTypeInfo.PayloadTypeId,
dkmClrCustomTypeInfo.Payload,
out dynamicFlags,
out tupleElementNames);
ValidateBytes(dynamicFlags, payload);
Assert.Null(tupleElementNames);
}
private static void ValidateIndexer(params bool[] flags)
private static void ValidateIndexer(params bool[] dynamicFlags)
{
var customTypeInfo = DynamicFlagsCustomTypeInfo.Create(flags);
if (flags == null)
if (dynamicFlags == null)
{
Assert.False(customTypeInfo[0]);
Assert.False(DynamicFlagsCustomTypeInfo.GetFlag(null, 0));
}
else
{
AssertEx.All(flags.Select((f, i) => f == customTypeInfo[i]), x => x);
Assert.False(customTypeInfo[flags.Length]);
var builder = ArrayBuilder<bool>.GetInstance(dynamicFlags.Length);
builder.AddRange(dynamicFlags);
var customTypeInfo = DynamicFlagsCustomTypeInfo.ToBytes(builder);
builder.Free();
AssertEx.All(dynamicFlags.Select((f, i) => f == DynamicFlagsCustomTypeInfo.GetFlag(customTypeInfo, i)), x => x);
Assert.False(DynamicFlagsCustomTypeInfo.GetFlag(customTypeInfo, dynamicFlags.Length));
}
}
private static void ValidateAny(params bool[] flags)
private static void ValidateToBytes(bool[] dynamicFlags, params byte[] expectedBytes)
{
var customTypeInfo = DynamicFlagsCustomTypeInfo.Create(flags);
if (flags == null)
{
Assert.False(customTypeInfo.Any());
}
else
{
Assert.Equal(flags.Any(x => x), customTypeInfo.Any());
}
Assert.NotNull(dynamicFlags);
Assert.NotNull(expectedBytes);
var builder = ArrayBuilder<bool>.GetInstance(dynamicFlags.Length);
builder.AddRange(dynamicFlags);
var actualBytes = DynamicFlagsCustomTypeInfo.ToBytes(builder);
builder.Free();
ValidateBytes(actualBytes, expectedBytes);
}
private static void ValidateCopyTo(byte[] dynamicFlags, params bool[] expectedFlags)
{
var builder = ArrayBuilder<bool>.GetInstance();
DynamicFlagsCustomTypeInfo.CopyTo(new ReadOnlyCollection<byte>(dynamicFlags), builder);
var actualFlags = builder.ToArrayAndFree();
Assert.Equal(expectedFlags, actualFlags);
}
private static void ValidateBytes(DynamicFlagsCustomTypeInfo dynamicFlags, params byte[] expectedBytes)
private static void ValidateBytes(ReadOnlyCollection<byte> actualBytes, params byte[] expectedBytes)
{
Assert.NotNull(expectedBytes);
var dkmClrCustomTypeInfo = dynamicFlags.GetCustomTypeInfo();
if (dynamicFlags.Any())
if (expectedBytes.Length == 0)
{
Assert.NotNull(dkmClrCustomTypeInfo);
var actualBytes = dkmClrCustomTypeInfo.Payload;
Assert.Equal(expectedBytes, actualBytes);
Assert.Null(actualBytes);
}
else
{
AssertEx.All(expectedBytes, b => b == 0);
Assert.Null(dkmClrCustomTypeInfo);
Assert.Equal(expectedBytes, actualBytes);
}
}
}
......
......@@ -2,11 +2,11 @@
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests
......@@ -18,7 +18,7 @@ public void Simple()
{
var value = CreateDkmClrValue(new object());
var rootExpr = "d";
var evalResult = FormatResult(rootExpr, rootExpr, value, declaredType: new DkmClrType((TypeImpl)typeof(object)), declaredTypeInfo: DynamicFlagsCustomTypeInfo.Create(true).GetCustomTypeInfo());
var evalResult = FormatResult(rootExpr, rootExpr, value, declaredType: new DkmClrType((TypeImpl)typeof(object)), declaredTypeInfo: MakeCustomTypeInfo(true));
Verify(evalResult,
EvalResult(rootExpr, "{object}", "dynamic {object}", rootExpr));
}
......@@ -62,7 +62,7 @@ class C<T, U>
var typeC_Constructed2 = typeC.MakeGenericType(typeof(object), typeC_Constructed1); // C<dynamic, C<object, dynamic>> (i.e. T = dynamic, U = C<object, dynamic>)
var value = CreateDkmClrValue(Activator.CreateInstance(typeC_Constructed2));
var rootExpr = "c";
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeC_Constructed2), DynamicFlagsCustomTypeInfo.Create(false, true, false, false, true).GetCustomTypeInfo());
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeC_Constructed2), MakeCustomTypeInfo(false, true, false, false, true));
Verify(evalResult,
EvalResult(rootExpr, "{C<object, C<object, object>>}", "C<dynamic, C<object, dynamic>> {C<object, C<object, object>>}", rootExpr, DkmEvaluationResultFlags.Expandable));
var children = GetChildren(evalResult);
......@@ -91,7 +91,7 @@ class Inner<U>
var typeInner_Constructed = typeInner.MakeGenericType(typeof(object), typeof(object)); // Outer<dynamic>.Inner<object>
var value = CreateDkmClrValue(Activator.CreateInstance(typeInner_Constructed));
var rootExpr = "i";
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeInner_Constructed), DynamicFlagsCustomTypeInfo.Create(false, true, false).GetCustomTypeInfo());
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeInner_Constructed), MakeCustomTypeInfo(false, true, false));
Verify(evalResult,
EvalResult(rootExpr, "{Outer<object>.Inner<object>}", "Outer<dynamic>.Inner<object> {Outer<object>.Inner<object>}", rootExpr, DkmEvaluationResultFlags.Expandable));
var children = GetChildren(evalResult);
......@@ -126,7 +126,7 @@ class D<T, U, V>
var typeC_Constructed = typeC.MakeGenericType(typeD_Constructed); // C<D<object, dynamic, int>>
var value = CreateDkmClrValue(Activator.CreateInstance(typeC_Constructed));
var rootExpr = "c";
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeC_Constructed), DynamicFlagsCustomTypeInfo.Create(false, false, false, true, false).GetCustomTypeInfo());
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeC_Constructed), MakeCustomTypeInfo(false, false, false, true, false));
Verify(evalResult,
EvalResult(rootExpr, "{C<D<object, object, int>>}", "C<D<object, dynamic, int>> {C<D<object, object, int>>}", rootExpr, DkmEvaluationResultFlags.Expandable));
var children = GetChildren(evalResult);
......@@ -171,7 +171,7 @@ class C<T, U> : I<long, T>, I<bool, U>
var typeC_Constructed = typeC.MakeGenericType(typeof(object), typeof(object)); // C<dynamic, object>
var value = CreateDkmClrValue(Activator.CreateInstance(typeC_Constructed));
var rootExpr = "c";
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeC_Constructed), DynamicFlagsCustomTypeInfo.Create(false, true, false).GetCustomTypeInfo());
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeC_Constructed), MakeCustomTypeInfo(false, true, false));
Verify(evalResult,
EvalResult(rootExpr, "{C<object, object>}", "C<dynamic, object> {C<object, object>}", rootExpr, DkmEvaluationResultFlags.Expandable));
var children = GetChildren(evalResult);
......@@ -206,7 +206,7 @@ class Derived<T, U> : Base<T, U, object, dynamic>
var typeDerived_Constructed = typeDerived.MakeGenericType(typeof(object), typeof(object)); // Derived<dynamic, object>
var value = CreateDkmClrValue(Activator.CreateInstance(typeDerived_Constructed));
var rootExpr = "d";
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeDerived_Constructed), DynamicFlagsCustomTypeInfo.Create(false, true, false).GetCustomTypeInfo());
var evalResult = FormatResult(rootExpr, rootExpr, value, new DkmClrType((TypeImpl)typeDerived_Constructed), MakeCustomTypeInfo(false, true, false));
Verify(evalResult,
EvalResult(rootExpr, "{Derived<object, object>}", "Derived<dynamic, object> {Derived<object, object>}", rootExpr, DkmEvaluationResultFlags.Expandable));
......@@ -228,7 +228,7 @@ public void ArrayElement()
{
var value = CreateDkmClrValue(new object[1]);
var rootExpr = "d";
var evalResult = FormatResult(rootExpr, rootExpr, value, declaredType: new DkmClrType((TypeImpl)typeof(object[])), declaredTypeInfo: DynamicFlagsCustomTypeInfo.Create(false, true).GetCustomTypeInfo());
var evalResult = FormatResult(rootExpr, rootExpr, value, declaredType: new DkmClrType((TypeImpl)typeof(object[])), declaredTypeInfo: MakeCustomTypeInfo(false, true));
Verify(evalResult,
EvalResult(rootExpr, "{object[1]}", "dynamic[] {object[]}", rootExpr, DkmEvaluationResultFlags.Expandable));
var children = GetChildren(evalResult);
......@@ -250,7 +250,7 @@ public void TypeVariables()
var assembly = ReflectionUtilities.Load(assemblyBytes);
var reflectionType = assembly.GetType(ExpressionCompilerConstants.TypeVariablesClassName).MakeGenericType(new[] { typeof(object), typeof(object), typeof(object[]) });
var value = CreateDkmClrValue(value: null, type: reflectionType, valueFlags: DkmClrValueFlags.Synthetic);
var evalResult = FormatResult("typevars", "typevars", value, new DkmClrType((TypeImpl)reflectionType), DynamicFlagsCustomTypeInfo.Create(false, true, false, false, true).GetCustomTypeInfo());
var evalResult = FormatResult("typevars", "typevars", value, new DkmClrType((TypeImpl)reflectionType), MakeCustomTypeInfo(false, true, false, false, true));
Verify(evalResult,
EvalResult("Type variables", "", "", null, DkmEvaluationResultFlags.Expandable | DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Data));
var children = GetChildren(evalResult);
......@@ -259,5 +259,32 @@ public void TypeVariables()
EvalResult("U", "object", "object", null, DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Data),
EvalResult("V", "dynamic[]", "dynamic[]", null, DkmEvaluationResultFlags.ReadOnly, DkmEvaluationResultCategory.Data));
}
[WorkItem(13554, "https://github.com/dotnet/roslyn/issues/13554")]
[Fact(Skip = "13554")]
public void DynamicBaseTypeArgument()
{
var source =
@"class A<T>
{
#pragma warning disable 0169
internal T F;
#pragma warning restore 0169
}
class B : A<dynamic>
{
B() { F = 1; }
}";
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(GetAssembly(source)));
using (runtime.Load())
{
var type = runtime.GetType("B");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult("F", "1", "dynamic {int}", "o.F"));
}
}
}
}
\ No newline at end of file
......@@ -1789,6 +1789,21 @@ class B : A { }
Verify(children);
}
[Fact]
public void DeclaredTypeAndRuntimeTypeDifferByCase()
{
var source =
@"class Object { }";
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(GetAssembly(source)));
using (runtime.Load())
{
var value = runtime.GetType("Object").Instantiate();
var evalResult = FormatResult("o", value, declaredType: runtime.GetType("System.Object"));
Verify(evalResult,
EvalResult("o", "{Object}", "object {Object}", "o", DkmEvaluationResultFlags.None));
}
}
/// <summary>
/// Full name should be null for members of thrown
/// exception since there's no valid expression.
......
......@@ -11,12 +11,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal static class TestTypeExtensions
{
public static string GetTypeName(this System.Type type, bool[] dynamicFlags = null, bool escapeKeywordIdentifiers = false)
{
return type.GetTypeName(DynamicFlagsCustomTypeInfo.Create(dynamicFlags).GetCustomTypeInfo(), escapeKeywordIdentifiers, null);
}
public static string GetTypeName(this System.Type type, DkmClrCustomTypeInfo typeInfo, bool escapeKeywordIdentifiers = false, DkmInspectionContext inspectionContext = null)
public static string GetTypeName(this System.Type type, DkmClrCustomTypeInfo typeInfo = null, bool escapeKeywordIdentifiers = false, DkmInspectionContext inspectionContext = null)
{
var formatter = new CSharpFormatter();
var clrType = new DkmClrType((TypeImpl)type);
......
......@@ -5,7 +5,9 @@
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Roslyn.Test.Utilities;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests
......@@ -38,8 +40,8 @@ struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> { }
Assert.Equal(0, cardinality);
type = runtime.GetType("System.ValueTuple`1", typeof(int));
Assert.False(type.GetLmrType().IsTupleCompatible(out cardinality));
Assert.Equal(0, cardinality);
Assert.True(type.GetLmrType().IsTupleCompatible(out cardinality));
Assert.Equal(1, cardinality);
type = runtime.GetType("System.ValueTuple`2", typeof(int), typeof(string));
Assert.True(type.GetLmrType().IsTupleCompatible(out cardinality));
......@@ -141,7 +143,7 @@ struct ValueTuple<T1, T2> { }
public void IsTupleCompatible_InvalidName()
{
var source =
@".class System.ValueTuple`3<T1, T2>
@".class sealed System.ValueTuple`3<T1, T2> extends [mscorlib]System.ValueType
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
......@@ -342,6 +344,308 @@ public void Dynamic()
}
}
[WorkItem(13625, "https://github.com/dotnet/roslyn/issues/13625")]
[Fact(Skip = "13625")]
public void Names_LongTuple()
{
var source =
@"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));
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("C");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult(
"F",
"((1, (2, 3), 4, 5, 6, 7, 8, 9), (10, 11, 12))",
"((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)",
"o.F",
DkmEvaluationResultFlags.Expandable));
}
}
[WorkItem(13625, "https://github.com/dotnet/roslyn/issues/13625")]
[Fact(Skip = "13625")]
public void PartialNames()
{
var source =
@"class C
{
((int A, (int B, int C) D, int, int F, int G, int, int I, int J, int K, int L) M, (int N, int, int P) Q) F =
((1, (2, 3), 4, 5, 6, 7, 8, 9, 10, 11), (12, 13, 14));
(int A, (int B, int)[] C, (object, object), (int, int D, int E, int F, int G, int H, int I, int J, int) K)[] G =
new[] { (1, new[] { (2, 3) }, ((object, object))(4, 5), (6, 7, 8, 9, 10, 11, 12, 13, 14)) };
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("C");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult(
"F",
"((1, (2, 3), 4, 5, 6, 7, 8, 9, 10, 11), (12, 13, 14))",
"((int A, (int B, int C) D, int, int F, int G, int, int I, int J, int K, int L) M, (int N, int, int P) Q)",
"o.F",
DkmEvaluationResultFlags.Expandable),
EvalResult(
"G",
"{(int, (int, int)[], (object, object), (int, int, int, int, int, int, int, int, int))[1]}",
"(int A, (int B, int)[] C, (object, object), (int, int D, int E, int F, int G, int H, int I, int J, int) K)[]",
"o.G",
DkmEvaluationResultFlags.Expandable));
children = GetChildren(children[1]);
Verify(children,
EvalResult(
"[0]",
"(1, {(int, int)[1]}, (4, 5), (6, 7, 8, 9, 10, 11, 12, 13, 14))",
"(int A, (int B, int)[] C, (object, object), (int, int D, int E, int F, int G, int H, int I, int J, int) K)",
"o.G[0]",
DkmEvaluationResultFlags.Expandable));
}
}
[Fact]
public void NamesAndValueTuple1()
{
var source =
@"using System;
class C<T>
{
internal C(T t) { }
}
class C
{
(ValueTuple<int> A, int B) F = (new ValueTuple<int>(1), 2);
(int A, ValueTuple<int> B) G = (3, new ValueTuple<int>(4));
ValueTuple<(int A, int B)> H = new ValueTuple<(int, int)>((5, 6));
(int A, ValueTuple<(int B, int C)> D) I = (7, new ValueTuple<(int, int)>((8, 9)));
C<(int A, int B)> J = new C<(int, int)>((10, 11));
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("C");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult("F", "({System.ValueTuple<int>}, 2)", "(System.ValueTuple<int> A, int B)", "o.F", DkmEvaluationResultFlags.Expandable),
EvalResult("G", "(3, {System.ValueTuple<int>})", "(int A, System.ValueTuple<int> B)", "o.G", DkmEvaluationResultFlags.Expandable),
EvalResult("H", "{System.ValueTuple<(int, int)>}", "System.ValueTuple<(int A, int B)>", "o.H", DkmEvaluationResultFlags.Expandable),
EvalResult("I", "(7, {System.ValueTuple<(int, int)>})", "(int A, System.ValueTuple<(int B, int C)> D)", "o.I", DkmEvaluationResultFlags.Expandable),
EvalResult("J", "{C<(int, int)>}", "C<(int A, int B)>", "o.J"));
}
}
[Fact]
public void NamesAndDynamic()
{
var source =
@"class C
{
(dynamic A, (int B, dynamic C)[] D, dynamic E, (int F, dynamic G, int H, int I, int J, int K, int L, int M, int N) O) F =
(1, new (int, dynamic)[] { (2, 3) }, (4, 5), (6, 7, 8, 9, 10, 11, 12, 13, 14));
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("C");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult(
"F",
"(1, {(int, object)[1]}, (4, 5), (6, 7, 8, 9, 10, 11, 12, 13, 14))",
"(dynamic A, (int B, dynamic C)[] D, dynamic E, (int F, dynamic G, int H, int I, int J, int K, int L, int M, int N) O) {(object, (int, object)[], object, (int, object, int, int, int, int, int, int, int))}",
"o.F",
DkmEvaluationResultFlags.Expandable));
}
}
[Fact]
public void NamesAndDynamic_Other()
{
var source =
@"class C1 { }
class C2 { }
class C3 { }
class C4 { }
class C5 { }
class C6 { }
class C7 { }
class C8 { }
class C9 { }
class C10 { }
class C11 { }
class C12 { }
class C
{
(((C1 C1, dynamic C2) B1, (C3 C3, dynamic C4)) A1, (dynamic B3, (C7 C7, C8 C8) B4) A2, ((C9 C9, C10 C10), dynamic B6) A3) F =
((
((new C1(), new C2()), (new C3(), new C4())),
((new C5(), new C6()), (new C7(), new C8())),
((new C9(), new C10()), (new C11(), new C12()))
));
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("C");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult(
"F",
"((({C1}, {C2}), ({C3}, {C4})), (({C5}, {C6}), ({C7}, {C8})), (({C9}, {C10}), ({C11}, {C12})))",
"(((C1 C1, dynamic C2) B1, (C3 C3, dynamic C4)) A1, (dynamic B3, (C7 C7, C8 C8) B4) A2, ((C9 C9, C10 C10), dynamic B6) A3) {(((C1, object), (C3, object)), (object, (C7, C8)), ((C9, C10), object))}",
"o.F",
DkmEvaluationResultFlags.Expandable));
}
}
[Fact]
public void NamesFromTypeArguments()
{
var source =
@"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)>();
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("C");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult("F", "{A<(object, object)[], (object, object[])>}", "A<(dynamic A, object B)[], (object C, dynamic[] D)> {A<(object, object)[], (object, object[])>}", "o.F", DkmEvaluationResultFlags.Expandable),
EvalResult("G", "{B<(object, B<(object, object)>.S)>}", "B<(object E, B<(object F, dynamic G)>.S H)> {B<(object, B<(object, object)>.S)>}", "o.G", DkmEvaluationResultFlags.Expandable));
var moreChildren = GetChildren(children[0]);
Verify(moreChildren,
EvalResult("F", "null", "(dynamic A, object B)[] {(object, object)[]}", "o.F.F"),
EvalResult("G", "{(object, object[])[0]}", "(object C, dynamic[] D)[] {(object, object[])[]}", "o.F.G"));
moreChildren = GetChildren(children[1]);
Verify(moreChildren,
EvalResult("F", "(null, (null, {B<(object, object)>.S}))", "(dynamic X, (object E, B<(object F, dynamic G)>.S H) Y) {(object, (object, B<(object, object)>.S))}", "o.G.F", DkmEvaluationResultFlags.Expandable));
moreChildren = GetChildren(moreChildren[0]);
Verify(moreChildren,
EvalResult("Item1", "null", "dynamic {object}", "o.G.F.Item1"),
EvalResult("Item2", "(null, {B<(object, object)>.S})", "(object E, B<(object F, dynamic G)>.S H) {(object, B<(object, object)>.S)}", "o.G.F.Item2", DkmEvaluationResultFlags.Expandable));
}
}
[WorkItem(13625, "https://github.com/dotnet/roslyn/issues/13625")]
[Fact(Skip = "13625")]
public void NamesFromTypeArguments_LongTuples()
{
var source =
@"class A1 { }
class A2 { }
class A3 { }
class A4 { }
class A5 { }
class A6 { }
class A7 { }
class A8 { }
class B1 { }
class B2 { }
class B3 { }
class B4 { }
class B5 { }
class B6 { }
class B7 { }
class B8 { }
class B9 { }
class B10 { }
class C1 { }
class C2 { }
class A<T, U>
{
(dynamic A1, A2 A2, T A3, A4 A4, A5 A5, U A6, A7 A7, A8 A8, (T A9, U A10) A11) F =
(new A1(), new A2(), default(T), new A4(), new A5(), default(U), new A7(), new A8(), (default(T), default(U)));
}
class B
{
A<((dynamic B1, B2 B2) B3, B4 B4, dynamic B5, B6 B6, B7 B7, dynamic B8, B9 B9, B10 B10, dynamic B11), (C1 C1, (C2 C2, dynamic C3) C4)> G =
new A<((dynamic B1, B2 B2) B3, B4 B4, dynamic B5, B6 B6, B7 B7, dynamic B8, B9 B9, B10 B10, dynamic B11), (C1 C1, (C2 C2, dynamic C3) C4)>();
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
var compilation1 = CSharpTestBaseBase.CreateCompilationWithMscorlib45AndCSruntime(source, additionalRefs: new[] { reference0 });
var assembly1 = compilation1.EmitToArray();
var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)));
using (runtime.Load())
{
var type = runtime.GetType("B");
var value = type.Instantiate();
var evalResult = FormatResult("o", value);
var children = GetChildren(evalResult);
Verify(children,
EvalResult(
"G",
"{A<((object, B2), B4, object, B6, B7, object, B9, B10, object), (C1, (C2, object))>}",
"A<((dynamic B1, B2 B2) B3, B4 B4, dynamic B5, B6 B6, B7 B7, dynamic B8, B9 B9, B10 B10, dynamic B11), (C1, (C2 C1, dynamic C4))> {A<((object, B2), B4, object, B6, B7, object, B9, B10, object), (C1, (C2, object))>}",
"o.G",
DkmEvaluationResultFlags.Expandable));
children = GetChildren(children[0]);
Verify(children,
EvalResult(
"F",
"({A1}, {A2}, ((null, null), null, null, null, null, null, null, null, null), {A4}, {A5}, (null, (null, null)), {A7}, {A8}, (((null, null), null, null, null, null, null, null, null, null), (null, (null, null))))",
"(dynamic A1, A2 A2, ((dynamic B1, B2 B2) B3, B4 B4, dynamic B5, B6 B6, B7 B7, dynamic B8, B9 B9, B10 B10, dynamic B11) A3, A4 A4, A5 A5, (C1, (C2 C2, dynamic C3) C4) A6, A7 A7, A8 A8, (((dynamic B1, B2 B2) B3, B4 B4, dynamic B5, B6 B6, B7 B7, dynamic B8, B9 B9, B10 B10, dynamic B11) A9, (C1, (C2 C2, dynamic C3) C4)) A10) A11) {(object, A2, ((object, B2), B4, object, B6, B7, object, B9, B10, object), A4, A5, (C1, (C2, object)), A7, A8, (((object, B2), B4, object, B6, B7, object, B9, B10, object), (C1, (C2, object))))}",
"o.G.F",
DkmEvaluationResultFlags.Expandable));
}
}
[Fact]
public void Keywords()
{
......@@ -354,7 +658,8 @@ struct @struct
}
class async
{
(async @var, @namespace.@struct @class) F;
static (async @var, @namespace.@struct @class) F() => (null, default(@namespace.@struct));
object _f = F();
}";
var assembly0 = GenerateTupleAssembly();
var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference();
......@@ -370,7 +675,11 @@ class async
EvalResult("o", "{async}", "async", "o", DkmEvaluationResultFlags.Expandable));
var children = GetChildren(evalResult);
Verify(children,
EvalResult("F", "(null, {namespace.struct})", "(async, namespace.struct)", "o.F", DkmEvaluationResultFlags.Expandable));
EvalResult("_f", "(null, {namespace.struct})", "object {(async, namespace.struct)}", "o._f", DkmEvaluationResultFlags.Expandable));
children = GetChildren(children[0]);
Verify(children,
EvalResult("Item1", "null", "async", "(((@async, @namespace.@struct))o._f).Item1"),
EvalResult("Item2", "{namespace.struct}", "namespace.struct", "(((@async, @namespace.@struct))o._f).Item2"));
}
}
......
......@@ -303,8 +303,8 @@ public class @null { }
public void DynamicAttribute_KeywordEscaping()
{
var attributes = new[] { true };
Assert.Equal("dynamic", typeof(object).GetTypeName(attributes, escapeKeywordIdentifiers: false));
Assert.Equal("dynamic", typeof(object).GetTypeName(attributes, escapeKeywordIdentifiers: true));
Assert.Equal("dynamic", typeof(object).GetTypeName(MakeCustomTypeInfo(attributes), escapeKeywordIdentifiers: false));
Assert.Equal("dynamic", typeof(object).GetTypeName(MakeCustomTypeInfo(attributes), escapeKeywordIdentifiers: true));
}
[WorkItem(1087216, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1087216")]
......@@ -312,14 +312,14 @@ public void DynamicAttribute_KeywordEscaping()
public void DynamicAttribute_Locations()
{
// Standalone.
Assert.Equal("dynamic", typeof(object).GetTypeName(new[] { true }));
Assert.Equal("dynamic", typeof(object).GetTypeName(MakeCustomTypeInfo(true)));
// Array element type.
Assert.Equal("dynamic[]", typeof(object[]).GetTypeName(new[] { false, true }));
Assert.Equal("dynamic[][]", typeof(object[][]).GetTypeName(new[] { false, false, true }));
Assert.Equal("dynamic[]", typeof(object[]).GetTypeName(MakeCustomTypeInfo(false, true)));
Assert.Equal("dynamic[][]", typeof(object[][]).GetTypeName(MakeCustomTypeInfo(false, false, true)));
// Type argument of top-level type.
Assert.Equal("System.Func<dynamic>", typeof(Func<object>).GetTypeName(new[] { false, true }));
Assert.Equal("System.Func<dynamic>", typeof(Func<object>).GetTypeName(MakeCustomTypeInfo(false, true)));
var source = @"
namespace N
......@@ -342,9 +342,9 @@ public struct C
var typeBConstructed = typeB.MakeGenericType(typeof(object), typeof(object));
// Type argument of nested type.
Assert.Equal("N.A<object>.B<dynamic>", typeBConstructed.GetTypeName(new[] { false, false, true }));
Assert.Equal("N.A<dynamic>.B<object>", typeBConstructed.GetTypeName(new[] { false, true, false }));
Assert.Equal("N.A<dynamic>.B<dynamic>[]", typeBConstructed.MakeArrayType().GetTypeName(new[] { false, false, true, true }));
Assert.Equal("N.A<object>.B<dynamic>", typeBConstructed.GetTypeName(MakeCustomTypeInfo(false, false, true)));
Assert.Equal("N.A<dynamic>.B<object>", typeBConstructed.GetTypeName(MakeCustomTypeInfo(false, true, false)));
Assert.Equal("N.A<dynamic>.B<dynamic>[]", typeBConstructed.MakeArrayType().GetTypeName(MakeCustomTypeInfo(false, false, true, true)));
}
[WorkItem(1087216, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1087216")]
......@@ -352,19 +352,19 @@ public struct C
public void DynamicAttribute_InvalidFlags()
{
// Invalid true.
Assert.Equal("int", typeof(int).GetTypeName(new[] { true }));
Assert.Equal("dynamic[]", typeof(object[]).GetTypeName(new[] { true, true }));
Assert.Equal("int", typeof(int).GetTypeName(MakeCustomTypeInfo(true)));
Assert.Equal("dynamic[]", typeof(object[]).GetTypeName(MakeCustomTypeInfo(true, true)));
// Too many.
Assert.Equal("dynamic", typeof(object).GetTypeName(new[] { true, true }));
Assert.Equal("object", typeof(object).GetTypeName(new[] { false, true }));
Assert.Equal("dynamic", typeof(object).GetTypeName(MakeCustomTypeInfo(true, true)));
Assert.Equal("object", typeof(object).GetTypeName(MakeCustomTypeInfo(false, true)));
// Too few.
Assert.Equal("object[]", typeof(object[]).GetTypeName(new[] { true }));
Assert.Equal("object[]", typeof(object[]).GetTypeName(new[] { false }));
Assert.Equal("object[]", typeof(object[]).GetTypeName(MakeCustomTypeInfo(true)));
Assert.Equal("object[]", typeof(object[]).GetTypeName(MakeCustomTypeInfo(false)));
// Type argument of top-level type.
Assert.Equal("System.Func<object>", typeof(Func<object>).GetTypeName(new[] { true }));
Assert.Equal("System.Func<object>", typeof(Func<object>).GetTypeName(MakeCustomTypeInfo(true)));
var source = @"
namespace N
......@@ -387,9 +387,9 @@ public struct C
var typeBConstructed = typeB.MakeGenericType(typeof(object), typeof(object));
// Type argument of nested type.
Assert.Equal("N.A<object>.B<object>", typeBConstructed.GetTypeName(new[] { false }));
Assert.Equal("N.A<dynamic>.B<object>", typeBConstructed.GetTypeName(new[] { false, true }));
Assert.Equal("N.A<dynamic>.B<object>[]", typeBConstructed.MakeArrayType().GetTypeName(new[] { false, false, true }));
Assert.Equal("N.A<object>.B<object>", typeBConstructed.GetTypeName(MakeCustomTypeInfo(false)));
Assert.Equal("N.A<dynamic>.B<object>", typeBConstructed.GetTypeName(MakeCustomTypeInfo(false, true)));
Assert.Equal("N.A<dynamic>.B<object>[]", typeBConstructed.MakeArrayType().GetTypeName(MakeCustomTypeInfo(false, false, true)));
}
[WorkItem(1087216, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1087216")]
......
......@@ -24,6 +24,6 @@ internal abstract class CompileResult
this.FormatSpecifiers = formatSpecifiers;
}
public abstract CustomTypeInfo GetCustomTypeInfo();
public abstract Guid GetCustomTypeInfo(out ReadOnlyCollection<byte> payload);
}
}
// 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.CodeAnalysis.Collections;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using System;
using System.Collections.ObjectModel;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using System.Text;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
/// <remarks>
/// We can't instantiate <see cref="DkmClrCustomTypeInfo"/> in the unit tests
/// (since we run against a reference assembly), so we use this type as an
/// intermediary.
/// </remarks>
internal struct CustomTypeInfo
internal static class CustomTypeInfo
{
public Guid PayloadTypeId;
public ReadOnlyCollection<byte> Payload;
internal static readonly Guid PayloadTypeId = new Guid("108766CE-DF68-46EE-B761-0DCB7AC805F1");
internal static DkmClrCustomTypeInfo Create(
ReadOnlyCollection<byte> dynamicFlags,
ReadOnlyCollection<string> tupleElementNames)
{
var payload = Encode(dynamicFlags, tupleElementNames);
return (payload == null) ? null : DkmClrCustomTypeInfo.Create(PayloadTypeId, payload);
}
/// <summary>
/// Return a copy of the custom type info without tuple element names.
/// </summary>
internal static DkmClrCustomTypeInfo WithNoTupleElementNames(this DkmClrCustomTypeInfo typeInfo)
{
if ((typeInfo == null) || (typeInfo.Payload == null) || typeInfo.PayloadTypeId != PayloadTypeId)
{
return typeInfo;
}
var payload = typeInfo.Payload;
int length = payload[0] + 1;
if (length == payload.Count)
{
return typeInfo;
}
return DkmClrCustomTypeInfo.Create(PayloadTypeId, new ReadOnlyCollection<byte>(CopyBytes(payload, 0, length)));
}
/// <summary>
/// Return a copy of the custom type info with the leading dynamic flag removed.
/// There are no changes to tuple element names since this is used for walking
/// into an array element type only which does not affect tuple element names.
/// </summary>
internal static DkmClrCustomTypeInfo SkipOne(DkmClrCustomTypeInfo customInfo)
{
if (customInfo == null)
{
return customInfo;
}
ReadOnlyCollection<byte> dynamicFlags;
ReadOnlyCollection<string> tupleElementNames;
CustomTypeInfo.Decode(
customInfo.PayloadTypeId,
customInfo.Payload,
out dynamicFlags,
out tupleElementNames);
if (dynamicFlags == null)
{
return customInfo;
}
return Create(DynamicFlagsCustomTypeInfo.SkipOne(dynamicFlags), tupleElementNames);
}
internal static string GetTupleElementNameIfAny(ReadOnlyCollection<string> tupleElementNames, int index)
{
return tupleElementNames?[index];
}
// 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 '|'.
internal static ReadOnlyCollection<byte> Encode(
ReadOnlyCollection<byte> dynamicFlags,
ReadOnlyCollection<string> tupleElementNames)
{
if ((dynamicFlags == null) && (tupleElementNames == null))
{
return null;
}
var builder = ArrayBuilder<byte>.GetInstance();
if (dynamicFlags == null)
{
builder.Add(0);
}
else
{
int length = dynamicFlags.Count;
if (length > byte.MaxValue)
{
// Length exceeds capacity of byte.
return null;
}
builder.Add((byte)length);
builder.AddRange(dynamicFlags);
}
if (tupleElementNames != null)
{
var bytes = EncodeNames(tupleElementNames);
builder.AddRange(bytes);
}
return new ReadOnlyCollection<byte>(builder.ToArrayAndFree());
}
internal static void Decode(
Guid payloadTypeId,
ReadOnlyCollection<byte> payload,
out ReadOnlyCollection<byte> dynamicFlags,
out ReadOnlyCollection<string> tupleElementNames)
{
dynamicFlags = null;
tupleElementNames = null;
if ((payload == null) || (payloadTypeId != PayloadTypeId))
{
return;
}
int length = payload[0];
if (length > 0)
{
dynamicFlags = new ReadOnlyCollection<byte>(CopyBytes(payload, 1, length));
}
int start = length + 1;
if (start < payload.Count)
{
tupleElementNames = DecodeNames(payload, start);
}
}
private const char NameSeparator = '|';
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();
return new ReadOnlyCollection<byte>(Encoding.UTF8.GetBytes(str));
}
public CustomTypeInfo(Guid payloadTypeId, ReadOnlyCollection<byte> payload)
private static ReadOnlyCollection<string> DecodeNames(ReadOnlyCollection<byte> bytes, int start)
{
this.PayloadTypeId = payloadTypeId;
this.Payload = payload;
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)));
}
public DynamicFlagsCustomTypeInfo ToDynamicFlagsCustomTypeInfo()
private static byte[] CopyBytes(ReadOnlyCollection<byte> bytes, int start, int length)
{
return DynamicFlagsCustomTypeInfo.Create(this);
var array = new byte[length];
for (int i = 0; i < length; i++)
{
array[i] = bytes[start + i];
}
return array;
}
public DkmClrCustomTypeInfo ToDkmClrCustomTypeInfo()
private static string[] NullNotEmpty(string[] names)
{
return Payload == null
? null
: DkmClrCustomTypeInfo.Create(PayloadTypeId, Payload);
var builder = ArrayBuilder<string>.GetInstance(names.Length);
bool hasNull = false;
foreach (var name in names)
{
if (string.IsNullOrEmpty(name))
{
hasNull = true;
builder.Add(null);
}
else
{
builder.Add(name);
}
}
if (hasNull)
{
names = builder.ToArray();
}
builder.Free();
return names;
}
}
}
......@@ -158,6 +158,9 @@ internal static object GetSymReader(this DkmClrModuleInstance clrModule)
Debug.Assert(compResult.TypeName != null);
Debug.Assert(compResult.MethodName != null);
ReadOnlyCollection<byte> customTypeInfo;
Guid customTypeInfoId = compResult.GetCustomTypeInfo(out customTypeInfo);
return DkmCompiledClrInspectionQuery.Create(
runtimeInstance,
Binary: new ReadOnlyCollection<byte>(compResult.Assembly),
......@@ -171,7 +174,12 @@ internal static object GetSymReader(this DkmClrModuleInstance clrModule)
Access: resultProperties.AccessType,
StorageType: resultProperties.StorageType,
TypeModifierFlags: resultProperties.ModifierFlags,
CustomTypeInfo: compResult.GetCustomTypeInfo().ToDkmClrCustomTypeInfo());
CustomTypeInfo: customTypeInfo.ToCustomTypeInfo(customTypeInfoId));
}
internal static DkmClrCustomTypeInfo ToCustomTypeInfo(this ReadOnlyCollection<byte> payload, Guid payloadTypeId)
{
return (payload == null) ? null : DkmClrCustomTypeInfo.Create(payloadTypeId, payload);
}
internal static ResultProperties GetResultProperties<TSymbol>(this TSymbol symbol, DkmClrCompilationResultFlags flags, bool isConstant)
......
// 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.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal partial struct DynamicFlagsCustomTypeInfo
internal static class DynamicFlagsCustomTypeInfo
{
/// <remarks>Internal for testing.</remarks>
internal static readonly Guid PayloadTypeId = new Guid("826D6EC1-DC4B-46AF-BE05-CD3F1A1FD4AC");
private readonly ReadOnlyCollection<byte> _bytes;
private DynamicFlagsCustomTypeInfo(ReadOnlyCollection<byte> bytes)
{
_bytes = bytes;
}
private DynamicFlagsCustomTypeInfo(ArrayBuilder<bool> dynamicFlags, int startIndex)
internal static ReadOnlyCollection<byte> ToBytes(ArrayBuilder<bool> dynamicFlags, int startIndex = 0)
{
Debug.Assert(dynamicFlags != null);
Debug.Assert(startIndex >= 0);
int numFlags = dynamicFlags.Count - startIndex;
Debug.Assert(numFlags > 0);
if (numFlags == 0)
{
return null;
}
int numBytes = (numFlags + 7) / 8;
byte[] bytes = new byte[numBytes];
......@@ -51,19 +42,19 @@ private DynamicFlagsCustomTypeInfo(ArrayBuilder<bool> dynamicFlags, int startInd
ALL_FLAGS_READ:
_bytes = seenTrue ? new ReadOnlyCollection<byte>(bytes) : null;
return seenTrue ? new ReadOnlyCollection<byte>(bytes) : null;
}
public bool this[int i]
internal static bool GetFlag(ReadOnlyCollection<byte> bytes, int index)
{
get
Debug.Assert(index >= 0);
if (bytes == null)
{
Debug.Assert(i >= 0);
var b = i / 8;
return _bytes != null &&
b < _bytes.Count &&
(_bytes[b] & (1 << (i % 8))) != 0;
return false;
}
var b = index / 8;
return b < bytes.Count &&
(bytes[b] & (1 << (index % 8))) != 0;
}
/// <remarks>
......@@ -72,14 +63,14 @@ private DynamicFlagsCustomTypeInfo(ArrayBuilder<bool> dynamicFlags, int startInd
/// It may have more (for padding) or fewer (for compactness) falses.
/// It is, however, guaranteed to include the last true.
/// </remarks>
internal void CopyTo(ArrayBuilder<bool> builder)
internal static void CopyTo(ReadOnlyCollection<byte> bytes, ArrayBuilder<bool> builder)
{
if (_bytes == null)
if (bytes == null)
{
return;
}
foreach (byte b in _bytes)
foreach (byte b in bytes)
{
for (int i = 0; i < 8; i++)
{
......@@ -88,40 +79,18 @@ internal void CopyTo(ArrayBuilder<bool> builder)
}
}
internal ReadOnlyCollection<byte> GetCustomTypeInfoPayload() => Any() ? _bytes : null;
public DkmClrCustomTypeInfo GetCustomTypeInfo() => Any() ? DkmClrCustomTypeInfo.Create(PayloadTypeId, _bytes) : null;
public DynamicFlagsCustomTypeInfo SkipOne()
internal static ReadOnlyCollection<byte> SkipOne(ReadOnlyCollection<byte> bytes)
{
if (_bytes == null)
if (bytes == null)
{
return this;
return bytes;
}
var builder = ArrayBuilder<bool>.GetInstance();
this.CopyTo(builder);
var result = new DynamicFlagsCustomTypeInfo(builder, startIndex: 1);
CopyTo(bytes, builder);
var result = ToBytes(builder, startIndex: 1);
builder.Free();
return result;
}
public bool Any()
{
if (_bytes == null)
{
return false;
}
for (int b = 0; b < _bytes.Count; b++)
{
if (_bytes[b] != 0)
{
return true;
}
}
return false;
}
}
}
// 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.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal partial struct DynamicFlagsCustomTypeInfo
{
public static DynamicFlagsCustomTypeInfo Create(CustomTypeInfo customTypeInfo)
{
return new DynamicFlagsCustomTypeInfo(customTypeInfo.PayloadTypeId == PayloadTypeId ? customTypeInfo.Payload : null);
}
public static DynamicFlagsCustomTypeInfo Create(ImmutableArray<bool> dynamicFlags)
{
Debug.Assert(!dynamicFlags.IsDefaultOrEmpty);
var builder = ArrayBuilder<bool>.GetInstance(dynamicFlags.Length);
builder.AddRange(dynamicFlags);
var result = new DynamicFlagsCustomTypeInfo(builder, startIndex: 0);
builder.Free();
return result;
}
}
}
......@@ -85,9 +85,8 @@ private static ImmutableArray<Alias> GetAliases(DkmClrRuntimeInstance runtimeIns
dkmAlias.Name,
dkmAlias.FullName,
dkmAlias.Type,
new CustomTypeInfo(
dkmAlias.CustomTypeInfoPayloadTypeId,
dkmAlias.CustomTypeInfoPayload)));
dkmAlias.CustomTypeInfoPayloadTypeId,
dkmAlias.CustomTypeInfoPayload));
}
return builder.ToImmutableAndFree();
}
......@@ -384,13 +383,15 @@ void IDkmModuleModifiedNotification.OnModuleModified(DkmModuleInstance moduleIns
private static DkmClrLocalVariableInfo ToLocalVariableInfo(LocalAndMethod local)
{
ReadOnlyCollection<byte> customTypeInfo;
Guid customTypeInfoId = local.GetCustomTypeInfo(out customTypeInfo);
return DkmClrLocalVariableInfo.Create(
local.LocalDisplayName,
local.LocalName,
local.MethodName,
local.Flags,
DkmEvaluationResultCategory.Data,
local.GetCustomTypeInfo().ToDkmClrCustomTypeInfo());
customTypeInfo.ToCustomTypeInfo(customTypeInfoId));
}
private struct GetLocalsResult
......
......@@ -29,7 +29,6 @@
<Compile Include="CustomTypeInfo.cs" />
<Compile Include="DebuggerDiagnosticFormatter.cs" />
<Compile Include="DynamicFlagsCustomTypeInfo.cs" />
<Compile Include="DynamicFlagsCustomTypeInfo_Factory.cs" />
<Compile Include="EESymbolProvider.cs" />
<Compile Include="ILSpan.cs" />
<Compile Include="PDB\MethodDebugInfo.Native.cs" />
......@@ -95,4 +94,4 @@
<None Include="project.json" />
</ItemGroup>
<Import Project="..\..\..\..\..\build\Targets\VSL.Imports.targets" />
</Project>
</Project>
\ No newline at end of file
// 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.Evaluation.ClrCompilation;
using System;
using System.Collections.ObjectModel;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
......@@ -23,6 +25,6 @@ public LocalAndMethod(string localName, string localDisplayName, string methodNa
this.Flags = flags;
}
public abstract CustomTypeInfo GetCustomTypeInfo();
public abstract Guid GetCustomTypeInfo(out ReadOnlyCollection<byte> payload);
}
}
......@@ -2,8 +2,8 @@
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using Roslyn.Utilities;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
......@@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal struct Alias
{
internal Alias(DkmClrAliasKind kind, string name, string fullName, string type, CustomTypeInfo customTypeInfo)
internal Alias(DkmClrAliasKind kind, string name, string fullName, string type, Guid customTypeInfoId, ReadOnlyCollection<byte> customTypeInfo)
{
Debug.Assert(!string.IsNullOrEmpty(fullName));
Debug.Assert(!string.IsNullOrEmpty(type));
......@@ -20,6 +20,7 @@ internal Alias(DkmClrAliasKind kind, string name, string fullName, string type,
this.Name = name;
this.FullName = fullName;
this.Type = type;
this.CustomTypeInfoId = customTypeInfoId;
this.CustomTypeInfo = customTypeInfo;
}
......@@ -27,7 +28,8 @@ internal Alias(DkmClrAliasKind kind, string name, string fullName, string type,
internal readonly string Name;
internal readonly string FullName;
internal readonly string Type;
internal readonly CustomTypeInfo CustomTypeInfo;
internal readonly Guid CustomTypeInfoId;
internal readonly ReadOnlyCollection<byte> CustomTypeInfo;
}
internal static class PseudoVariableUtilities
......
......@@ -37,7 +37,7 @@ internal static DynamicViewExpansion CreateExpansion(DkmInspectionContext inspec
var proxyType = proxyValue.Type;
var itemsMemberExpansion = RootHiddenExpansion.CreateExpansion(
proxyType.GetMemberByName("Items"),
DynamicFlagsMap.Create(new TypeAndCustomInfo(proxyType)));
CustomTypeInfoTypeArgumentMap.Create(new TypeAndCustomInfo(proxyType)));
return new DynamicViewExpansion(proxyValue, itemsMemberExpansion);
}
......
......@@ -53,7 +53,7 @@ internal sealed class MemberExpansion : Expansion
return null;
}
var dynamicFlagsMap = DynamicFlagsMap.Create(declaredTypeAndInfo);
var customTypeInfoMap = CustomTypeInfoTypeArgumentMap.Create(declaredTypeAndInfo);
var expansions = ArrayBuilder<Expansion>.GetInstance();
......@@ -93,7 +93,7 @@ internal sealed class MemberExpansion : Expansion
Expansion nonPublicInstanceExpansion;
GetPublicAndNonPublicMembers(
instanceMembers,
dynamicFlagsMap,
customTypeInfoMap,
out publicInstanceExpansion,
out nonPublicInstanceExpansion);
......@@ -102,7 +102,7 @@ internal sealed class MemberExpansion : Expansion
Expansion nonPublicStaticExpansion;
GetPublicAndNonPublicMembers(
staticMembers,
dynamicFlagsMap,
customTypeInfoMap,
out publicStaticExpansion,
out nonPublicStaticExpansion);
......@@ -162,7 +162,7 @@ internal sealed class MemberExpansion : Expansion
private static void GetPublicAndNonPublicMembers(
ArrayBuilder<MemberAndDeclarationInfo> allMembers,
DynamicFlagsMap dynamicFlagsMap,
CustomTypeInfoTypeArgumentMap customTypeInfoMap,
out Expansion publicExpansion,
out Expansion nonPublicExpansion)
{
......@@ -179,10 +179,10 @@ internal sealed class MemberExpansion : Expansion
case DkmClrDebuggerBrowsableAttributeState.RootHidden:
if (publicMembers.Count > 0)
{
publicExpansions.Add(new MemberExpansion(publicMembers.ToArray(), dynamicFlagsMap));
publicExpansions.Add(new MemberExpansion(publicMembers.ToArray(), customTypeInfoMap));
publicMembers.Clear();
}
publicExpansions.Add(new RootHiddenExpansion(member, dynamicFlagsMap));
publicExpansions.Add(new RootHiddenExpansion(member, customTypeInfoMap));
continue;
case DkmClrDebuggerBrowsableAttributeState.Never:
continue;
......@@ -201,7 +201,7 @@ internal sealed class MemberExpansion : Expansion
if (publicMembers.Count > 0)
{
publicExpansions.Add(new MemberExpansion(publicMembers.ToArray(), dynamicFlagsMap));
publicExpansions.Add(new MemberExpansion(publicMembers.ToArray(), customTypeInfoMap));
}
publicMembers.Free();
......@@ -210,22 +210,22 @@ internal sealed class MemberExpansion : Expansion
nonPublicExpansion = (nonPublicMembers.Count > 0) ?
new NonPublicMembersExpansion(
members: new MemberExpansion(nonPublicMembers.ToArray(), dynamicFlagsMap)) :
members: new MemberExpansion(nonPublicMembers.ToArray(), customTypeInfoMap)) :
null;
nonPublicMembers.Free();
}
private readonly MemberAndDeclarationInfo[] _members;
private readonly DynamicFlagsMap _dynamicFlagsMap;
private readonly CustomTypeInfoTypeArgumentMap _customTypeInfoMap;
private MemberExpansion(MemberAndDeclarationInfo[] members, DynamicFlagsMap dynamicFlagsMap)
private MemberExpansion(MemberAndDeclarationInfo[] members, CustomTypeInfoTypeArgumentMap customTypeInfoMap)
{
Debug.Assert(members != null);
Debug.Assert(members.Length > 0);
Debug.Assert(dynamicFlagsMap != null);
Debug.Assert(customTypeInfoMap != null);
_members = members;
_dynamicFlagsMap = dynamicFlagsMap;
_customTypeInfoMap = customTypeInfoMap;
}
internal override void GetRows(
......@@ -246,7 +246,7 @@ private MemberExpansion(MemberAndDeclarationInfo[] members, DynamicFlagsMap dyna
int offset = startIndex2 - index;
for (int i = 0; i < count2; i++)
{
rows.Add(GetMemberRow(resultProvider, inspectionContext, value, _members[i + offset], parent, _dynamicFlagsMap));
rows.Add(GetMemberRow(resultProvider, inspectionContext, value, _members[i + offset], parent, _customTypeInfoMap));
}
index += _members.Length;
......@@ -258,7 +258,7 @@ private MemberExpansion(MemberAndDeclarationInfo[] members, DynamicFlagsMap dyna
DkmClrValue value,
MemberAndDeclarationInfo member,
EvalResultDataItem parent,
DynamicFlagsMap dynamicFlagsMap)
CustomTypeInfoTypeArgumentMap customTypeInfoMap)
{
var memberValue = value.GetMemberValue(member, inspectionContext);
return CreateMemberDataItem(
......@@ -267,7 +267,7 @@ private MemberExpansion(MemberAndDeclarationInfo[] members, DynamicFlagsMap dyna
member,
memberValue,
parent,
dynamicFlagsMap,
customTypeInfoMap,
ExpansionFlags.All);
}
......@@ -407,17 +407,17 @@ internal StaticMembersExpansion(DkmClrType type, Expansion members)
MemberAndDeclarationInfo member,
DkmClrValue memberValue,
EvalResultDataItem parent,
DynamicFlagsMap dynamicFlagsMap,
CustomTypeInfoTypeArgumentMap customTypeInfoMap,
ExpansionFlags flags)
{
var fullNameProvider = resultProvider.FullNameProvider;
var declaredType = member.Type;
var declaredTypeInfo = dynamicFlagsMap.SubstituteDynamicFlags(member.OriginalDefinitionType, DynamicFlagsCustomTypeInfo.Create(member.TypeInfo)).GetCustomTypeInfo();
var declaredTypeInfo = customTypeInfoMap.SubstituteCustomTypeInfo(member.OriginalDefinitionType, member.TypeInfo);
string memberName;
// Considering, we're not handling the case of a member inherited from a generic base type.
var typeDeclaringMember = member.GetExplicitlyImplementedInterface(out memberName) ?? member.DeclaringType;
var typeDeclaringMemberInfo = typeDeclaringMember.IsInterface
? dynamicFlagsMap.SubstituteDynamicFlags(typeDeclaringMember.GetInterfaceListEntry(member.DeclaringType), originalDynamicFlags: default(DynamicFlagsCustomTypeInfo)).GetCustomTypeInfo()
? customTypeInfoMap.SubstituteCustomTypeInfo(typeDeclaringMember.GetInterfaceListEntry(member.DeclaringType), customInfo: null)
: null;
var memberNameForFullName = fullNameProvider.GetClrValidIdentifier(inspectionContext, memberName);
var appDomain = memberValue.Type.AppDomain;
......
......@@ -9,18 +9,18 @@ internal sealed class RootHiddenExpansion : Expansion
{
internal static Expansion CreateExpansion(
MemberAndDeclarationInfo members,
DynamicFlagsMap dynamicFlagsMap)
CustomTypeInfoTypeArgumentMap customTypeInfoMap)
{
return new RootHiddenExpansion(members, dynamicFlagsMap);
return new RootHiddenExpansion(members, customTypeInfoMap);
}
private readonly MemberAndDeclarationInfo _member;
private readonly DynamicFlagsMap _dynamicFlagsMap;
private readonly CustomTypeInfoTypeArgumentMap _customTypeInfoMap;
internal RootHiddenExpansion(MemberAndDeclarationInfo member, DynamicFlagsMap dynamicFlagsMap)
internal RootHiddenExpansion(MemberAndDeclarationInfo member, CustomTypeInfoTypeArgumentMap customTypeInfoMap)
{
_member = member;
_dynamicFlagsMap = dynamicFlagsMap;
_customTypeInfoMap = customTypeInfoMap;
}
internal override void GetRows(
......@@ -58,7 +58,7 @@ internal RootHiddenExpansion(MemberAndDeclarationInfo member, DynamicFlagsMap dy
_member,
memberValue,
parent,
_dynamicFlagsMap,
_customTypeInfoMap,
ExpansionFlags.IncludeBaseMembers | ExpansionFlags.IncludeResultsView);
var expansion = other.Expansion;
if (expansion != null)
......
......@@ -13,7 +13,7 @@ internal sealed class TypeVariablesExpansion : Expansion
{
private readonly Type[] _typeParameters;
private readonly Type[] _typeArguments;
private readonly DynamicFlagsMap _dynamicFlagsMap;
private readonly CustomTypeInfoTypeArgumentMap _customTypeInfoMap;
internal TypeVariablesExpansion(TypeAndCustomInfo declaredTypeAndInfo)
{
......@@ -21,7 +21,7 @@ internal TypeVariablesExpansion(TypeAndCustomInfo declaredTypeAndInfo)
Debug.Assert(declaredType.IsGenericType);
Debug.Assert(!declaredType.IsGenericTypeDefinition);
_dynamicFlagsMap = DynamicFlagsMap.Create(declaredTypeAndInfo);
_customTypeInfoMap = CustomTypeInfoTypeArgumentMap.Create(declaredTypeAndInfo);
var typeDef = declaredType.GetGenericTypeDefinition();
_typeParameters = typeDef.GetGenericArguments();
......@@ -64,7 +64,7 @@ internal TypeVariablesExpansion(TypeAndCustomInfo declaredTypeAndInfo)
{
var typeParameter = _typeParameters[index];
var typeArgument = _typeArguments[index];
var typeArgumentInfo = _dynamicFlagsMap.SubstituteDynamicFlags(typeParameter, default(DynamicFlagsCustomTypeInfo)).GetCustomTypeInfo();
var typeArgumentInfo = _customTypeInfoMap.SubstituteCustomTypeInfo(typeParameter, customInfo: null);
var formatSpecifiers = Formatter.NoFormatSpecifiers;
return new EvalResult(
ExpansionKind.TypeVariable,
......
// 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.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis.Collections;
......@@ -21,10 +22,26 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
throw new ArgumentNullException(nameof(type));
}
var dynamicFlags = DynamicFlagsCustomTypeInfo.Create(typeAndInfo.Info);
var index = 0;
ReadOnlyCollection<byte> dynamicFlags = null;
ReadOnlyCollection<string> tupleElementNames = null;
var typeInfo = typeAndInfo.Info;
if (typeInfo != null)
{
CustomTypeInfo.Decode(typeInfo.PayloadTypeId, typeInfo.Payload, out dynamicFlags, out tupleElementNames);
}
var dynamicFlagIndex = 0;
var tupleElementIndex = 0;
var pooled = PooledStringBuilder.GetInstance();
AppendQualifiedTypeName(pooled.Builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers, out sawInvalidIdentifier);
AppendQualifiedTypeName(
pooled.Builder,
type,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
escapeKeywordIdentifiers,
out sawInvalidIdentifier);
return pooled.ToStringAndFree();
}
......@@ -38,13 +55,14 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
/// No special handling is required for anonymous types - they are expected to be
/// emitted with <see cref="DebuggerDisplayAttribute.Type"/> set to "&lt;Anonymous Type&gt;.
/// This is fortunate, since we don't have a good way to recognize them in metadata.
/// Does not call itself (directly).
/// </remarks>
protected void AppendQualifiedTypeName(
StringBuilder builder,
Type type,
DynamicFlagsCustomTypeInfo dynamicFlags,
ref int index,
ReadOnlyCollection<byte> dynamicFlags,
ref int dynamicFlagIndex,
ReadOnlyCollection<string> tupleElementNames,
ref int tupleElementIndex,
bool escapeKeywordIdentifiers,
out bool sawInvalidIdentifier)
{
......@@ -54,7 +72,7 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
// We'll reconstruct this information later from originalType.
while (type.IsArray)
{
index++;
dynamicFlagIndex++;
type = type.GetElementType();
}
......@@ -67,7 +85,7 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
// Null for function pointers.
break;
}
index++;
dynamicFlagIndex++;
pointerCount++;
type = elementType;
}
......@@ -76,7 +94,7 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
Type typeArg;
while ((typeArg = type.GetNullableTypeArgument()) != null)
{
index++;
dynamicFlagIndex++;
nullableCount++;
type = typeArg;
}
......@@ -84,7 +102,15 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
Debug.Assert(pointerCount == 0 || nullableCount == 0, "Benign: pointer to nullable?");
AppendQualifiedTypeNameInternal(builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers, out sawInvalidIdentifier);
AppendQualifiedTypeNameInternal(
builder,
type,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
escapeKeywordIdentifiers,
out sawInvalidIdentifier);
builder.Append('?', nullableCount);
builder.Append('*', pointerCount);
......@@ -111,12 +137,14 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
private void AppendQualifiedTypeNameInternal(
StringBuilder builder,
Type type,
DynamicFlagsCustomTypeInfo dynamicFlags,
ref int index,
ReadOnlyCollection<byte> dynamicFlags,
ref int dynamicFlagIndex,
ReadOnlyCollection<string> tupleElementNames,
ref int tupleElementIndex,
bool escapeKeywordIdentifiers,
out bool sawInvalidIdentifier)
{
var isDynamic = dynamicFlags[index++] && type.IsObject();
var isDynamic = DynamicFlagsCustomTypeInfo.GetFlag(dynamicFlags, dynamicFlagIndex++) && type.IsObject();
if (AppendSpecialTypeName(builder, type, isDynamic))
{
sawInvalidIdentifier = false;
......@@ -135,8 +163,25 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
int cardinality;
if (type.IsTupleCompatible(out cardinality))
{
AppendTupleFields(builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers, out sawInvalidIdentifier);
return;
if (cardinality == 1)
{
// Not displayed as a tuple but is included in tuple element names.
tupleElementIndex++;
}
else
{
AppendTupleElements(
builder,
type,
cardinality,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
escapeKeywordIdentifiers,
out sawInvalidIdentifier);
return;
}
}
// Note: in the Reflection/LMR object model, all type arguments are on the most nested type.
......@@ -178,7 +223,18 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
// ACASEY: I explored the type in the debugger and couldn't find the arity stored/exposed separately.
int arity = hasTypeArguments ? containingType.GetGenericArguments().Length - typeArgumentOffset : 0;
AppendUnqualifiedTypeName(builder, containingType, dynamicFlags, ref index, escapeKeywordIdentifiers, typeArguments, typeArgumentOffset, arity, out sawSingleInvalidIdentifier);
AppendUnqualifiedTypeName(
builder,
containingType,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
escapeKeywordIdentifiers,
typeArguments,
typeArgumentOffset,
arity,
out sawSingleInvalidIdentifier);
sawInvalidIdentifier |= sawSingleInvalidIdentifier;
builder.Append('.');
......@@ -193,7 +249,18 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
sawInvalidIdentifier |= sawSingleInvalidIdentifier;
}
AppendUnqualifiedTypeName(builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers, typeArguments, typeArgumentOffset, numTypeArguments - typeArgumentOffset, out sawSingleInvalidIdentifier);
AppendUnqualifiedTypeName(
builder,
type,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
escapeKeywordIdentifiers,
typeArguments,
typeArgumentOffset,
numTypeArguments - typeArgumentOffset,
out sawSingleInvalidIdentifier);
sawInvalidIdentifier |= sawSingleInvalidIdentifier;
}
......@@ -245,7 +312,9 @@ private void AppendNamespacePrefix(StringBuilder builder, Type type, bool escape
/// <param name="builder">Builder to which the name will be appended.</param>
/// <param name="type">Type, the name of which will be appended.</param>
/// <param name="dynamicFlags">Flags indicating which occurrences of &quot;object&quot; need to be replaced by &quot;dynamic&quot;.</param>
/// <param name="index">Current index into <paramref name="dynamicFlags"/>.</param>
/// <param name="dynamicFlagIndex">Current index into <paramref name="dynamicFlags"/>.</param>
/// <param name="tupleElementNames">Non-default tuple names.</param>
/// <param name="tupleElementIndex">Current index into <paramref name="tupleElementNames"/>.</param>
/// <param name="escapeKeywordIdentifiers">True if identifiers that are also keywords should be prefixed with '@'.</param>
/// <param name="typeArguments">
/// The type arguments of the type passed to <see cref="AppendQualifiedTypeNameInternal"/>, which might be nested
......@@ -267,8 +336,10 @@ private void AppendNamespacePrefix(StringBuilder builder, Type type, bool escape
private void AppendUnqualifiedTypeName(
StringBuilder builder,
Type type,
DynamicFlagsCustomTypeInfo dynamicFlags,
ref int index,
ReadOnlyCollection<byte> dynamicFlags,
ref int dynamicFlagIndex,
ReadOnlyCollection<string> tupleElementNames,
ref int tupleElementIndex,
bool escapeKeywordIdentifiers,
Type[] typeArguments,
int typeArgumentOffset,
......@@ -287,19 +358,34 @@ private void AppendNamespacePrefix(StringBuilder builder, Type type, bool escape
AppendIdentifier(builder, escapeKeywordIdentifiers, unmangledName, out sawInvalidIdentifier);
bool argumentsSawInvalidIdentifier;
AppendGenericTypeArguments(builder, typeArguments, typeArgumentOffset, dynamicFlags, ref index, arity, escapeKeywordIdentifiers, out argumentsSawInvalidIdentifier);
AppendGenericTypeArguments(
builder,
typeArguments,
typeArgumentOffset,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
arity,
escapeKeywordIdentifiers,
out argumentsSawInvalidIdentifier);
sawInvalidIdentifier |= argumentsSawInvalidIdentifier;
}
private void AppendTupleFields(
private void AppendTupleElements(
StringBuilder builder,
Type type,
DynamicFlagsCustomTypeInfo dynamicFlags,
ref int index,
int cardinality,
ReadOnlyCollection<byte> dynamicFlags,
ref int dynamicFlagIndex,
ReadOnlyCollection<string> tupleElementNames,
ref int tupleElementIndex,
bool escapeKeywordIdentifiers,
out bool sawInvalidIdentifier)
{
sawInvalidIdentifier = false;
int nameIndex = tupleElementIndex;
tupleElementIndex += cardinality;
builder.Append('(');
bool any = false;
while (true)
......@@ -316,7 +402,18 @@ private void AppendNamespacePrefix(StringBuilder builder, Type type, bool escape
builder.Append(", ");
}
bool sawSingleInvalidIdentifier;
AppendQualifiedTypeName(builder, typeArguments[i], dynamicFlags, ref index, escapeKeywordIdentifiers, out sawSingleInvalidIdentifier);
var name = CustomTypeInfo.GetTupleElementNameIfAny(tupleElementNames, nameIndex);
nameIndex++;
AppendTupleElement(
builder,
typeArguments[i],
name,
dynamicFlags,
ref dynamicFlagIndex,
tupleElementNames,
ref tupleElementIndex,
escapeKeywordIdentifiers,
sawInvalidIdentifier: out sawSingleInvalidIdentifier);
sawInvalidIdentifier |= sawSingleInvalidIdentifier;
any = true;
}
......@@ -324,8 +421,8 @@ private void AppendNamespacePrefix(StringBuilder builder, Type type, bool escape
{
break;
}
Debug.Assert(!dynamicFlags[index]);
index++;
Debug.Assert(!DynamicFlagsCustomTypeInfo.GetFlag(dynamicFlags, dynamicFlagIndex));
dynamicFlagIndex++;
type = typeArguments[nTypeArgs - 1];
}
builder.Append(')');
......@@ -352,12 +449,25 @@ protected void AppendIdentifier(StringBuilder builder, bool escapeKeywordIdentif
StringBuilder builder,
Type[] typeArguments,
int typeArgumentOffset,
DynamicFlagsCustomTypeInfo dynamicFlags,
ref int index,
ReadOnlyCollection<byte> dynamicFlags,
ref int dynamicFlagIndex,
ReadOnlyCollection<string> tupleElementNames,
ref int tupleElementIndex,
int arity,
bool escapeKeywordIdentifiers,
out bool sawInvalidIdentifier);
protected abstract void AppendTupleElement(
StringBuilder builder,
Type type,
string nameOpt,
ReadOnlyCollection<byte> dynamicFlags,
ref int dynamicFlagIndex,
ReadOnlyCollection<string> tupleElementNames,
ref int tupleElementIndex,
bool escapeKeywordIdentifiers,
out bool sawInvalidIdentifier);
protected abstract void AppendRankSpecifier(StringBuilder builder, int rank);
protected abstract bool AppendSpecialTypeName(StringBuilder builder, Type type, bool isDynamic);
......
......@@ -103,7 +103,7 @@ private string GetValueString(DkmClrValue value, DkmInspectionContext inspection
else
{
int cardinality;
if (lmrType.IsTupleCompatible(out cardinality))
if (lmrType.IsTupleCompatible(out cardinality) && (cardinality > 1))
{
var values = ArrayBuilder<string>.GetInstance();
value.GetTupleFieldValues(cardinality, values, inspectionContext);
......
// 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.ClrCompilation;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal partial struct DynamicFlagsCustomTypeInfo
{
public static DynamicFlagsCustomTypeInfo Create(DkmClrCustomTypeInfo typeInfo)
{
return new DynamicFlagsCustomTypeInfo(typeInfo != null && typeInfo.PayloadTypeId == PayloadTypeId ? typeInfo.Payload : null);
}
public static DynamicFlagsCustomTypeInfo Create(ArrayBuilder<bool> dynamicFlags)
{
Debug.Assert(dynamicFlags != null);
Debug.Assert(dynamicFlags.Count > 0);
return new DynamicFlagsCustomTypeInfo(dynamicFlags, startIndex: 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.Collections;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Type = Microsoft.VisualStudio.Debugger.Metadata.Type;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal sealed class DynamicFlagsMap
internal sealed class CustomTypeInfoTypeArgumentMap
{
private static readonly DynamicFlagsMap s_empty = new DynamicFlagsMap();
private static readonly CustomTypeInfoTypeArgumentMap s_empty = new CustomTypeInfoTypeArgumentMap();
private readonly Type _typeDefinition;
private readonly DynamicFlagsCustomTypeInfo _dynamicFlags;
private readonly int[] _startIndices;
private readonly ReadOnlyCollection<byte> _dynamicFlags;
private readonly int[] _dynamicFlagStartIndices;
private readonly ReadOnlyCollection<string> _tupleElementNames;
private readonly int[] _tupleElementNameStartIndices;
private DynamicFlagsMap()
private CustomTypeInfoTypeArgumentMap()
{
}
private DynamicFlagsMap(
private CustomTypeInfoTypeArgumentMap(
Type typeDefinition,
DynamicFlagsCustomTypeInfo dynamicFlagsArray,
int[] startIndices)
ReadOnlyCollection<byte> dynamicFlags,
int[] dynamicFlagStartIndices,
ReadOnlyCollection<string> tupleElementNames,
int[] tupleElementNameStartIndices)
{
Debug.Assert(typeDefinition != null);
Debug.Assert(startIndices != null);
Debug.Assert((dynamicFlags != null) == (dynamicFlagStartIndices != null));
Debug.Assert((tupleElementNames != null) == (tupleElementNameStartIndices != null));
#if DEBUG
Debug.Assert(typeDefinition.IsGenericTypeDefinition);
Debug.Assert(startIndices.Length == typeDefinition.GetGenericArguments().Length + 1);
int n = typeDefinition.GetGenericArguments().Length;
Debug.Assert(dynamicFlagStartIndices == null || dynamicFlagStartIndices.Length == n + 1);
Debug.Assert(tupleElementNameStartIndices == null || tupleElementNameStartIndices.Length == n + 1);
#endif
_typeDefinition = typeDefinition;
_dynamicFlags = dynamicFlagsArray;
_startIndices = startIndices;
_dynamicFlags = dynamicFlags;
_dynamicFlagStartIndices = dynamicFlagStartIndices;
_tupleElementNames = tupleElementNames;
_tupleElementNameStartIndices = tupleElementNameStartIndices;
}
internal static DynamicFlagsMap Create(TypeAndCustomInfo typeAndInfo)
internal static CustomTypeInfoTypeArgumentMap Create(TypeAndCustomInfo typeAndInfo)
{
var type = typeAndInfo.Type;
Debug.Assert(type != null);
if (!type.IsGenericType)
var typeInfo = typeAndInfo.Info;
if (typeInfo == null)
{
return s_empty;
}
var dynamicFlags = DynamicFlagsCustomTypeInfo.Create(typeAndInfo.Info);
if (!dynamicFlags.Any())
var type = typeAndInfo.Type;
Debug.Assert(type != null);
if (!type.IsGenericType)
{
return s_empty;
}
ReadOnlyCollection<byte> dynamicFlags;
ReadOnlyCollection<string> tupleElementNames;
CustomTypeInfo.Decode(typeInfo.PayloadTypeId, typeInfo.Payload, out dynamicFlags, out tupleElementNames);
Debug.Assert(dynamicFlags != null || tupleElementNames != null);
var typeDefinition = type.GetGenericTypeDefinition();
Debug.Assert(typeDefinition != null);
var dynamicFlagStartIndices = (dynamicFlags == null) ? null : GetDynamicFlagStartIndices(type);
var tupleElementNameStartIndices = (tupleElementNames == null) ? null : GetTupleElementNameStartIndices(type);
return new CustomTypeInfoTypeArgumentMap(
typeDefinition,
dynamicFlags,
dynamicFlagStartIndices,
tupleElementNames,
tupleElementNameStartIndices);
}
internal DkmClrCustomTypeInfo SubstituteCustomTypeInfo(Type type, DkmClrCustomTypeInfo customInfo)
{
if (_typeDefinition == null)
{
return customInfo;
}
ReadOnlyCollection<byte> dynamicFlags = null;
ReadOnlyCollection<string> tupleElementNames = null;
if (customInfo != null)
{
CustomTypeInfo.Decode(
customInfo.PayloadTypeId,
customInfo.Payload,
out dynamicFlags,
out tupleElementNames);
}
var substitutedFlags = SubstituteDynamicFlags(type, dynamicFlags);
var substitutedNames = SubstituteTupleElementNames(type, tupleElementNames);
return CustomTypeInfo.Create(substitutedFlags, substitutedNames);
}
private ReadOnlyCollection<byte> SubstituteDynamicFlags(Type type, ReadOnlyCollection<byte> dynamicFlagsOpt)
{
var builder = ArrayBuilder<bool>.GetInstance();
int f = 0;
foreach (Type curr in new TypeWalker(type))
{
if (curr.IsGenericParameter && curr.DeclaringType.Equals(_typeDefinition))
{
AppendRangeFor(
curr,
_dynamicFlags,
_dynamicFlagStartIndices,
DynamicFlagsCustomTypeInfo.GetFlag,
builder);
}
else
{
builder.Add(DynamicFlagsCustomTypeInfo.GetFlag(dynamicFlagsOpt, f));
}
f++;
}
var result = DynamicFlagsCustomTypeInfo.ToBytes(builder);
builder.Free();
return result;
}
private ReadOnlyCollection<string> SubstituteTupleElementNames(Type type, ReadOnlyCollection<string> tupleElementNamesOpt)
{
var builder = ArrayBuilder<string>.GetInstance();
int i = 0;
foreach (Type curr in new TypeWalker(type))
{
if (curr.IsGenericParameter && curr.DeclaringType.Equals(_typeDefinition))
{
AppendRangeFor(
curr,
_tupleElementNames,
_tupleElementNameStartIndices,
CustomTypeInfo.GetTupleElementNameIfAny,
builder);
}
else
{
int n = GetTupleCardinalityIfAny(curr);
AppendRange(tupleElementNamesOpt, i, i + n, CustomTypeInfo.GetTupleElementNameIfAny, builder);
i += n;
}
}
var result = (builder.Count == 0) ? null : builder.ToImmutable();
builder.Free();
return result;
}
private static int[] GetDynamicFlagStartIndices(Type type)
{
var typeArgs = type.GetGenericArguments();
Debug.Assert(typeArgs.Length > 0);
int pos = 1; // Consider "type" to have already been consumed.
var startsBuilder = ArrayBuilder<int>.GetInstance();
var tupleElementNameStartIndices = ArrayBuilder<int>.GetInstance();
foreach (var typeArg in typeArgs)
{
startsBuilder.Add(pos);
......@@ -69,49 +182,73 @@ internal static DynamicFlagsMap Create(TypeAndCustomInfo typeAndInfo)
Debug.Assert(pos > 1);
startsBuilder.Add(pos);
return new DynamicFlagsMap(typeDefinition, dynamicFlags, startsBuilder.ToArrayAndFree());
return startsBuilder.ToArrayAndFree();
}
internal DynamicFlagsCustomTypeInfo SubstituteDynamicFlags(Type type, DynamicFlagsCustomTypeInfo originalDynamicFlags)
private static int[] GetTupleElementNameStartIndices(Type type)
{
if (_typeDefinition == null)
{
return originalDynamicFlags;
}
var substitutedFlags = ArrayBuilder<bool>.GetInstance();
int f = 0;
var typeArgs = type.GetGenericArguments();
Debug.Assert(typeArgs.Length > 0);
foreach (Type curr in new TypeWalker(type))
int pos = GetTupleCardinalityIfAny(type);
var startsBuilder = ArrayBuilder<int>.GetInstance();
var tupleElementNameStartIndices = ArrayBuilder<int>.GetInstance();
foreach (var typeArg in typeArgs)
{
if (curr.IsGenericParameter && curr.DeclaringType.Equals(_typeDefinition))
{
AppendFlagsFor(curr, substitutedFlags);
}
else
startsBuilder.Add(pos);
foreach (Type curr in new TypeWalker(typeArg))
{
substitutedFlags.Add(originalDynamicFlags[f]);
pos += GetTupleCardinalityIfAny(curr);
}
f++;
}
var result = DynamicFlagsCustomTypeInfo.Create(substitutedFlags);
substitutedFlags.Free();
return result;
Debug.Assert(pos > 1);
startsBuilder.Add(pos);
return startsBuilder.ToArrayAndFree();
}
private void AppendFlagsFor(Type type, ArrayBuilder<bool> builder)
// Returns cardinality if tuple type, otherwise 0.
private static int GetTupleCardinalityIfAny(Type type)
{
Debug.Assert(type.IsGenericParameter);
int cardinality;
type.IsTupleCompatible(out cardinality);
return cardinality;
}
private delegate U Map<T, U>(ReadOnlyCollection<T> collection, int index);
private static void AppendRangeFor<T, U>(
Type type,
ReadOnlyCollection<T> collection,
int[] startIndices,
Map<T, U> map,
ArrayBuilder<U> builder)
{
Debug.Assert(type.IsGenericParameter);
if (startIndices == null)
{
return;
}
var genericParameterPosition = type.GenericParameterPosition;
var start = _startIndices[genericParameterPosition];
var nextStart = _startIndices[genericParameterPosition + 1];
for (int i = start; i < nextStart; i++)
AppendRange(
collection,
startIndices[genericParameterPosition],
startIndices[genericParameterPosition + 1],
map,
builder);
}
private static void AppendRange<T, U>(
ReadOnlyCollection<T> collection,
int start,
int end,
Map<T, U> map,
ArrayBuilder<U> builder)
{
for (int i = start; i < end; i++)
{
builder.Add(_dynamicFlags[i]);
builder.Add(map(collection, i));
}
}
}
......
......@@ -2,50 +2,89 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using Microsoft.VisualStudio.Debugger.Metadata;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal static class DynamicHelpers
internal static class AttributeHelpers
{
public static DynamicFlagsCustomTypeInfo GetDynamicFlags(this IList<CustomAttributeData> attributes)
internal static DkmClrCustomTypeInfo GetCustomTypeInfo(this IList<CustomAttributeData> attributes)
{
ReadOnlyCollection<byte> dynamicFlags = null;
ReadOnlyCollection<string> tupleElementNames = null;
foreach (var attribute in attributes)
{
if (attribute.Constructor.DeclaringType.IsType("System.Runtime.CompilerServices", "DynamicAttribute"))
var attributeType = attribute.Constructor.DeclaringType;
if (attributeType.IsType("System.Runtime.CompilerServices", "DynamicAttribute"))
{
var arguments = attribute.ConstructorArguments;
if (arguments.Count == 0)
dynamicFlags = GetDynamicFlags(attribute);
}
else if (attributeType.IsType("System.Runtime.CompilerServices", "TupleElementNamesAttribute"))
{
tupleElementNames = GetTupleElementNames(attribute);
}
}
return CustomTypeInfo.Create(dynamicFlags, tupleElementNames);
}
private static ReadOnlyCollection<CustomAttributeTypedArgument> GetAttributeArrayArgumentValue(CustomAttributeTypedArgument argument)
{
// Per https://msdn.microsoft.com/en-us/library/system.reflection.customattributetypedargument.argumenttype(v=vs.110).aspx,
// if ArgumentType indicates an array, then Value will actually be a ReadOnlyCollection.
return (ReadOnlyCollection<CustomAttributeTypedArgument>)argument.Value;
}
private static readonly ReadOnlyCollection<byte> DynamicFlagsTrue = new ReadOnlyCollection<byte>(new byte[] { 1 });
private static ReadOnlyCollection<byte> GetDynamicFlags(CustomAttributeData attribute)
{
var arguments = attribute.ConstructorArguments;
if (arguments.Count == 0)
{
return DynamicFlagsTrue;
}
else if (arguments.Count == 1)
{
var argument = arguments[0];
var argumentType = argument.ArgumentType;
if (argumentType.IsArray && argumentType.GetElementType().IsBoolean())
{
var collection = GetAttributeArrayArgumentValue(argument);
var numFlags = collection.Count;
var builder = ArrayBuilder<bool>.GetInstance(numFlags);
foreach (var typedArg in collection)
{
var builder = ArrayBuilder<bool>.GetInstance(1);
builder.Add(true);
var result = DynamicFlagsCustomTypeInfo.Create(builder);
builder.Free();
return result;
builder.Add((bool)typedArg.Value);
}
else if (arguments.Count == 1)
var result = DynamicFlagsCustomTypeInfo.ToBytes(builder);
builder.Free();
return result;
}
}
return null;
}
private static ReadOnlyCollection<string> GetTupleElementNames(CustomAttributeData attribute)
{
var arguments = attribute.ConstructorArguments;
if (arguments.Count == 1)
{
var argument = arguments[0];
var argumentType = argument.ArgumentType;
if (argumentType.IsArray && argumentType.GetElementType().IsString())
{
var collection = GetAttributeArrayArgumentValue(argument);
var numFlags = collection.Count;
var builder = ArrayBuilder<string>.GetInstance(numFlags);
foreach (var typedArg in collection)
{
var argumentType = arguments[0].ArgumentType;
if (argumentType.IsArray && argumentType.GetElementType().IsBoolean())
{
// Per https://msdn.microsoft.com/en-us/library/system.reflection.customattributetypedargument.argumenttype(v=vs.110).aspx,
// if ArgumentType indicates an array, then Value will actually be a ReadOnlyCollection.
var collection = (ReadOnlyCollection<CustomAttributeTypedArgument>)arguments[0].Value;
var numFlags = collection.Count;
var builder = ArrayBuilder<bool>.GetInstance(numFlags);
foreach (var typedArg in collection)
{
builder.Add((bool)typedArg.Value);
}
var result = DynamicFlagsCustomTypeInfo.Create(builder);
builder.Free();
return result;
}
builder.Add((string)typedArg.Value);
}
return builder.ToImmutableAndFree();
}
}
return default(DynamicFlagsCustomTypeInfo);
return null;
}
}
}
......@@ -163,7 +163,7 @@ public DkmClrCustomTypeInfo TypeInfo
{
case MemberTypes.Field:
case MemberTypes.Property:
return _member.GetCustomAttributesData().GetDynamicFlags().GetCustomTypeInfo();
return _member.GetCustomAttributesData().GetCustomTypeInfo();
default:
// If we ever see a method, we'll have to use ReturnTypeCustomAttributes.
throw ExceptionUtilities.UnexpectedValue(_member.MemberType);
......
......@@ -354,17 +354,6 @@ internal static DkmClrValue GetNullableValue(this DkmClrValue value, DkmInspecti
// See NamedTypeSymbol.IsTupleCompatible.
internal static bool IsTupleCompatible(this Type type, out int cardinality)
{
if (type.IsTupleCompatibleInternal(out cardinality) &&
cardinality > 1) // ValueTuple<T> is not a tuple.
{
return true;
}
cardinality = 0;
return false;
}
private static bool IsTupleCompatibleInternal(this Type type, out int cardinality)
{
if (type.IsGenericType &&
AreNamesEqual(type.Namespace, "System") &&
......@@ -388,7 +377,7 @@ private static bool IsTupleCompatibleInternal(this Type type, out int cardinalit
var restType = typeArguments[n - 1];
int restCardinality;
if (restType.IsTupleCompatibleInternal(out restCardinality))
if (restType.IsTupleCompatible(out restCardinality))
{
cardinality = n - 1 + restCardinality;
return true;
......
// 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.Collections;
using System.Diagnostics;
using Type = Microsoft.VisualStudio.Debugger.Metadata.Type;
......
......@@ -55,6 +55,9 @@
<Compile Include="..\..\..\..\..\Test\PdbUtilities\Shared\DateTimeUtilities.cs">
<Link>Helpers\DateTimeUtilities.cs</Link>
</Compile>
<Compile Include="..\..\ExpressionCompiler\CustomTypeInfo.cs">
<Link>ExpressionCompiler\CustomTypeInfo.cs</Link>
</Compile>
<Compile Include="..\..\ExpressionCompiler\DynamicFlagsCustomTypeInfo.cs">
<Link>ExpressionCompiler\DynamicFlagsCustomTypeInfo.cs</Link>
</Compile>
......
......@@ -59,6 +59,9 @@
<Compile Include="..\..\..\..\..\Test\PdbUtilities\Shared\DateTimeUtilities.cs">
<Link>Helpers\DateTimeUtilities.cs</Link>
</Compile>
<Compile Include="..\..\ExpressionCompiler\CustomTypeInfo.cs">
<Link>ExpressionCompiler\CustomTypeInfo.cs</Link>
</Compile>
<Compile Include="..\..\ExpressionCompiler\DynamicFlagsCustomTypeInfo.cs">
<Link>ExpressionCompiler\DynamicFlagsCustomTypeInfo.cs</Link>
</Compile>
......
......@@ -469,17 +469,26 @@ private static string GetTypeName(DkmInspectionContext inspectionContext, DkmClr
{
var declaredLmrType = declaredType.GetLmrType();
var runtimeType = value.Type;
var runtimeLmrType = runtimeType.GetLmrType();
var declaredTypeName = inspectionContext.GetTypeName(declaredType, declaredTypeInfo, Formatter.NoFormatSpecifiers);
var runtimeTypeName = inspectionContext.GetTypeName(runtimeType, CustomTypeInfo: null, FormatSpecifiers: Formatter.NoFormatSpecifiers);
var includeRuntimeTypeName =
!string.Equals(declaredTypeName, runtimeTypeName, StringComparison.OrdinalIgnoreCase) && // Names will reflect "dynamic", types will not.
!declaredLmrType.IsPointer &&
// Include the runtime type if distinct.
if (!declaredLmrType.IsPointer &&
(kind != ExpansionKind.PointerDereference) &&
(!declaredLmrType.IsNullable() || value.EvalFlags.Includes(DkmEvaluationResultFlags.ExceptionThrown));
return includeRuntimeTypeName ?
string.Format("{0} {{{1}}}", declaredTypeName, runtimeTypeName) :
declaredTypeName;
(!declaredLmrType.IsNullable() || value.EvalFlags.Includes(DkmEvaluationResultFlags.ExceptionThrown)))
{
// Generate the declared type name without tuple element names.
var declaredTypeInfoNoTupleElementNames = declaredTypeInfo.WithNoTupleElementNames();
var declaredTypeNameNoTupleElementNames = (declaredTypeInfo == declaredTypeInfoNoTupleElementNames) ?
declaredTypeName :
inspectionContext.GetTypeName(declaredType, declaredTypeInfoNoTupleElementNames, Formatter.NoFormatSpecifiers);
// Generate the runtime type name with no tuple element names and no dynamic.
var runtimeTypeName = inspectionContext.GetTypeName(runtimeType, null, FormatSpecifiers: Formatter.NoFormatSpecifiers);
// If the two names are distinct, include both.
if (!string.Equals(declaredTypeNameNoTupleElementNames, runtimeTypeName, StringComparison.Ordinal)) // Names will reflect "dynamic", types will not.
{
return string.Format("{0} {{{1}}}", declaredTypeName, runtimeTypeName);
}
}
return declaredTypeName;
}
internal EvalResult CreateDataItem(
......@@ -897,7 +906,7 @@ private static string GetTypeName(DkmInspectionContext inspectionContext, DkmClr
if (declaredType.IsArray)
{
elementType = declaredType.GetElementType();
elementTypeInfo = DynamicFlagsCustomTypeInfo.Create(declaredTypeAndInfo.Info).SkipOne().GetCustomTypeInfo();
elementTypeInfo = CustomTypeInfo.SkipOne(declaredTypeAndInfo.Info);
}
else
{
......@@ -921,8 +930,8 @@ private static string GetTypeName(DkmInspectionContext inspectionContext, DkmClr
if (declaredType.IsPointer)
{
// If this ever happens, the element type info is just .SkipOne().
Debug.Assert(!DynamicFlagsCustomTypeInfo.Create(declaredTypeAndInfo.Info).Any());
// If this assert fails, the element type info is just .SkipOne().
Debug.Assert(declaredTypeAndInfo.Info?.PayloadTypeId != CustomTypeInfo.PayloadTypeId);
var elementType = declaredType.GetElementType();
return value.IsNull || elementType.IsVoid()
? null
......
......@@ -13,7 +13,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Formatter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Formatter.TypeNames.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Formatter.Values.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\DynamicFlagsCustomTypeInfo_Factory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\TypeAndCustomInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\TypeWalker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\DynamicFlagsMap.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.
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal partial struct DynamicFlagsCustomTypeInfo
{
internal static DynamicFlagsCustomTypeInfo Create(params bool[] dynamicFlags)
{
if (dynamicFlags == null || dynamicFlags.Length == 0)
{
return default(DynamicFlagsCustomTypeInfo);
}
var builder = ArrayBuilder<bool>.GetInstance(dynamicFlags.Length);
builder.AddRange(dynamicFlags);
var result = new DynamicFlagsCustomTypeInfo(builder, startIndex: 0);
builder.Free();
return result;
}
}
}
......@@ -25,6 +25,20 @@ internal static string GetDynamicDebugViewEmptyMessage()
return (string)emptyProperty.GetValue(exceptionType.Instantiate());
}
internal static DkmClrCustomTypeInfo MakeCustomTypeInfo(params bool[] dynamicFlags)
{
if (dynamicFlags == null || dynamicFlags.Length == 0)
{
return null;
}
var builder = ArrayBuilder<bool>.GetInstance(dynamicFlags.Length);
builder.AddRange(dynamicFlags);
var result = CustomTypeInfo.Create(DynamicFlagsCustomTypeInfo.ToBytes(builder), tupleElementNames: null);
builder.Free();
return result;
}
private readonly DkmInspectionSession _inspectionSession;
internal readonly DkmInspectionContext DefaultInspectionContext;
......
......@@ -70,6 +70,9 @@
<Compile Include="..\..\..\..\Test\PdbUtilities\Shared\DateTimeUtilities.cs">
<Link>DateTimeUtilities.cs</Link>
</Compile>
<Compile Include="..\..\Source\ExpressionCompiler\CustomTypeInfo.cs">
<Link>ExpressionCompiler\CustomTypeInfo.cs</Link>
</Compile>
<Compile Include="..\..\Source\ExpressionCompiler\DynamicFlagsCustomTypeInfo.cs">
<Link>ExpressionCompiler\DynamicFlagsCustomTypeInfo.cs</Link>
</Compile>
......@@ -143,7 +146,6 @@
<Compile Include="Debugger\MemberInfo\ParameterInfoImpl.cs" />
<Compile Include="Debugger\MemberInfo\PropertyInfoImpl.cs" />
<Compile Include="Debugger\MemberInfo\TypeImpl.cs" />
<Compile Include="DynamicFlagsCustomTypeInfo_Factory.cs" />
<Compile Include="ReflectionUtilities.cs" />
<Compile Include="ResultProviderTestBase.cs" />
</ItemGroup>
......@@ -167,4 +169,4 @@
<Import Project="..\..\Source\ResultProvider\ResultProvider.projitems" Label="Shared" />
<Import Project="..\..\..\..\..\build\Targets\VSL.Imports.targets" />
<Import Project="..\..\..\..\..\build\Targets\Roslyn.Toolsets.Xunit.targets" />
</Project>
</Project>
\ No newline at end of file
......@@ -16,7 +16,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
MyBase.New(assembly, typeName, methodName, formatSpecifiers)
End Sub
Public Overrides Function GetCustomTypeInfo() As CustomTypeInfo
Public Overrides Function GetCustomTypeInfo(ByRef payload As ReadOnlyCollection(Of Byte)) As Guid
payload = Nothing
Return Nothing
End Function
End Class
......
' 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 System.Collections.ObjectModel
Imports Microsoft.CodeAnalysis.ExpressionEvaluator
Imports Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation
......@@ -11,7 +12,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
MyBase.New(localName, localDisplayName, methodName, flags)
End Sub
Public Overrides Function GetCustomTypeInfo() As CustomTypeInfo
Public Overrides Function GetCustomTypeInfo(ByRef payload As ReadOnlyCollection(Of Byte)) As Guid
payload = Nothing
Return Nothing
End Function
End Class
......
' 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 System.Collections.ObjectModel
Imports System.Runtime.InteropServices
Imports System.Text
Imports Microsoft.CodeAnalysis.ExpressionEvaluator
Imports Type = Microsoft.VisualStudio.Debugger.Metadata.Type
Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
......@@ -30,8 +30,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
builder As StringBuilder,
typeArguments() As Type,
typeArgumentOffset As Integer,
dynamicFlags As DynamicFlagsCustomTypeInfo,
ByRef index As Integer, arity As Integer,
dynamicFlags As ReadOnlyCollection(Of Byte),
ByRef dynamicFlagIndex As Integer,
tupleElementNames As ReadOnlyCollection(Of String),
ByRef tupleElementIndex As Integer,
arity As Integer,
escapeKeywordIdentifiers As Boolean,
<Out> ByRef sawInvalidIdentifier As Boolean)
......@@ -42,14 +45,52 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
builder.Append(", ")
End If
Dim sawSingleInvalidIdentifier As Boolean = Nothing
Dim sawSingleInvalidIdentifier = False
Dim typeArgument As Type = typeArguments(typeArgumentOffset + i)
AppendQualifiedTypeName(builder, typeArgument, dynamicFlags, index, escapeKeywordIdentifiers, sawSingleInvalidIdentifier)
AppendQualifiedTypeName(
builder,
typeArgument,
dynamicFlags,
dynamicFlagIndex,
tupleElementNames,
tupleElementIndex,
escapeKeywordIdentifiers,
sawSingleInvalidIdentifier)
sawInvalidIdentifier = sawInvalidIdentifier Or sawSingleInvalidIdentifier
Next
builder.Append(")"c)
End Sub
Protected Overrides Sub AppendTupleElement(
builder As StringBuilder,
type As Type,
nameOpt As String,
dynamicFlags As ReadOnlyCollection(Of Byte),
ByRef dynamicFlagIndex As Integer,
tupleElementNames As ReadOnlyCollection(Of String),
ByRef tupleElementIndex As Integer,
escapeKeywordIdentifiers As Boolean,
<Out> ByRef sawInvalidIdentifier As Boolean)
sawInvalidIdentifier = False
Dim sawSingleInvalidIdentifier = False
If Not String.IsNullOrEmpty(nameOpt) Then
AppendIdentifier(builder, escapeKeywordIdentifiers, nameOpt, sawSingleInvalidIdentifier)
sawInvalidIdentifier = sawInvalidIdentifier Or sawSingleInvalidIdentifier
builder.Append(" As ")
End If
AppendQualifiedTypeName(
builder,
type,
dynamicFlags,
dynamicFlagIndex,
tupleElementNames,
tupleElementIndex,
escapeKeywordIdentifiers,
sawSingleInvalidIdentifier)
Debug.Assert(Not sawSingleInvalidIdentifier)
End Sub
Protected Overrides Sub AppendRankSpecifier(builder As StringBuilder, rank As Integer)
Debug.Assert(rank > 0)
......
......@@ -20,8 +20,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Private Sub AppendEnumTypeAndName(builder As StringBuilder, typeToDisplayOpt As Type, name As String)
If typeToDisplayOpt IsNot Nothing Then
Dim index As Integer = 0
AppendQualifiedTypeName(builder, typeToDisplayOpt, Nothing, index, escapeKeywordIdentifiers:=True, sawInvalidIdentifier:=Nothing)
Dim index1 As Integer = 0
Dim index2 As Integer = 0
AppendQualifiedTypeName(
builder,
typeToDisplayOpt,
Nothing,
index1,
Nothing,
index2,
escapeKeywordIdentifiers:=True,
sawInvalidIdentifier:=Nothing)
builder.Append("."c)
End If
......
......@@ -316,7 +316,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests
End Function
Friend Shared Function VariableAlias(name As String, typeAssemblyQualifiedName As String) As [Alias]
Return New [Alias](DkmClrAliasKind.Variable, name, name, typeAssemblyQualifiedName, Nothing)
Return New [Alias](DkmClrAliasKind.Variable, name, name, typeAssemblyQualifiedName, Nothing, Nothing)
End Function
Friend Shared Function ObjectIdAlias(id As UInteger, Optional type As Type = Nothing) As [Alias]
......@@ -326,7 +326,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests
Friend Shared Function ObjectIdAlias(id As UInteger, typeAssemblyQualifiedName As String) As [Alias]
Assert.NotEqual(Of UInteger)(0, id) ' Not a valid id.
Dim name = $"${id}"
Return New [Alias](DkmClrAliasKind.ObjectId, name, name, typeAssemblyQualifiedName, Nothing)
Return New [Alias](DkmClrAliasKind.ObjectId, name, name, typeAssemblyQualifiedName, Nothing, Nothing)
End Function
Friend Shared Function ReturnValueAlias(Optional id As Integer = -1, Optional type As Type = Nothing) As [Alias]
......@@ -336,7 +336,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests
Friend Shared Function ReturnValueAlias(id As Integer, typeAssemblyQualifiedName As String) As [Alias]
Dim name = $"Method M{If(id < 0, "", id.ToString())} returned"
Dim fullName = If(id < 0, "$ReturnValue", $"$ReturnValue{id}")
Return New [Alias](DkmClrAliasKind.ReturnValue, name, fullName, typeAssemblyQualifiedName, Nothing)
Return New [Alias](DkmClrAliasKind.ReturnValue, name, fullName, typeAssemblyQualifiedName, Nothing, Nothing)
End Function
Friend Shared Function ExceptionAlias(Optional type As Type = Nothing, Optional stowed As Boolean = False) As [Alias]
......@@ -347,11 +347,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests
Dim fullName = If(stowed, "$stowedexception", "$exception")
Const name = "Error"
Dim kind = If(stowed, DkmClrAliasKind.StowedException, DkmClrAliasKind.Exception)
Return New [Alias](kind, name, fullName, typeAssemblyQualifiedName, Nothing)
End Function
Friend Shared Function [Alias](kind As DkmClrAliasKind, name As String, fullName As String, typeAssemblyQualifiedName As String, customTypeInfo As CustomTypeInfo) As [Alias]
Return New [Alias](kind, name, fullName, typeAssemblyQualifiedName, customTypeInfo)
Return New [Alias](kind, name, fullName, typeAssemblyQualifiedName, Nothing, Nothing)
End Function
Friend Shared Function GetMethodDebugInfo(runtime As RuntimeInstance, qualifiedMethodName As String, Optional ilOffset As Integer = 0) As MethodDebugInfo(Of TypeSymbol, LocalSymbol)
......
......@@ -13,12 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests
Friend Module TestTypeExtensions
<Extension>
Public Function GetTypeName(type As System.Type, Optional dynamicFlags As Boolean() = Nothing, Optional escapeKeywordIdentifiers As Boolean = False) As String
Return type.GetTypeName(DynamicFlagsCustomTypeInfo.Create(dynamicFlags).GetCustomTypeInfo(), escapeKeywordIdentifiers, Nothing)
End Function
<Extension>
Public Function GetTypeName(type As System.Type, typeInfo As DkmClrCustomTypeInfo, Optional escapeKeywordIdentifiers As Boolean = False, Optional inspectionContext As DkmInspectionContext = Nothing) As String
Public Function GetTypeName(type As System.Type, Optional typeInfo As DkmClrCustomTypeInfo = Nothing, Optional escapeKeywordIdentifiers As Boolean = False, Optional inspectionContext As DkmInspectionContext = Nothing) As String
Dim formatter = New VisualBasicFormatter()
Dim clrType = New DkmClrType(New TypeImpl(type))
If inspectionContext Is Nothing Then
......
......@@ -62,6 +62,83 @@ End Class"
End Using
End Sub
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/12347")>
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"
Dim assembly0 = GenerateTupleAssembly()
Dim reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference()
Dim compilation1 = CreateCompilationWithMscorlib({source}, options:=TestOptions.ReleaseDll, references:={reference0}, assemblyName:=GetUniqueName())
Dim assembly1 = compilation1.EmitToArray()
Dim runtime = New DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)))
Using runtime.Load()
Dim type = runtime.GetType("C")
Dim value = type.Instantiate()
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("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,
EvalResult("F", "Nothing", "(A As Object, B As Object)()", "o.F.F"),
EvalResult("G", "{Length=0}", "(C As Object, D As Object())()", "o.F.G"))
moreChildren = GetChildren(children(1))
Verify(moreChildren,
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("Item1", "Nothing", "Object", "o.G.F.Item1"),
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))
End Using
End Sub
<Fact>
Public Sub Keywords()
Const source =
"Namespace [Namespace]
Structure [Structure]
End Structure
End Namespace
Class [As]
Shared Function F() As ([As] As [As], [Class] As [Namespace].[Structure])
Return (Nothing, Nothing)
End Function
Private _f As Object = F()
End Class"
Dim assembly0 = GenerateTupleAssembly()
Dim reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference()
Dim compilation1 = CreateCompilationWithMscorlib({source}, options:=TestOptions.ReleaseDll, references:={reference0}, assemblyName:=GetUniqueName())
Dim assembly1 = compilation1.EmitToArray()
Dim runtime = New DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1)))
Using runtime.Load()
Dim type = runtime.GetType("As")
Dim value = type.Instantiate()
Dim result = FormatResult("o", value)
Verify(result,
EvalResult("o", "{As}", "As", "o", DkmEvaluationResultFlags.Expandable))
Dim children = GetChildren(result)
Verify(children,
EvalResult("_f", "(Nothing, {Namespace.Structure})", "Object {(As, Namespace.Structure)}", "o._f", DkmEvaluationResultFlags.Expandable))
children = GetChildren(children(0))
Verify(children,
EvalResult("Item1", "Nothing", "As", "DirectCast(o._f, ([As], [Namespace].[Structure])).Item1"),
EvalResult("Item2", "{Namespace.Structure}", "Namespace.Structure", "DirectCast(o._f, ([As], [Namespace].[Structure])).Item2"))
End Using
End Sub
Private Shared Function GenerateTupleAssembly() As ImmutableArray(Of Byte)
Const source =
"Namespace System
......
......@@ -269,8 +269,8 @@ End Namespace
<WorkItem(1087216, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1087216")>
<Fact>
Public Sub DynamicAttribute_ValidFlags()
Assert.Equal("Object", GetType(Object).GetTypeName({True}))
Assert.Equal("Object()", GetType(Object()).GetTypeName({False, True}))
Assert.Equal("Object", GetType(Object).GetTypeName(MakeCustomTypeInfo(True)))
Assert.Equal("Object()", GetType(Object()).GetTypeName(MakeCustomTypeInfo(False, True)))
End Sub
<WorkItem(1087216, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1087216")>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册