From 0f10ee1b9bd2b6c0cd6ba24e7735ff4be496fc3e Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Wed, 5 Aug 2026 14:36:00 +0200 Subject: [PATCH] Add VBPretty fixtures for VB anonymous types and queries VBPretty had no coverage of VB's anonymous types, so nothing caught that their use sites decompiled to the raw metadata names while their definitions were hidden from the output. The expected C# is written as it should read once the generated-name predicates agree with each other; it fails until then. Roslyn 2.10 targeting .NET Core 2.2 is branched off with #if: there the query operator calls are not restored to extension-method syntax, so no query expression is formed and the lowered form survives. Assisted-by: Claude:claude-fable-5:Claude Code --- .../ICSharpCode.Decompiler.Tests.csproj | 1 + .../TestCases/VBPretty/VBAnonymousTypes.cs | 89 +++++++++++++++++++ .../TestCases/VBPretty/VBAnonymousTypes.vb | 62 +++++++++++++ .../VBPrettyTestRunner.cs | 7 ++ 4 files changed, 159 insertions(+) create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.cs create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.vb diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index c93687145..29015d86a 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -149,6 +149,7 @@ + diff --git a/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.cs b/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.cs new file mode 100644 index 000000000..cc35f4ead --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +using Microsoft.VisualBasic.CompilerServices; + +[StandardModule] +public sealed class VBAnonymousTypes +{ + public static void MutableAnonymousType() + { + var anon = new { + Value = 1, + Name = "test" + }; + Console.WriteLine(anon.Value); + Console.WriteLine(anon.Name); + } + + public static void KeyAnonymousType() + { + var anon = new { + Value = 1, + Name = "test" + }; + Console.WriteLine(anon.Value); + Console.WriteLine(anon.Name); + } + + public static void AnonymousTypeAsArgument() + { + Console.WriteLine(new { + Value = 1, + Name = "test" + }.ToString()); + } + + public static void SelectAnonymousType(IEnumerable items) + { + var enumerable = items.Select([SpecialName] (int i) => new { + Value = i, + Square = checked(i * i) + }); + foreach (var item in enumerable) + { + Console.WriteLine(item.Value); + Console.WriteLine(item.Square); + } + } + + public static void LetWhereSelect(IEnumerable items) + { + var enumerable = from i in items + let square = checked(i * i) + where square > 4 + select new { i, square }; + foreach (var item in enumerable) + { + Console.WriteLine(item.i); + Console.WriteLine(item.square); + } + } + + public static void JoinSelect(IEnumerable left, IEnumerable right) + { + var enumerable = from x in left + join y in right on x equals y + select new { x, y }; + foreach (var item in enumerable) + { + Console.WriteLine(item.x); + Console.WriteLine(item.y); + } + } + + public static void OrderBySelect(IEnumerable items) + { + var enumerable = from i in items + let doubled = checked(i * 2) + orderby doubled + select new { i, doubled }; + foreach (var item in enumerable) + { + Console.WriteLine(item.i); + Console.WriteLine(item.doubled); + } + } +} diff --git a/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.vb b/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.vb new file mode 100644 index 000000000..b789de35e --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBAnonymousTypes.vb @@ -0,0 +1,62 @@ +Imports System +Imports System.Collections.Generic +Imports System.Linq + +Public Module VBAnonymousTypes + Public Sub MutableAnonymousType() + Dim value = New With {.Value = 1, .Name = "test"} + Console.WriteLine(value.Value) + Console.WriteLine(value.Name) + End Sub + + Public Sub KeyAnonymousType() + Dim value = New With {Key .Value = 1, Key .Name = "test"} + Console.WriteLine(value.Value) + Console.WriteLine(value.Name) + End Sub + + Public Sub AnonymousTypeAsArgument() + Console.WriteLine(New With {Key .Value = 1, Key .Name = "test"}.ToString()) + End Sub + + Public Sub SelectAnonymousType(items As IEnumerable(Of Integer)) + Dim query = From i In items + Select New With {Key .Value = i, Key .Square = i * i} + For Each item In query + Console.WriteLine(item.Value) + Console.WriteLine(item.Square) + Next + End Sub + + Public Sub LetWhereSelect(items As IEnumerable(Of Integer)) + Dim query = From i In items + Let square = i * i + Where square > 4 + Select i, square + For Each item In query + Console.WriteLine(item.i) + Console.WriteLine(item.square) + Next + End Sub + + Public Sub JoinSelect(left As IEnumerable(Of Integer), right As IEnumerable(Of Integer)) + Dim query = From x In left + Join y In right On x Equals y + Select x, y + For Each item In query + Console.WriteLine(item.x) + Console.WriteLine(item.y) + Next + End Sub + + Public Sub OrderBySelect(items As IEnumerable(Of Integer)) + Dim query = From i In items + Let doubled = i * 2 + Order By doubled + Select i, doubled + For Each item In query + Console.WriteLine(item.i) + Console.WriteLine(item.doubled) + Next + End Sub +End Module diff --git a/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs index ff2feb797..3cd9f3b09 100644 --- a/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs @@ -125,6 +125,13 @@ namespace ICSharpCode.Decompiler.Tests await Run(options: options | CompilerOptions.Library); } + [Test] + public async Task VBAnonymousTypes([ValueSource(nameof(defaultOptions))] CompilerOptions options) + { + IgnoreIfVbRuntimeSubstituted(options); + await Run(options: options | CompilerOptions.Library); + } + [Test] public async Task Issue1906([ValueSource(nameof(defaultOptions))] CompilerOptions options) {