Upstream icsharpcode/ILSpy state of the touched files before d5ff770959

This commit is contained in:
upstream committed 2026-09-11 23:55:33 +02:00
1 parent 167098573c
commit aa0b6871d2
3 files changed
+756

No files matched your search

@@ -0,0 +1,309 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net11.0</TargetFramework>
<LangVersion>preview</LangVersion>
<!-- A single (host) RID makes the build copy the native DiaSymReader.Native assets the
Windows PDB tests need; the explicit RID list makes packages.lock.json carry every RID
(host-independent), so the lock does not drift between Linux and Windows restores. -->
<RuntimeIdentifier>$(NETCoreSdkRuntimeIdentifier)</RuntimeIdentifier>
<RuntimeIdentifiers>win-x64;win-arm64;linux-x64;osx-arm64</RuntimeIdentifiers>
<IsPackable>false</IsPackable>
<GenerateTestingPlatformEntryPoint>true</GenerateTestingPlatformEntryPoint>
<StartupObject>ICSharpCode.Decompiler.Tests.MicrosoftTestingPlatformEntryPoint</StartupObject>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<!-- The suite runs dozens of allocation-heavy decompiles concurrently (one NUnit worker per
logical CPU, each roundtrip adding WholeProjectDecompiler's own Parallel.ForEach). Workstation
GC stops the whole process for every gen0/gen1 collection any worker triggers; measured on a
24-thread machine that was ~300 s of pause in a ~550 s run. Server GC gives each core its own
heap and collects in parallel. -->
<ServerGarbageCollection>true</ServerGarbageCollection>
<!-- NU1902/1903 are "Package 'X' has a known security vulnerability". In our tests, we don't care. -->
<!-- CA1416 fires because the TFM dropped its -windows suffix: Windows-only helpers (SdkUtility,
Tester.SignAssembly/FindMSBuild/RunWithTestRunner) and Windows-only test inputs (Console.CapsLock
in Async/Switch fixtures) are reachable from non-Windows in principle, but gated by
OperatingSystem.IsWindows() + Assert.Ignore at runtime. The analyzer can't see that. -->
<NoWarn>$(NoWarn);1701;1702;1705,67,169,1058,728,1720,649,168,251,660,661,675;1998;162;8632;626;8618;8714;8602;8981;NU1902;NU1903;CA1416</NoWarn>
<DefineConstants>ROSLYN;ROSLYN2;ROSLYN3;ROSLYN4;NET60;CS60;CS70;CS71;CS72;CS73;CS80;CS90;CS100;CS110;CS120;CS130</DefineConstants>
<GenerateAssemblyVersionAttribute>False</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>False</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>False</GenerateAssemblyInformationalVersionAttribute>
<!-- Compile items come from the SDK default **/*.cs glob; the ItemGroup near the end excludes
only the test-case sources that still do not compile under the current toolchain. Default
None globbing stays off so the non-C# inputs (.il/.vb/.fs) and Content stay explicit. -->
<EnableDefaultNoneItems>false</EnableDefaultNoneItems>
<AutoGenerateBindingRedirects>True</AutoGenerateBindingRedirects>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DiffLib" />
<PackageReference Include="CliWrap" />
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="NuGet.Protocol" />
<PackageReference Include="System.Collections.Immutable" />
<PackageReference Include="System.Reflection.Metadata" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" />
<PackageReference Include="Microsoft.DiaSymReader.Converter.Xml" />
<PackageReference Include="Microsoft.DiaSymReader" />
<!-- Referenced unconditionally so restore yields the same packages.lock.json on every OS.
The native asset only resolves for win-* RIDs; non-Windows builds ignore it, and the
tests that use it are gated by OperatingSystem.IsWindows() + Assert.Ignore at runtime. -->
<PackageReference Include="Microsoft.DiaSymReader.Native" />
<PackageReference Include="NUnit3TestAdapter" />
<PackageReference Include="coverlet.MTP" />
<PackageReference Include="NUnit" />
<PackageReference Include="AwesomeAssertions" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" />
<PackageReference Include="Microsoft.Testing.Extensions.VSTestBridge" />
<PackageReference Include="System.Memory" />
<PackageReference Include="Mono.Cecil" />
<PackageReference Include="Microsoft.NETCore.ILAsm" />
<PackageReference Include="Microsoft.NETCore.ILDAsm" />
<PackageReference Include="System.Resources.Extensions" />
</ItemGroup>
<ItemGroup>
<!-- A .resources container holding two stream entries, so this assembly itself is the module
WholeProjectDecompiler's per-entry resource path can be exercised against. -->
<EmbeddedResource Include="Helpers\TwoStreamEntries.resources" LogicalName="TwoStreamEntries.g.resources" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.ILSpyX\ICSharpCode.ILSpyX.csproj" />
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="TestCases\Correctness\Jmp.il" />
<None Include="TestCases\Correctness\StackTests.il" />
<None Include="TestCases\Correctness\StackTypes.il" />
<None Include="TestCases\Correctness\Uninit.vb" />
<None Include="TestCases\Disassembler\Pretty\GenericConstraints.il" />
<None Include="TestCases\Disassembler\Pretty\NegativeConstants.il" />
<None Include="TestCases\Disassembler\Pretty\InterfaceImplAttributes.il" />
<None Include="TestCases\Disassembler\Pretty\SortMembers.expected.il" />
<None Include="TestCases\Disassembler\Pretty\SortMembers.il" />
<None Include="TestCases\IsolatedDecompilation\IsolatedStaticCtor.il" />
<None Include="TestCases\ILPretty\ExtensionEncodingV2.il" />
<None Include="testcases\ilpretty\ExtensionEncodingV1.il" />
<None Include="TestCases\ILPretty\GuessAccessors.il" />
<None Include="TestCases\ILPretty\InaccessibleParameterTypes.il" />
<None Include="TestCases\ILPretty\Issue2260SwitchString.il" />
<None Include="TestCases\ILPretty\Issue3442.il" />
<None Include="TestCases\ILPretty\Issue3344CkFinite.il" />
<None Include="testcases\ilpretty\Issue3465.il" />
<None Include="TestCases\ILPretty\Issue3466.il" />
<None Include="testcases\ilpretty\Issue3504.il" />
<None Include="testcases\ilpretty\Issue3524.il" />
<None Include="testcases\ilpretty\Issue3552.il" />
<None Include="TestCases\ILPretty\MonoFixed.il" />
<None Include="TestCases\Correctness\NonGenericConstrainedCallVirt.il" />
<None Include="TestCases\ILPretty\UnknownTypes.il" />
<None Include="TestCases\ILPretty\EvalOrder.il" />
<None Include="TestCases\ILPretty\CallIndirect.il" />
<None Include="TestCases\ILPretty\Issue1454.il" />
<None Include="TestCases\ILPretty\Issue1681.il" />
<None Include="TestCases\ILPretty\Issue1922.il" />
<None Include="TestCases\ILPretty\Issue1918.il" />
<None Include="TestCases\ILPretty\Issue2104.il" />
<None Include="TestCases\ILPretty\Issue3421.il" />
<None Include="TestCases\ILPretty\WeirdEnums.il" />
<None Include="TestCases\ILPretty\EnumArithmeticOutOfRange.il" />
<None Include="TestCases\ILPretty\ConstantBlobs.il" />
<None Include="TestCases\ILPretty\CS1xSwitch_Debug.il" />
<None Include="TestCases\ILPretty\CS1xSwitch_Release.il" />
<None Include="TestCases\ILPretty\Issue1157.il" />
<None Include="TestCases\ILPretty\Issue684.il" />
<None Include="TestCases\ILPretty\FSharpLoops.fs" />
<None Include="TestCases\ILPretty\FSharpLoops_Debug.il" />
<None Include="TestCases\ILPretty\FSharpLoops_Release.il" />
<None Include="TestCases\ILPretty\FSharpUsing.fs" />
<None Include="TestCases\ILPretty\FSharpUsing_Debug.il" />
<None Include="TestCases\ILPretty\DirectCallToExplicitInterfaceImpl.il" />
<None Include="TestCases\ILPretty\TruncatedAccessorBody.il" />
<None Include="TestCases\ILPretty\FSharpUsing_Release.il" />
<None Include="TestCases\Correctness\BitNot.il" />
<None Include="TestCases\Correctness\Readme.txt" />
</ItemGroup>
<ItemGroup>
<None Include="TestCases\VBPretty\VBAutomaticEvents.vb" />
<None Include="TestCases\VBPretty\VBNonGenericForEach.vb" />
<None Include="TestCases\VBPretty\YieldReturn.vb" />
<None Include="TestCases\VBPretty\Issue1906.vb" />
<None Include="TestCases\VBPretty\Issue2192.vb" />
<None Include="TestCases\VBPretty\Select.vb" />
<None Include="TestCases\VBPretty\VBAnonymousTypes.vb" />
<None Include="TestCases\VBPretty\ParameterizedProperties.vb" />
<None Include="TestCases\ILPretty\Unsafe.il" />
<None Include="TestCases\ILPretty\Issue1389.il" />
<None Include="TestCases\ILPretty\SequenceOfNestedIfs.il" />
<None Include="TestCases\ILPretty\Issue1256.il" />
<None Include="TestCases\ILPretty\Issue1323.il" />
<None Include="TestCases\ILPretty\Issue1325.il" />
<None Include="TestCases\Disassembler\Pretty\SecurityDeclarations.il" />
<None Include="TestCases\ILPretty\Issue1038.il" />
<None Include="TestCases\ILPretty\Issue1145.il" />
<None Include="TestCases\ILPretty\NoAccessorProperties.il" />
<None Include="TestCases\ILPretty\Issue1047.il" />
<None Include="TestCases\ILPretty\Issue959.il" />
</ItemGroup>
<ItemGroup>
<None Include="TestCases\PdbGen\*.cs" />
<None Include="TestCases\PdbGen\PinnedRegionWarning.il" />
<None Include="TestCases\PdbGen\PinnedLocalSlot.il" />
</ItemGroup>
<ItemGroup>
<None Include="TestCases\ILPretty\Issue646.il" />
<None Include="TestCases\ILPretty\Issue379.il" />
<None Include="TestCases\ILPretty\Issue982.il" />
<None Include="TestCases\Pretty\Readme.txt" />
<None Include="TestCases\VBPretty\VBCompoundAssign.vb" />
<None Include="TestCases\VBPretty\Async.vb" />
<None Include="TestCases\VBPretty\VBPropertiesTest.vb" />
</ItemGroup>
<ItemGroup Label="ExcludedTestInputs">
<!-- Test-case sources that cannot be compiled into the test assembly: decompiler inputs that
are not valid standalone C#, expected-output fixtures that reuse type names, and
MetadataAttributes.cs (applies assembly/module attributes that break NUnit discovery).
The harness compiles these from disk at test time; kept as None for IDE visibility. -->
<Compile Remove="TestCases\PdbGen\*.cs" />
<Compile Remove="TestCases\Correctness\ComInterop.cs" />
<None Include="TestCases\Correctness\ComInterop.cs" />
<Compile Remove="TestCases\ILPretty\CS1xSwitch_Debug.cs" />
<None Include="TestCases\ILPretty\CS1xSwitch_Debug.cs" />
<Compile Remove="TestCases\ILPretty\CS1xSwitch_Release.cs" />
<None Include="TestCases\ILPretty\CS1xSwitch_Release.cs" />
<Compile Remove="TestCases\ILPretty\CallIndirect.cs" />
<None Include="TestCases\ILPretty\CallIndirect.cs" />
<Compile Remove="TestCases\ILPretty\InstanceOperatorCall.cs" />
<None Include="TestCases\ILPretty\InstanceOperatorCall.cs" />
<None Include="TestCases\ILPretty\InstanceOperatorCall.il" />
<Compile Remove="TestCases\ILPretty\EnumArithmeticOutOfRange.cs" />
<None Include="TestCases\ILPretty\EnumArithmeticOutOfRange.cs" />
<Compile Remove="TestCases\ILPretty\EmptyBodies.cs" />
<None Include="TestCases\ILPretty\EmptyBodies.cs" />
<Compile Remove="TestCases\ILPretty\TruncatedAccessorBody.cs" />
<None Include="TestCases\ILPretty\TruncatedAccessorBody.cs" />
<Compile Remove="TestCases\ILPretty\SealedRecordProtectedCopyCtor.cs" />
<None Include="TestCases\ILPretty\SealedRecordProtectedCopyCtor.cs" />
<Compile Remove="TestCases\ILPretty\Issue3729.cs" />
<None Include="TestCases\ILPretty\Issue3729.cs" />
<None Include="TestCases\ILPretty\Issue3729.il" />
<Compile Remove="TestCases\ILPretty\SpanConversionOperatorMismatch.cs" />
<None Include="TestCases\ILPretty\SpanConversionOperatorMismatch.cs" />
<Compile Remove="TestCases\ILPretty\FSharpLoops_Debug.cs" />
<None Include="TestCases\ILPretty\FSharpLoops_Debug.cs" />
<Compile Remove="TestCases\ILPretty\FSharpLoops_Release.cs" />
<None Include="TestCases\ILPretty\FSharpLoops_Release.cs" />
<Compile Remove="TestCases\ILPretty\FSharpUsing_Release.cs" />
<None Include="TestCases\ILPretty\FSharpUsing_Release.cs" />
<Compile Remove="TestCases\ILPretty\GuessAccessors.cs" />
<None Include="TestCases\ILPretty\GuessAccessors.cs" />
<Compile Remove="TestCases\ILPretty\InaccessibleParameterTypes.cs" />
<None Include="TestCases\ILPretty\InaccessibleParameterTypes.cs" />
<Compile Remove="TestCases\ILPretty\NoAccessorProperties.cs" />
<None Include="TestCases\ILPretty\NoAccessorProperties.cs" />
<Compile Remove="TestCases\ILPretty\Issue1145.cs" />
<None Include="TestCases\ILPretty\Issue1145.cs" />
<Compile Remove="TestCases\ILPretty\Issue1325.cs" />
<None Include="TestCases\ILPretty\Issue1325.cs" />
<Compile Remove="TestCases\ILPretty\Issue1918.cs" />
<None Include="TestCases\ILPretty\Issue1918.cs" />
<Compile Remove="TestCases\ILPretty\Issue2260SwitchString.cs" />
<None Include="TestCases\ILPretty\Issue2260SwitchString.cs" />
<Compile Remove="TestCases\ILPretty\Issue2443.cs" />
<None Include="TestCases\ILPretty\Issue2443.cs" />
<Compile Remove="TestCases\ILPretty\Issue3504.cs" />
<None Include="TestCases\ILPretty\Issue3504.cs" />
<Compile Remove="TestCases\ILPretty\Issue646.cs" />
<None Include="TestCases\ILPretty\Issue646.cs" />
<Compile Remove="TestCases\ILPretty\UnknownTypes.cs" />
<None Include="TestCases\ILPretty\UnknownTypes.cs" />
<Compile Remove="TestCases\ILPretty\Unsafe.cs" />
<None Include="TestCases\ILPretty\Unsafe.cs" />
<Compile Remove="TestCases\ILPretty\WeirdEnums.cs" />
<None Include="TestCases\ILPretty\WeirdEnums.cs" />
<Compile Remove="TestCases\Pretty\FieldKeyword.cs" />
<None Include="TestCases\Pretty\FieldKeyword.cs" />
<Compile Remove="TestCases\Pretty\IndexRangeTest.cs" />
<None Include="TestCases\Pretty\IndexRangeTest.cs" />
<Compile Remove="TestCases\Pretty\MetadataAttributes.cs" />
<None Include="TestCases\Pretty\MetadataAttributes.cs" />
<Compile Remove="TestCases\Pretty\NullableRefTypes.cs" />
<None Include="TestCases\Pretty\NullableRefTypes.cs" />
<Compile Remove="TestCases\Ugly\AggressiveScalarReplacementOfAggregates.Expected.cs" />
<None Include="TestCases\Ugly\AggressiveScalarReplacementOfAggregates.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoArrayInitializers.Expected.cs" />
<None Include="TestCases\Ugly\NoArrayInitializers.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoAutomaticProperties.Expected.cs" />
<None Include="TestCases\Ugly\NoAutomaticProperties.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoDecimalConstants.Expected.cs" />
<None Include="TestCases\Ugly\NoDecimalConstants.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoExtensionMethods.Expected.cs" />
<None Include="TestCases\Ugly\NoExtensionMethods.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoFieldKeyword.Expected.cs" />
<None Include="TestCases\Ugly\NoFieldKeyword.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoForEachStatement.Expected.cs" />
<None Include="TestCases\Ugly\NoForEachStatement.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoGetterOnlyAutomaticProperties.Expected.cs" />
<None Include="TestCases\Ugly\NoGetterOnlyAutomaticProperties.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoInitAccessors.Expected.cs" />
<None Include="TestCases\Ugly\NoInitAccessors.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoLocalFunctions.Expected.cs" />
<None Include="TestCases\Ugly\NoLocalFunctions.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoNewOfT.Expected.cs" />
<None Include="TestCases\Ugly\NoNewOfT.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoPropertiesAndEvents.Expected.cs" />
<None Include="TestCases\Ugly\NoPropertiesAndEvents.Expected.cs" />
<Compile Remove="TestCases\Ugly\NoUnsignedRightShift.Expected.cs" />
<None Include="TestCases\Ugly\NoUnsignedRightShift.Expected.cs" />
<!-- top-level statements: neither the input nor the expected output can be compiled
into the test assembly, which is a library and has its own entry point rules -->
<Compile Remove="TestCases\Ugly\TopLevelProgram.cs" />
<None Include="TestCases\Ugly\TopLevelProgram.cs" />
<Compile Remove="TestCases\Ugly\TopLevelProgram.Expected.cs" />
<None Include="TestCases\Ugly\TopLevelProgram.Expected.cs" />
<Compile Remove="TestCases\Ugly\TopLevelProgramAsync.cs" />
<None Include="TestCases\Ugly\TopLevelProgramAsync.cs" />
<Compile Remove="TestCases\Ugly\TopLevelProgramAsync.Expected.cs" />
<None Include="TestCases\Ugly\TopLevelProgramAsync.Expected.cs" />
<Compile Remove="TestCases\VBPretty\VBCompoundAssign.cs" />
<None Include="TestCases\VBPretty\VBCompoundAssign.cs" />
</ItemGroup>
</Project>
@@ -0,0 +1,203 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.Tests.Helpers;
using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests
{
[TestFixture, Parallelizable(ParallelScope.All)]
public class VBPrettyTestRunner
{
static readonly string TestCasePath = Tester.TestCasePath + "/VBPretty";
[Test]
public void AllFilesHaveTests()
{
var testNames = typeof(VBPrettyTestRunner).GetMethods()
.Where(m => m.GetCustomAttributes(typeof(TestAttribute), false).Any())
.Select(m => m.Name)
.ToArray();
foreach (var file in new DirectoryInfo(TestCasePath).EnumerateFiles())
{
if (file.Extension.Equals(".vb", StringComparison.OrdinalIgnoreCase))
{
var testName = file.Name.Split('.')[0];
Assert.That(testNames, Has.Member(testName));
Assert.That(File.Exists(Path.Combine(TestCasePath, testName + ".cs")));
}
}
}
static readonly CompilerOptions[] defaultOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize,
CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslynLatest | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn1_3_2,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2,
CompilerOptions.UseRoslyn2_10_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0,
CompilerOptions.UseRoslyn3_11_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0,
CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
});
static readonly CompilerOptions[] roslynOnlyOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslynLatest | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn1_3_2,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2,
CompilerOptions.UseRoslyn2_10_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0,
CompilerOptions.UseRoslyn3_11_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0,
CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
});
[Test]
public async Task Async([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
await Run(options: options | CompilerOptions.Library);
}
[Test] // TODO: legacy VB compound assign
public async Task VBCompoundAssign([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions options)
{
await Run(options: options | CompilerOptions.Library);
}
[Test]
public async Task ParameterizedProperties([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
await Run(options: options | CompilerOptions.Library);
}
[Test]
public async Task Select([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
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)
{
await Run(options: options | CompilerOptions.Library);
}
[Test]
public async Task Issue2192([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
IgnoreIfVbRuntimeSubstituted(options);
await Run(options: options | CompilerOptions.Library);
}
[Test]
public async Task VBPropertiesTest([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
await Run(options: options | CompilerOptions.Library);
}
[Test]
public async Task VBAutomaticEvents([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
await Run(options: options | CompilerOptions.Library);
}
[Test]
public async Task VBNonGenericForEach([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
IgnoreIfVbRuntimeSubstituted(options);
await Run(options: options | CompilerOptions.Library);
}
[Test]
public async Task YieldReturn([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
await Run(options: options | CompilerOptions.Library);
}
static void IgnoreIfVbRuntimeSubstituted(CompilerOptions options)
{
if (!OperatingSystem.IsWindows()
&& (options & CompilerOptions.UseRoslynMask) == CompilerOptions.UseRoslyn2_10_0
&& (options & CompilerOptions.TargetNet40) == 0)
{
Assert.Ignore("The non-Windows netcore-2.2 configuration substitutes the legacy " +
"Microsoft.VisualBasic as -vbruntime (see Tester.CompileVB); the resulting " +
"reference graph changes this test's decompiled output.");
}
}
async Task Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null)
{
var vbFile = Path.Combine(TestCasePath, testName + ".vb");
var csFile = Path.Combine(TestCasePath, testName + ".cs");
var exeFile = TestsAssemblyOutput.GetFilePath(TestCasePath, testName, Tester.GetSuffix(options) + ".exe");
if (options.HasFlag(CompilerOptions.Library))
{
exeFile = Path.ChangeExtension(exeFile, ".dll");
}
var executable = await Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile).ConfigureAwait(false);
settings ??= new DecompilerSettings { FileScopedNamespaces = false, SortCustomAttributes = true };
var decompiled = await Tester.DecompileCSharp(executable.PathToAssembly, settings).ConfigureAwait(false);
CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(options).ToArray());
Tester.RepeatOnIOError(() => File.Delete(decompiled));
}
}
}
@@ -0,0 +1,244 @@
// Copyright (c) 2017 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms
{
public class DetectCatchWhenConditionBlocks : IILTransform
{
public void Run(ILFunction function, ILTransformContext context)
{
foreach (var catchBlock in function.Descendants.OfType<TryCatchHandler>())
{
if (catchBlock.Filter is BlockContainer container
&& MatchCatchWhenEntryPoint(catchBlock.Variable, container, container.EntryPoint,
out var exceptionType, out var exceptionSlot, out var whenConditionBlock)
&& exceptionType.GetStackType() == catchBlock.Variable.StackType)
{
// set exceptionType
catchBlock.Variable.Type = exceptionType;
// Block entryPoint (incoming: 1) {
// stloc temp(isinst exceptionType(ldloc exceptionVar))
// if (comp(ldloc temp != ldnull)) br whenConditionBlock
// br falseBlock
// }
// =>
// Block entryPoint (incoming: 1) {
// stloc temp(ldloc exceptionSlot)
// br whenConditionBlock
// }
var instructions = container.EntryPoint.Instructions;
if (instructions.Count == 3)
{
// stloc temp(isinst exceptionType(ldloc exceptionVar))
// if (comp(ldloc temp != ldnull)) br whenConditionBlock
// br falseBlock
context.Step($"Detected catch-when for {catchBlock.Variable.Name} (extra store)", instructions[0]);
((StLoc)instructions[0]).Value = exceptionSlot;
instructions[1].ReplaceWith(new Branch(whenConditionBlock));
instructions.RemoveAt(2);
container.SortBlocks(deleteUnreachableBlocks: true);
}
else if (instructions.Count == 2)
{
// if (comp(isinst exceptionType(ldloc exceptionVar) != ldnull)) br whenConditionBlock
// br falseBlock
context.Step($"Detected catch-when for {catchBlock.Variable.Name}", instructions[0]);
var branch = new Branch(whenConditionBlock);
instructions[0].ReplaceWith(branch);
instructions.RemoveAt(1);
context.EndStep(branch);
container.SortBlocks(deleteUnreachableBlocks: true);
}
PropagateExceptionVariable(context, catchBlock);
}
}
}
/// <summary>
/// catch E_189 : 0200007C System.Exception when (BlockContainer {
/// Block IL_0079 (incoming: 1) {
/// stloc S_30(ldloc E_189)
/// br IL_0085
/// }
///
/// Block IL_0085 (incoming: 1) {
/// stloc I_1(ldloc S_30)
/// where S_30 and I_1 are single definition
/// =>
/// copy-propagate E_189 to replace all uses of S_30 and I_1
/// </summary>
static void PropagateExceptionVariable(ILTransformContext context, TryCatchHandler handler)
{
var exceptionVariable = handler.Variable;
if (!exceptionVariable.IsSingleDefinition)
return;
context.StepStartGroup(nameof(PropagateExceptionVariable));
int i = 0;
while (i < exceptionVariable.LoadInstructions.Count)
{
var load = exceptionVariable.LoadInstructions[i];
if (!load.IsDescendantOf(handler))
{
i++;
continue;
}
// We are only interested in store "statements" copying the exception variable
// without modifying it.
var statement = Block.GetContainingStatement(load);
if (!(statement is StLoc stloc))
{
i++;
continue;
}
// simple copy case:
// stloc b(ldloc a)
if (stloc.Value == load)
{
PropagateExceptionInstance(stloc);
}
// if the type of the cast-class instruction matches the exceptionType,
// this cast can be removed without losing any side-effects.
// Note: this would also hold true iff exceptionType were an exception derived
// from cc.Type, however, we are more restrictive to match the pattern exactly.
// stloc b(castclass exceptionType(ldloc a))
else if (stloc.Value is CastClass cc && cc.Type.Equals(exceptionVariable.Type) && cc.Argument == load)
{
stloc.Value = load;
PropagateExceptionInstance(stloc);
}
else
{
i++;
}
void PropagateExceptionInstance(StLoc store)
{
foreach (var load in store.Variable.LoadInstructions.ToArray())
{
if (!load.IsDescendantOf(handler))
continue;
load.ReplaceWith(new LdLoc(exceptionVariable).WithILRange(load));
}
if (store.Variable.LoadCount == 0 && store.Parent is Block block)
{
block.Instructions.RemoveAt(store.ChildIndex);
}
else
{
i++;
}
}
}
context.StepEndGroup(keepIfEmpty: false);
}
/// <summary>
/// Block entryPoint (incoming: 1) {
/// stloc temp(isinst exceptionType(ldloc exceptionVar))
/// if (comp(ldloc temp != ldnull)) br whenConditionBlock
/// br falseBlock
/// }
/// </summary>
bool MatchCatchWhenEntryPoint(ILVariable exceptionVar, BlockContainer container, Block entryPoint, out IType exceptionType, out ILInstruction exceptionSlot, out Block whenConditionBlock)
{
exceptionType = null;
exceptionSlot = null;
whenConditionBlock = null;
if (entryPoint == null || entryPoint.IncomingEdgeCount != 1)
return false;
if (entryPoint.Instructions.Count == 3)
{
// stloc temp(isinst exceptionType(ldloc exceptionVar))
// if (comp(ldloc temp != ldnull)) br whenConditionBlock
// br falseBlock
if (!entryPoint.Instructions[0].MatchStLoc(out var temp, out var isinst) ||
temp.Kind != VariableKind.StackSlot || !isinst.MatchIsInst(out exceptionSlot, out exceptionType))
return false;
if (!exceptionSlot.MatchLdLoc(exceptionVar))
return false;
if (!entryPoint.Instructions[1].MatchIfInstruction(out var condition, out var branch))
return false;
if (!condition.MatchCompNotEquals(out var left, out var right))
return false;
if (!entryPoint.Instructions[2].MatchBranch(out var falseBlock) || !MatchFalseBlock(container, falseBlock, out var returnVar, out var exitBlock))
return false;
if ((left.MatchLdNull() && right.MatchLdLoc(temp)) || (right.MatchLdNull() && left.MatchLdLoc(temp)))
{
return branch.MatchBranch(out whenConditionBlock);
}
}
else if (entryPoint.Instructions.Count == 2)
{
// if (comp(isinst exceptionType(ldloc exceptionVar) != ldnull)) br whenConditionBlock
// br falseBlock
if (!entryPoint.Instructions[0].MatchIfInstruction(out var condition, out var branch))
return false;
if (!condition.MatchCompNotEquals(out var left, out var right))
return false;
if (!entryPoint.Instructions[1].MatchBranch(out var falseBlock) || !MatchFalseBlock(container, falseBlock, out var returnVar, out var exitBlock))
return false;
if (!left.MatchIsInst(out exceptionSlot, out exceptionType))
return false;
if (!exceptionSlot.MatchLdLoc(exceptionVar))
return false;
if (right.MatchLdNull())
{
return branch.MatchBranch(out whenConditionBlock);
}
}
return false;
}
/// <summary>
/// Block falseBlock (incoming: 1) {
/// stloc returnVar(ldc.i4 0)
/// br exitBlock
/// }
/// </summary>
bool MatchFalseBlock(BlockContainer container, Block falseBlock, out ILVariable returnVar, out Block exitBlock)
{
returnVar = null;
exitBlock = null;
if (falseBlock.IncomingEdgeCount != 1 || falseBlock.Instructions.Count != 2)
return false;
return falseBlock.Instructions[0].MatchStLoc(out returnVar, out var zero) &&
zero.MatchLdcI4(0) && falseBlock.Instructions[1].MatchBranch(out exitBlock) &&
MatchExitBlock(container, exitBlock, returnVar);
}
/// <summary>
/// Block exitBlock(incoming: 2) {
/// leave container(ldloc returnVar)
/// }
/// </summary>
bool MatchExitBlock(BlockContainer container, Block exitBlock, ILVariable returnVar)
{
if (exitBlock.IncomingEdgeCount != 2 || exitBlock.Instructions.Count != 1)
return false;
return exitBlock.Instructions[0].MatchLeave(container, out var value) &&
value.MatchLdLoc(returnVar);
}
}
}