internal static DkmClrCustomTypeInfo GetCustomTypeInfo( this IList <CustomAttributeData> attributes ) { ReadOnlyCollection <byte> dynamicFlags = null; ReadOnlyCollection <string> tupleElementNames = null; foreach (var attribute in attributes) { var attributeType = attribute.Constructor.DeclaringType; if (attributeType.IsType("System.Runtime.CompilerServices", "DynamicAttribute")) { dynamicFlags = GetDynamicFlags(attribute); } else if ( attributeType.IsType( "System.Runtime.CompilerServices", "TupleElementNamesAttribute" ) ) { tupleElementNames = GetTupleElementNames(attribute); } } return(CustomTypeInfo.Create(dynamicFlags, tupleElementNames)); }
/// <returns>The qualified name (i.e. including containing types and namespaces) of a named, /// pointer, or array type.</returns> internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIdentifiers, out bool sawInvalidIdentifier) { var type = typeAndInfo.Type; if (type == null) { throw new ArgumentNullException(nameof(type)); } 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 dynamicFlagIndex, tupleElementNames, ref tupleElementIndex, escapeKeywordIdentifiers, out sawInvalidIdentifier); return(pooled.ToStringAndFree()); }
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)); }
internal InspectionContextImpl Add(string id, string typeName, CustomTypeInfo customTypeInfo = default(CustomTypeInfo)) { var builder = ArrayBuilder <Alias> .GetInstance(); builder.AddRange(_variables); builder.Add(new Alias(GetPseudoVariableKind(id), id, id, typeName, customTypeInfo)); return(new InspectionContextImpl(new ReadOnlyCollection <Alias>(builder.ToArrayAndFree()))); }
private void AppendTupleElements( StringBuilder builder, Type type, 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) { var typeArguments = type.GetGenericArguments(); int nTypeArgs = typeArguments.Length; Debug.Assert(nTypeArgs > 0); Debug.Assert(nTypeArgs <= TypeHelpers.TupleFieldRestPosition); int nFields = Math.Min(nTypeArgs, TypeHelpers.TupleFieldRestPosition - 1); for (int i = 0; i < nFields; i++) { if (any) { builder.Append(", "); } bool 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; } if (nTypeArgs < TypeHelpers.TupleFieldRestPosition) { break; } Debug.Assert(!DynamicFlagsCustomTypeInfo.GetFlag(dynamicFlags, dynamicFlagIndex)); dynamicFlagIndex++; type = typeArguments[nTypeArgs - 1]; } builder.Append(')'); }
internal Alias(DkmClrAliasKind kind, string name, string fullName, string type, CustomTypeInfo customTypeInfo) { Debug.Assert(!string.IsNullOrEmpty(fullName)); Debug.Assert(!string.IsNullOrEmpty(type)); this.Kind = kind; this.Name = name; this.FullName = fullName; this.Type = type; this.CustomTypeInfo = customTypeInfo; }
internal Alias(AliasKind kind, string name, string fullName, string type, CustomTypeInfo customTypeInfo) { Debug.Assert(kind != AliasKind.None); Debug.Assert(!string.IsNullOrEmpty(fullName)); Debug.Assert(!string.IsNullOrEmpty(type)); this.Kind = kind; this.Name = name; this.FullName = fullName; this.Type = type; this.CustomTypeInfo = customTypeInfo; }
internal static CustomTypeInfoTypeArgumentMap Create(TypeAndCustomInfo typeAndInfo) { var typeInfo = typeAndInfo.Info; if (typeInfo == null) { return(s_empty); } 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 ); if (dynamicFlags == null && tupleElementNames == null) { return(s_empty); } var typeDefinition = type.GetGenericTypeDefinition(); Debug.Assert(typeDefinition != null); var dynamicFlagStartIndices = (dynamicFlags == null) ? null : GetStartIndices(type, t => 1); var tupleElementNameStartIndices = (tupleElementNames == null) ? null : GetStartIndices(type, TypeHelpers.GetTupleCardinalityIfAny); return(new CustomTypeInfoTypeArgumentMap( typeDefinition, dynamicFlags, dynamicFlagStartIndices, tupleElementNames, tupleElementNameStartIndices )); }
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); }
/// <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 Expansion GetTypeExpansion( DkmInspectionContext inspectionContext, TypeAndCustomInfo declaredTypeAndInfo, DkmClrValue value, ExpansionFlags flags) { var declaredType = declaredTypeAndInfo.Type; Debug.Assert(!declaredType.IsTypeVariables()); if ((inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoExpansion) != 0) { return(null); } var runtimeType = value.Type.GetLmrType(); // If the value is an array, expand the array elements. if (runtimeType.IsArray) { var sizes = value.ArrayDimensions; if (sizes == null) { // Null array. No expansion. return(null); } var lowerBounds = value.ArrayLowerBounds; Type elementType; DkmClrCustomTypeInfo elementTypeInfo; if (declaredType.IsArray) { elementType = declaredType.GetElementType(); elementTypeInfo = CustomTypeInfo.SkipOne(declaredTypeAndInfo.Info); } else { elementType = runtimeType.GetElementType(); elementTypeInfo = null; } return(ArrayExpansion.CreateExpansion(new TypeAndCustomInfo(DkmClrType.Create(declaredTypeAndInfo.ClrType.AppDomain, elementType), elementTypeInfo), sizes, lowerBounds)); } if (this.IsPrimitiveType(runtimeType)) { return(null); } if (declaredType.IsFunctionPointer()) { // Function pointers have no expansion return(null); } if (declaredType.IsPointer) { // 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 : new PointerDereferenceExpansion(new TypeAndCustomInfo(DkmClrType.Create(declaredTypeAndInfo.ClrType.AppDomain, elementType)))); } if (value.EvalFlags.Includes(DkmEvaluationResultFlags.ExceptionThrown) && runtimeType.IsEmptyResultsViewException()) { // The value is an exception thrown expanding an empty // IEnumerable. Use the runtime type of the exception and // skip base types. (This matches the native EE behavior // to expose a single property from the exception.) flags &= ~ExpansionFlags.IncludeBaseMembers; } return(MemberExpansion.CreateExpansion(inspectionContext, declaredTypeAndInfo, value, flags, TypeHelpers.IsVisibleMember, this)); }
public static DynamicFlagsCustomTypeInfo Create(CustomTypeInfo customTypeInfo) { return(new DynamicFlagsCustomTypeInfo(customTypeInfo.PayloadTypeId == PayloadTypeId ? customTypeInfo.Payload : null)); }
private static Fields GetFields(TypeAndCustomInfo declaringTypeAndInfo, int cardinality, bool useRawView) { Debug.Assert(declaringTypeAndInfo.Type.GetTupleCardinalityIfAny() == cardinality); var appDomain = declaringTypeAndInfo.ClrType.AppDomain; var customTypeInfoMap = CustomTypeInfoTypeArgumentMap.Create(declaringTypeAndInfo); var tupleElementNames = customTypeInfoMap.TupleElementNames; var builder = ArrayBuilder <Field> .GetInstance(); Field parent = null; int offset = 0; bool includeRawView = false; while (true) { var declaringType = declaringTypeAndInfo.Type; int n = Math.Min(cardinality, TypeHelpers.TupleFieldRestPosition - 1); for (int index = 0; index < n; index++) { var fieldName = TypeHelpers.GetTupleFieldName(index); var field = declaringType.GetTupleField(fieldName); if (field == null) { // Ignore missing fields. continue; } var fieldTypeAndInfo = GetTupleFieldTypeAndInfo(appDomain, field, customTypeInfoMap); if (!useRawView) { var name = CustomTypeInfo.GetTupleElementNameIfAny(tupleElementNames, offset + index); if (name != null) { includeRawView = true; builder.Add(new Field(declaringTypeAndInfo, fieldTypeAndInfo, field, name, parent, isRest: false)); continue; } } builder.Add(new Field( declaringTypeAndInfo, fieldTypeAndInfo, field, (offset == 0) ? fieldName : TypeHelpers.GetTupleFieldName(offset + index), parent, isRest: false)); } cardinality -= n; if (cardinality == 0) { break; } var rest = declaringType.GetTupleField(TypeHelpers.TupleFieldRestName); if (rest == null) { // Ignore remaining fields. break; } var restTypeAndInfo = GetTupleFieldTypeAndInfo(appDomain, rest, customTypeInfoMap); var restField = new Field(declaringTypeAndInfo, restTypeAndInfo, rest, TypeHelpers.TupleFieldRestName, parent, isRest: true); if (useRawView) { builder.Add(restField); break; } includeRawView = true; parent = restField; declaringTypeAndInfo = restTypeAndInfo; offset += TypeHelpers.TupleFieldRestPosition - 1; } return(new Fields(builder.ToImmutableAndFree(), includeRawView)); }
private static ReadOnlyCollection <Field> GetFields(TypeAndCustomInfo declaringTypeAndInfo, int cardinality) { Debug.Assert(declaringTypeAndInfo.Type.GetTupleCardinalityIfAny() == cardinality); var appDomain = declaringTypeAndInfo.ClrType.AppDomain; var customTypeInfoMap = CustomTypeInfoTypeArgumentMap.Create(declaringTypeAndInfo); var tupleElementNames = customTypeInfoMap.TupleElementNames; var builder = ArrayBuilder <Field> .GetInstance(); Field parent = null; int offset = 0; while (true) { var declaringType = declaringTypeAndInfo.Type; int n = Math.Min(cardinality, TypeHelpers.TupleFieldRestPosition - 1); for (int index = 0; index < n; index++) { var fieldName = TypeHelpers.GetTupleFieldName(index); var field = declaringType.GetTupleField(fieldName); if (field == null) { // Ignore missing fields. continue; } var fieldTypeAndInfo = GetTupleFieldTypeAndInfo(appDomain, field, customTypeInfoMap); var name = CustomTypeInfo.GetTupleElementNameIfAny(tupleElementNames, offset + index); if (name != null) { builder.Add(new Field(declaringTypeAndInfo, fieldTypeAndInfo, field, name, parent)); } builder.Add(new Field( declaringTypeAndInfo, fieldTypeAndInfo, field, (offset == 0) ? fieldName : TypeHelpers.GetTupleFieldName(offset + index), parent)); } cardinality -= n; if (cardinality == 0) { break; } var rest = declaringType.GetTupleField(TypeHelpers.TupleFieldRestName); if (rest == null) { // Ignore remaining fields. break; } var restTypeAndInfo = GetTupleFieldTypeAndInfo(appDomain, rest, customTypeInfoMap); parent = new Field(declaringTypeAndInfo, restTypeAndInfo, rest, TypeHelpers.TupleFieldRestName, parent); declaringTypeAndInfo = restTypeAndInfo; offset += TypeHelpers.TupleFieldRestPosition - 1; } // If there were any nested ValueTuples, // add the Rest field of the outermost. if (parent != null) { while (parent.Parent != null) { parent = parent.Parent; } builder.Add(parent); } return(builder.ToImmutableAndFree()); }
public static DynamicFlagsCustomTypeInfo Create(CustomTypeInfo customTypeInfo) { return new DynamicFlagsCustomTypeInfo(customTypeInfo.PayloadTypeId == PayloadTypeId ? customTypeInfo.Payload : null); }
internal static Alias Alias(DkmClrAliasKind kind, string name, string fullName, string type, CustomTypeInfo customTypeInfo) { return new Alias(kind, name, fullName, type, customTypeInfo); }
private static void VerifyCustomTypeInfo(CustomTypeInfo customTypeInfo, byte[] expectedBytes) { Assert.Equal(DynamicFlagsCustomTypeInfo.PayloadTypeId, customTypeInfo.PayloadTypeId); Assert.Equal(expectedBytes, customTypeInfo.Payload); }
internal InspectionContextImpl Add(string id, Type type, CustomTypeInfo customTypeInfo = default(CustomTypeInfo)) { return(Add(id, type.AssemblyQualifiedName, customTypeInfo)); }