/// <summary> /// Returns an enumerable debug view. These types are located in System.Core / System.Linq. If <paramref name="enumerableType"/> /// is <see cref="System.Collections.IEnumerable"/>, then <c>System.Linq.SystemCore_EnumerableDebugView</c>'s constructor /// is returned, else if <paramref name="enumerableType"/> is <see cref="IEnumerable{T}"/>, then /// <c>System.Linq.SystemCore_EnumerableDebugView`1</c>'s constructor is returned. /// </summary> /// <param name="enumerableType">Enumerable type, must be one of <see cref="System.Collections.IEnumerable"/>, <see cref="IEnumerable{T}"/></param> /// <returns></returns> public static DmdConstructorInfo GetEnumerableDebugViewConstructor(DmdType enumerableType) { Debug.Assert(enumerableType == enumerableType.AppDomain.System_Collections_IEnumerable || (enumerableType.IsConstructedGenericType && enumerableType.GetGenericTypeDefinition() == enumerableType.AppDomain.System_Collections_Generic_IEnumerable_T)); var appDomain = enumerableType.AppDomain; var wellKnownType = enumerableType.IsConstructedGenericType ? DmdWellKnownType.System_Linq_SystemCore_EnumerableDebugView_T : DmdWellKnownType.System_Linq_SystemCore_EnumerableDebugView; var debugViewType = appDomain.GetWellKnownType(wellKnownType, isOptional: true); // If this fails, System.Core (.NET Framework) / System.Linq (.NET Core) hasn't been loaded yet if ((object)debugViewType == null) { return(null); } if (enumerableType.IsConstructedGenericType) { var genericArgs = enumerableType.GetGenericArguments(); if (debugViewType.GetGenericArguments().Count != genericArgs.Count) { return(null); } debugViewType = debugViewType.MakeGenericType(genericArgs); } var ctor = debugViewType.GetConstructor(DmdBindingFlags.Public | DmdBindingFlags.NonPublic | DmdBindingFlags.Instance, DmdCallingConventions.Standard | DmdCallingConventions.HasThis, new[] { enumerableType }); Debug.Assert((object)ctor != null); return(ctor); }
DmdType WriteTupleFields(DmdType type, ref int index) { var args = type.GetGenericArguments(); Debug.Assert(0 < args.Count && args.Count <= TypeFormatterUtils.MAX_TUPLE_ARITY); if (args.Count > TypeFormatterUtils.MAX_TUPLE_ARITY) { OutputWrite("???", BoxedTextColor.Error); return(null); } for (int i = 0; i < args.Count && i < TypeFormatterUtils.MAX_TUPLE_ARITY - 1; i++) { if (i > 0) { WriteCommaSpace(); } //TODO: Write tuple name used in source string fieldName = null; if (fieldName != null) { OutputWrite(fieldName, BoxedTextColor.InstanceField); WriteSpace(); OutputWrite("As", BoxedTextColor.Keyword); WriteSpace(); } Format(args[i], null); index++; } if (args.Count == TypeFormatterUtils.MAX_TUPLE_ARITY) { return(args[TypeFormatterUtils.MAX_TUPLE_ARITY - 1]); } return(null); }
public static int GetTupleArity(DmdType type) { int arity = 0; for (;;) { if (type.MetadataNamespace != "System") { return(-1); } var genArgs = type.GetGenericArguments(); if (genArgs.Count == 0) { return(-1); } if (type.IsNested) { return(-1); } if (!type.IsValueType) { return(-1); } int currentArity; switch (type.MetadataName) { case "ValueTuple`1": currentArity = 1; break; case "ValueTuple`2": currentArity = 2; break; case "ValueTuple`3": currentArity = 3; break; case "ValueTuple`4": currentArity = 4; break; case "ValueTuple`5": currentArity = 5; break; case "ValueTuple`6": currentArity = 6; break; case "ValueTuple`7": currentArity = 7; break; case "ValueTuple`8": currentArity = 8; break; default: return(-1); } if (genArgs.Count != currentArity) { return(-1); } if (currentArity != 8) { return(arity + currentArity); } arity += currentArity - 1; type = genArgs[currentArity - 1]; } }
static ReadOnlyCollection<DmdType> GetGenericArguments(DmdType type) { if (!type.IsMetadataReference) return type.GetGenericArguments(); var resolvedType = type.ResolveNoThrow(); if ((object)resolvedType != null) return resolvedType.GetGenericArguments(); return ReadOnlyCollectionHelpers.Empty<DmdType>(); }
public void Add(DmdType type) { if (recursionCounter > 100) { return; } recursionCounter++; while (type.GetElementType() is DmdType etype) { type = etype; } switch (type.TypeSignatureKind) { case DmdTypeSignatureKind.Type: modules.Add(type.Module); break; case DmdTypeSignatureKind.Pointer: case DmdTypeSignatureKind.ByRef: case DmdTypeSignatureKind.TypeGenericParameter: case DmdTypeSignatureKind.MethodGenericParameter: case DmdTypeSignatureKind.SZArray: case DmdTypeSignatureKind.MDArray: break; case DmdTypeSignatureKind.GenericInstance: modules.Add(type.GetGenericTypeDefinition().Module); foreach (var ga in type.GetGenericArguments()) { Add(ga); } break; case DmdTypeSignatureKind.FunctionPointer: var sig = type.GetFunctionPointerMethodSignature(); Add(sig.ReturnType); foreach (var t in sig.GetParameterTypes()) { Add(t); } foreach (var t in sig.GetVarArgsParameterTypes()) { Add(t); } break; default: Debug.Fail($"Unknown kind: {type.TypeSignatureKind}"); break; } recursionCounter--; }
public static (DmdConstructorInfo ctor, DmdMethodInfo toArrayMethod) GetListEnumerableMethods(DmdType objType, DmdType enumerableType) { Debug.Assert(enumerableType == enumerableType.AppDomain.System_Collections_IEnumerable || (enumerableType.IsConstructedGenericType && enumerableType.GetGenericTypeDefinition() == enumerableType.AppDomain.System_Collections_Generic_IEnumerable_T)); var appDomain = enumerableType.AppDomain; if (enumerableType.IsConstructedGenericType) { var genArgs = enumerableType.GetGenericArguments(); Debug.Assert(genArgs.Count == 1); if (genArgs.Count != 1) { return(default);
static EnumerableTypeKind GetEnumerableTypeKind(DmdType type, DmdType enumerableType, DmdType enumerableOfTType) { if (type == enumerableType) { return(EnumerableTypeKind.Enumerable); } if (type.IsConstructedGenericType && type.GetGenericArguments().Count == 1) { if (type.GetGenericTypeDefinition() == enumerableOfTType) { return(EnumerableTypeKind.EnumerableOfT); } } return(EnumerableTypeKind.None); }
static ReadOnlyCollection <DmdType> GetGenericArguments(DmdType type) { if (!type.IsMetadataReference) { return(type.GetGenericArguments()); } var resolvedType = type.ResolveNoThrow(); if (!(resolvedType is null)) { return(resolvedType.GetGenericArguments()); } return(ReadOnlyCollectionHelpers.Empty <DmdType>()); }
void WriteGenericArguments(DmdType type, IList <DmdType> genericArgs, ref int genericArgsIndex) { var gas = type.GetGenericArguments(); if (genericArgsIndex < genericArgs.Count && genericArgsIndex < gas.Count) { OutputWrite(GENERICS_OPEN_PAREN, BoxedTextColor.Punctuation); int startIndex = genericArgsIndex; for (int j = startIndex; j < genericArgs.Count && j < gas.Count; j++, genericArgsIndex++) { if (j > startIndex) { WriteCommaSpace(); } Format(genericArgs[j], null); } OutputWrite(GENERICS_CLOSE_PAREN, BoxedTextColor.Punctuation); } }
static DmdConstructorInfo?GetConstructor(DmdType?proxyType, DmdType targetType) { if (proxyType is null) { return(null); } if (proxyType.IsConstructedGenericType) { return(null); } var proxyTypeGenericArgs = proxyType.GetGenericArguments(); var targetTypeGenericArgs = targetType.GetGenericArguments(); if (proxyTypeGenericArgs.Count != targetTypeGenericArgs.Count) { return(null); } if (targetTypeGenericArgs.Count != 0) { proxyType = proxyType.MakeGenericType(targetTypeGenericArgs); } var ctors = proxyType.GetConstructors(DmdBindingFlags.Public | DmdBindingFlags.NonPublic | DmdBindingFlags.Instance); foreach (var ctor in ctors) { var types = ctor.GetMethodSignature().GetParameterTypes(); if (types.Count != 1) { continue; } if (!types[0].IsAssignableFrom(targetType)) { continue; } return(ctor); } return(null); }
public CorType Create(DmdType type) { if ((object)type == null) { throw new ArgumentNullException(nameof(type)); } if (recursionCounter++ > 100) { throw new InvalidOperationException(); } CorType result; int i; ReadOnlyCollection <DmdType> types; CorType[] corTypes; DnModule dnModule; switch (type.TypeSignatureKind) { case DmdTypeSignatureKind.Type: if (!engine.TryGetDnModule(type.Module.GetDebuggerModule() ?? throw new InvalidOperationException(), out dnModule)) { throw new InvalidOperationException(); } Debug.Assert((type.MetadataToken >> 24) == 0x02); result = dnModule.CorModule.GetClassFromToken((uint)type.MetadataToken).GetParameterizedType(type.IsValueType ? CorElementType.ValueType : CorElementType.Class); break; case DmdTypeSignatureKind.Pointer: result = Create(type.GetElementType()); result = appDomain.GetPtr(result); break; case DmdTypeSignatureKind.ByRef: result = Create(type.GetElementType()); result = appDomain.GetByRef(result); break; case DmdTypeSignatureKind.TypeGenericParameter: case DmdTypeSignatureKind.MethodGenericParameter: throw new InvalidOperationException(); case DmdTypeSignatureKind.SZArray: result = Create(type.GetElementType()); result = appDomain.GetSZArray(result); break; case DmdTypeSignatureKind.MDArray: result = Create(type.GetElementType()); result = appDomain.GetArray(result, (uint)type.GetArrayRank()); break; case DmdTypeSignatureKind.GenericInstance: result = Create(type.GetGenericTypeDefinition()); types = type.GetGenericArguments(); corTypes = new CorType[types.Count]; for (i = 0; i < corTypes.Length; i++) { corTypes[i] = Create(types[i]); } result = result.Class.GetParameterizedType(type.IsValueType ? CorElementType.ValueType : CorElementType.Class, corTypes); break; case DmdTypeSignatureKind.FunctionPointer: var methodSig = type.GetFunctionPointerMethodSignature(); types = methodSig.GetParameterTypes(); corTypes = new CorType[1 + types.Count + methodSig.GetVarArgsParameterTypes().Count]; corTypes[0] = Create(methodSig.ReturnType); for (i = 0; i < types.Count; i++) { corTypes[i + 1] = Create(types[i]); } types = methodSig.GetVarArgsParameterTypes(); for (i = 0; i < types.Count; i++) { corTypes[i + 1 + methodSig.GetParameterTypes().Count] = Create(types[i]); } result = appDomain.GetFnPtr(corTypes); break; default: throw new InvalidOperationException(); } if (result == null) { throw new InvalidOperationException(); } recursionCounter--; return(result); }
public void Format(DmdType type, DbgDotNetValue value) { if ((object)type == null) { throw new ArgumentNullException(nameof(type)); } List <(DmdType type, DbgDotNetValue value)> arrayTypesList = null; try { if (recursionCounter++ >= MAX_RECURSION) { return; } switch (type.TypeSignatureKind) { case DmdTypeSignatureKind.SZArray: case DmdTypeSignatureKind.MDArray: // Array types are shown in reverse order arrayTypesList = new List <(DmdType type, DbgDotNetValue value)>(); do { arrayTypesList.Add((type, arrayTypesList.Count == 0 ? value : null)); type = type.GetElementType(); } while (type.IsArray); var t = arrayTypesList[arrayTypesList.Count - 1]; Format(t.type.GetElementType(), null); foreach (var tuple in arrayTypesList) { var aryType = tuple.type; var aryValue = tuple.value; uint elementCount; if (aryType.IsVariableBoundArray) { OutputWrite(ARRAY_OPEN_PAREN, BoxedTextColor.Punctuation); int rank = Math.Min(aryType.GetArrayRank(), MAX_ARRAY_RANK); if (rank <= 0) { OutputWrite("???", BoxedTextColor.Error); } else { if (rank == 1) { OutputWrite("*", BoxedTextColor.Operator); } if (aryValue == null || aryValue.IsNull || !aryValue.GetArrayInfo(out elementCount, out var dimensionInfos)) { dimensionInfos = null; } if (ShowArrayValueSizes && dimensionInfos != null && dimensionInfos.Length == rank) { for (int i = 0; i < rank; i++) { if (i > 0) { OutputWrite(",", BoxedTextColor.Punctuation); WriteSpace(); } if (dimensionInfos[i].BaseIndex == 0) { WriteUInt32(dimensionInfos[i].Length); } else { WriteInt32(dimensionInfos[i].BaseIndex); OutputWrite("..", BoxedTextColor.Operator); WriteInt32(dimensionInfos[i].BaseIndex + (int)dimensionInfos[i].Length - 1); } } } else { OutputWrite(TypeFormatterUtils.GetArrayCommas(rank), BoxedTextColor.Punctuation); } } OutputWrite(ARRAY_CLOSE_PAREN, BoxedTextColor.Punctuation); } else { Debug.Assert(aryType.IsSZArray); OutputWrite(ARRAY_OPEN_PAREN, BoxedTextColor.Punctuation); if (ShowArrayValueSizes && aryValue != null && !aryValue.IsNull) { if (aryValue.GetArrayCount(out elementCount)) { WriteUInt32(elementCount); } } OutputWrite(ARRAY_CLOSE_PAREN, BoxedTextColor.Punctuation); } } break; case DmdTypeSignatureKind.Pointer: Format(type.GetElementType(), null); OutputWrite("*", BoxedTextColor.Operator); break; case DmdTypeSignatureKind.ByRef: OutputWrite(BYREF_KEYWORD, BoxedTextColor.Keyword); WriteSpace(); Format(type.GetElementType(), value?.LoadIndirect()); break; case DmdTypeSignatureKind.TypeGenericParameter: WriteIdentifier(type.MetadataName, BoxedTextColor.TypeGenericParameter); break; case DmdTypeSignatureKind.MethodGenericParameter: WriteIdentifier(type.MetadataName, BoxedTextColor.MethodGenericParameter); break; case DmdTypeSignatureKind.Type: case DmdTypeSignatureKind.GenericInstance: if (type.IsNullable) { Format(type.GetNullableElementType(), null); OutputWrite("?", BoxedTextColor.Operator); } else if (TypeFormatterUtils.IsTupleType(type)) { OutputWrite(TUPLE_OPEN_PAREN, BoxedTextColor.Punctuation); var tupleType = type; int tupleIndex = 0; for (;;) { tupleType = WriteTupleFields(tupleType, ref tupleIndex); if ((object)tupleType != null) { WriteCommaSpace(); } else { break; } } OutputWrite(TUPLE_CLOSE_PAREN, BoxedTextColor.Punctuation); } else { var genericArgs = type.GetGenericArguments(); int genericArgsIndex = 0; KeywordType keywordType; if ((object)type.DeclaringType == null) { keywordType = GetKeywordType(type); if (keywordType == KeywordType.NoKeyword) { WriteNamespace(type); } WriteTypeName(type, keywordType); WriteGenericArguments(type, genericArgs, ref genericArgsIndex); } else { var typesList = new List <DmdType>(); typesList.Add(type); while (type.DeclaringType != null) { type = type.DeclaringType; typesList.Add(type); } keywordType = GetKeywordType(type); if (keywordType == KeywordType.NoKeyword) { WriteNamespace(type); } for (int i = typesList.Count - 1; i >= 0; i--) { WriteTypeName(typesList[i], i == 0 ? keywordType : KeywordType.NoKeyword); WriteGenericArguments(typesList[i], genericArgs, ref genericArgsIndex); if (i != 0) { OutputWrite(".", BoxedTextColor.Operator); } } } } break; case DmdTypeSignatureKind.FunctionPointer: //TODO: OutputWrite("fnptr", BoxedTextColor.Keyword); break; default: throw new InvalidOperationException(); } } finally { recursionCounter--; if (arrayTypesList != null) { foreach (var info in arrayTypesList) { if (info.value != value) { info.value?.Dispose(); } } } } }