From 86c0bbc1b63d2675d35165717f80bfd9f973601d Mon Sep 17 00:00:00 2001 From: Anders Sundheim Date: Fri, 14 Nov 2025 17:04:21 -0800 Subject: [PATCH 1/4] Use ArrayExpansion for [InlineArray] structs --- ...sis.CSharp.ResultProvider.UnitTests.csproj | 19 ++++- .../NetCoreTests/InlineArrayExpansionTests.cs | 35 +++++++++ .../ExpressionEvaluatorFatalError.cs | 2 +- .../Helpers/InlineArrayHelpers.cs | 72 +++++++++++++++++++ .../Source/ResultProvider/ResultProvider.cs | 10 +++ .../ResultProvider/ResultProvider.projitems | 1 + .../Debugger/Engine/DkmClrValue.cs | 42 ++++++++++- ...deAnalysis.ResultProvider.Utilities.csproj | 6 +- .../Test/ResultProvider/SampleInlineArray.cs | 37 ++++++++++ 9 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 src/ExpressionEvaluator/CSharp/Test/ResultProvider/NetCoreTests/InlineArrayExpansionTests.cs create mode 100644 src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs create mode 100644 src/ExpressionEvaluator/Core/Test/ResultProvider/SampleInlineArray.cs diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/Microsoft.CodeAnalysis.CSharp.ResultProvider.UnitTests.csproj b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/Microsoft.CodeAnalysis.CSharp.ResultProvider.UnitTests.csproj index 444ab1bd8ef7a..fe56796c9181a 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/Microsoft.CodeAnalysis.CSharp.ResultProvider.UnitTests.csproj +++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/Microsoft.CodeAnalysis.CSharp.ResultProvider.UnitTests.csproj @@ -5,7 +5,7 @@ Library Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.ResultProvider.UnitTests - net472 + net472;$(NetRoslyn) true @@ -17,10 +17,25 @@ - + + + + + + + + + + + + diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/NetCoreTests/InlineArrayExpansionTests.cs b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/NetCoreTests/InlineArrayExpansionTests.cs new file mode 100644 index 0000000000000..35010b802ba34 --- /dev/null +++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/NetCoreTests/InlineArrayExpansionTests.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.ExpressionEvaluator; +using Microsoft.VisualStudio.Debugger.Evaluation; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests.NetCoreTests; + +public class InlineArrayExpansionTests : CSharpResultProviderTestBase +{ + [Fact] + public void InlineArrayExpansion() + { + var hostObject = new SampleInlineArray(); + for (int i = 0; i < SampleInlineArray.Length; i++) + { + hostObject[i] = i; + } + + var value = CreateDkmClrValue(hostObject, typeof(SampleInlineArray), evalFlags: DkmEvaluationResultFlags.None); + + const string rootExpr = "new SampleInlineArray()"; + var evalResult = (DkmSuccessEvaluationResult)FormatResult(rootExpr, value); + Verify(evalResult, + EvalResult(rootExpr, "0,1,2,3", "Microsoft.CodeAnalysis.ExpressionEvaluator.SampleInlineArray", rootExpr, DkmEvaluationResultFlags.Expandable)); + + Verify(GetChildren(evalResult), + EvalResult("[0]", "0", "int", "(new SampleInlineArray())[0]", DkmEvaluationResultFlags.None), + EvalResult("[1]", "1", "int", "(new SampleInlineArray())[1]", DkmEvaluationResultFlags.None), + EvalResult("[2]", "2", "int", "(new SampleInlineArray())[2]", DkmEvaluationResultFlags.None), + EvalResult("[3]", "3", "int", "(new SampleInlineArray())[3]", DkmEvaluationResultFlags.None)); + } +} diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs index ede4341c1ea7e..8c9b52c5e1c54 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs @@ -27,7 +27,7 @@ internal static class RegistryHelpers var hKeyCurrentUserField = registryType.GetTypeInfo().GetDeclaredField("CurrentUser"); if (hKeyCurrentUserField != null && hKeyCurrentUserField.IsStatic) { - using var currentUserKey = (IDisposable)hKeyCurrentUserField.GetValue(null); + using var currentUserKey = (IDisposable)hKeyCurrentUserField.GetValue(null)!; var openSubKeyMethod = currentUserKey.GetType().GetTypeInfo().GetDeclaredMethod("OpenSubKey", [typeof(string), typeof(bool)]); using var eeKey = (IDisposable?)openSubKeyMethod?.Invoke(currentUserKey, new object[] { RegistryKey, /*writable*/ false }); diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs new file mode 100644 index 0000000000000..5dbd0a77817aa --- /dev/null +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using BindingFlags = Microsoft.VisualStudio.Debugger.Metadata.BindingFlags; +using FieldInfo = Microsoft.VisualStudio.Debugger.Metadata.FieldInfo; +using CustomAttributeData = Microsoft.VisualStudio.Debugger.Metadata.CustomAttributeData; +using Type = Microsoft.VisualStudio.Debugger.Metadata.Type; +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.CodeAnalysis.ExpressionEvaluator; + +internal static class InlineArrayHelpers +{ + private const string InlineArrayAttributeName = "System.Runtime.CompilerServices.InlineArrayAttribute"; + + public static bool IsInlineArray(Type t) + { + if (t.IsValueType) + { + IList attributes = t.GetCustomAttributesData(); + foreach (var attribute in attributes) + { + if (attribute.Constructor?.DeclaringType?.FullName?.Equals(InlineArrayAttributeName, StringComparison.Ordinal) == true) + { + return true; + } + } + } + + return false; + } + + public static bool TryGetInlineArrayInfo(Type t, out int arrayLength, [NotNullWhen(true)] out Type? tElementType) + { + arrayLength = -1; + tElementType = null; + + IList customAttributes = t.GetCustomAttributesData(); + foreach (var attribute in customAttributes) + { + if (attribute.Constructor?.DeclaringType?.FullName?.Equals(InlineArrayAttributeName, StringComparison.Ordinal) == true) + { + if (attribute.ConstructorArguments.Count == 1 && attribute.ConstructorArguments[0].Value is int length) + { + arrayLength = length; + } + } + } + + // Inline arrays must have length > 0 + if (arrayLength <= 0) + { + return false; + } + + FieldInfo[] fields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + if (fields.Length == 1) + { + tElementType = fields[0].FieldType; + } + else + { + // Inline arrays must have exactly one field + return false; + } + + return true; + } +} diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs index a3bd70266c3c4..dad8284f38d49 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs @@ -1012,6 +1012,16 @@ internal Expansion GetTypeExpansion( return TupleExpansion.CreateExpansion(inspectionContext, declaredTypeAndInfo, value, cardinality); } + if (InlineArrayHelpers.IsInlineArray(runtimeType) && + InlineArrayHelpers.TryGetInlineArrayInfo(runtimeType, out int inlineArrayLength, out Type inlineArrayElementType)) + { + // Inline arrays are always 1D, zero-based arrays. + return ArrayExpansion.CreateExpansion( + elementTypeAndInfo: new TypeAndCustomInfo(DkmClrType.Create(declaredTypeAndInfo.ClrType.AppDomain, inlineArrayElementType), null), + sizes: new ReadOnlyCollection([inlineArrayLength]), + lowerBounds: new ReadOnlyCollection([0])); + } + return MemberExpansion.CreateExpansion(inspectionContext, declaredTypeAndInfo, value, flags, TypeHelpers.IsVisibleMember, this, isProxyType: false, supportsFavorites); } diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.projitems b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.projitems index e612fce34c869..7a25078611b18 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.projitems +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.projitems @@ -16,6 +16,7 @@ + diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs index c76545d9d58c9..c9c14769cf3ee 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs @@ -565,9 +565,45 @@ public DkmClrValue GetArrayElement(int[] indices, DkmInspectionContext inspectio throw new ArgumentNullException(nameof(inspectionContext)); } - var array = (System.Array)RawValue; - var element = array.GetValue(indices); - var type = DkmClrType.Create(this.Type.AppDomain, (TypeImpl)((element == null) ? array.GetType().GetElementType() : element.GetType())); + object element; + System.Type elementType; + if (RawValue is Array array) + { + element = array.GetValue(indices); + elementType = (element == null) ? array.GetType().GetElementType() : element.GetType(); + } + else + { +#if NET8_0_OR_GREATER + // Might be an inline array struct + if (indices.Length == 1 && InlineArrayHelpers.IsInlineArray(Type.GetLmrType())) + { + // Since reflection is inadequate to dynamically access inline array elements, + // we have to assume it's the special SampleInlineArray type we define for testing and + // cast appropriately. + element = RawValue switch + { + SampleInlineArray intInlineArray => intInlineArray[indices[0]], + // Add more cases here for other types as needed for testing + _ => throw new InvalidOperationException($"Missing cast case for SampleInlineArray"), + }; + + var fields = RawValue.GetType().GetFields(System.Reflection.BindingFlags.Public | + System.Reflection.BindingFlags.NonPublic | + System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.DeclaredOnly); + elementType = fields[0].FieldType; + } + else + { + throw new InvalidOperationException("Not an array"); + } +#else + throw new InvalidOperationException("Not an array"); +#endif + } + + var type = DkmClrType.Create(this.Type.AppDomain, (TypeImpl)(elementType)); return new DkmClrValue( element, element, diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Microsoft.CodeAnalysis.ResultProvider.Utilities.csproj b/src/ExpressionEvaluator/Core/Test/ResultProvider/Microsoft.CodeAnalysis.ResultProvider.Utilities.csproj index cdc5d592e5ce2..b27b900a4fb13 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Microsoft.CodeAnalysis.ResultProvider.Utilities.csproj +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Microsoft.CodeAnalysis.ResultProvider.Utilities.csproj @@ -6,7 +6,7 @@ Microsoft.CodeAnalysis.ExpressionEvaluator Microsoft.CodeAnalysis.ExpressionEvaluator.ResultProvider.Utilities true - net472 + net472;$(NetRoslyn) false true @@ -23,14 +23,14 @@ $(NoWarn);CA1825 - + + - diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/SampleInlineArray.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/SampleInlineArray.cs new file mode 100644 index 0000000000000..e2908938eed70 --- /dev/null +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/SampleInlineArray.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Microsoft.VisualStudio.Debugger.Evaluation; +using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; + +namespace Microsoft.CodeAnalysis.ExpressionEvaluator; + +#if NET8_0_OR_GREATER + +/// +/// Reflection APIs are inadequate to introspect inline arrays as they box the value type, making +/// it impossible to take a ref to the first element field and read elements out of it. +/// This definition is intended to be used when testing inline arrays. +/// +/// +/// To support testing new types, +/// add an appropriate cast in +/// +[InlineArray(Length)] +[DebuggerDisplay("{ToString(),nq}")] +internal struct SampleInlineArray +{ + public const int Length = 4; + public T _elem0; + + public override string ToString() + { + return string.Join(",", MemoryMarshal.CreateSpan(ref _elem0, Length).ToArray()); + } +} + +#endif From 70b34e2508e39bb5402f3e212cbd5bea0cad8948 Mon Sep 17 00:00:00 2001 From: Anders Sundheim Date: Mon, 17 Nov 2025 10:53:57 -0800 Subject: [PATCH 2/4] PR comments / cleanup --- .../Helpers/InlineArrayHelpers.cs | 22 ++++++------------- .../Source/ResultProvider/ResultProvider.cs | 3 +-- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs index 5dbd0a77817aa..8a8d66334d4fc 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs @@ -9,6 +9,7 @@ using CustomAttributeData = Microsoft.VisualStudio.Debugger.Metadata.CustomAttributeData; using Type = Microsoft.VisualStudio.Debugger.Metadata.Type; using System.Diagnostics.CodeAnalysis; +using System.Linq; namespace Microsoft.CodeAnalysis.ExpressionEvaluator; @@ -17,27 +18,18 @@ internal static class InlineArrayHelpers private const string InlineArrayAttributeName = "System.Runtime.CompilerServices.InlineArrayAttribute"; public static bool IsInlineArray(Type t) - { - if (t.IsValueType) - { - IList attributes = t.GetCustomAttributesData(); - foreach (var attribute in attributes) - { - if (attribute.Constructor?.DeclaringType?.FullName?.Equals(InlineArrayAttributeName, StringComparison.Ordinal) == true) - { - return true; - } - } - } - - return false; - } + => t.IsValueType && t.GetCustomAttributesData().Any(static a => a.Constructor?.DeclaringType?.FullName == InlineArrayAttributeName); public static bool TryGetInlineArrayInfo(Type t, out int arrayLength, [NotNullWhen(true)] out Type? tElementType) { arrayLength = -1; tElementType = null; + if (!t.IsValueType) + { + return false; + } + IList customAttributes = t.GetCustomAttributesData(); foreach (var attribute in customAttributes) { diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs index dad8284f38d49..770923d603f10 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs @@ -1012,8 +1012,7 @@ internal Expansion GetTypeExpansion( return TupleExpansion.CreateExpansion(inspectionContext, declaredTypeAndInfo, value, cardinality); } - if (InlineArrayHelpers.IsInlineArray(runtimeType) && - InlineArrayHelpers.TryGetInlineArrayInfo(runtimeType, out int inlineArrayLength, out Type inlineArrayElementType)) + if (InlineArrayHelpers.TryGetInlineArrayInfo(runtimeType, out int inlineArrayLength, out Type inlineArrayElementType)) { // Inline arrays are always 1D, zero-based arrays. return ArrayExpansion.CreateExpansion( From 2e9652031d17e9fecfce7b3d45ae81d9be40ceb3 Mon Sep 17 00:00:00 2001 From: Anders Sundheim Date: Tue, 18 Nov 2025 13:23:19 -0800 Subject: [PATCH 3/4] remove IsInlineArray, check metadata signature, various --- .../ExpressionEvaluatorFatalError.cs | 3 ++- .../ResultProvider/Helpers/InlineArrayHelpers.cs | 15 ++++++--------- .../Source/ResultProvider/Helpers/TypeHelpers.cs | 5 +++++ .../ResultProvider/Debugger/Engine/DkmClrValue.cs | 2 +- .../Debugger/MemberInfo/ConstructorInfoImpl.cs | 3 ++- .../Debugger/MemberInfo/ParameterInfoImpl.cs | 15 +++------------ 6 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs index 8c9b52c5e1c54..0aa0713c0b528 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs @@ -27,7 +27,8 @@ internal static class RegistryHelpers var hKeyCurrentUserField = registryType.GetTypeInfo().GetDeclaredField("CurrentUser"); if (hKeyCurrentUserField != null && hKeyCurrentUserField.IsStatic) { - using var currentUserKey = (IDisposable)hKeyCurrentUserField.GetValue(null)!; + using var currentUserKey = hKeyCurrentUserField.GetValue(null) as IDisposable; + RoslynDebug.AssertNotNull(currentUserKey); var openSubKeyMethod = currentUserKey.GetType().GetTypeInfo().GetDeclaredMethod("OpenSubKey", [typeof(string), typeof(bool)]); using var eeKey = (IDisposable?)openSubKeyMethod?.Invoke(currentUserKey, new object[] { RegistryKey, /*writable*/ false }); diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs index 8a8d66334d4fc..01f6a5d16d661 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/InlineArrayHelpers.cs @@ -2,14 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using BindingFlags = Microsoft.VisualStudio.Debugger.Metadata.BindingFlags; -using FieldInfo = Microsoft.VisualStudio.Debugger.Metadata.FieldInfo; using CustomAttributeData = Microsoft.VisualStudio.Debugger.Metadata.CustomAttributeData; +using FieldInfo = Microsoft.VisualStudio.Debugger.Metadata.FieldInfo; using Type = Microsoft.VisualStudio.Debugger.Metadata.Type; -using System.Diagnostics.CodeAnalysis; -using System.Linq; namespace Microsoft.CodeAnalysis.ExpressionEvaluator; @@ -17,9 +15,6 @@ internal static class InlineArrayHelpers { private const string InlineArrayAttributeName = "System.Runtime.CompilerServices.InlineArrayAttribute"; - public static bool IsInlineArray(Type t) - => t.IsValueType && t.GetCustomAttributesData().Any(static a => a.Constructor?.DeclaringType?.FullName == InlineArrayAttributeName); - public static bool TryGetInlineArrayInfo(Type t, out int arrayLength, [NotNullWhen(true)] out Type? tElementType) { arrayLength = -1; @@ -33,9 +28,11 @@ public static bool TryGetInlineArrayInfo(Type t, out int arrayLength, [NotNullWh IList customAttributes = t.GetCustomAttributesData(); foreach (var attribute in customAttributes) { - if (attribute.Constructor?.DeclaringType?.FullName?.Equals(InlineArrayAttributeName, StringComparison.Ordinal) == true) + if (InlineArrayAttributeName.Equals(attribute.Constructor?.DeclaringType?.FullName)) { - if (attribute.ConstructorArguments.Count == 1 && attribute.ConstructorArguments[0].Value is int length) + var ctorParams = attribute.Constructor.GetParameters(); + if (ctorParams.Length == 1 && ctorParams[0].ParameterType.IsInt32() && + attribute.ConstructorArguments.Count == 1 && attribute.ConstructorArguments[0].Value is int length) { arrayLength = length; } diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs index 91bf946abbe7c..35fa353196e0e 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs @@ -278,6 +278,11 @@ private static MethodInfo GetNonIndexerGetMethod(PropertyInfo property) : null; } + internal static bool IsInt32(this Type type) + { + return Type.GetTypeCode(type) == TypeCode.Int32; + } + internal static bool IsBoolean(this Type type) { return Type.GetTypeCode(type) == TypeCode.Boolean; diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs index c9c14769cf3ee..4f4cb8e4a8d5c 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrValue.cs @@ -576,7 +576,7 @@ public DkmClrValue GetArrayElement(int[] indices, DkmInspectionContext inspectio { #if NET8_0_OR_GREATER // Might be an inline array struct - if (indices.Length == 1 && InlineArrayHelpers.IsInlineArray(Type.GetLmrType())) + if (indices.Length == 1 && InlineArrayHelpers.TryGetInlineArrayInfo(Type.GetLmrType(), out _, out _)) { // Since reflection is inadequate to dynamically access inline array elements, // we have to assume it's the special SampleInlineArray type we define for testing and diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/ConstructorInfoImpl.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/ConstructorInfoImpl.cs index e3060c4c7c83b..dd72573c11413 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/ConstructorInfoImpl.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/ConstructorInfoImpl.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.Linq; using Microsoft.VisualStudio.Debugger.Metadata; using Type = Microsoft.VisualStudio.Debugger.Metadata.Type; @@ -135,7 +136,7 @@ public override System.Reflection.MethodImplAttributes GetMethodImplementationFl public override Microsoft.VisualStudio.Debugger.Metadata.ParameterInfo[] GetParameters() { - throw new NotImplementedException(); + return [.. Constructor.GetParameters().Select(p => new ParameterInfoImpl(p))]; } public override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/ParameterInfoImpl.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/ParameterInfoImpl.cs index 193664f1eed01..5a250f1684d22 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/ParameterInfoImpl.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/ParameterInfoImpl.cs @@ -37,20 +37,11 @@ public override MemberInfo Member get { throw new NotImplementedException(); } } - public override string Name - { - get { throw new NotImplementedException(); } - } + public override string Name => Parameter.Name; - public override Type ParameterType - { - get { throw new NotImplementedException(); } - } + public override Type ParameterType => new TypeImpl(Parameter.ParameterType); - public override int Position - { - get { throw new NotImplementedException(); } - } + public override int Position => Parameter.Position; public override object RawDefaultValue { From 849bb8d2756e21a4759d5424b2298a9432232d5a Mon Sep 17 00:00:00 2001 From: Anders Sundheim Date: Tue, 18 Nov 2025 15:17:11 -0800 Subject: [PATCH 4/4] (IDisposable?) --- .../Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs index 0aa0713c0b528..0ad1905244eff 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs @@ -27,7 +27,7 @@ internal static class RegistryHelpers var hKeyCurrentUserField = registryType.GetTypeInfo().GetDeclaredField("CurrentUser"); if (hKeyCurrentUserField != null && hKeyCurrentUserField.IsStatic) { - using var currentUserKey = hKeyCurrentUserField.GetValue(null) as IDisposable; + using var currentUserKey = (IDisposable?)hKeyCurrentUserField.GetValue(null); RoslynDebug.AssertNotNull(currentUserKey); var openSubKeyMethod = currentUserKey.GetType().GetTypeInfo().GetDeclaredMethod("OpenSubKey", [typeof(string), typeof(bool)]);