diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/CSharpResultProviderTest.csproj b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/CSharpResultProviderTest.csproj
index b01b1d95e5b8882fc8aff52d10580b8aa53ea4cb..9df052226c1ff34a23a1229d4a61b5b6a9a02b56 100644
--- a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/CSharpResultProviderTest.csproj
+++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/CSharpResultProviderTest.csproj
@@ -91,6 +91,7 @@
+
diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/FunctionPointerTests.cs b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/FunctionPointerTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8afd5f939e6f1f290a417640c50c7750f8f1062f
--- /dev/null
+++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/FunctionPointerTests.cs
@@ -0,0 +1,65 @@
+// 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.ExpressionEvaluator;
+using Microsoft.VisualStudio.Debugger.Clr;
+using Microsoft.VisualStudio.Debugger.Evaluation;
+using System;
+using System.Diagnostics;
+using Xunit;
+using Type = Microsoft.VisualStudio.Debugger.Metadata.Type;
+
+namespace Microsoft.CodeAnalysis.CSharp.UnitTests
+{
+ public class FunctionPointerTests : CSharpResultProviderTestBase
+ {
+ [Fact]
+ public void Root()
+ {
+ const int ptr = 0x1234;
+ var value = CreateDkmClrValue(ptr, type: new DkmClrType(FunctionPointerType.Instance));
+ var evalResult = FormatResult("pfn", value);
+ Verify(evalResult,
+ EvalResult("pfn", PointerToString(new IntPtr(ptr)), "System.Object*", "pfn", DkmEvaluationResultFlags.None, DkmEvaluationResultCategory.Other));
+ }
+
+ [Fact]
+ public void Member()
+ {
+ var source =
+@"class C
+{
+ object pfn;
+}";
+ const int ptr = 0x0;
+ GetMemberValueDelegate getMemberValue = (v, m) => (m == "pfn") ? CreateDkmClrValue(ptr, type: new DkmClrType(FunctionPointerType.Instance)) : null;
+ var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlibAndSystemCore(GetAssembly(source)), getMemberValue: getMemberValue);
+ using (runtime.Load())
+ {
+ var type = runtime.GetType("C");
+ var value = CreateDkmClrValue(type.Instantiate(), type: type);
+ var evalResult = FormatResult("o", value);
+ Verify(evalResult,
+ EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable, DkmEvaluationResultCategory.Other));
+ var children = GetChildren(evalResult);
+ Verify(children,
+ EvalResult("pfn", PointerToString(new IntPtr(ptr)), "object {System.Object*}", "o.pfn", DkmEvaluationResultFlags.None, DkmEvaluationResultCategory.Other));
+ }
+ }
+
+ // Function pointer type has IsPointer == true and GetElementType() == null.
+ private sealed class FunctionPointerType : TypeImpl
+ {
+ internal static readonly FunctionPointerType Instance = new FunctionPointerType();
+
+ private FunctionPointerType() : base(typeof(object).MakePointerType())
+ {
+ Debug.Assert(this.IsPointer);
+ }
+
+ public override Type GetElementType()
+ {
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.TypeNames.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.TypeNames.cs
index 8231bae212944760b6e095185a49a405858169be..05b6b9e3475ea9d306d952d551b2f629d1c05c40 100644
--- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.TypeNames.cs
+++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.TypeNames.cs
@@ -61,9 +61,15 @@ internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIde
int pointerCount = 0;
while (type.IsPointer)
{
+ var elementType = type.GetElementType();
+ if (elementType == null)
+ {
+ // Null for function pointers.
+ break;
+ }
index++;
pointerCount++;
- type = type.GetElementType();
+ type = elementType;
}
int nullableCount = 0;
diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/TypeImpl.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/TypeImpl.cs
index c8dd7e747f8db62fbc0daebdf3af476f424e0aee..7318ba0feb28849641b4977220f882aacf50fc52 100644
--- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/TypeImpl.cs
+++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/MemberInfo/TypeImpl.cs
@@ -11,11 +11,11 @@
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
- internal sealed class TypeImpl : Type
+ internal class TypeImpl : Type
{
internal readonly System.Type Type;
- private TypeImpl(System.Type type)
+ internal TypeImpl(System.Type type)
{
Debug.Assert(type != null);
this.Type = type;