Browse Source

Merge remote-tracking branch 'origin/master' into unsafe

pull/924/head
Daniel Grunwald 9 years ago
parent
commit
ccc1a4418f
  1. 6
      BuildTools/appveyor-install.ps1
  2. 1
      BuildTools/update-assemblyinfo.ps1
  3. 30
      ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpPatternTests.cs
  4. 64
      ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs
  5. 64
      ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpUsing.fs.Release.cs
  6. 87
      ICSharpCode.Decompiler.Tests/FSharpPatterns/TestHelpers.cs
  7. 99
      ICSharpCode.Decompiler.Tests/FSharpPatterns/ToolLocator.cs
  8. 3
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  9. 11
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  10. 26
      ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
  11. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  12. 30
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops.fs
  13. 209
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs
  14. 586
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.il
  15. 210
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs
  16. 561
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.il
  17. 0
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing.fs
  18. 58
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Debug.cs
  19. 0
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Debug.il
  20. 58
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Release.cs
  21. 0
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Release.il
  22. 484
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs
  23. 1522
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il
  24. 1281
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il
  25. 1314
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il
  26. 1533
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il
  27. 15
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  28. 70
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il
  29. 57
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il
  30. 64
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il
  31. 74
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il
  32. 11
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs
  33. 60
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.il
  34. 43
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.il
  35. 37
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.roslyn.il
  36. 53
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.roslyn.il
  37. 26
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
  38. 80
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.il
  39. 72
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.il
  40. 45
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.roslyn.il
  41. 54
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.roslyn.il
  42. 14
      ICSharpCode.Decompiler/CSharp/Annotations.cs
  43. 173
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  44. 41
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  45. 32
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  46. 24
      ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs
  47. 49
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  48. 12
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertMissingTokensDecorator.cs
  49. 6
      ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterTokenWriter.cs
  50. 2
      ICSharpCode.Decompiler/CSharp/Resolver/LambdaResolveResult.cs
  51. 329
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  52. 1
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  53. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/PrimitiveExpression.cs
  54. 15
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  55. 4
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  56. 30
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  57. 4
      ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
  58. 45
      ICSharpCode.Decompiler/DecompilerSettings.cs
  59. 80
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  60. 19
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  61. 2
      ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs
  62. 352
      ICSharpCode.Decompiler/DotNetCore/UniversalAssemblyResolver.cs
  63. 22
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  64. 15
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec.template
  65. 17
      ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
  66. 20
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  67. 81
      ICSharpCode.Decompiler/IL/ILAstWritingOptions.cs
  68. 9
      ICSharpCode.Decompiler/IL/ILReader.cs
  69. 11
      ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
  70. 37
      ICSharpCode.Decompiler/IL/Instructions.cs
  71. 1
      ICSharpCode.Decompiler/IL/Instructions.tt
  72. 1
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  73. 1
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  74. 1
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  75. 1
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  76. 1
      ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
  77. 1
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  78. 1
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs
  79. 1
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  80. 1
      ICSharpCode.Decompiler/IL/Instructions/Conv.cs
  81. 33
      ICSharpCode.Decompiler/IL/Instructions/DefaultValue.cs
  82. 32
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  83. 35
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  84. 20
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  85. 1
      ICSharpCode.Decompiler/IL/Instructions/LdLen.cs
  86. 1
      ICSharpCode.Decompiler/IL/Instructions/Leave.cs
  87. 1
      ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
  88. 4
      ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs
  89. 1
      ICSharpCode.Decompiler/IL/Instructions/NullCoalescingInstruction.cs
  90. 15
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  91. 1
      ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs
  92. 2
      ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs
  93. 4
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  94. 1
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  95. 1
      ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs
  96. 41
      ICSharpCode.Decompiler/IL/SequencePoint.cs
  97. 32
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  98. 5
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
  99. 4
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  100. 1
      ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs
  101. Some files were not shown because too many files have changed in this diff Show More

6
BuildTools/appveyor-install.ps1

@ -32,5 +32,7 @@ if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { @@ -32,5 +32,7 @@ if ($env:APPVEYOR_PULL_REQUEST_NUMBER) {
$revision = [Int32]::Parse((git rev-list --count "$baseCommit..HEAD")) + $baseCommitRev;
$newVersion="$major.$minor.$build.$revision";
$env:appveyor_build_version="$newVersion$branch$versionName$suffix";
appveyor UpdateBuild -Version "$newVersion$branch$versionName$suffix";
$env:APPVEYOR_BUILD_VERSION="$newVersion$branch$versionName$suffix";
$env:ILSPY_VERSION_NUMBER="$newVersion$branch$versionName$suffix";
appveyor UpdateBuild -Version "$newVersion$branch$versionName$suffix";
Write-Host "new version: $newVersion$branch$versionName$suffix";

1
BuildTools/update-assemblyinfo.ps1

@ -42,6 +42,7 @@ function gitBranch() { @@ -42,6 +42,7 @@ function gitBranch() {
$templateFiles = (
@{Input=$globalAssemblyInfoTemplateFile; Output="ILSpy/Properties/AssemblyInfo.cs"},
@{Input="ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs"; Output="ICSharpCode.Decompiler/Properties/AssemblyInfo.cs"},
@{Input="ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec.template"; Output="ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec"},
@{Input="ILSpy/Properties/app.config.template"; Output = "ILSpy/app.config"}
);
[string]$mutexId = "ILSpyUpdateAssemblyInfo" + $PSScriptRoot.GetHashCode();

30
ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpPatternTests.cs

@ -1,30 +0,0 @@ @@ -1,30 +0,0 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.FSharpPatterns
{
[TestFixture]
public class FSharpPatternTests
{
[Test]
public void FSharpUsingDecompilesToCSharpUsing_Debug()
{
var ilCode = TestHelpers.FuzzyReadResource("FSharpUsing.fs.Debug.il");
var csharpCode = TestHelpers.FuzzyReadResource("FSharpUsing.fs.Debug.cs");
TestHelpers.RunIL(ilCode, csharpCode);
}
[Test]
public void FSharpUsingDecompilesToCSharpUsing_Release()
{
var ilCode = TestHelpers.FuzzyReadResource("FSharpUsing.fs.Release.il");
var csharpCode = TestHelpers.FuzzyReadResource("FSharpUsing.fs.Release.cs");
TestHelpers.RunIL(ilCode, csharpCode);
}
}
}

64
ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs

@ -1,64 +0,0 @@ @@ -1,64 +0,0 @@
using System;
using System.IO;
public static class FSharpUsingPatterns
{
public static void sample1()
{
using (FileStream fs = File.Create("x.txt"))
{
fs.WriteByte((byte)1);
}
}
public static void sample2()
{
Console.WriteLine("some text");
using (FileStream fs = File.Create("x.txt"))
{
fs.WriteByte((byte)2);
Console.WriteLine("some text");
}
}
public static void sample3()
{
Console.WriteLine("some text");
using (FileStream fs = File.Create("x.txt"))
{
fs.WriteByte((byte)3);
}
Console.WriteLine("some text");
}
public static void sample4()
{
Console.WriteLine("some text");
int num;
using (FileStream fs = File.OpenRead("x.txt"))
{
num = fs.ReadByte();
}
int firstByte = num;
Console.WriteLine("read:" + firstByte.ToString());
}
public static void sample5()
{
Console.WriteLine("some text");
int num;
using (FileStream fs = File.OpenRead("x.txt"))
{
num = fs.ReadByte();
}
int firstByte = num;
int num3;
using (FileStream fs = File.OpenRead("x.txt"))
{
int num2 = fs.ReadByte();
num3 = fs.ReadByte();
}
int secondByte = num3;
Console.WriteLine("read: {0}, {1}", firstByte, secondByte);
}
}

64
ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpUsing.fs.Release.cs

@ -1,64 +0,0 @@ @@ -1,64 +0,0 @@
using System;
using System.IO;
public static class FSharpUsingPatterns
{
public static void sample1()
{
using (FileStream fs = File.Create("x.txt"))
{
fs.WriteByte(1);
}
}
public static void sample2()
{
Console.WriteLine("some text");
using (FileStream fs = File.Create("x.txt"))
{
fs.WriteByte(2);
Console.WriteLine("some text");
}
}
public static void sample3()
{
Console.WriteLine("some text");
using (FileStream fs = File.Create("x.txt"))
{
fs.WriteByte(3);
}
Console.WriteLine("some text");
}
public static void sample4()
{
Console.WriteLine("some text");
int num;
using (FileStream fs = File.OpenRead("x.txt"))
{
num = fs.ReadByte();
}
int firstByte = num;
Console.WriteLine("read:" + firstByte.ToString());
}
public static void sample5()
{
Console.WriteLine("some text");
int secondByte;
using (FileStream fs = File.OpenRead("x.txt"))
{
secondByte = fs.ReadByte();
}
int firstByte = secondByte;
int num2;
using (FileStream fs = File.OpenRead("x.txt"))
{
int num = fs.ReadByte();
num2 = fs.ReadByte();
}
secondByte = num2;
Console.WriteLine("read: {0}, {1}", firstByte, secondByte);
}
}

87
ICSharpCode.Decompiler.Tests/FSharpPatterns/TestHelpers.cs

@ -1,87 +0,0 @@ @@ -1,87 +0,0 @@
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Tests.Helpers;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.FSharpPatterns
{
public class TestHelpers
{
public static string FuzzyReadResource(string resourceName)
{
var asm = Assembly.GetExecutingAssembly();
var allResources = asm.GetManifestResourceNames();
var fullResourceName = allResources.Single(r => r.EndsWith(resourceName, StringComparison.OrdinalIgnoreCase));
return new StreamReader(asm.GetManifestResourceStream(fullResourceName)).ReadToEnd();
}
static Lazy<string> ilasm = new Lazy<string>(() => ToolLocator.FindTool("ilasm.exe"));
static Lazy<string> ildasm = new Lazy<string>(() => ToolLocator.FindTool("ildasm.exe"));
public static string CompileIL(string source)
{
if (ilasm.Value == null)
Assert.NotNull(ilasm.Value, "Could not find ILASM.exe");
var tmp = Path.GetTempFileName();
File.Delete(tmp);
var sourceFile = Path.ChangeExtension(tmp, ".il");
File.WriteAllText(sourceFile, source);
var asmFile = Path.ChangeExtension(sourceFile, ".dll");
var args = string.Format("{0} /dll /debug /output:{1}", sourceFile, asmFile);
using (var proc = Process.Start(new ProcessStartInfo(ilasm.Value, args) { UseShellExecute = false, }))
{
proc.WaitForExit();
Assert.AreEqual(0, proc.ExitCode);
}
File.Delete(sourceFile);
Assert.True(File.Exists(asmFile), "Assembly File does not exist");
return asmFile;
}
public static void RunIL(string ilCode, string expectedCSharpCode)
{
var asmFilePath = CompileIL(ilCode);
CompareAssemblyAgainstCSharp(expectedCSharpCode, asmFilePath);
}
private static void CompareAssemblyAgainstCSharp(string expectedCSharpCode, string asmFilePath)
{
var module = ModuleDefinition.ReadModule(asmFilePath);
try
{
try { module.ReadSymbols(); } catch { }
AstBuilder decompiler = new AstBuilder(new DecompilerContext(module));
decompiler.AddAssembly(module);
new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree);
StringWriter output = new StringWriter();
// the F# assembly contains a namespace `<StartupCode$tmp6D55>` where the part after tmp is randomly generated.
// remove this from the ast to simplify the diff
var startupCodeNode = decompiler.SyntaxTree.Children.OfType<NamespaceDeclaration>().SingleOrDefault(d => d.Name.StartsWith("<StartupCode$", StringComparison.Ordinal));
if (startupCodeNode != null)
startupCodeNode.Remove();
decompiler.GenerateCode(new PlainTextOutput(output));
var fullCSharpCode = output.ToString();
CodeAssert.AreEqual(expectedCSharpCode, output.ToString());
}
finally
{
File.Delete(asmFilePath);
File.Delete(Path.ChangeExtension(asmFilePath, ".pdb"));
}
}
}
}

99
ICSharpCode.Decompiler.Tests/FSharpPatterns/ToolLocator.cs

@ -1,99 +0,0 @@ @@ -1,99 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.FSharpPatterns
{
public class ToolLocator
{
public static string FindTool(string fileName)
{
var allPaths = FindPathForDotNetFramework().Concat(FindPathForWindowsSdk());
return allPaths.Select(dir => Path.Combine(dir, fileName)).FirstOrDefault(File.Exists);
}
private static IEnumerable<string> FindPathForWindowsSdk()
{
string[] windowsSdkPaths = new[]
{
@"Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\",
@"Microsoft SDKs\Windows\v8.0A\bin\",
@"Microsoft SDKs\Windows\v8.0\bin\NETFX 4.0 Tools\",
@"Microsoft SDKs\Windows\v8.0\bin\",
@"Microsoft SDKs\Windows\v7.1A\bin\NETFX 4.0 Tools\",
@"Microsoft SDKs\Windows\v7.1A\bin\",
@"Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\",
@"Microsoft SDKs\Windows\v7.0A\bin\",
@"Microsoft SDKs\Windows\v6.1A\bin\",
@"Microsoft SDKs\Windows\v6.0A\bin\",
@"Microsoft SDKs\Windows\v6.0\bin\",
@"Microsoft.NET\FrameworkSDK\bin"
};
foreach (var possiblePath in windowsSdkPaths)
{
string fullPath = string.Empty;
// Check alternate program file paths as well as 64-bit versions.
if (Environment.Is64BitProcess)
{
fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), possiblePath, "x64");
if (Directory.Exists(fullPath))
{
yield return fullPath;
}
fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), possiblePath, "x64");
if (Directory.Exists(fullPath))
{
yield return fullPath;
}
}
fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), possiblePath);
if (Directory.Exists(fullPath))
{
yield return fullPath;
}
fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), possiblePath);
if (Directory.Exists(fullPath))
{
yield return fullPath;
}
}
}
private static IEnumerable<string> FindPathForDotNetFramework()
{
string[] frameworkPaths = new[]
{
@"Microsoft.NET\Framework\v4.0.30319",
@"Microsoft.NET\Framework\v2.0.50727"
};
foreach (var possiblePath in frameworkPaths)
{
string fullPath = string.Empty;
if (Environment.Is64BitProcess)
{
fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), possiblePath.Replace(@"\Framework\", @"\Framework64\"));
if (Directory.Exists(fullPath))
{
yield return fullPath;
}
}
fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), possiblePath);
if (Directory.Exists(fullPath))
{
yield return fullPath;
}
}
}
}
}

3
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -111,7 +111,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -111,7 +111,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
using (var writer = new StreamWriter(outputFile)) {
module.Name = Path.GetFileNameWithoutExtension(outputFile);
var output = new PlainTextOutput(writer);
ReflectionDisassembler rd = new ReflectionDisassembler(output, false, CancellationToken.None);
ReflectionDisassembler rd = new ReflectionDisassembler(output, CancellationToken.None);
rd.DetectControlStructure = false;
rd.WriteAssemblyReferences(module);
if (module.Assembly != null)
rd.WriteAssemblyHeader(module.Assembly);

11
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -45,6 +45,12 @@ @@ -45,6 +45,12 @@
<ItemGroup>
<None Include="TestCases\Correctness\Jmp.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\FSharpUsing_Release.il" />
<None Include="TestCases\Correctness\BitNot.il" />
<None Include="TestCases\Correctness\Readme.txt" />
</ItemGroup>
@ -52,7 +58,11 @@ @@ -52,7 +58,11 @@
<ItemGroup>
<Compile Include="DataFlowTest.cs" />
<Compile Include="TestCases\Correctness\LINQRaytracer.cs" />
<None Include="TestCases\ILPretty\FSharpLoops_Debug.cs" />
<None Include="TestCases\ILPretty\FSharpLoops_Release.cs" />
<Compile Include="TestCases\Pretty\DelegateConstruction.cs" />
<None Include="TestCases\ILPretty\FSharpUsing_Debug.cs" />
<None Include="TestCases\ILPretty\FSharpUsing_Release.cs" />
<Compile Include="Helpers\CodeAssert.cs" />
<Compile Include="Helpers\SdkUtility.cs" />
<Compile Include="Helpers\RemoveCompilerAttribute.cs" />
@ -67,6 +77,7 @@ @@ -67,6 +77,7 @@
<Compile Include="TestCases\ILPretty\Issue379.cs" />
<Compile Include="TestCases\Pretty\FixProxyCalls.cs" />
<Compile Include="TestCases\Pretty\UnsafeCode.cs" />
<Compile Include="TestCases\Pretty\InitializerTests.cs" />
<None Include="TestCases\ILPretty\Issue646.cs" />
<Compile Include="TestCases\Pretty\Async.cs" />
<Compile Include="TestCases\Pretty\CheckedUnchecked.cs" />

26
ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

@ -41,7 +41,31 @@ namespace ICSharpCode.Decompiler.Tests @@ -41,7 +41,31 @@ namespace ICSharpCode.Decompiler.Tests
{
Run();
}
[Test]
public void FSharpUsing_Debug()
{
Run();
}
[Test]
public void FSharpUsing_Release()
{
Run();
}
[Test, Ignore]
public void FSharpLoops_Debug()
{
Run();
}
[Test, Ignore]
public void FSharpLoops_Release()
{
Run();
}
void Run([CallerMemberName] string testName = null)
{
var ilFile = Path.Combine(TestCasePath, testName + ".il");

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -194,6 +194,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -194,6 +194,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions, asmOptions: AssemblerOptions.UseOwnDisassembler);
}
[Test]
public void InitializerTests([ValueSource("defaultOptions")] CompilerOptions cscOptions)
{
Run(cscOptions: cscOptions);
}
[Test]
public void FixProxyCalls([Values(CompilerOptions.None, CompilerOptions.Optimize, CompilerOptions.UseRoslyn)] CompilerOptions cscOptions)
{

30
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops.fs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
open System
let disposable() = { new IDisposable with member x.Dispose() = () }
let getSeq() = seq { yield 1; }
let getList() = [ 1 ]
let getArray() = [| 1 |]
[<EntryPoint>]
let main argv =
// nested using scopes?
use disp1 =
use disp2 = disposable()
Console.WriteLine "Hello 1"
disposable()
// for loop over seq
for i in getSeq() do
Console.WriteLine i
// for loop over list
for i in getList() do
Console.WriteLine i
// for loop over array
for i in getArray() do
Console.WriteLine i
0 // return an integer exit code

209
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs

@ -0,0 +1,209 @@ @@ -0,0 +1,209 @@
// C:\Users\Siegfried\Documents\Visual Studio 2017\Projects\ConsoleApp13\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
// ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// Global type: <Module>
// Entry point: Program.main
// Architecture: AnyCPU (32-bit preferred)
// Runtime: .NET 4.0
using Microsoft.FSharp.Collections;
using Microsoft.FSharp.Core;
using Microsoft.FSharp.Core.CompilerServices;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
[assembly: FSharpInterfaceDataVersion(2, 0, 0)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("e0674ff5-5e8f-4d4e-a88f-e447192454c7")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations)]
[assembly: AssemblyVersion("1.0.0.0")]
[CompilationMapping(SourceConstructFlags.Module)]
public static class Program
{
[Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[CompilationMapping(SourceConstructFlags.Closure)]
internal sealed class disposable@3 : IDisposable
{
public disposable@3()
{
((object)this)..ctor();
}
private void System-IDisposable-Dispose()
{
}
void IDisposable.Dispose()
{
//ILSpy generated this explicit interface implementation from .override directive in System-IDisposable-Dispose
this.System-IDisposable-Dispose();
}
}
[Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[CompilationMapping(SourceConstructFlags.Closure)]
internal sealed class getSeq@5 : GeneratedSequenceBase<int>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public int pc = pc;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public int current = current;
public getSeq@5(int pc, int current)
{
}
public override int GenerateNext(ref IEnumerable<int> next)
{
switch (this.pc)
{
default:
this.pc = 1;
this.current = 1;
return 1;
case 1:
this.pc = 2;
break;
case 2:
break;
}
this.current = 0;
return 0;
}
public override void Close()
{
this.pc = 2;
}
public override bool get_CheckClose()
{
switch (this.pc)
{
default:
return false;
case 0:
case 2:
return false;
}
}
[CompilerGenerated]
[DebuggerNonUserCode]
public override int get_LastGenerated()
{
return this.current;
}
[CompilerGenerated]
[DebuggerNonUserCode]
public override IEnumerator<int> GetFreshEnumerator()
{
return new getSeq@5(0, 0);
}
}
public static IDisposable disposable()
{
return new disposable@3();
}
public static IEnumerable<int> getSeq()
{
return new getSeq@5(0, 0);
}
public static FSharpList<int> getList()
{
return FSharpList<int>.Cons(1, FSharpList<int>.Empty);
}
public static int[] getArray()
{
return new int[1]
{
1
};
}
[EntryPoint]
public static int main(string[] argv)
{
IDisposable disposable = default(IDisposable);
using (Program.disposable())
{
Console.WriteLine("Hello 1");
disposable = Program.disposable();
}
using (disposable)
{
IEnumerable<int> seq = Program.getSeq();
using (IEnumerator<int> enumerator = seq.GetEnumerator())
{
while (true)
{
if (!enumerator.MoveNext())
break;
int k = enumerator.Current;
Console.WriteLine(k);
}
}
FSharpList<int> fSharpList = Program.getList();
FSharpList<int> tailOrNull = fSharpList.TailOrNull;
while (true)
{
if (tailOrNull == null)
break;
int j = fSharpList.HeadOrDefault;
Console.WriteLine(j);
fSharpList = tailOrNull;
tailOrNull = fSharpList.TailOrNull;
}
int[] array = Program.getArray();
for (int l = 0; l < array.Length; l++)
{
int i = array[l];
Console.WriteLine(i);
}
return 0;
}
}
}
namespace <StartupCode$ConsoleApplication1>
{
internal static class $Program
{
}
internal static class $AssemblyInfo
{
}
}
namespace <StartupCode$ConsoleApplication1>.$.NETFramework,Version=v4.6.1
{
internal static class AssemblyAttributes
{
}
}

586
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.il

@ -0,0 +1,586 @@ @@ -0,0 +1,586 @@
// C:\Users\Siegfried\Documents\Visual Studio 2017\Projects\ConsoleApp13\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
.assembly extern mscorlib
{
.publickeytoken = (
b7 7a 5c 56 19 34 e0 89
)
.ver 4:0:0:0
}
.assembly extern FSharp.Core
{
.publickeytoken = (
b0 3f 5f 7f 11 d5 0a 3a
)
.ver 4:4:1:0
}
.assembly ConsoleApplication1
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, int32, int32) = (
01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = (
01 00 1c 2e 4e 45 54 46 72 61 6d 65 77 6f 72 6b
2c 56 65 72 73 69 6f 6e 3d 76 34 2e 36 2e 31 01
00 54 0e 14 46 72 61 6d 65 77 6f 72 6b 44 69 73
70 6c 61 79 4e 61 6d 65 14 2e 4e 45 54 20 46 72
61 6d 65 77 6f 72 6b 20 34 2e 36 2e 31
)
.custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = (
01 00 13 43 6f 6e 73 6f 6c 65 41 70 70 6c 69 63
61 74 69 6f 6e 31 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = (
01 00 13 43 6f 6e 73 6f 6c 65 41 70 70 6c 69 63
61 74 69 6f 6e 31 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = (
01 00 12 43 6f 70 79 72 69 67 68 74 20 c2 a9 20
20 32 30 31 37 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyCultureAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = (
01 00 24 65 30 36 37 34 66 66 35 2d 35 65 38 66
2d 34 64 34 65 2d 61 38 38 66 2d 65 34 34 37 31
39 32 34 35 34 63 37 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyVersionAttribute::.ctor(string) = (
01 00 07 31 2e 30 2e 30 2e 30 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = (
01 00 07 31 2e 30 2e 30 2e 30 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
01 00 01 01 00 00 00 00
)
.hash algorithm 0x00008004 // SHA1
.ver 1:0:0:0
}
.module ConsoleApplication1.exe
// MVID: {59F64D20-6A1F-D4CE-A745-0383204DF659}
.corflags 0x00020003 // ILOnly, Required32Bit, Preferred32Bit
.class private auto ansi '<Module>'
extends [mscorlib]System.Object
{
} // end of class <Module>
.class public auto ansi abstract sealed Program
extends [mscorlib]System.Object
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = (
01 00 07 00 00 00 00 00
)
// Nested Types
.class nested assembly auto auto sealed specialname serializable beforefieldinit disposable@3
extends [mscorlib]System.Object
implements [mscorlib]System.IDisposable
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = (
01 00 06 00 00 00 00 00
)
// Methods
.method public specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x21c8
// Code size 9 (0x9)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: pop
IL_0008: ret
} // end of method disposable@3::.ctor
.method private final hidebysig newslot virtual
instance void 'System-IDisposable-Dispose' () cil managed
{
.override method instance void [mscorlib]System.IDisposable::Dispose()
// Method begins at RVA 0x21d4
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method disposable@3::'System-IDisposable-Dispose'
} // end of class disposable@3
.class nested assembly auto auto sealed specialname serializable beforefieldinit getSeq@5
extends class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int32>
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = (
01 00 06 00 00 00 00 00
)
// Fields
.field public int32 pc
.custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = (
01 00 00 00 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = (
01 00 00 00
)
.field public int32 current
.custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = (
01 00 00 00 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = (
01 00 00 00
)
// Methods
.method public specialname rtspecialname
instance void .ctor (
int32 pc,
int32 current
) cil managed
{
// Method begins at RVA 0x21d8
// Code size 21 (0x15)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 Program/getSeq@5::pc
IL_0007: ldarg.0
IL_0008: ldarg.2
IL_0009: stfld int32 Program/getSeq@5::current
IL_000e: ldarg.0
IL_000f: call instance void class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int32>::.ctor()
IL_0014: ret
} // end of method getSeq@5::.ctor
.method public strict virtual
instance int32 GenerateNext (
class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>& next
) cil managed
{
// Method begins at RVA 0x21f0
// Code size 66 (0x42)
.maxstack 6
IL_0000: ldarg.0
IL_0001: ldfld int32 Program/getSeq@5::pc
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: switch (IL_0017, IL_0019)
IL_0015: br.s IL_0021
IL_0017: br.s IL_001b
IL_0019: br.s IL_001e
IL_001b: nop
IL_001c: br.s IL_0032
IL_001e: nop
IL_001f: br.s IL_0039
IL_0021: nop
IL_0022: ldarg.0
IL_0023: ldc.i4.1
IL_0024: stfld int32 Program/getSeq@5::pc
IL_0029: ldarg.0
IL_002a: ldc.i4.1
IL_002b: stfld int32 Program/getSeq@5::current
IL_0030: ldc.i4.1
IL_0031: ret
IL_0032: ldarg.0
IL_0033: ldc.i4.2
IL_0034: stfld int32 Program/getSeq@5::pc
IL_0039: ldarg.0
IL_003a: ldc.i4.0
IL_003b: stfld int32 Program/getSeq@5::current
IL_0040: ldc.i4.0
IL_0041: ret
} // end of method getSeq@5::GenerateNext
.method public strict virtual
instance void Close () cil managed
{
// Method begins at RVA 0x2240
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.2
IL_0002: stfld int32 Program/getSeq@5::pc
IL_0007: ret
} // end of method getSeq@5::Close
.method public strict virtual
instance bool get_CheckClose () cil managed
{
// Method begins at RVA 0x224c
// Code size 45 (0x2d)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 Program/getSeq@5::pc
IL_0006: switch (IL_0019, IL_001b, IL_001d)
IL_0017: br.s IL_0028
IL_0019: br.s IL_001f
IL_001b: br.s IL_0022
IL_001d: br.s IL_0025
IL_001f: nop
IL_0020: br.s IL_002b
IL_0022: nop
IL_0023: br.s IL_0029
IL_0025: nop
IL_0026: br.s IL_002b
IL_0028: nop
IL_0029: ldc.i4.0
IL_002a: ret
IL_002b: ldc.i4.0
IL_002c: ret
} // end of method getSeq@5::get_CheckClose
.method public strict virtual
instance int32 get_LastGenerated () cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x227c
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 Program/getSeq@5::current
IL_0006: ret
} // end of method getSeq@5::get_LastGenerated
.method public strict virtual
instance class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> GetFreshEnumerator () cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2284
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: ldc.i4.0
IL_0002: newobj instance void Program/getSeq@5::.ctor(int32, int32)
IL_0007: ret
} // end of method getSeq@5::GetFreshEnumerator
} // end of class getSeq@5
// Methods
.method public static
class [mscorlib]System.IDisposable disposable () cil managed
{
// Method begins at RVA 0x2050
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj instance void Program/disposable@3::.ctor()
IL_0005: ret
} // end of method Program::disposable
.method public static
class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> getSeq () cil managed
{
// Method begins at RVA 0x2058
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: ldc.i4.0
IL_0002: newobj instance void Program/getSeq@5::.ctor(int32, int32)
IL_0007: ret
} // end of method Program::getSeq
.method public static
class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32> getList () cil managed
{
// Method begins at RVA 0x2064
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_Empty()
IL_0006: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0>)
IL_000b: ret
} // end of method Program::getList
.method public static
int32[] getArray () cil managed
{
// Method begins at RVA 0x2074
// Code size 15 (0xf)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: newarr [mscorlib]System.Int32
IL_0006: dup
IL_0007: ldc.i4.0
IL_0008: ldc.i4.1
IL_0009: stelem.any [mscorlib]System.Int32
IL_000e: ret
} // end of method Program::getArray
.method public static
int32 main (
string[] argv
) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2084
// Code size 270 (0x10e)
.maxstack 4
.entrypoint
.locals init (
[0] class [mscorlib]System.IDisposable,
[1] class [mscorlib]System.IDisposable,
[2] class [mscorlib]System.IDisposable,
[3] class [mscorlib]System.IDisposable,
[4] int32,
[5] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>,
[6] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>,
[7] class [FSharp.Core]Microsoft.FSharp.Core.Unit,
[8] int32,
[9] class [mscorlib]System.IDisposable,
[10] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>,
[11] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>,
[12] int32,
[13] int32[],
[14] int32,
[15] int32,
[16] class [mscorlib]System.IDisposable
)
IL_0000: call class [mscorlib]System.IDisposable Program::disposable()
IL_0005: stloc.1
.try
{
IL_0006: ldstr "Hello 1"
IL_000b: call void [mscorlib]System.Console::WriteLine(string)
IL_0010: call class [mscorlib]System.IDisposable Program::disposable()
IL_0015: stloc.2
IL_0016: leave.s IL_0032
} // end .try
finally
{
IL_0018: ldloc.1
IL_0019: isinst [mscorlib]System.IDisposable
IL_001e: stloc.3
IL_001f: ldloc.3
IL_0020: brfalse.s IL_0024
IL_0022: br.s IL_0026
IL_0024: br.s IL_002f
IL_0026: ldloc.3
IL_0027: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_002c: ldnull
IL_002d: pop
IL_002e: endfinally
IL_002f: ldnull
IL_0030: pop
IL_0031: endfinally
} // end handler
IL_0032: ldloc.2
IL_0033: stloc.0
.try
{
IL_0034: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> Program::getSeq()
IL_0039: stloc.s 5
IL_003b: ldloc.s 5
IL_003d: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
IL_0042: stloc.s 6
.try
{
// loop start (head: IL_0044)
IL_0044: ldloc.s 6
IL_0046: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_004b: brfalse.s IL_0060
IL_004d: ldloc.s 6
IL_004f: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
IL_0054: stloc.s 8
IL_0056: ldloc.s 8
IL_0058: call void [mscorlib]System.Console::WriteLine(int32)
IL_005d: nop
IL_005e: br.s IL_0044
// end loop
IL_0060: ldnull
IL_0061: stloc.s 7
IL_0063: leave.s IL_0083
} // end .try
finally
{
IL_0065: ldloc.s 6
IL_0067: isinst [mscorlib]System.IDisposable
IL_006c: stloc.s 9
IL_006e: ldloc.s 9
IL_0070: brfalse.s IL_0074
IL_0072: br.s IL_0076
IL_0074: br.s IL_0080
IL_0076: ldloc.s 9
IL_0078: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_007d: ldnull
IL_007e: pop
IL_007f: endfinally
IL_0080: ldnull
IL_0081: pop
IL_0082: endfinally
} // end handler
IL_0083: ldloc.s 7
IL_0085: pop
IL_0086: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32> Program::getList()
IL_008b: stloc.s 10
IL_008d: ldloc.s 10
IL_008f: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_TailOrNull()
IL_0094: stloc.s 11
// loop start (head: IL_0096)
IL_0096: ldloc.s 11
IL_0098: ldnull
IL_0099: cgt.un
IL_009b: brfalse.s IL_00bd
IL_009d: ldloc.s 10
IL_009f: call instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_HeadOrDefault()
IL_00a4: stloc.s 12
IL_00a6: ldloc.s 12
IL_00a8: call void [mscorlib]System.Console::WriteLine(int32)
IL_00ad: ldloc.s 11
IL_00af: stloc.s 10
IL_00b1: ldloc.s 10
IL_00b3: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_TailOrNull()
IL_00b8: stloc.s 11
IL_00ba: nop
IL_00bb: br.s IL_0096
// end loop
IL_00bd: call int32[] Program::getArray()
IL_00c2: stloc.s 13
IL_00c4: ldc.i4.0
IL_00c5: stloc.s 14
IL_00c7: br.s IL_00e1
// loop start (head: IL_00e1)
IL_00c9: ldloc.s 13
IL_00cb: ldloc.s 14
IL_00cd: ldelem.any [mscorlib]System.Int32
IL_00d2: stloc.s 15
IL_00d4: ldloc.s 15
IL_00d6: call void [mscorlib]System.Console::WriteLine(int32)
IL_00db: ldloc.s 14
IL_00dd: ldc.i4.1
IL_00de: add
IL_00df: stloc.s 14
IL_00e1: ldloc.s 14
IL_00e3: ldloc.s 13
IL_00e5: ldlen
IL_00e6: conv.i4
IL_00e7: blt.s IL_00c9
// end loop
IL_00e9: ldc.i4.0
IL_00ea: stloc.s 4
IL_00ec: leave.s IL_010b
} // end .try
finally
{
IL_00ee: ldloc.0
IL_00ef: isinst [mscorlib]System.IDisposable
IL_00f4: stloc.s 16
IL_00f6: ldloc.s 16
IL_00f8: brfalse.s IL_00fc
IL_00fa: br.s IL_00fe
IL_00fc: br.s IL_0108
IL_00fe: ldloc.s 16
IL_0100: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0105: ldnull
IL_0106: pop
IL_0107: endfinally
IL_0108: ldnull
IL_0109: pop
IL_010a: endfinally
} // end handler
IL_010b: ldloc.s 4
IL_010d: ret
} // end of method Program::main
} // end of class Program
.class private auto ansi abstract sealed '<StartupCode$ConsoleApplication1>.$Program'
extends [mscorlib]System.Object
{
} // end of class <StartupCode$ConsoleApplication1>.$Program
.class private auto ansi abstract sealed '<StartupCode$ConsoleApplication1>.$AssemblyInfo'
extends [mscorlib]System.Object
{
} // end of class <StartupCode$ConsoleApplication1>.$AssemblyInfo
.class private auto ansi abstract sealed '<StartupCode$ConsoleApplication1>.$.NETFramework,Version=v4.6.1.AssemblyAttributes'
extends [mscorlib]System.Object
{
} // end of class <StartupCode$ConsoleApplication1>.$.NETFramework,Version=v4.6.1.AssemblyAttributes

210
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs

@ -0,0 +1,210 @@ @@ -0,0 +1,210 @@
// C:\Users\Siegfried\Documents\Visual Studio 2017\Projects\ConsoleApp13\ConsoleApplication1\bin\Release\ConsoleApplication1.exe
// ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// Global type: <Module>
// Entry point: Program.main
// Architecture: AnyCPU (32-bit preferred)
// Runtime: .NET 4.0
using Microsoft.FSharp.Collections;
using Microsoft.FSharp.Core;
using Microsoft.FSharp.Core.CompilerServices;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
[assembly: FSharpInterfaceDataVersion(2, 0, 0)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("e0674ff5-5e8f-4d4e-a88f-e447192454c7")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.None)]
[assembly: AssemblyVersion("1.0.0.0")]
[CompilationMapping(SourceConstructFlags.Module)]
public static class Program
{
[Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[CompilationMapping(SourceConstructFlags.Closure)]
internal sealed class disposable@3 : IDisposable
{
public disposable@3()
{
((object)this)..ctor();
}
private void System-IDisposable-Dispose()
{
}
void IDisposable.Dispose()
{
//ILSpy generated this explicit interface implementation from .override directive in System-IDisposable-Dispose
this.System-IDisposable-Dispose();
}
}
[Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[CompilationMapping(SourceConstructFlags.Closure)]
internal sealed class getSeq@5 : GeneratedSequenceBase<int>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public int pc = pc;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public int current = current;
public getSeq@5(int pc, int current)
{
}
public override int GenerateNext(ref IEnumerable<int> next)
{
switch (this.pc)
{
default:
this.pc = 1;
this.current = 1;
return 1;
case 1:
this.pc = 2;
break;
case 2:
break;
}
this.current = 0;
return 0;
}
public override void Close()
{
this.pc = 2;
}
public override bool get_CheckClose()
{
switch (this.pc)
{
default:
return false;
case 0:
case 2:
return false;
}
}
[CompilerGenerated]
[DebuggerNonUserCode]
public override int get_LastGenerated()
{
return this.current;
}
[CompilerGenerated]
[DebuggerNonUserCode]
public override IEnumerator<int> GetFreshEnumerator()
{
return new getSeq@5(0, 0);
}
}
public static IDisposable disposable()
{
return new disposable@3();
}
public static IEnumerable<int> getSeq()
{
return new getSeq@5(0, 0);
}
public static FSharpList<int> getList()
{
return FSharpList<int>.Cons(1, FSharpList<int>.Empty);
}
public static int[] getArray()
{
return new int[1]
{
1
};
}
[EntryPoint]
public static int main(string[] argv)
{
IDisposable disposable = default(IDisposable);
using (Program.disposable())
{
Console.WriteLine("Hello 1");
disposable = Program.disposable();
}
using (disposable)
{
IEnumerable<int> seq = Program.getSeq();
using (IEnumerator<int> enumerator = seq.GetEnumerator())
{
while (true)
{
if (!enumerator.MoveNext())
break;
Console.WriteLine(enumerator.Current);
}
}
FSharpList<int> fSharpList = FSharpList<int>.Cons(1, FSharpList<int>.Empty);
FSharpList<int> tailOrNull = fSharpList.TailOrNull;
while (true)
{
if (tailOrNull == null)
break;
int j = fSharpList.HeadOrDefault;
Console.WriteLine(j);
fSharpList = tailOrNull;
tailOrNull = fSharpList.TailOrNull;
}
int[] array = new int[1]
{
1
};
for (int j = 0; j < array.Length; j++)
{
Console.WriteLine(array[j]);
}
return 0;
}
}
}
namespace <StartupCode$ConsoleApplication1>
{
internal static class $Program
{
}
internal static class $AssemblyInfo
{
}
}
namespace <StartupCode$ConsoleApplication1>.$.NETFramework,Version=v4.6.1
{
internal static class AssemblyAttributes
{
}
}

561
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.il

@ -0,0 +1,561 @@ @@ -0,0 +1,561 @@
// C:\Users\Siegfried\Documents\Visual Studio 2017\Projects\ConsoleApp13\ConsoleApplication1\bin\Release\ConsoleApplication1.exe
.assembly extern mscorlib
{
.publickeytoken = (
b7 7a 5c 56 19 34 e0 89
)
.ver 4:0:0:0
}
.assembly extern FSharp.Core
{
.publickeytoken = (
b0 3f 5f 7f 11 d5 0a 3a
)
.ver 4:4:1:0
}
.assembly ConsoleApplication1
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32, int32, int32) = (
01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = (
01 00 1c 2e 4e 45 54 46 72 61 6d 65 77 6f 72 6b
2c 56 65 72 73 69 6f 6e 3d 76 34 2e 36 2e 31 01
00 54 0e 14 46 72 61 6d 65 77 6f 72 6b 44 69 73
70 6c 61 79 4e 61 6d 65 14 2e 4e 45 54 20 46 72
61 6d 65 77 6f 72 6b 20 34 2e 36 2e 31
)
.custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = (
01 00 13 43 6f 6e 73 6f 6c 65 41 70 70 6c 69 63
61 74 69 6f 6e 31 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = (
01 00 13 43 6f 6e 73 6f 6c 65 41 70 70 6c 69 63
61 74 69 6f 6e 31 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = (
01 00 12 43 6f 70 79 72 69 67 68 74 20 c2 a9 20
20 32 30 31 37 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyCultureAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = (
01 00 24 65 30 36 37 34 66 66 35 2d 35 65 38 66
2d 34 64 34 65 2d 61 38 38 66 2d 65 34 34 37 31
39 32 34 35 34 63 37 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyVersionAttribute::.ctor(string) = (
01 00 07 31 2e 30 2e 30 2e 30 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = (
01 00 07 31 2e 30 2e 30 2e 30 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
01 00 00 00 00 00 00 00
)
.hash algorithm 0x00008004 // SHA1
.ver 1:0:0:0
}
.module ConsoleApplication1.exe
// MVID: {59F64D28-6A1F-D4CE-A745-0383284DF659}
.corflags 0x00020003 // ILOnly, Required32Bit, Preferred32Bit
.class private auto ansi '<Module>'
extends [mscorlib]System.Object
{
} // end of class <Module>
.class public auto ansi abstract sealed Program
extends [mscorlib]System.Object
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = (
01 00 07 00 00 00 00 00
)
// Nested Types
.class nested assembly auto auto sealed specialname serializable beforefieldinit disposable@3
extends [mscorlib]System.Object
implements [mscorlib]System.IDisposable
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = (
01 00 06 00 00 00 00 00
)
// Methods
.method public specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x21bc
// Code size 9 (0x9)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: pop
IL_0008: ret
} // end of method disposable@3::.ctor
.method private final hidebysig newslot virtual
instance void 'System-IDisposable-Dispose' () cil managed
{
.override method instance void [mscorlib]System.IDisposable::Dispose()
// Method begins at RVA 0x21c8
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method disposable@3::'System-IDisposable-Dispose'
} // end of class disposable@3
.class nested assembly auto auto sealed specialname serializable beforefieldinit getSeq@5
extends class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int32>
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = (
01 00 06 00 00 00 00 00
)
// Fields
.field public int32 pc
.custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = (
01 00 00 00 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = (
01 00 00 00
)
.field public int32 current
.custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = (
01 00 00 00 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = (
01 00 00 00
)
// Methods
.method public specialname rtspecialname
instance void .ctor (
int32 pc,
int32 current
) cil managed
{
// Method begins at RVA 0x21cc
// Code size 21 (0x15)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 Program/getSeq@5::pc
IL_0007: ldarg.0
IL_0008: ldarg.2
IL_0009: stfld int32 Program/getSeq@5::current
IL_000e: ldarg.0
IL_000f: call instance void class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int32>::.ctor()
IL_0014: ret
} // end of method getSeq@5::.ctor
.method public strict virtual
instance int32 GenerateNext (
class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>& next
) cil managed
{
// Method begins at RVA 0x21e4
// Code size 62 (0x3e)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 Program/getSeq@5::pc
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: switch (IL_0018, IL_001b)
IL_0015: nop
IL_0016: br.s IL_001e
IL_0018: nop
IL_0019: br.s IL_002e
IL_001b: nop
IL_001c: br.s IL_0035
IL_001e: ldarg.0
IL_001f: ldc.i4.1
IL_0020: stfld int32 Program/getSeq@5::pc
IL_0025: ldarg.0
IL_0026: ldc.i4.1
IL_0027: stfld int32 Program/getSeq@5::current
IL_002c: ldc.i4.1
IL_002d: ret
IL_002e: ldarg.0
IL_002f: ldc.i4.2
IL_0030: stfld int32 Program/getSeq@5::pc
IL_0035: ldarg.0
IL_0036: ldc.i4.0
IL_0037: stfld int32 Program/getSeq@5::current
IL_003c: ldc.i4.0
IL_003d: ret
} // end of method getSeq@5::GenerateNext
.method public strict virtual
instance void Close () cil managed
{
// Method begins at RVA 0x2224
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.2
IL_0002: stfld int32 Program/getSeq@5::pc
IL_0007: ret
} // end of method getSeq@5::Close
.method public strict virtual
instance bool get_CheckClose () cil managed
{
// Method begins at RVA 0x2230
// Code size 39 (0x27)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 Program/getSeq@5::pc
IL_0006: switch (IL_001a, IL_001d, IL_0020)
IL_0017: nop
IL_0018: br.s IL_0023
IL_001a: nop
IL_001b: br.s IL_0025
IL_001d: nop
IL_001e: br.s IL_0023
IL_0020: nop
IL_0021: br.s IL_0025
IL_0023: ldc.i4.0
IL_0024: ret
IL_0025: ldc.i4.0
IL_0026: ret
} // end of method getSeq@5::get_CheckClose
.method public strict virtual
instance int32 get_LastGenerated () cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2258
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 Program/getSeq@5::current
IL_0006: ret
} // end of method getSeq@5::get_LastGenerated
.method public strict virtual
instance class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> GetFreshEnumerator () cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2260
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: ldc.i4.0
IL_0002: newobj instance void Program/getSeq@5::.ctor(int32, int32)
IL_0007: ret
} // end of method getSeq@5::GetFreshEnumerator
} // end of class getSeq@5
// Methods
.method public static
class [mscorlib]System.IDisposable disposable () cil managed
{
// Method begins at RVA 0x2050
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj instance void Program/disposable@3::.ctor()
IL_0005: ret
} // end of method Program::disposable
.method public static
class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> getSeq () cil managed
{
// Method begins at RVA 0x2058
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: ldc.i4.0
IL_0002: newobj instance void Program/getSeq@5::.ctor(int32, int32)
IL_0007: ret
} // end of method Program::getSeq
.method public static
class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32> getList () cil managed
{
// Method begins at RVA 0x2064
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_Empty()
IL_0006: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0>)
IL_000b: ret
} // end of method Program::getList
.method public static
int32[] getArray () cil managed
{
// Method begins at RVA 0x2074
// Code size 15 (0xf)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: newarr [mscorlib]System.Int32
IL_0006: dup
IL_0007: ldc.i4.0
IL_0008: ldc.i4.1
IL_0009: stelem.any [mscorlib]System.Int32
IL_000e: ret
} // end of method Program::getArray
.method public static
int32 main (
string[] argv
) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2084
// Code size 259 (0x103)
.maxstack 6
.entrypoint
.locals init (
[0] class [mscorlib]System.IDisposable,
[1] class [mscorlib]System.IDisposable,
[2] class [mscorlib]System.IDisposable,
[3] class [mscorlib]System.IDisposable,
[4] int32,
[5] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>,
[6] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>,
[7] class [FSharp.Core]Microsoft.FSharp.Core.Unit,
[8] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>,
[9] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>,
[10] int32,
[11] int32[]
)
IL_0000: call class [mscorlib]System.IDisposable Program::disposable()
IL_0005: stloc.1
.try
{
IL_0006: ldstr "Hello 1"
IL_000b: call void [mscorlib]System.Console::WriteLine(string)
IL_0010: call class [mscorlib]System.IDisposable Program::disposable()
IL_0015: stloc.2
IL_0016: leave.s IL_002e
} // end .try
finally
{
IL_0018: ldloc.1
IL_0019: isinst [mscorlib]System.IDisposable
IL_001e: stloc.3
IL_001f: ldloc.3
IL_0020: brfalse.s IL_002b
IL_0022: ldloc.3
IL_0023: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0028: ldnull
IL_0029: pop
IL_002a: endfinally
IL_002b: ldnull
IL_002c: pop
IL_002d: endfinally
} // end handler
IL_002e: ldloc.2
IL_002f: stloc.0
.try
{
IL_0030: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> Program::getSeq()
IL_0035: stloc.s 5
IL_0037: ldloc.s 5
IL_0039: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
IL_003e: stloc.s 6
.try
{
// loop start (head: IL_0040)
IL_0040: ldloc.s 6
IL_0042: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0047: brfalse.s IL_0058
IL_0049: ldloc.s 6
IL_004b: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
IL_0050: call void [mscorlib]System.Console::WriteLine(int32)
IL_0055: nop
IL_0056: br.s IL_0040
// end loop
IL_0058: ldnull
IL_0059: stloc.s 7
IL_005b: leave.s IL_0074
} // end .try
finally
{
IL_005d: ldloc.s 6
IL_005f: isinst [mscorlib]System.IDisposable
IL_0064: stloc.1
IL_0065: ldloc.1
IL_0066: brfalse.s IL_0071
IL_0068: ldloc.1
IL_0069: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_006e: ldnull
IL_006f: pop
IL_0070: endfinally
IL_0071: ldnull
IL_0072: pop
IL_0073: endfinally
} // end handler
IL_0074: ldloc.s 7
IL_0076: pop
IL_0077: ldc.i4.1
IL_0078: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_Empty()
IL_007d: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0>)
IL_0082: stloc.s 8
IL_0084: ldloc.s 8
IL_0086: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_TailOrNull()
IL_008b: stloc.s 9
// loop start (head: IL_008d)
IL_008d: ldloc.s 9
IL_008f: ldnull
IL_0090: cgt.un
IL_0092: brfalse.s IL_00b4
IL_0094: ldloc.s 8
IL_0096: call instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_HeadOrDefault()
IL_009b: stloc.s 10
IL_009d: ldloc.s 10
IL_009f: call void [mscorlib]System.Console::WriteLine(int32)
IL_00a4: ldloc.s 9
IL_00a6: stloc.s 8
IL_00a8: ldloc.s 8
IL_00aa: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<int32>::get_TailOrNull()
IL_00af: stloc.s 9
IL_00b1: nop
IL_00b2: br.s IL_008d
// end loop
IL_00b4: ldc.i4.1
IL_00b5: newarr [mscorlib]System.Int32
IL_00ba: dup
IL_00bb: ldc.i4.0
IL_00bc: ldc.i4.1
IL_00bd: stelem.any [mscorlib]System.Int32
IL_00c2: stloc.s 11
IL_00c4: ldc.i4.0
IL_00c5: stloc.s 10
IL_00c7: br.s IL_00dd
// loop start (head: IL_00dd)
IL_00c9: ldloc.s 11
IL_00cb: ldloc.s 10
IL_00cd: ldelem.any [mscorlib]System.Int32
IL_00d2: call void [mscorlib]System.Console::WriteLine(int32)
IL_00d7: ldloc.s 10
IL_00d9: ldc.i4.1
IL_00da: add
IL_00db: stloc.s 10
IL_00dd: ldloc.s 10
IL_00df: ldloc.s 11
IL_00e1: ldlen
IL_00e2: conv.i4
IL_00e3: blt.s IL_00c9
// end loop
IL_00e5: ldc.i4.0
IL_00e6: stloc.s 4
IL_00e8: leave.s IL_0100
} // end .try
finally
{
IL_00ea: ldloc.0
IL_00eb: isinst [mscorlib]System.IDisposable
IL_00f0: stloc.1
IL_00f1: ldloc.1
IL_00f2: brfalse.s IL_00fd
IL_00f4: ldloc.1
IL_00f5: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_00fa: ldnull
IL_00fb: pop
IL_00fc: endfinally
IL_00fd: ldnull
IL_00fe: pop
IL_00ff: endfinally
} // end handler
IL_0100: ldloc.s 4
IL_0102: ret
} // end of method Program::main
} // end of class Program
.class private auto ansi abstract sealed '<StartupCode$ConsoleApplication1>.$Program'
extends [mscorlib]System.Object
{
} // end of class <StartupCode$ConsoleApplication1>.$Program
.class private auto ansi abstract sealed '<StartupCode$ConsoleApplication1>.$AssemblyInfo'
extends [mscorlib]System.Object
{
} // end of class <StartupCode$ConsoleApplication1>.$AssemblyInfo
.class private auto ansi abstract sealed '<StartupCode$ConsoleApplication1>.$.NETFramework,Version=v4.6.1.AssemblyAttributes'
extends [mscorlib]System.Object
{
} // end of class <StartupCode$ConsoleApplication1>.$.NETFramework,Version=v4.6.1.AssemblyAttributes

0
ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpUsing.fs → ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing.fs

58
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Debug.cs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
using System;
using System.IO;
public static class FSharpUsingPatterns
{
public static void sample1()
{
using (FileStream fileStream = File.Create("x.txt")) {
fileStream.WriteByte((byte)1);
}
}
public static void sample2()
{
Console.WriteLine("some text");
using (FileStream fileStream = File.Create("x.txt")) {
fileStream.WriteByte((byte)2);
Console.WriteLine("some text");
}
}
public static void sample3()
{
Console.WriteLine("some text");
using (FileStream fileStream = File.Create("x.txt")) {
fileStream.WriteByte((byte)3);
}
Console.WriteLine("some text");
}
public static void sample4()
{
Console.WriteLine("some text");
int num = default(int);
using (FileStream fileStream = File.OpenRead("x.txt")) {
num = fileStream.ReadByte();
}
int num2 = num;
Console.WriteLine("read:" + num2.ToString());
}
public static void sample5()
{
Console.WriteLine("some text");
int num = default(int);
using (FileStream fileStream = File.OpenRead("x.txt")) {
num = fileStream.ReadByte();
}
int num2 = num;
int num3 = default(int);
using (FileStream fileStream = File.OpenRead("x.txt")) {
fileStream.ReadByte();
num3 = fileStream.ReadByte();
}
int num4 = num3;
Console.WriteLine("read: {0}, {1}", num2, num4);
}
}

0
ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpUsing.fs.Debug.il → ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Debug.il

58
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Release.cs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
using System;
using System.IO;
public static class FSharpUsingPatterns
{
public static void sample1()
{
using (FileStream fileStream = File.Create("x.txt")) {
fileStream.WriteByte(1);
}
}
public static void sample2()
{
Console.WriteLine("some text");
using (FileStream fileStream = File.Create("x.txt")) {
fileStream.WriteByte(2);
Console.WriteLine("some text");
}
}
public static void sample3()
{
Console.WriteLine("some text");
using (FileStream fileStream = File.Create("x.txt")) {
fileStream.WriteByte(3);
}
Console.WriteLine("some text");
}
public static void sample4()
{
Console.WriteLine("some text");
int num = default(int);
using (FileStream fileStream = File.OpenRead("x.txt")) {
num = fileStream.ReadByte();
}
int num2 = num;
Console.WriteLine("read:" + num2.ToString());
}
public static void sample5()
{
Console.WriteLine("some text");
int num = default(int);
using (FileStream fileStream = File.OpenRead("x.txt")) {
num = fileStream.ReadByte();
}
int num2 = num;
int num3 = default(int);
using (FileStream fileStream = File.OpenRead("x.txt")) {
fileStream.ReadByte();
num3 = fileStream.ReadByte();
}
num = num3;
Console.WriteLine("read: {0}, {1}", num2, num);
}
}

0
ICSharpCode.Decompiler.Tests/FSharpPatterns/FSharpUsing.fs.Release.il → ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpUsing_Release.il

484
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs

@ -0,0 +1,484 @@ @@ -0,0 +1,484 @@
// 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.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class InitializerTests
{
#region Types and helpers
public class C
{
public int Z;
public S Y;
public List<S> L;
}
public struct S
{
public int A;
public int B;
public S(int a)
{
this.A = a;
this.B = 0;
}
}
private enum MyEnum
{
a = 0,
b = 1
}
private enum MyEnum2
{
c = 0,
d = 1
}
private class Data
{
public List<MyEnum2> FieldList = new List<MyEnum2>();
public MyEnum a {
get;
set;
}
public MyEnum b {
get;
set;
}
public List<MyEnum2> PropertyList {
get;
set;
}
public Data MoreData {
get;
set;
}
public StructData NestedStruct {
get;
set;
}
public Data this[int i] {
get {
return null;
}
set {
}
}
public Data this[int i, string j] {
get {
return null;
}
set {
}
}
public event EventHandler TestEvent;
}
private struct StructData
{
public int Field;
public int Property {
get;
set;
}
public Data MoreData {
get;
set;
}
public StructData(int initialValue)
{
this = default(StructData);
this.Field = initialValue;
this.Property = initialValue;
}
}
// Helper methods used to ensure initializers used within expressions work correctly
private static void X(object a, object b)
{
}
private static object Y()
{
return null;
}
public static void TestCall(int a, Thread thread)
{
}
public static C TestCall(int a, C c)
{
return c;
}
#endregion
public C Test1()
{
C c = new C();
c.L = new List<S>();
c.L.Add(new S(1));
return c;
}
public C Test1Alternative()
{
return InitializerTests.TestCall(1, new C {
L = new List<S> {
new S(1)
}
});
}
public C Test2()
{
C c = new C();
c.Z = 1;
c.Z = 2;
return c;
}
public C Test3()
{
C c = new C();
c.Y = new S(1);
c.Y.A = 2;
return c;
}
public C Test3b()
{
return InitializerTests.TestCall(0, new C {
Z = 1,
Y = {
A = 2
}
});
}
public C Test4()
{
C c = new C();
c.Y.A = 1;
c.Z = 2;
c.Y.B = 3;
return c;
}
public static void CollectionInitializerList()
{
InitializerTests.X(InitializerTests.Y(), new List<int> {
1,
2,
3
});
}
public static object RecursiveCollectionInitializer()
{
List<object> list = new List<object>();
list.Add(list);
return list;
}
public static void CollectionInitializerDictionary()
{
InitializerTests.X(InitializerTests.Y(), new Dictionary<string, int> {
{
"First",
1
},
{
"Second",
2
},
{
"Third",
3
}
});
}
public static void CollectionInitializerDictionaryWithEnumTypes()
{
InitializerTests.X(InitializerTests.Y(), new Dictionary<MyEnum, MyEnum2> {
{
MyEnum.a,
MyEnum2.c
},
{
MyEnum.b,
MyEnum2.d
}
});
}
public static void NotACollectionInitializer()
{
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
InitializerTests.X(InitializerTests.Y(), list);
}
public static void ObjectInitializer()
{
InitializerTests.X(InitializerTests.Y(), new Data {
a = MyEnum.a
});
}
public static void NotAnObjectInitializer()
{
Data data = new Data();
data.a = MyEnum.a;
InitializerTests.X(InitializerTests.Y(), data);
}
public static void NotAnObjectInitializerWithEvent()
{
Data data = new Data();
data.TestEvent += delegate(object sender, EventArgs e) {
Console.WriteLine();
};
InitializerTests.X(InitializerTests.Y(), data);
}
public static void ObjectInitializerAssignCollectionToField()
{
InitializerTests.X(InitializerTests.Y(), new Data {
a = MyEnum.a,
FieldList = new List<MyEnum2> {
MyEnum2.c,
MyEnum2.d
}
});
}
public static void ObjectInitializerAddToCollectionInField()
{
InitializerTests.X(InitializerTests.Y(), new Data {
a = MyEnum.a,
FieldList = {
MyEnum2.c,
MyEnum2.d
}
});
}
public static void ObjectInitializerAssignCollectionToProperty()
{
InitializerTests.X(InitializerTests.Y(), new Data {
a = MyEnum.a,
PropertyList = new List<MyEnum2> {
MyEnum2.c,
MyEnum2.d
}
});
}
public static void ObjectInitializerAddToCollectionInProperty()
{
InitializerTests.X(InitializerTests.Y(), new Data {
a = MyEnum.a,
PropertyList = {
MyEnum2.c,
MyEnum2.d
}
});
}
public static void ObjectInitializerWithInitializationOfNestedObjects()
{
InitializerTests.X(InitializerTests.Y(), new Data {
MoreData = {
a = MyEnum.a,
MoreData = {
a = MyEnum.b
}
}
});
}
private static int GetInt()
{
return 1;
}
private static string GetString()
{
return "Test";
}
#if !LEGACY_CSC
public static void SimpleDictInitializer()
{
InitializerTests.X(InitializerTests.Y(), new Data {
MoreData = {
a = MyEnum.a,
[2] = null
}
});
}
public static void MixedObjectAndDictInitializer()
{
InitializerTests.X(InitializerTests.Y(), new Data {
MoreData = {
a = MyEnum.a,
[InitializerTests.GetInt()] = {
a = MyEnum.b,
FieldList = {
MyEnum2.c
},
[InitializerTests.GetInt(), InitializerTests.GetString()] = new Data(),
[2] = null
}
}
});
}
#endif
public static void ObjectInitializerWithInitializationOfDeeplyNestedObjects()
{
InitializerTests.X(InitializerTests.Y(), new Data {
a = MyEnum.b,
MoreData = {
a = MyEnum.a,
MoreData = {
MoreData = {
MoreData = {
MoreData = {
MoreData = {
MoreData = {
a = MyEnum.b
}
}
}
}
}
}
}
});
}
public static void CollectionInitializerInsideObjectInitializers()
{
InitializerTests.X(InitializerTests.Y(), new Data {
MoreData = new Data {
a = MyEnum.a,
b = MyEnum.b,
PropertyList = {
MyEnum2.c
}
}
});
}
public static void NotAStructInitializer_DefaultConstructor()
{
StructData structData = default(StructData);
structData.Field = 1;
structData.Property = 2;
InitializerTests.X(InitializerTests.Y(), structData);
}
public static void StructInitializer_DefaultConstructor()
{
InitializerTests.X(InitializerTests.Y(), new StructData {
Field = 1,
Property = 2
});
}
public static void NotAStructInitializer_ExplicitConstructor()
{
StructData structData = new StructData(0);
structData.Field = 1;
structData.Property = 2;
InitializerTests.X(InitializerTests.Y(), structData);
}
public static void StructInitializer_ExplicitConstructor()
{
InitializerTests.X(InitializerTests.Y(), new StructData(0) {
Field = 1,
Property = 2
});
}
public static void StructInitializerWithInitializationOfNestedObjects()
{
InitializerTests.X(InitializerTests.Y(), new StructData {
MoreData = {
a = MyEnum.a,
FieldList = {
MyEnum2.c,
MyEnum2.d
}
}
});
}
public static void StructInitializerWithinObjectInitializer()
{
InitializerTests.X(InitializerTests.Y(), new Data {
NestedStruct = new StructData(2) {
Field = 1,
Property = 2
}
});
}
public static void Bug270_NestedInitialisers()
{
NumberFormatInfo[] source = null;
InitializerTests.TestCall(0, new Thread(InitializerTests.Bug270_NestedInitialisers) {
Priority = ThreadPriority.BelowNormal,
CurrentCulture = new CultureInfo(0) {
DateTimeFormat = new DateTimeFormatInfo {
ShortDatePattern = "ddmmyy"
},
NumberFormat = (from format in source
where format.CurrencySymbol == "$"
select format).First()
}
});
}
}
}

1522
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il

File diff suppressed because it is too large Load Diff

1281
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il

File diff suppressed because it is too large Load Diff

1314
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il

File diff suppressed because it is too large Load Diff

1533
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il

File diff suppressed because it is too large Load Diff

15
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs

@ -252,6 +252,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -252,6 +252,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
private IEnumerable<string> alternatives;
private static void Operation(ref int item)
{
}
@ -260,10 +262,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -260,10 +262,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
}
public void ForEach(IEnumerable<string> enumerable)
public void ForEachOnField()
{
foreach (string item in enumerable) {
item.ToLower();
foreach (string alternative in this.alternatives) {
alternative.ToLower();
}
}
public void ForEach(IEnumerable<string> alternatives)
{
foreach (string alternative in alternatives) {
alternative.ToLower();
}
}

70
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
// Copyright (c) Microsoft Corporation. All rights reserved.
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. Alle Rechte vorbehalten.
@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly y5enlto2
.assembly ic2bztjj
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module y5enlto2.dll
// MVID: {7F6CCF81-BE23-4326-8F55-7E3BF0A8B7A2}
.module ic2bztjj.dll
// MVID: {821665CB-F67F-4600-8C6C-27617D873D36}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x009B0000
// Image base: 0x01550000
// =============== CLASS MEMBERS DECLARATION ===================
@ -618,6 +618,7 @@ @@ -618,6 +618,7 @@
} // end of class '<>c__DisplayClass1'
.field private class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives
.method private hidebysig static void Operation(int32& item) cil managed
{
// Code size 2 (0x2)
@ -635,7 +636,60 @@ @@ -635,7 +636,60 @@
} // end of method Loops::Operation
.method public hidebysig instance void
ForEach(class [mscorlib]System.Collections.Generic.IEnumerable`1<string> enumerable) cil managed
ForEachOnField() cil managed
{
// Code size 62 (0x3e)
.maxstack 2
.locals init (string V_0,
class [mscorlib]System.Collections.Generic.IEnumerator`1<string> V_1,
bool V_2)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.0
IL_0003: ldfld class [mscorlib]System.Collections.Generic.IEnumerable`1<string> ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::alternatives
IL_0008: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator()
IL_000d: stloc.1
.try
{
IL_000e: br.s IL_0020
IL_0010: ldloc.1
IL_0011: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
IL_0016: stloc.0
IL_0017: nop
IL_0018: ldloc.0
IL_0019: callvirt instance string [mscorlib]System.String::ToLower()
IL_001e: pop
IL_001f: nop
IL_0020: ldloc.1
IL_0021: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0026: stloc.2
IL_0027: ldloc.2
IL_0028: brtrue.s IL_0010
IL_002a: leave.s IL_003c
} // end .try
finally
{
IL_002c: ldloc.1
IL_002d: ldnull
IL_002e: ceq
IL_0030: stloc.2
IL_0031: ldloc.2
IL_0032: brtrue.s IL_003b
IL_0034: ldloc.1
IL_0035: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003a: nop
IL_003b: endfinally
} // end handler
IL_003c: nop
IL_003d: ret
} // end of method Loops::ForEachOnField
.method public hidebysig instance void
ForEach(class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives) cil managed
{
// Code size 57 (0x39)
.maxstack 2
@ -1750,4 +1804,4 @@ @@ -1750,4 +1804,4 @@
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file ../../../TestCases/Pretty\Loops.res
// Warnung: Win32-Ressourcendatei "../../../TestCases/Pretty\Loops.res" wurde erstellt.

57
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
// Copyright (c) Microsoft Corporation. All rights reserved.
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. Alle Rechte vorbehalten.
@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly jiaqp12i
.assembly fabjeeha
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module jiaqp12i.dll
// MVID: {34208704-52B8-49EB-BC77-C3A95E1CBA19}
.module fabjeeha.dll
// MVID: {4FB3AE1F-ECE0-4E7D-84DC-E693282CA0AF}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02520000
// Image base: 0x00D90000
// =============== CLASS MEMBERS DECLARATION ===================
@ -535,6 +535,7 @@ @@ -535,6 +535,7 @@
} // end of class '<>c__DisplayClass1'
.field private class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives
.method private hidebysig static void Operation(int32& item) cil managed
{
// Code size 1 (0x1)
@ -550,7 +551,47 @@ @@ -550,7 +551,47 @@
} // end of method Loops::Operation
.method public hidebysig instance void
ForEach(class [mscorlib]System.Collections.Generic.IEnumerable`1<string> enumerable) cil managed
ForEachOnField() cil managed
{
// Code size 49 (0x31)
.maxstack 1
.locals init (string V_0,
class [mscorlib]System.Collections.Generic.IEnumerator`1<string> V_1)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.IEnumerable`1<string> ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::alternatives
IL_0006: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator()
IL_000b: stloc.1
.try
{
IL_000c: br.s IL_001c
IL_000e: ldloc.1
IL_000f: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: callvirt instance string [mscorlib]System.String::ToLower()
IL_001b: pop
IL_001c: ldloc.1
IL_001d: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0022: brtrue.s IL_000e
IL_0024: leave.s IL_0030
} // end .try
finally
{
IL_0026: ldloc.1
IL_0027: brfalse.s IL_002f
IL_0029: ldloc.1
IL_002a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_002f: endfinally
} // end handler
IL_0030: ret
} // end of method Loops::ForEachOnField
.method public hidebysig instance void
ForEach(class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives) cil managed
{
// Code size 44 (0x2c)
.maxstack 1
@ -1361,4 +1402,4 @@ @@ -1361,4 +1402,4 @@
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file ../../../TestCases/Pretty\Loops.opt.res
// Warnung: Win32-Ressourcendatei "../../../TestCases/Pretty\Loops.opt.res" wurde erstellt.

64
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
// Copyright (c) Microsoft Corporation. All rights reserved.
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. Alle Rechte vorbehalten.
@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module Loops.dll
// MVID: {8D392B4A-5D21-407A-B579-FCDFA93069CE}
// MVID: {F03B196B-9B00-49BE-A335-2D460586E39A}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00DA0000
// Image base: 0x02D60000
// =============== CLASS MEMBERS DECLARATION ===================
@ -510,7 +510,7 @@ @@ -510,7 +510,7 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // end of class CustomStructEnumeratorWithIDisposable`1
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass23_0'
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass25_0'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
@ -523,7 +523,7 @@ @@ -523,7 +523,7 @@
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method '<>c__DisplayClass23_0'::.ctor
} // end of method '<>c__DisplayClass25_0'::.ctor
.method assembly hidebysig instance bool
'<ForeachWithCapturedVariable>b__0'() cil managed
@ -531,14 +531,15 @@ @@ -531,14 +531,15 @@
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0'::c
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c
IL_0006: ldc.i4.5
IL_0007: ceq
IL_0009: ret
} // end of method '<>c__DisplayClass23_0'::'<ForeachWithCapturedVariable>b__0'
} // end of method '<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0'
} // end of class '<>c__DisplayClass23_0'
} // end of class '<>c__DisplayClass25_0'
.field private class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives
.method private hidebysig static void Operation(int32& item) cil managed
{
// Code size 1 (0x1)
@ -554,7 +555,44 @@ @@ -554,7 +555,44 @@
} // end of method Loops::Operation
.method public hidebysig instance void
ForEach(class [mscorlib]System.Collections.Generic.IEnumerable`1<string> enumerable) cil managed
ForEachOnField() cil managed
{
// Code size 47 (0x2f)
.maxstack 1
.locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<string> V_0)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.IEnumerable`1<string> ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::alternatives
IL_0006: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator()
IL_000b: stloc.0
.try
{
IL_000c: br.s IL_001a
IL_000e: ldloc.0
IL_000f: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
IL_0014: callvirt instance string [mscorlib]System.String::ToLower()
IL_0019: pop
IL_001a: ldloc.0
IL_001b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0020: brtrue.s IL_000e
IL_0022: leave.s IL_002e
} // end .try
finally
{
IL_0024: ldloc.0
IL_0025: brfalse.s IL_002d
IL_0027: ldloc.0
IL_0028: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_002d: endfinally
} // end handler
IL_002e: ret
} // end of method Loops::ForEachOnField
.method public hidebysig instance void
ForEach(class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives) cil managed
{
// Code size 42 (0x2a)
.maxstack 1
@ -1063,11 +1101,11 @@ @@ -1063,11 +1101,11 @@
IL_0009: ldloca.s V_0
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0010: stloc.1
IL_0011: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0'::.ctor()
IL_0011: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::.ctor()
IL_0016: dup
IL_0017: ldloc.1
IL_0018: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0'::c
IL_001d: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0'::'<ForeachWithCapturedVariable>b__0'()
IL_0018: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c
IL_001d: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0'()
IL_0023: newobj instance void class [mscorlib]System.Func`1<bool>::.ctor(object,
native int)
IL_0028: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Operation(class [mscorlib]System.Func`1<bool>)

74
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
// Copyright (c) Microsoft Corporation. All rights reserved.
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. Alle Rechte vorbehalten.
@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module Loops.dll
// MVID: {C6DBFA5B-CB31-4084-8E6F-7BA877923008}
// MVID: {F66BA703-8DC0-4A56-81BC-D288A1D83D30}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00A80000
// Image base: 0x02D60000
// =============== CLASS MEMBERS DECLARATION ===================
@ -592,7 +592,7 @@ @@ -592,7 +592,7 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // end of class CustomStructEnumeratorWithIDisposable`1
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass23_0'
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass25_0'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
@ -606,7 +606,7 @@ @@ -606,7 +606,7 @@
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method '<>c__DisplayClass23_0'::.ctor
} // end of method '<>c__DisplayClass25_0'::.ctor
.method assembly hidebysig instance bool
'<ForeachWithCapturedVariable>b__0'() cil managed
@ -614,14 +614,15 @@ @@ -614,14 +614,15 @@
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0'::c
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c
IL_0006: ldc.i4.5
IL_0007: ceq
IL_0009: ret
} // end of method '<>c__DisplayClass23_0'::'<ForeachWithCapturedVariable>b__0'
} // end of method '<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0'
} // end of class '<>c__DisplayClass23_0'
} // end of class '<>c__DisplayClass25_0'
.field private class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives
.method private hidebysig static void Operation(int32& item) cil managed
{
// Code size 2 (0x2)
@ -639,7 +640,52 @@ @@ -639,7 +640,52 @@
} // end of method Loops::Operation
.method public hidebysig instance void
ForEach(class [mscorlib]System.Collections.Generic.IEnumerable`1<string> enumerable) cil managed
ForEachOnField() cil managed
{
// Code size 54 (0x36)
.maxstack 1
.locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<string> V_0,
string V_1)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.0
IL_0003: ldfld class [mscorlib]System.Collections.Generic.IEnumerable`1<string> ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::alternatives
IL_0008: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator()
IL_000d: stloc.0
.try
{
IL_000e: br.s IL_0020
IL_0010: ldloc.0
IL_0011: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
IL_0016: stloc.1
IL_0017: nop
IL_0018: ldloc.1
IL_0019: callvirt instance string [mscorlib]System.String::ToLower()
IL_001e: pop
IL_001f: nop
IL_0020: ldloc.0
IL_0021: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0026: brtrue.s IL_0010
IL_0028: leave.s IL_0035
} // end .try
finally
{
IL_002a: ldloc.0
IL_002b: brfalse.s IL_0034
IL_002d: ldloc.0
IL_002e: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0033: nop
IL_0034: endfinally
} // end handler
IL_0035: ret
} // end of method Loops::ForEachOnField
.method public hidebysig instance void
ForEach(class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives) cil managed
{
// Code size 49 (0x31)
.maxstack 1
@ -1259,7 +1305,7 @@ @@ -1259,7 +1305,7 @@
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> V_0,
int32 V_1,
class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0' V_2)
class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0' V_2)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.0
@ -1272,14 +1318,14 @@ @@ -1272,14 +1318,14 @@
IL_000b: ldloca.s V_0
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0012: stloc.1
IL_0013: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0'::.ctor()
IL_0013: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::.ctor()
IL_0018: stloc.2
IL_0019: nop
IL_001a: ldloc.2
IL_001b: ldloc.1
IL_001c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0'::c
IL_001c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c
IL_0021: ldloc.2
IL_0022: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass23_0'::'<ForeachWithCapturedVariable>b__0'()
IL_0022: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0'()
IL_0028: newobj instance void class [mscorlib]System.Func`1<bool>::.ctor(object,
native int)
IL_002d: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Operation(class [mscorlib]System.Func`1<bool>)

11
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs

@ -27,6 +27,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -27,6 +27,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public abstract void B(bool b);
public abstract bool F(int i);
public abstract int GetInt(int i);
public abstract void M1();
public abstract void M2();
public abstract void E();
@ -91,6 +92,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -91,6 +92,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
this.E();
}
public void StmtOr4()
{
if (this.GetInt(0) != 0 || this.GetInt(1) != 0) {
this.M1();
} else {
this.M2();
}
this.E();
}
public void StmtComplex()
{
if (this.F(0) && this.F(1) && !this.F(2) && (this.F(3) || this.F(4))) {

60
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.il

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly '0fqx5k1s'
.assembly bqtfnoxz
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module '0fqx5k1s.dll'
// MVID: {40923C21-ED40-40E0-8D2A-58DE2CA84852}
.module bqtfnoxz.dll
// MVID: {E41D831E-089A-4F86-AA5D-FD2CB6D7C452}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x031A0000
// Image base: 0x03120000
// =============== CLASS MEMBERS DECLARATION ===================
@ -46,6 +46,11 @@ @@ -46,6 +46,11 @@
{
} // end of method ShortCircuit::F
.method public hidebysig newslot abstract virtual
instance int32 GetInt(int32 i) cil managed
{
} // end of method ShortCircuit::GetInt
.method public hidebysig newslot abstract virtual
instance void M1() cil managed
{
@ -348,6 +353,49 @@ @@ -348,6 +353,49 @@
IL_0040: ret
} // end of method ShortCircuit::StmtOr3
.method public hidebysig instance void
StmtOr4() cil managed
{
// Code size 56 (0x38)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.0
IL_0003: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::GetInt(int32)
IL_0008: brtrue.s IL_0016
IL_000a: ldarg.0
IL_000b: ldc.i4.1
IL_000c: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::GetInt(int32)
IL_0011: ldc.i4.0
IL_0012: ceq
IL_0014: br.s IL_0017
IL_0016: ldc.i4.0
IL_0017: nop
IL_0018: stloc.0
IL_0019: ldloc.0
IL_001a: brtrue.s IL_0027
IL_001c: nop
IL_001d: ldarg.0
IL_001e: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1()
IL_0023: nop
IL_0024: nop
IL_0025: br.s IL_0030
IL_0027: nop
IL_0028: ldarg.0
IL_0029: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2()
IL_002e: nop
IL_002f: nop
IL_0030: ldarg.0
IL_0031: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E()
IL_0036: nop
IL_0037: ret
} // end of method ShortCircuit::StmtOr4
.method public hidebysig instance void
StmtComplex() cil managed
{
@ -588,4 +636,4 @@ @@ -588,4 +636,4 @@
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file ../../Tests/TestCases/Pretty\ShortCircuit.res
// WARNING: Created Win32 resource file ../../../TestCases/Pretty\ShortCircuit.res

43
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.il

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly gbge3vmw
.assembly '4yyrmwig'
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module gbge3vmw.dll
// MVID: {39FE0BDC-C8CF-421C-936D-85782F68AEF4}
.module '4yyrmwig.dll'
// MVID: {A53FB590-72B6-46AB-809D-9F6F92B64475}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00C00000
// Image base: 0x015D0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -46,6 +46,11 @@ @@ -46,6 +46,11 @@
{
} // end of method ShortCircuit::F
.method public hidebysig newslot abstract virtual
instance int32 GetInt(int32 i) cil managed
{
} // end of method ShortCircuit::GetInt
.method public hidebysig newslot abstract virtual
instance void M1() cil managed
{
@ -268,6 +273,32 @@ @@ -268,6 +273,32 @@
IL_002f: ret
} // end of method ShortCircuit::StmtOr3
.method public hidebysig instance void
StmtOr4() cil managed
{
// Code size 39 (0x27)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::GetInt(int32)
IL_0007: brtrue.s IL_0012
IL_0009: ldarg.0
IL_000a: ldc.i4.1
IL_000b: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::GetInt(int32)
IL_0010: brfalse.s IL_001a
IL_0012: ldarg.0
IL_0013: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1()
IL_0018: br.s IL_0020
IL_001a: ldarg.0
IL_001b: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2()
IL_0020: ldarg.0
IL_0021: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E()
IL_0026: ret
} // end of method ShortCircuit::StmtOr4
.method public hidebysig instance void
StmtComplex() cil managed
{
@ -433,4 +464,4 @@ @@ -433,4 +464,4 @@
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file ../../Tests/TestCases/Pretty\ShortCircuit.opt.res
// WARNING: Created Win32 resource file ../../../TestCases/Pretty\ShortCircuit.opt.res

37
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.opt.roslyn.il

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module ShortCircuit.dll
// MVID: {A27E149C-542B-41C0-AB29-FA01A65D43CB}
// MVID: {FAFDF41B-AD51-4575-890D-F2652CF85283}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02490000
// Image base: 0x00710000
// =============== CLASS MEMBERS DECLARATION ===================
@ -50,6 +50,11 @@ @@ -50,6 +50,11 @@
{
} // end of method ShortCircuit::F
.method public hidebysig newslot abstract virtual
instance int32 GetInt(int32 i) cil managed
{
} // end of method ShortCircuit::GetInt
.method public hidebysig newslot abstract virtual
instance void M1() cil managed
{
@ -272,6 +277,32 @@ @@ -272,6 +277,32 @@
IL_002f: ret
} // end of method ShortCircuit::StmtOr3
.method public hidebysig instance void
StmtOr4() cil managed
{
// Code size 39 (0x27)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::GetInt(int32)
IL_0007: brtrue.s IL_0012
IL_0009: ldarg.0
IL_000a: ldc.i4.1
IL_000b: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::GetInt(int32)
IL_0010: brfalse.s IL_001a
IL_0012: ldarg.0
IL_0013: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1()
IL_0018: br.s IL_0020
IL_001a: ldarg.0
IL_001b: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2()
IL_0020: ldarg.0
IL_0021: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E()
IL_0026: ret
} // end of method ShortCircuit::StmtOr4
.method public hidebysig instance void
StmtComplex() cil managed
{

53
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.roslyn.il

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module ShortCircuit.dll
// MVID: {5FB25D31-D6C4-4D39-B72D-A6EBD832225B}
// MVID: {B0D8F5AF-A2A3-4091-846A-B19B13874A74}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00D60000
// Image base: 0x00AD0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -50,6 +50,11 @@ @@ -50,6 +50,11 @@
{
} // end of method ShortCircuit::F
.method public hidebysig newslot abstract virtual
instance int32 GetInt(int32 i) cil managed
{
} // end of method ShortCircuit::GetInt
.method public hidebysig newslot abstract virtual
instance void M1() cil managed
{
@ -336,6 +341,48 @@ @@ -336,6 +341,48 @@
IL_003c: ret
} // end of method ShortCircuit::StmtOr3
.method public hidebysig instance void
StmtOr4() cil managed
{
// Code size 55 (0x37)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.0
IL_0003: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::GetInt(int32)
IL_0008: brtrue.s IL_0016
IL_000a: ldarg.0
IL_000b: ldc.i4.1
IL_000c: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::GetInt(int32)
IL_0011: ldc.i4.0
IL_0012: cgt.un
IL_0014: br.s IL_0017
IL_0016: ldc.i4.1
IL_0017: stloc.0
IL_0018: ldloc.0
IL_0019: brfalse.s IL_0026
IL_001b: nop
IL_001c: ldarg.0
IL_001d: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M1()
IL_0022: nop
IL_0023: nop
IL_0024: br.s IL_002f
IL_0026: nop
IL_0027: ldarg.0
IL_0028: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::M2()
IL_002d: nop
IL_002e: nop
IL_002f: ldarg.0
IL_0030: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.ShortCircuit::E()
IL_0035: nop
IL_0036: ret
} // end of method ShortCircuit::StmtOr4
.method public hidebysig instance void
StmtComplex() cil managed
{

26
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs

@ -60,19 +60,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -60,19 +60,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
//public static bool? SwitchOverNullableEnum(State? state)
//{
// switch (state) {
// case State.False:
// return false;
// case State.True:
// return true;
// case State.Null:
// return null;
// default:
// throw new InvalidOperationException();
// }
//}
public static bool? SwitchOverNullableEnum(State? state)
{
switch (state) {
case State.False:
return false;
case State.True:
return true;
case State.Null:
return null;
default:
throw new InvalidOperationException();
}
}
public static string SparseIntegerSwitch(int i)
{

80
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly mhfw1ujx
.assembly o03zflju
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module mhfw1ujx.dll
// MVID: {2E35825E-3352-4C5E-B230-3B3F7055B304}
.module o03zflju.dll
// MVID: {0EF64C57-A49E-4138-9C3F-BDAB86B2E450}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x005A0000
// Image base: 0x01330000
// =============== CLASS MEMBERS DECLARATION ===================
@ -142,6 +142,52 @@ @@ -142,6 +142,52 @@
IL_0034: ret
} // end of method Switch::SwitchOverNullableBool
.method public hidebysig static valuetype [mscorlib]System.Nullable`1<bool>
SwitchOverNullableEnum(valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State> state) cil managed
{
// Code size 75 (0x4b)
.maxstack 2
.locals init (valuetype [mscorlib]System.Nullable`1<bool> V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State V_1,
valuetype [mscorlib]System.Nullable`1<bool> V_2)
IL_0000: nop
IL_0001: ldarga.s state
IL_0003: dup
IL_0004: call instance !0 valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State>::GetValueOrDefault()
IL_0009: stloc.1
IL_000a: call instance bool valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State>::get_HasValue()
IL_000f: brfalse.s IL_0043
IL_0011: ldloc.1
IL_0012: switch (
IL_0025,
IL_002e,
IL_0037)
IL_0023: br.s IL_0043
IL_0025: ldc.i4.0
IL_0026: newobj instance void valuetype [mscorlib]System.Nullable`1<bool>::.ctor(!0)
IL_002b: stloc.0
IL_002c: br.s IL_0049
IL_002e: ldc.i4.1
IL_002f: newobj instance void valuetype [mscorlib]System.Nullable`1<bool>::.ctor(!0)
IL_0034: stloc.0
IL_0035: br.s IL_0049
IL_0037: ldloca.s V_2
IL_0039: initobj valuetype [mscorlib]System.Nullable`1<bool>
IL_003f: ldloc.2
IL_0040: stloc.0
IL_0041: br.s IL_0049
IL_0043: newobj instance void [mscorlib]System.InvalidOperationException::.ctor()
IL_0048: throw
IL_0049: ldloc.0
IL_004a: ret
} // end of method Switch::SwitchOverNullableEnum
.method public hidebysig static string
SparseIntegerSwitch(int32 i) cil managed
{
@ -834,7 +880,7 @@ @@ -834,7 +880,7 @@
IL_0015: brfalse IL_00e9
IL_001a: volatile.
IL_001c: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x600000c-1'
IL_001c: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x600000d-1'
IL_0021: brtrue.s IL_0084
IL_0023: ldc.i4.7
@ -875,9 +921,9 @@ @@ -875,9 +921,9 @@
IL_0078: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0,
!1)
IL_007d: volatile.
IL_007f: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x600000c-1'
IL_007f: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x600000d-1'
IL_0084: volatile.
IL_0086: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x600000c-1'
IL_0086: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x600000d-1'
IL_008b: ldloc.1
IL_008c: ldloca.s V_2
IL_008e: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::TryGetValue(!0,
@ -949,7 +995,7 @@ @@ -949,7 +995,7 @@
IL_0013: brfalse IL_0158
IL_0018: volatile.
IL_001a: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x600000d-1'
IL_001a: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x600000e-1'
IL_001f: brtrue IL_00b8
IL_0024: ldc.i4.s 11
@ -1010,9 +1056,9 @@ @@ -1010,9 +1056,9 @@
IL_00ac: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0,
!1)
IL_00b1: volatile.
IL_00b3: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x600000d-1'
IL_00b3: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x600000e-1'
IL_00b8: volatile.
IL_00ba: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x600000d-1'
IL_00ba: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x600000e-1'
IL_00bf: ldloc.1
IL_00c0: ldloca.s V_2
IL_00c2: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::TryGetValue(!0,
@ -1297,7 +1343,7 @@ @@ -1297,7 +1343,7 @@
IL_0030: brfalse IL_0121
IL_0035: volatile.
IL_0037: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x6000012-1'
IL_0037: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x6000013-1'
IL_003c: brtrue.s IL_0093
IL_003e: ldc.i4.6
@ -1333,9 +1379,9 @@ @@ -1333,9 +1379,9 @@
IL_0087: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0,
!1)
IL_008c: volatile.
IL_008e: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x6000012-1'
IL_008e: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x6000013-1'
IL_0093: volatile.
IL_0095: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'::'$$method0x6000012-1'
IL_0095: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'::'$$method0x6000013-1'
IL_009a: ldloc.s V_5
IL_009c: ldloca.s V_6
IL_009e: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::TryGetValue(!0,
@ -1562,14 +1608,14 @@ @@ -1562,14 +1608,14 @@
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch
.class private auto ansi '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'
.class private auto ansi '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x600000c-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x600000d-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000012-1'
} // end of class '<PrivateImplementationDetails>{2E35825E-3352-4C5E-B230-3B3F7055B304}'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x600000e-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000013-1'
} // end of class '<PrivateImplementationDetails>{0EF64C57-A49E-4138-9C3F-BDAB86B2E450}'
// =============================================================

72
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly okac2jza
.assembly pryqrprl
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module okac2jza.dll
// MVID: {7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}
.module pryqrprl.dll
// MVID: {FFEEBB9C-152A-467A-A4B4-51CF03878E20}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x01A40000
// Image base: 0x00B70000
// =============== CLASS MEMBERS DECLARATION ===================
@ -126,6 +126,44 @@ @@ -126,6 +126,44 @@
IL_002b: throw
} // end of method Switch::SwitchOverNullableBool
.method public hidebysig static valuetype [mscorlib]System.Nullable`1<bool>
SwitchOverNullableEnum(valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State> state) cil managed
{
// Code size 66 (0x42)
.maxstack 2
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State V_0,
valuetype [mscorlib]System.Nullable`1<bool> V_1)
IL_0000: ldarga.s state
IL_0002: dup
IL_0003: call instance !0 valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State>::GetValueOrDefault()
IL_0008: stloc.0
IL_0009: call instance bool valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State>::get_HasValue()
IL_000e: brfalse.s IL_003c
IL_0010: ldloc.0
IL_0011: switch (
IL_0024,
IL_002b,
IL_0032)
IL_0022: br.s IL_003c
IL_0024: ldc.i4.0
IL_0025: newobj instance void valuetype [mscorlib]System.Nullable`1<bool>::.ctor(!0)
IL_002a: ret
IL_002b: ldc.i4.1
IL_002c: newobj instance void valuetype [mscorlib]System.Nullable`1<bool>::.ctor(!0)
IL_0031: ret
IL_0032: ldloca.s V_1
IL_0034: initobj valuetype [mscorlib]System.Nullable`1<bool>
IL_003a: ldloc.1
IL_003b: ret
IL_003c: newobj instance void [mscorlib]System.InvalidOperationException::.ctor()
IL_0041: throw
} // end of method Switch::SwitchOverNullableEnum
.method public hidebysig static string
SparseIntegerSwitch(int32 i) cil managed
{
@ -711,7 +749,7 @@ @@ -711,7 +749,7 @@
IL_0013: brfalse IL_00db
IL_0018: volatile.
IL_001a: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x600000c-1'
IL_001a: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x600000d-1'
IL_001f: brtrue.s IL_0082
IL_0021: ldc.i4.7
@ -752,9 +790,9 @@ @@ -752,9 +790,9 @@
IL_0076: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0,
!1)
IL_007b: volatile.
IL_007d: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x600000c-1'
IL_007d: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x600000d-1'
IL_0082: volatile.
IL_0084: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x600000c-1'
IL_0084: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x600000d-1'
IL_0089: ldloc.0
IL_008a: ldloca.s V_1
IL_008c: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::TryGetValue(!0,
@ -812,7 +850,7 @@ @@ -812,7 +850,7 @@
IL_0011: brfalse IL_013d
IL_0016: volatile.
IL_0018: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x600000d-1'
IL_0018: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x600000e-1'
IL_001d: brtrue IL_00b6
IL_0022: ldc.i4.s 11
@ -873,9 +911,9 @@ @@ -873,9 +911,9 @@
IL_00aa: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0,
!1)
IL_00af: volatile.
IL_00b1: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x600000d-1'
IL_00b1: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x600000e-1'
IL_00b6: volatile.
IL_00b8: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x600000d-1'
IL_00b8: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x600000e-1'
IL_00bd: ldloc.0
IL_00be: ldloca.s V_1
IL_00c0: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::TryGetValue(!0,
@ -1099,7 +1137,7 @@ @@ -1099,7 +1137,7 @@
IL_002d: brfalse IL_0115
IL_0032: volatile.
IL_0034: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x6000012-1'
IL_0034: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x6000013-1'
IL_0039: brtrue.s IL_0090
IL_003b: ldc.i4.6
@ -1135,9 +1173,9 @@ @@ -1135,9 +1173,9 @@
IL_0084: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0,
!1)
IL_0089: volatile.
IL_008b: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x6000012-1'
IL_008b: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x6000013-1'
IL_0090: volatile.
IL_0092: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'::'$$method0x6000012-1'
IL_0092: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'::'$$method0x6000013-1'
IL_0097: ldloc.s V_5
IL_0099: ldloca.s V_6
IL_009b: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::TryGetValue(!0,
@ -1331,14 +1369,14 @@ @@ -1331,14 +1369,14 @@
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch
.class private auto ansi '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'
.class private auto ansi '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x600000c-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x600000d-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000012-1'
} // end of class '<PrivateImplementationDetails>{7ED4313F-4304-4C85-87F6-5AD4A6E6AA1F}'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x600000e-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000013-1'
} // end of class '<PrivateImplementationDetails>{FFEEBB9C-152A-467A-A4B4-51CF03878E20}'
// =============================================================

45
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module Switch.dll
// MVID: {6F3B5958-B8BE-48C6-82B8-5D3026DEACD1}
// MVID: {5D628BA5-FC59-43EC-A162-63729510F134}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x03160000
// Image base: 0x01390000
// =============== CLASS MEMBERS DECLARATION ===================
@ -136,6 +136,47 @@ @@ -136,6 +136,47 @@
IL_0027: throw
} // end of method Switch::SwitchOverNullableBool
.method public hidebysig static valuetype [mscorlib]System.Nullable`1<bool>
SwitchOverNullableEnum(valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State> state) cil managed
{
// Code size 69 (0x45)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State> V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State V_1,
valuetype [mscorlib]System.Nullable`1<bool> V_2)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call instance bool valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State>::get_HasValue()
IL_0009: brfalse.s IL_003f
IL_000b: ldloca.s V_0
IL_000d: call instance !0 valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State>::GetValueOrDefault()
IL_0012: stloc.1
IL_0013: ldloc.1
IL_0014: switch (
IL_0027,
IL_002e,
IL_0035)
IL_0025: br.s IL_003f
IL_0027: ldc.i4.0
IL_0028: newobj instance void valuetype [mscorlib]System.Nullable`1<bool>::.ctor(!0)
IL_002d: ret
IL_002e: ldc.i4.1
IL_002f: newobj instance void valuetype [mscorlib]System.Nullable`1<bool>::.ctor(!0)
IL_0034: ret
IL_0035: ldloca.s V_2
IL_0037: initobj valuetype [mscorlib]System.Nullable`1<bool>
IL_003d: ldloc.2
IL_003e: ret
IL_003f: newobj instance void [mscorlib]System.InvalidOperationException::.ctor()
IL_0044: throw
} // end of method Switch::SwitchOverNullableEnum
.method public hidebysig static string
SparseIntegerSwitch(int32 i) cil managed
{

54
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.roslyn.il

@ -25,7 +25,7 @@ @@ -25,7 +25,7 @@
.ver 0:0:0:0
}
.module Switch.dll
// MVID: {7ADDBD28-42D6-469D-B92D-065C803347D0}
// MVID: {EF7D776C-0F54-445C-8A74-2D49ADE35F46}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
@ -152,6 +152,58 @@ @@ -152,6 +152,58 @@
IL_0034: ret
} // end of method Switch::SwitchOverNullableBool
.method public hidebysig static valuetype [mscorlib]System.Nullable`1<bool>
SwitchOverNullableEnum(valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State> state) cil managed
{
// Code size 81 (0x51)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State> V_0,
valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State> V_1,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State V_2,
valuetype [mscorlib]System.Nullable`1<bool> V_3,
valuetype [mscorlib]System.Nullable`1<bool> V_4)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: stloc.1
IL_0003: ldloc.1
IL_0004: stloc.0
IL_0005: ldloca.s V_0
IL_0007: call instance bool valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State>::get_HasValue()
IL_000c: brfalse.s IL_0049
IL_000e: ldloca.s V_0
IL_0010: call instance !0 valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State>::GetValueOrDefault()
IL_0015: stloc.2
IL_0016: ldloc.2
IL_0017: switch (
IL_002a,
IL_0033,
IL_003c)
IL_0028: br.s IL_0049
IL_002a: ldc.i4.0
IL_002b: newobj instance void valuetype [mscorlib]System.Nullable`1<bool>::.ctor(!0)
IL_0030: stloc.3
IL_0031: br.s IL_004f
IL_0033: ldc.i4.1
IL_0034: newobj instance void valuetype [mscorlib]System.Nullable`1<bool>::.ctor(!0)
IL_0039: stloc.3
IL_003a: br.s IL_004f
IL_003c: ldloca.s V_4
IL_003e: initobj valuetype [mscorlib]System.Nullable`1<bool>
IL_0044: ldloc.s V_4
IL_0046: stloc.3
IL_0047: br.s IL_004f
IL_0049: newobj instance void [mscorlib]System.InvalidOperationException::.ctor()
IL_004e: throw
IL_004f: ldloc.3
IL_0050: ret
} // end of method Switch::SwitchOverNullableEnum
.method public hidebysig static string
SparseIntegerSwitch(int32 i) cil managed
{

14
ICSharpCode.Decompiler/CSharp/Annotations.cs

@ -164,4 +164,18 @@ namespace ICSharpCode.Decompiler.CSharp @@ -164,4 +164,18 @@ namespace ICSharpCode.Decompiler.CSharp
this.Variable = v;
}
}
public class ForeachAnnotation
{
public readonly ILInstruction GetEnumeratorCall;
public readonly ILInstruction MoveNextCall;
public readonly ILInstruction GetCurrentCall;
public ForeachAnnotation(ILInstruction getEnumeratorCall, ILInstruction moveNextCall, ILInstruction getCurrentCall)
{
GetEnumeratorCall = getEnumeratorCall;
MoveNextCall = moveNextCall;
GetCurrentCall = getCurrentCall;
}
}
}

173
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -31,6 +31,8 @@ using ICSharpCode.Decompiler.IL.ControlFlow; @@ -31,6 +31,8 @@ using ICSharpCode.Decompiler.IL.ControlFlow;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.Util;
using System.IO;
namespace ICSharpCode.Decompiler.CSharp
{
@ -168,6 +170,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -168,6 +170,11 @@ namespace ICSharpCode.Decompiler.CSharp
get { return astTransforms; }
}
public CSharpDecompiler(string fileName, DecompilerSettings settings)
: this(UniversalAssemblyResolver.LoadMainModule(fileName, settings.ThrowOnAssemblyResolveErrors, settings.LoadInMemory), settings)
{
}
public CSharpDecompiler(ModuleDefinition module, DecompilerSettings settings)
: this(new DecompilerTypeSystem(module), settings)
{
@ -180,7 +187,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -180,7 +187,7 @@ namespace ICSharpCode.Decompiler.CSharp
this.typeSystem = typeSystem;
this.settings = settings;
}
#region MemberIsHidden
public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
{
@ -210,7 +217,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -210,7 +217,7 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
}
}
FieldDefinition field = member as FieldDefinition;
if (field != null) {
if (field.IsCompilerGenerated()) {
@ -232,10 +239,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -232,10 +239,10 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
}
}
return false;
}
static bool IsSwitchOnStringCache(FieldDefinition field)
{
return field.Name.StartsWith("<>f__switch", StringComparison.Ordinal);
@ -260,7 +267,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -260,7 +267,7 @@ namespace ICSharpCode.Decompiler.CSharp
return type.BaseType.FullName == "System.Object" && !type.HasInterfaces;
}
#endregion
TypeSystemAstBuilder CreateAstBuilder(ITypeResolveContext decompilationContext)
{
var typeSystemAstBuilder = new TypeSystemAstBuilder();
@ -269,7 +276,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -269,7 +276,7 @@ namespace ICSharpCode.Decompiler.CSharp
typeSystemAstBuilder.AddResolveResultAnnotations = true;
return typeSystemAstBuilder;
}
void RunTransforms(AstNode rootNode, ITypeResolveContext decompilationContext)
{
var typeSystemAstBuilder = CreateAstBuilder(decompilationContext);
@ -280,7 +287,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -280,7 +287,14 @@ namespace ICSharpCode.Decompiler.CSharp
}
rootNode.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
}
string SyntaxTreeToString(SyntaxTree syntaxTree)
{
StringWriter w = new StringWriter();
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, settings.CSharpFormattingOptions));
return w.ToString();
}
/// <summary>
/// Decompile assembly and module attributes.
/// </summary>
@ -294,6 +308,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -294,6 +308,14 @@ namespace ICSharpCode.Decompiler.CSharp
return syntaxTree;
}
/// <summary>
/// Decompile assembly and module attributes.
/// </summary>
public string DecompileModuleAndAssemblyAttributesToString()
{
return SyntaxTreeToString(DecompileModuleAndAssemblyAttributes());
}
void DoDecompileModuleAndAssemblyAttributes(ITypeResolveContext decompilationContext, SyntaxTree syntaxTree)
{
foreach (var a in typeSystem.Compilation.MainAssembly.AssemblyAttributes) {
@ -327,7 +349,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -327,7 +349,7 @@ namespace ICSharpCode.Decompiler.CSharp
groupNode.AddChild(typeDecl, SyntaxTree.MemberRole);
}
}
/// <summary>
/// Decompiles the whole module into a single syntax tree.
/// </summary>
@ -341,7 +363,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -341,7 +363,15 @@ namespace ICSharpCode.Decompiler.CSharp
RunTransforms(syntaxTree, decompilationContext);
return syntaxTree;
}
/// <summary>
/// Decompiles the whole module into a single string.
/// </summary>
public string DecompileWholeModuleAsString()
{
return SyntaxTreeToString(DecompileWholeModuleAsSingleFile());
}
/// <summary>
/// Decompile the given types.
/// </summary>
@ -360,6 +390,47 @@ namespace ICSharpCode.Decompiler.CSharp @@ -360,6 +390,47 @@ namespace ICSharpCode.Decompiler.CSharp
return syntaxTree;
}
/// <summary>
/// Decompile the given types.
/// </summary>
/// <remarks>
/// Unlike Decompile(IMemberDefinition[]), this method will add namespace declarations around the type definitions.
/// </remarks>
public string DecompileTypesAsString(IEnumerable<TypeDefinition> types)
{
return SyntaxTreeToString(DecompileTypes(types));
}
/// <summary>
/// Decompile the given type.
/// </summary>
/// <remarks>
/// Unlike Decompile(IMemberDefinition[]), this method will add namespace declarations around the type definition.
/// </remarks>
public SyntaxTree DecompileType(FullTypeName fullTypeName)
{
var type = typeSystem.Compilation.FindType(fullTypeName).GetDefinition();
if (type == null)
throw new InvalidOperationException($"Could not find type definition {fullTypeName} in type system.");
var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainAssembly);
syntaxTree = new SyntaxTree();
definedSymbols = new HashSet<string>();
DoDecompileTypes(new[] { typeSystem.GetCecil(type) }, decompilationContext, syntaxTree);
RunTransforms(syntaxTree, decompilationContext);
return syntaxTree;
}
/// <summary>
/// Decompile the given type.
/// </summary>
/// <remarks>
/// Unlike Decompile(IMemberDefinition[]), this method will add namespace declarations around the type definition.
/// </remarks>
public string DecompileTypeAsString(FullTypeName fullTypeName)
{
return SyntaxTreeToString(DecompileType(fullTypeName));
}
/// <summary>
/// Decompile the specified types and/or members.
/// </summary>
@ -424,6 +495,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -424,6 +495,22 @@ namespace ICSharpCode.Decompiler.CSharp
return syntaxTree;
}
/// <summary>
/// Decompile the specified types and/or members.
/// </summary>
public string DecompileAsString(params IMemberDefinition[] definitions)
{
return SyntaxTreeToString(Decompile(definitions));
}
/// <summary>
/// Decompile the specified types and/or members.
/// </summary>
public string DecompileAsString(IList<IMemberDefinition> definitions)
{
return SyntaxTreeToString(Decompile(definitions));
}
IEnumerable<EntityDeclaration> AddInterfaceImplHelpers(EntityDeclaration memberDecl, MethodDefinition methodDef,
TypeSystemAstBuilder astBuilder)
{
@ -443,7 +530,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -443,7 +530,7 @@ namespace ICSharpCode.Decompiler.CSharp
methodDecl.Parameters.AddRange(memberDecl.GetChildrenByRole(Roles.Parameter).Select(n => n.Clone()));
methodDecl.Constraints.AddRange(memberDecl.GetChildrenByRole(Roles.Constraint)
.Select(n => (Constraint)n.Clone()));
methodDecl.Body = new BlockStatement();
methodDecl.Body.AddChild(new Comment(
"ILSpy generated this explicit interface implementation from .override directive in " + memberDecl.Name),
@ -460,7 +547,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -460,7 +547,7 @@ namespace ICSharpCode.Decompiler.CSharp
yield return methodDecl;
}
}
Expression ForwardParameter(ParameterDeclaration p)
{
switch (p.ParameterModifier) {
@ -472,7 +559,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -472,7 +559,7 @@ namespace ICSharpCode.Decompiler.CSharp
return new IdentifierExpression(p.Name);
}
}
/// <summary>
/// Sets new modifier if the member hides some other member from a base type.
/// </summary>
@ -482,7 +569,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -482,7 +569,7 @@ namespace ICSharpCode.Decompiler.CSharp
bool addNewModifier = false;
var entity = (IEntity)member.GetSymbol();
var lookup = new MemberLookup(entity.DeclaringTypeDefinition, entity.ParentAssembly);
var baseTypes = entity.DeclaringType.GetNonInterfaceBaseTypes().Where(t => entity.DeclaringType != t);
if (entity is ITypeDefinition) {
addNewModifier = baseTypes.SelectMany(b => b.GetNestedTypes(t => t.Name == entity.Name && lookup.IsAccessible(t, true))).Any();
@ -520,7 +607,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -520,7 +607,7 @@ namespace ICSharpCode.Decompiler.CSharp
i++;
}
}
EntityDeclaration DoDecompile(ITypeDefinition typeDef, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentTypeDefinition == typeDef);
@ -619,7 +706,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -619,7 +706,7 @@ namespace ICSharpCode.Decompiler.CSharp
};
return method;
}
EntityDeclaration DoDecompile(MethodDefinition methodDefinition, IMethod method, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentMember == method);
@ -658,7 +745,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -658,7 +745,7 @@ namespace ICSharpCode.Decompiler.CSharp
i++;
}
}
var context = new ILTransformContext(function, specializingTypeSystem, settings) {
CancellationToken = CancellationToken
};
@ -798,7 +885,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -798,7 +885,7 @@ namespace ICSharpCode.Decompiler.CSharp
SetNewModifier(propertyDecl);
return propertyDecl;
}
EntityDeclaration DoDecompile(EventDefinition eventDefinition, IEvent ev, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentMember == ev);
@ -878,13 +965,31 @@ namespace ICSharpCode.Decompiler.CSharp @@ -878,13 +965,31 @@ namespace ICSharpCode.Decompiler.CSharp
} else if (type is GenericParameter) {
return new SimpleType(type.Name);
} else if (type.IsNested) {
AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions);
string namepart = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name);
MemberType memberType = new MemberType { Target = typeRef, MemberName = namepart };
memberType.AddAnnotation(type);
AstType memberType;
if ((options & (ConvertTypeOptions.IncludeOuterTypeName | ConvertTypeOptions.IncludeNamespace)) != 0) {
AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions);
memberType = new MemberType { Target = typeRef, MemberName = namepart };
if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) {
AddTypeParameterDefininitionsTo(type, memberType);
}
} else {
memberType = new SimpleType(namepart);
if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) {
if (type.HasGenericParameters) {
List<AstType> typeArguments = new List<AstType>();
foreach (GenericParameter gp in type.GenericParameters) {
typeArguments.Add(new SimpleType(gp.Name));
}
ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out int typeParameterCount);
if (typeParameterCount > typeArguments.Count)
typeParameterCount = typeArguments.Count;
((SimpleType)memberType).TypeArguments.AddRange(typeArguments.GetRange(typeArguments.Count - typeParameterCount, typeParameterCount));
typeArguments.RemoveRange(typeArguments.Count - typeParameterCount, typeParameterCount);
}
}
}
memberType.AddAnnotation(type);
return memberType;
} else {
string ns = type.Namespace ?? string.Empty;
@ -973,14 +1078,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -973,14 +1078,22 @@ namespace ICSharpCode.Decompiler.CSharp
{
SimpleType st = baseType as SimpleType;
if (st != null) {
TypeReference type = st.Annotation<TypeReference>();
if (type != null) {
ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out int typeParameterCount);
if (typeParameterCount > typeArguments.Count)
typeParameterCount = typeArguments.Count;
st.TypeArguments.AddRange(typeArguments.GetRange(typeArguments.Count - typeParameterCount, typeParameterCount));
} else {
st.TypeArguments.AddRange(typeArguments);
}
}
MemberType mt = baseType as MemberType;
if (mt != null) {
TypeReference type = mt.Annotation<TypeReference>();
if (type != null) {
int typeParameterCount;
ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount);
ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out int typeParameterCount);
if (typeParameterCount > typeArguments.Count)
typeParameterCount = typeArguments.Count;
mt.TypeArguments.AddRange(typeArguments.GetRange(typeArguments.Count - typeParameterCount, typeParameterCount));
@ -1013,6 +1126,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1013,6 +1126,19 @@ namespace ICSharpCode.Decompiler.CSharp
}
#endregion
#region Sequence Points
/// <summary>
/// Creates sequence points for the given syntax tree.
///
/// This only works correctly when the nodes in the syntax tree have line/column information.
/// </summary>
public Dictionary<ILFunction, List<SequencePoint>> CreateSequencePoints(SyntaxTree syntaxTree)
{
SequencePointBuilder spb = new SequencePointBuilder();
syntaxTree.AcceptVisitor(spb);
return spb.GetSequencePoints();
}
#endregion
}
[Flags]
@ -1021,6 +1147,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1021,6 +1147,7 @@ namespace ICSharpCode.Decompiler.CSharp
None = 0,
IncludeNamespace = 1,
IncludeTypeParameterDefinitions = 2,
DoNotUsePrimitiveTypeNames = 4
DoNotUsePrimitiveTypeNames = 4,
IncludeOuterTypeName = 8,
}
}

41
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -143,10 +143,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -143,10 +143,16 @@ namespace ICSharpCode.Decompiler.CSharp
.WithILInstruction(inst)
.WithRR(rr);
} else {
if (IsUnambiguousCall(inst, target, method, Array.Empty<IType>(), arguments) != OverloadResolutionErrors.None) {
for (int i = 0; i < arguments.Count; i++) {
if (!settings.AnonymousTypes || !expectedParameters[i].Type.ContainsAnonymousType())
if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) {
if (arguments[i].Expression is LambdaExpression lambda) {
ModifyReturnTypeOfLambda(lambda);
}
} else {
arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder);
}
}
}
return new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), arguments.SelectArray(arg => arg.Expression))
@ -180,8 +186,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -180,8 +186,13 @@ namespace ICSharpCode.Decompiler.CSharp
if (!argumentsCasted) {
argumentsCasted = true;
for (int i = 0; i < arguments.Count; i++) {
if (!settings.AnonymousTypes || !expectedParameters[i].Type.ContainsAnonymousType())
if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) {
if (arguments[i].Expression is LambdaExpression lambda) {
ModifyReturnTypeOfLambda(lambda);
}
} else {
arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder);
}
}
} else if (!targetCasted) {
targetCasted = true;
@ -213,6 +224,29 @@ namespace ICSharpCode.Decompiler.CSharp @@ -213,6 +224,29 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
private void ModifyReturnTypeOfLambda(LambdaExpression lambda)
{
var resolveResult = (DecompiledLambdaResolveResult)lambda.GetResolveResult();
if (lambda.Body is Expression exprBody)
lambda.Body = new TranslatedExpression(exprBody.Detach()).ConvertTo(resolveResult.ReturnType, expressionBuilder);
else
ModifyReturnStatementInsideLambda(resolveResult.ReturnType, lambda);
resolveResult.InferredReturnType = resolveResult.ReturnType;
}
private void ModifyReturnStatementInsideLambda(IType returnType, AstNode parent)
{
foreach (var child in parent.Children) {
if (child is LambdaExpression || child is AnonymousMethodExpression)
continue;
if (child is ReturnStatement ret) {
ret.Expression = new TranslatedExpression(ret.Expression.Detach()).ConvertTo(returnType, expressionBuilder);
continue;
}
ModifyReturnStatementInsideLambda(returnType, child);
}
}
private bool IsDelegateEqualityComparison(IMethod method, IList<TranslatedExpression> arguments)
{
// Comparison on a delegate type is a C# builtin operator
@ -343,7 +377,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -343,7 +377,8 @@ namespace ICSharpCode.Decompiler.CSharp
break;
case OpCode.ILFunction:
method = ((ILFunction)func).Method;
return expressionBuilder.TranslateFunction(inst.Method.DeclaringType, (ILFunction)func);
return expressionBuilder.TranslateFunction(inst.Method.DeclaringType, (ILFunction)func)
.WithILInstruction(inst);
default:
throw new ArgumentException($"Unknown instruction type: {func.OpCode}");
}

32
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -325,8 +325,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -325,8 +325,15 @@ namespace ICSharpCode.Decompiler.CSharp
internal ExpressionWithResolveResult GetDefaultValueExpression(IType type)
{
var expr = type.IsReferenceType == true ? (Expression)new NullReferenceExpression() : new DefaultValueExpression(ConvertType(type));
var constantType = type.IsReferenceType == true ? SpecialType.NullType : type;
Expression expr;
IType constantType;
if (type.IsReferenceType == true || type.IsKnownType(KnownTypeCode.NullableOfT)) {
expr = new NullReferenceExpression();
constantType = SpecialType.NullType;
} else {
expr = new DefaultValueExpression(ConvertType(type));
constantType = type;
}
return expr.WithRR(new ConstantResolveResult(constantType, null));
}
@ -905,6 +912,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -905,6 +912,11 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
if (op.IsBitwise() && (left.Type.Kind == TypeKind.Enum || right.Type.Kind == TypeKind.Enum)) {
left = AdjustConstantExpressionToType(left, right.Type);
right = AdjustConstantExpressionToType(right, left.Type);
}
var rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
if (rr.IsError || NullableType.GetUnderlyingType(rr.Type).GetStackType() != inst.UnderlyingResultType
|| !IsCompatibleWithSign(left.Type, inst.Sign) || !IsCompatibleWithSign(right.Type, inst.Sign))
@ -1284,7 +1296,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1284,7 +1296,7 @@ namespace ICSharpCode.Decompiler.CSharp
return new CallBuilder(this, typeSystem, settings).Build(inst);
}
internal TranslatedExpression TranslateFunction(IType delegateType, ILFunction function)
internal ExpressionWithResolveResult TranslateFunction(IType delegateType, ILFunction function)
{
var method = function.Method.MemberDefinition as IMethod;
Debug.Assert(method != null);
@ -1356,7 +1368,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1356,7 +1368,7 @@ namespace ICSharpCode.Decompiler.CSharp
TranslatedExpression translatedLambda = replacement.WithILInstruction(function).WithRR(rr);
return new CastExpression(ConvertType(delegateType), translatedLambda)
.WithoutILInstruction().WithRR(new ConversionResolveResult(delegateType, rr, LambdaConversion.Instance));
.WithRR(new ConversionResolveResult(delegateType, rr, LambdaConversion.Instance));
}
IType InferReturnType(BlockStatement body)
@ -1723,11 +1735,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1723,11 +1735,10 @@ namespace ICSharpCode.Decompiler.CSharp
if (currentPath == null) {
currentPath = info.Path;
} else {
int firstDifferenceIndex = Math.Min(currentPath.Count, info.Path.Count);
int index = 0;
while (index < firstDifferenceIndex && info.Path[index] == currentPath[index])
index++;
firstDifferenceIndex = index;
int minLen = Math.Min(currentPath.Count, info.Path.Count);
int firstDifferenceIndex = 0;
while (firstDifferenceIndex < minLen && info.Path[firstDifferenceIndex] == currentPath[firstDifferenceIndex])
firstDifferenceIndex++;
while (elementsStack.Count - 1 > firstDifferenceIndex) {
var methodElement = currentPath[elementsStack.Count - 1];
var pathElement = currentPath[elementsStack.Count - 2];
@ -1944,7 +1955,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1944,7 +1955,8 @@ namespace ICSharpCode.Decompiler.CSharp
// ILAst LogicAnd/LogicOr can return a different value than 0 or 1
// if the rhs is evaluated.
// We can only correctly translate it to C# if the rhs is of type boolean:
if (op != BinaryOperatorType.Any && rhs.Type.IsKnownType(KnownTypeCode.Boolean)) {
if (op != BinaryOperatorType.Any && (rhs.Type.IsKnownType(KnownTypeCode.Boolean) || IfInstruction.IsInConditionSlot(inst))) {
rhs = rhs.ConvertToBoolean(this);
return new BinaryOperatorExpression(condition, op, rhs)
.WithILInstruction(inst)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Boolean)));

24
ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs

@ -17,8 +17,10 @@ @@ -17,8 +17,10 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.IL;
namespace ICSharpCode.Decompiler.CSharp
{
@ -31,7 +33,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -31,7 +33,7 @@ namespace ICSharpCode.Decompiler.CSharp
node.AddAnnotation(annotation);
return node;
}
public static T CopyAnnotationsFrom<T>(this T node, AstNode other) where T : AstNode
{
foreach (object annotation in other.Annotations) {
@ -39,7 +41,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -39,7 +41,15 @@ namespace ICSharpCode.Decompiler.CSharp
}
return node;
}
public static T CopyInstructionsFrom<T>(this T node, AstNode other) where T : AstNode
{
foreach (object annotation in other.Annotations.OfType<ILInstruction>()) {
node.AddAnnotation(annotation);
}
return node;
}
public static T Detach<T>(this T node) where T : AstNode
{
node.Remove();
@ -89,5 +99,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -89,5 +99,15 @@ namespace ICSharpCode.Decompiler.CSharp
var simpleType = type as SimpleType;
return simpleType != null && simpleType.Identifier == "__arglist";
}
/// <summary>
/// Returns true if <paramref name="operatorType"/> is bitwise and, bitwise or, or exclusive or.
/// </summary>
public static bool IsBitwise(this BinaryOperatorType operatorType)
{
return operatorType == BinaryOperatorType.BitwiseAnd
|| operatorType == BinaryOperatorType.BitwiseOr
|| operatorType == BinaryOperatorType.ExclusiveOr;
}
}
}

49
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -90,6 +90,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -90,6 +90,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space(policy.SpaceBeforeBracketComma);
// TODO: Comma policy has changed.
writer.WriteToken(Roles.Comma, ",");
isAfterSpace = false;
Space(!noSpaceAfterComma && policy.SpaceAfterBracketComma);
// TODO: Comma policy has changed.
}
@ -194,6 +195,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -194,6 +195,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
#region Write tokens
protected bool isAtStartOfLine = true;
protected bool isAfterSpace;
/// <summary>
/// Writes a keyword, and all specials up to
@ -207,18 +209,21 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -207,18 +209,21 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
writer.WriteKeyword(tokenRole, token);
isAtStartOfLine = false;
isAfterSpace = false;
}
protected virtual void WriteIdentifier(Identifier identifier)
{
writer.WriteIdentifier(identifier);
isAtStartOfLine = false;
isAfterSpace = false;
}
protected virtual void WriteIdentifier(string identifier)
{
AstType.Create(identifier).AcceptVisitor(this);
isAtStartOfLine = false;
isAfterSpace = false;
}
protected virtual void WriteToken(TokenRole tokenRole)
@ -230,6 +235,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -230,6 +235,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
writer.WriteToken(tokenRole, token);
isAtStartOfLine = false;
isAfterSpace = false;
}
protected virtual void LPar()
@ -260,8 +266,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -260,8 +266,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
/// </summary>
protected virtual void Space(bool addSpace = true)
{
if (addSpace) {
if (addSpace && !isAfterSpace) {
writer.Space();
isAfterSpace = true;
}
}
@ -269,6 +276,31 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -269,6 +276,31 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
writer.NewLine();
isAtStartOfLine = true;
isAfterSpace = false;
}
int GetCallChainLengthLimited(MemberReferenceExpression expr)
{
int callChainLength = 0;
var node = expr;
while (node.Target is InvocationExpression invocation && invocation.Target is MemberReferenceExpression mre && callChainLength < 4) {
node = mre;
callChainLength++;
}
return callChainLength;
}
protected virtual void InsertNewLineWhenInMethodCallChain(MemberReferenceExpression expr)
{
int callChainLength = GetCallChainLengthLimited(expr);
if (callChainLength < 3) return;
if (callChainLength == 3)
writer.Indent();
writer.NewLine();
isAtStartOfLine = true;
isAfterSpace = false;
}
protected virtual void OpenBrace(BraceStyle style)
@ -278,7 +310,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -278,7 +310,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
case BraceStyle.EndOfLine:
case BraceStyle.BannerStyle:
if (!isAtStartOfLine)
writer.Space();
Space();
writer.WriteToken(Roles.LBrace, "{");
break;
case BraceStyle.EndOfLineWithoutSpace:
@ -802,6 +834,12 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -802,6 +834,12 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
invocationExpression.Target.AcceptVisitor(this);
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInParenthesis(invocationExpression.Arguments, policy.SpaceWithinMethodCallParentheses);
if (!(invocationExpression.Parent is MemberReferenceExpression)) {
if (invocationExpression.Target is MemberReferenceExpression mre) {
if (GetCallChainLengthLimited(mre) > 3)
writer.Unindent();
}
}
EndNode(invocationExpression);
}
@ -851,6 +889,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -851,6 +889,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(memberReferenceExpression);
memberReferenceExpression.Target.AcceptVisitor(this);
InsertNewLineWhenInMethodCallChain(memberReferenceExpression);
WriteToken(Roles.Dot);
WriteIdentifier(memberReferenceExpression.MemberNameToken);
WriteTypeArguments(memberReferenceExpression.TypeArguments);
@ -882,6 +921,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -882,6 +921,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(nullReferenceExpression);
writer.WritePrimitiveValue(null);
isAfterSpace = false;
EndNode(nullReferenceExpression);
}
@ -937,6 +977,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -937,6 +977,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(primitiveExpression);
writer.WritePrimitiveValue(primitiveExpression.Value, primitiveExpression.UnsafeLiteralValue);
isAfterSpace = false;
EndNode(primitiveExpression);
}
#endregion
@ -1849,8 +1890,10 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1849,8 +1890,10 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space(policy.SpaceBeforeConstructorDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(constructorDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
if (!constructorDeclaration.Initializer.IsNull) {
Space();
NewLine();
writer.Indent();
constructorDeclaration.Initializer.AcceptVisitor(this);
writer.Unindent();
}
WriteMethodBody(constructorDeclaration.Body, policy.ConstructorBraceStyle);
EndNode(constructorDeclaration);

12
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertMissingTokensDecorator.cs

@ -88,7 +88,10 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -88,7 +88,10 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
if (node != null)
node.Location = start;
}
if (t != null) currentList.Add(t);
if (t != null) {
currentList.Add(t);
t.Role = role;
}
base.WriteKeyword(role, keyword);
}
@ -103,13 +106,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -103,13 +106,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public override void WritePrimitiveValue(object value, string literalValue = null)
{
Expression node = nodes.Peek().LastOrDefault() as Expression;
var startLocation = locationProvider.Location;
base.WritePrimitiveValue(value, literalValue);
if (node is PrimitiveExpression) {
((PrimitiveExpression)node).SetStartLocation(locationProvider.Location);
((PrimitiveExpression)node).SetLocation(startLocation, locationProvider.Location);
}
if (node is NullReferenceExpression) {
((NullReferenceExpression)node).SetStartLocation(locationProvider.Location);
((NullReferenceExpression)node).SetStartLocation(startLocation);
}
base.WritePrimitiveValue(value, literalValue);
}
public override void WritePrimitiveType(string type)

6
ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterOutputFormatter.cs → ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterTokenWriter.cs

@ -128,7 +128,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -128,7 +128,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
case CommentType.SingleLine:
textWriter.Write("//");
textWriter.WriteLine(content);
column += 2 + content.Length;
column = 1;
line++;
needsIndent = true;
isAtStartOfLine = true;
break;
@ -144,7 +145,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -144,7 +145,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
case CommentType.Documentation:
textWriter.Write("///");
textWriter.WriteLine(content);
column += 3 + content.Length;
column = 1;
line++;
needsIndent = true;
isAtStartOfLine = true;
break;

2
ICSharpCode.Decompiler/CSharp/Resolver/LambdaResolveResult.cs

@ -109,7 +109,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -109,7 +109,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// Can differ from <c>ReturnType</c> if a return statement
/// performs an implicit conversion.
/// </summary>
public readonly IType InferredReturnType;
public IType InferredReturnType;
public DecompiledLambdaResolveResult(IL.ILFunction function,
IType delegateType,

329
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -0,0 +1,329 @@ @@ -0,0 +1,329 @@
// Copyright (c) 2017 Daniel Grunwald
//
// 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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.CSharp
{
/// <summary>
/// Given a SyntaxTree that was output from the decompiler, constructs the list of sequence points.
/// </summary>
class SequencePointBuilder : DepthFirstAstVisitor
{
struct StatePerSequencePoint
{
/// <summary>
/// Main AST node associated with this sequence point.
/// </summary>
internal readonly AstNode PrimaryNode;
/// <summary>
/// List of IL intervals that are associated with this sequence point.
/// </summary>
internal readonly List<Interval> Intervals;
/// <summary>
/// The function containing this sequence point.
/// </summary>
internal ILFunction Function;
public StatePerSequencePoint(AstNode primaryNode)
{
this.PrimaryNode = primaryNode;
this.Intervals = new List<Interval>();
this.Function = null;
}
}
readonly List<(ILFunction, SequencePoint)> sequencePoints = new List<(ILFunction, SequencePoint)>();
readonly HashSet<ILInstruction> mappedInstructions = new HashSet<ILInstruction>();
// Stack holding information for outer statements.
readonly Stack<StatePerSequencePoint> outerStates = new Stack<StatePerSequencePoint>();
// Collects information for the current sequence point.
StatePerSequencePoint current;
void VisitAsSequencePoint(AstNode node)
{
if (node.IsNull) return;
StartSequencePoint(node);
node.AcceptVisitor(this);
EndSequencePoint(node.StartLocation, node.EndLocation);
}
protected override void VisitChildren(AstNode node)
{
base.VisitChildren(node);
AddToSequencePoint(node);
}
public override void VisitBlockStatement(BlockStatement blockStatement)
{
foreach (var stmt in blockStatement.Statements) {
VisitAsSequencePoint(stmt);
}
}
public override void VisitForStatement(ForStatement forStatement)
{
// Every element of a for-statement is it's own sequence point.
foreach (var init in forStatement.Initializers) {
VisitAsSequencePoint(init);
}
VisitAsSequencePoint(forStatement.Condition);
foreach (var inc in forStatement.Iterators) {
VisitAsSequencePoint(inc);
}
VisitAsSequencePoint(forStatement.EmbeddedStatement);
}
public override void VisitSwitchStatement(SwitchStatement switchStatement)
{
StartSequencePoint(switchStatement);
switchStatement.Expression.AcceptVisitor(this);
foreach (var section in switchStatement.SwitchSections) {
// note: sections will not contribute to the current sequence point
section.AcceptVisitor(this);
}
// add switch statement itself to sequence point
// (call only after the sections are visited)
AddToSequencePoint(switchStatement);
EndSequencePoint(switchStatement.StartLocation, switchStatement.RParToken.EndLocation);
}
public override void VisitSwitchSection(Syntax.SwitchSection switchSection)
{
// every statement in the switch section is its own sequence point
foreach (var stmt in switchSection.Statements) {
VisitAsSequencePoint(stmt);
}
}
public override void VisitLambdaExpression(LambdaExpression lambdaExpression)
{
AddToSequencePoint(lambdaExpression);
VisitAsSequencePoint(lambdaExpression.Body);
}
public override void VisitUsingStatement(UsingStatement usingStatement)
{
StartSequencePoint(usingStatement);
usingStatement.ResourceAcquisition.AcceptVisitor(this);
VisitAsSequencePoint(usingStatement.EmbeddedStatement);
AddToSequencePoint(usingStatement);
EndSequencePoint(usingStatement.StartLocation, usingStatement.RParToken.EndLocation);
}
public override void VisitForeachStatement(ForeachStatement foreachStatement)
{
var foreachInfo = foreachStatement.Annotation<ForeachAnnotation>();
if (foreachInfo == null) {
base.VisitForeachStatement(foreachStatement);
return;
}
// TODO : Add a sequence point on foreach token (mapped to nop before using instruction).
StartSequencePoint(foreachStatement);
foreachStatement.InExpression.AcceptVisitor(this);
AddToSequencePoint(foreachInfo.GetEnumeratorCall);
EndSequencePoint(foreachStatement.InExpression.StartLocation, foreachStatement.InExpression.EndLocation);
StartSequencePoint(foreachStatement);
AddToSequencePoint(foreachInfo.MoveNextCall);
EndSequencePoint(foreachStatement.InToken.StartLocation, foreachStatement.InToken.EndLocation);
StartSequencePoint(foreachStatement);
AddToSequencePoint(foreachInfo.GetCurrentCall);
EndSequencePoint(foreachStatement.VariableType.StartLocation, foreachStatement.VariableNameToken.EndLocation);
VisitAsSequencePoint(foreachStatement.EmbeddedStatement);
}
public override void VisitLockStatement(LockStatement lockStatement)
{
StartSequencePoint(lockStatement);
lockStatement.Expression.AcceptVisitor(this);
VisitAsSequencePoint(lockStatement.EmbeddedStatement);
AddToSequencePoint(lockStatement);
EndSequencePoint(lockStatement.StartLocation, lockStatement.RParToken.EndLocation);
}
public override void VisitIfElseStatement(IfElseStatement ifElseStatement)
{
StartSequencePoint(ifElseStatement);
ifElseStatement.Condition.AcceptVisitor(this);
VisitAsSequencePoint(ifElseStatement.TrueStatement);
VisitAsSequencePoint(ifElseStatement.FalseStatement);
AddToSequencePoint(ifElseStatement);
EndSequencePoint(ifElseStatement.StartLocation, ifElseStatement.RParToken.EndLocation);
}
public override void VisitWhileStatement(WhileStatement whileStatement)
{
StartSequencePoint(whileStatement);
whileStatement.Condition.AcceptVisitor(this);
VisitAsSequencePoint(whileStatement.EmbeddedStatement);
AddToSequencePoint(whileStatement);
EndSequencePoint(whileStatement.StartLocation, whileStatement.RParToken.EndLocation);
}
public override void VisitDoWhileStatement(DoWhileStatement doWhileStatement)
{
StartSequencePoint(doWhileStatement);
VisitAsSequencePoint(doWhileStatement.EmbeddedStatement);
doWhileStatement.Condition.AcceptVisitor(this);
AddToSequencePoint(doWhileStatement);
EndSequencePoint(doWhileStatement.WhileToken.StartLocation, doWhileStatement.RParToken.EndLocation);
}
public override void VisitFixedStatement(FixedStatement fixedStatement)
{
foreach (var v in fixedStatement.Variables) {
VisitAsSequencePoint(v);
}
VisitAsSequencePoint(fixedStatement.EmbeddedStatement);
}
/// <summary>
/// Start a new C# statement = new sequence point.
/// </summary>
void StartSequencePoint(AstNode primaryNode)
{
outerStates.Push(current);
current = new StatePerSequencePoint(primaryNode);
}
void EndSequencePoint(TextLocation startLocation, TextLocation endLocation)
{
Debug.Assert(!startLocation.IsEmpty, "missing startLocation");
Debug.Assert(!endLocation.IsEmpty, "missing endLocation");
if (current.Intervals.Count > 0 && current.Function != null) {
// use LongSet to deduplicate and merge the intervals
var longSet = new LongSet(current.Intervals.Select(i => new LongInterval(i.Start, i.End)));
Debug.Assert(!longSet.IsEmpty);
sequencePoints.Add((current.Function, new SequencePoint {
Offset = (int)longSet.Intervals[0].Start,
EndOffset = (int)longSet.Intervals[0].End,
StartLine = startLocation.Line,
StartColumn = startLocation.Column,
EndLine = endLocation.Line,
EndColumn = endLocation.Column
}));
}
current = outerStates.Pop();
}
/// <summary>
/// Add the ILAst instruction associated with the AstNode to the sequence point.
/// Also add all its ILAst sub-instructions (unless they were already added to another sequence point).
/// </summary>
void AddToSequencePoint(AstNode node)
{
foreach (var inst in node.Annotations.OfType<ILInstruction>()) {
AddToSequencePoint(inst);
}
}
void AddToSequencePoint(ILInstruction inst)
{
if (!mappedInstructions.Add(inst)) {
// inst was already used by a nested sequence point within this sequence point
return;
}
// Add the IL range associated with this instruction to the current sequence point.
if (HasUsableILRange(inst) && current.Intervals != null) {
current.Intervals.Add(inst.ILRange);
var function = inst.Parent.Ancestors.OfType<ILFunction>().FirstOrDefault();
Debug.Assert(current.Function == null || current.Function == function);
current.Function = function;
}
// Do not add instructions of lambdas/delegates.
if (inst is ILFunction)
return;
// Also add the child IL instructions, unless they were already processed by
// another C# expression.
foreach (var child in inst.Children) {
AddToSequencePoint(child);
}
}
internal static bool HasUsableILRange(ILInstruction inst)
{
if (inst.ILRange.IsEmpty)
return false;
return !(inst is BlockContainer || inst is Block);
}
/// <summary>
/// Called after the visitor is done to return the results.
/// </summary>
internal Dictionary<ILFunction, List<SequencePoint>> GetSequencePoints()
{
var dict = new Dictionary<ILFunction, List<SequencePoint>>();
foreach (var (function, sequencePoint) in this.sequencePoints) {
if (!dict.TryGetValue(function, out var list)) {
dict.Add(function, list = new List<SequencePoint>());
}
list.Add(sequencePoint);
}
foreach (var (function, list) in dict.ToList()) {
// For each function, sort sequence points and fix overlaps+gaps
var newList = new List<SequencePoint>();
int pos = 0;
foreach (var sequencePoint in list.OrderBy(sp => sp.Offset).ThenBy(sp => sp.EndOffset)) {
if (sequencePoint.Offset < pos) {
// overlapping sequence point?
// delete previous sequence points that are after sequencePoint.Offset
while (newList.Count > 0 && newList.Last().EndOffset > pos) {
var last = newList.Last();
if (last.Offset >= sequencePoint.Offset) {
newList.RemoveAt(newList.Count - 1);
} else {
last.EndOffset = sequencePoint.Offset;
newList[newList.Count - 1] = last;
}
}
} else if (sequencePoint.Offset > pos) {
// insert hidden sequence point in the gap.
var hidden = new SequencePoint();
hidden.Offset = pos;
hidden.EndOffset = sequencePoint.Offset;
hidden.SetHidden();
newList.Add(hidden);
}
newList.Add(sequencePoint);
pos = sequencePoint.EndOffset;
}
if (pos < function.CecilMethod.Body.CodeSize) {
var hidden = new SequencePoint();
hidden.Offset = pos;
hidden.EndOffset = function.CecilMethod.Body.CodeSize;
hidden.SetHidden();
newList.Add(hidden);
}
dict[function] = newList;
}
return dict;
}
}
}

1
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -506,6 +506,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -506,6 +506,7 @@ namespace ICSharpCode.Decompiler.CSharp
};
// Add the variable annotation for highlighting (TokenTextWriter expects it directly on the ForeachStatement).
foreachStmt.AddAnnotation(new ILVariableResolveResult(foreachVariable, foreachVariable.Type));
foreachStmt.AddAnnotation(new ForeachAnnotation(inst.ResourceExpression, loop.Conditions.Single(), singleGetter));
// If there was an optional return statement, return it as well.
if (optionalReturnAfterLoop != null) {
return new BlockStatement {

6
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/PrimitiveExpression.cs

@ -43,11 +43,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,11 +43,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
internal void SetStartLocation(TextLocation value)
internal void SetLocation(TextLocation startLocation, TextLocation endLocation)
{
ThrowIfFrozen();
this.startLocation = value;
this.endLocation = null;
this.startLocation = startLocation;
this.endLocation = endLocation;
}
string literalValue;

15
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs

@ -43,15 +43,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -43,15 +43,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
this.context = context;
this.usingScope = this.rootUsingScope = rootNode.Annotation<UsingScope>();
currentMember = context.DecompiledMember;
SetContext();
rootNode.AcceptVisitor(this);
}
void SetContext()
{
this.usingScope = rootUsingScope;
foreach (var name in currentMember.Namespace.Split('.'))
usingScope = new UsingScope(usingScope, name);
resolveContext = new CSharpTypeResolveContext(currentMember.ParentAssembly, usingScope.Resolve(context.TypeSystem.Compilation), currentMember.DeclaringTypeDefinition, currentMember);
string ns = currentMember?.Namespace ?? context.DecompiledTypeDefinition?.Namespace;
if (ns != null) {
foreach (var name in ns.Split('.'))
usingScope = new UsingScope(usingScope, name);
}
resolveContext = new CSharpTypeResolveContext(
context.DecompiledAssembly,
usingScope.Resolve(context.TypeSystem.Compilation),
currentMember?.DeclaringTypeDefinition ?? context.DecompiledTypeDefinition,
currentMember);
resolver = new CSharpResolver(resolveContext);
}

4
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -69,7 +69,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -69,7 +69,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
case "System.Type.GetTypeFromHandle":
if (arguments.Length == 1) {
if (typeHandleOnTypeOfPattern.IsMatch(arguments[0])) {
invocationExpression.ReplaceWith(((MemberReferenceExpression)arguments[0]).Target);
Expression target = ((MemberReferenceExpression)arguments[0]).Target;
target.CopyInstructionsFrom(invocationExpression);
invocationExpression.ReplaceWith(target);
return;
}
}

30
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -173,16 +173,26 @@ namespace ICSharpCode.Decompiler.CSharp @@ -173,16 +173,26 @@ namespace ICSharpCode.Decompiler.CSharp
var type = this.Type;
if (type.Equals(targetType)) {
// Make explicit conversion implicit, if possible
if (allowImplicitConversion && ResolveResult is ConversionResolveResult conversion) {
if (Expression is CastExpression cast
&& (type.IsKnownType(KnownTypeCode.Object) && conversion.Conversion.IsBoxingConversion
|| type.Kind == TypeKind.Delegate && conversion.Conversion.IsAnonymousFunctionConversion
)) {
return this.UnwrapChild(cast.Expression);
} else if (Expression is ObjectCreateExpression oce && conversion.Conversion.IsMethodGroupConversion
&& oce.Arguments.Count == 1 && expressionBuilder.settings.UseImplicitMethodGroupConversion)
{
return this.UnwrapChild(oce.Arguments.Single());
if (allowImplicitConversion) {
switch (ResolveResult) {
case ConversionResolveResult conversion: {
if (Expression is CastExpression cast
&& (type.IsKnownType(KnownTypeCode.Object) && conversion.Conversion.IsBoxingConversion
|| type.Kind == TypeKind.Delegate && conversion.Conversion.IsAnonymousFunctionConversion
)) {
return this.UnwrapChild(cast.Expression);
} else if (Expression is ObjectCreateExpression oce && conversion.Conversion.IsMethodGroupConversion
&& oce.Arguments.Count == 1 && expressionBuilder.settings.UseImplicitMethodGroupConversion) {
return this.UnwrapChild(oce.Arguments.Single());
}
break;
}
case InvocationResolveResult invocation: {
if (Expression is ObjectCreateExpression oce && oce.Arguments.Count == 1 && invocation.Type.IsKnownType(KnownTypeCode.NullableOfT)) {
return this.UnwrapChild(oce.Arguments.Single());
}
break;
}
}
}
return this;

4
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -283,8 +283,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -283,8 +283,8 @@ namespace ICSharpCode.Decompiler.CSharp
const string prop = "Properties";
if (directories.Add(prop))
Directory.CreateDirectory(Path.Combine(targetDirectory, prop));
string assemblyInfo = Path.Combine(targetDirectory, prop, "AssemblyInfo.cs");
using (StreamWriter w = new StreamWriter(assemblyInfo)) {
string assemblyInfo = Path.Combine(prop, "AssemblyInfo.cs");
using (StreamWriter w = new StreamWriter(Path.Combine(targetDirectory, assemblyInfo))) {
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, settings.CSharpFormattingOptions));
}
return new Tuple<string, string>[] { Tuple.Create("Compile", assemblyInfo) };

45
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -375,8 +375,49 @@ namespace ICSharpCode.Decompiler @@ -375,8 +375,49 @@ namespace ICSharpCode.Decompiler
}
}
}
bool showDebugInfo;
public bool ShowDebugInfo {
get { return showDebugInfo; }
set {
if (showDebugInfo != value) {
showDebugInfo = value;
OnPropertyChanged();
}
}
}
#endregion
#region Assembly Load and Resolve options
bool loadInMemory = false;
public bool LoadInMemory {
get { return loadInMemory; }
set {
if (loadInMemory != value) {
loadInMemory = value;
OnPropertyChanged();
}
}
}
bool throwOnAssemblyResolveErrors = false;
public bool ThrowOnAssemblyResolveErrors {
get { return throwOnAssemblyResolveErrors; }
set {
if (throwOnAssemblyResolveErrors != value) {
throwOnAssemblyResolveErrors = value;
OnPropertyChanged();
}
}
}
#endregion
CSharpFormattingOptions csharpFormattingOptions;
public CSharpFormattingOptions CSharpFormattingOptions {
@ -397,7 +438,7 @@ namespace ICSharpCode.Decompiler @@ -397,7 +438,7 @@ namespace ICSharpCode.Decompiler
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)

80
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -21,28 +21,38 @@ using System.Collections.Generic; @@ -21,28 +21,38 @@ using System.Collections.Generic;
using System.Threading;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
namespace ICSharpCode.Decompiler.Disassembler
{
/// <summary>
/// Disassembles a method body.
/// </summary>
public sealed class MethodBodyDisassembler
public class MethodBodyDisassembler
{
readonly ITextOutput output;
readonly bool detectControlStructure;
readonly CancellationToken cancellationToken;
public MethodBodyDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken)
/// <summary>
/// Show .try/finally as blocks in IL code; indent loops.
/// </summary>
public bool DetectControlStructure { get; set; } = true;
/// <summary>
/// Show sequence points if debug information is loaded in Cecil.
/// </summary>
public bool ShowSequencePoints { get; set; }
Collection<SequencePoint> sequencePoints;
int nextSequencePointIndex;
public MethodBodyDisassembler(ITextOutput output, CancellationToken cancellationToken)
{
if (output == null)
throw new ArgumentNullException(nameof(output));
this.output = output;
this.detectControlStructure = detectControlStructure;
this.output = output ?? throw new ArgumentNullException(nameof(output));
this.cancellationToken = cancellationToken;
}
public void Disassemble(MethodBody body/*, MemberMapping methodMapping*/)
public virtual void Disassemble(MethodBody body)
{
// start writing IL code
MethodDefinition method = body.Method;
@ -55,30 +65,20 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -55,30 +65,20 @@ namespace ICSharpCode.Decompiler.Disassembler
DisassembleLocalsBlock(body);
output.WriteLine();
if (detectControlStructure && body.Instructions.Count > 0) {
sequencePoints = method.DebugInformation?.SequencePoints;
nextSequencePointIndex = 0;
if (DetectControlStructure && body.Instructions.Count > 0) {
Instruction inst = body.Instructions[0];
HashSet<int> branchTargets = GetBranchTargets(body.Instructions);
WriteStructureBody(new ILStructure(body), branchTargets, ref inst, method.Body.CodeSize);
} else {
foreach (var inst in method.Body.Instructions) {
//var startLocation = output.Location;
inst.WriteTo(output);
/*
if (debugSymbols != null) {
// add IL code mappings - used in debugger
debugSymbols.SequencePoints.Add(
new SequencePoint() {
StartLocation = output.Location,
EndLocation = output.Location,
ILRanges = new ILRange[] { new ILRange(inst.Offset, inst.Next == null ? method.Body.CodeSize : inst.Next.Offset) }
});
}*/
WriteInstruction(output, inst);
output.WriteLine();
}
WriteExceptionHandlers(body);
}
sequencePoints = null;
}
private void DisassembleLocalsBlock(MethodBody body)
@ -191,19 +191,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -191,19 +191,7 @@ namespace ICSharpCode.Decompiler.Disassembler
if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) {
output.WriteLine(); // put an empty line after branches, and in front of branch targets
}
//var startLocation = output.Location;
inst.WriteTo(output);
/*// add IL code mappings - used in debugger
if (debugSymbols != null) {
debugSymbols.SequencePoints.Add(
new SequencePoint() {
StartLocation = startLocation,
EndLocation = output.Location,
ILRanges = new ILRange[] { new ILRange(inst.Offset, inst.Next == null ? codeSize : inst.Next.Offset) }
});
}*/
WriteInstruction(output, inst);
output.WriteLine();
prevInstructionWasBranch = inst.OpCode.FlowControl == FlowControl.Branch
@ -237,5 +225,25 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -237,5 +225,25 @@ namespace ICSharpCode.Decompiler.Disassembler
throw new NotSupportedException();
}
}
protected virtual void WriteInstruction(ITextOutput output, Instruction instruction)
{
if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count) {
SequencePoint sp = sequencePoints[nextSequencePointIndex];
if (sp.Offset <= instruction.Offset) {
output.Write("// sequence point: ");
if (sp.Offset != instruction.Offset) {
output.Write("!! at " + DisassemblerHelpers.OffsetToString(sp.Offset) + " !!");
}
if (sp.IsHidden) {
output.WriteLine("hidden");
} else {
output.WriteLine($"(line {sp.StartLine}, col {sp.StartColumn}) to (line {sp.EndLine}, col {sp.EndColumn}) in {sp.Document?.Url}");
}
nextSequencePointIndex++;
}
}
instruction.WriteTo(output);
}
}
}

19
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -35,13 +35,28 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -35,13 +35,28 @@ namespace ICSharpCode.Decompiler.Disassembler
MethodBodyDisassembler methodBodyDisassembler;
MemberReference currentMember;
public ReflectionDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken)
public bool DetectControlStructure {
get => methodBodyDisassembler.DetectControlStructure;
set => methodBodyDisassembler.DetectControlStructure = value;
}
public bool ShowSequencePoints {
get => methodBodyDisassembler.ShowSequencePoints;
set => methodBodyDisassembler.ShowSequencePoints = value;
}
public ReflectionDisassembler(ITextOutput output, CancellationToken cancellationToken)
: this(output, new MethodBodyDisassembler(output, cancellationToken), cancellationToken)
{
}
public ReflectionDisassembler(ITextOutput output, MethodBodyDisassembler methodBodyDisassembler, CancellationToken cancellationToken)
{
if (output == null)
throw new ArgumentNullException(nameof(output));
this.output = output;
this.cancellationToken = cancellationToken;
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken);
this.methodBodyDisassembler = methodBodyDisassembler;
}
#region Disassemble Method

2
ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs

@ -52,7 +52,7 @@ namespace ICSharpCode.Decompiler @@ -52,7 +52,7 @@ namespace ICSharpCode.Decompiler
var depsJsonFileName = Path.Combine(basePath, $"{assemblyName}.deps.json");
if (!File.Exists(depsJsonFileName)) {
loadInfo.AddMessage(assemblyName, MessageKind.Error, $"{assemblyName}.deps.json could not be found!");
loadInfo.AddMessage(assemblyName, MessageKind.Warning, $"{assemblyName}.deps.json could not be found!");
return;
}

352
ICSharpCode.Decompiler/DotNetCore/UniversalAssemblyResolver.cs

@ -0,0 +1,352 @@ @@ -0,0 +1,352 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
namespace ICSharpCode.Decompiler
{
public class UniversalAssemblyResolver : IAssemblyResolver
{
DotNetCorePathFinder dotNetCorePathFinder;
readonly bool throwOnError;
readonly string mainAssemblyFileName;
readonly string baseDirectory;
readonly Dictionary<string, UnresolvedAssemblyNameReference> loadedAssemblyReferences;
readonly List<string> directories;
readonly List<string> gac_paths = GetGacPaths();
public static readonly bool OnMono = Type.GetType("Mono.Runtime") != null;
public event AssemblyResolveEventHandler ResolveFailed;
public void AddSearchDirectory(string directory)
{
directories.Add(directory);
}
public void RemoveSearchDirectory(string directory)
{
directories.Remove(directory);
}
public string[] GetSearchDirectories()
{
return directories.ToArray();
}
public string TargetFramework { get; set; }
private UniversalAssemblyResolver(string mainAssemblyFileName, bool throwOnError)
{
this.mainAssemblyFileName = mainAssemblyFileName;
this.baseDirectory = Path.GetDirectoryName(mainAssemblyFileName);
this.throwOnError = throwOnError;
if (string.IsNullOrWhiteSpace(this.baseDirectory))
this.baseDirectory = Environment.CurrentDirectory;
AddSearchDirectory(baseDirectory);
}
public static ModuleDefinition LoadMainModule(string mainAssemblyFileName, bool throwOnError = true, bool inMemory = false)
{
var resolver = new UniversalAssemblyResolver(mainAssemblyFileName, throwOnError);
var module = ModuleDefinition.ReadModule(mainAssemblyFileName, new ReaderParameters {
AssemblyResolver = resolver,
InMemory = inMemory
});
resolver.TargetFramework = module.Assembly.DetectTargetFrameworkId();
return module;
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
return Resolve(name, new ReaderParameters());
}
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
var targetFramework = TargetFramework.Split(new[] { ",Version=v" }, StringSplitOptions.None);
string file = null;
switch (targetFramework[0]) {
case ".NETCoreApp":
case ".NETStandard":
if (targetFramework.Length != 2) goto default;
if (dotNetCorePathFinder == null) {
var version = targetFramework[1].Length == 3 ? targetFramework[1] + ".0" : targetFramework[1];
dotNetCorePathFinder = new DotNetCorePathFinder(mainAssemblyFileName, TargetFramework, version, this.loadedAssemblyReferences);
}
file = dotNetCorePathFinder.TryResolveDotNetCore(name);
if (file == null)
goto default;
else {
var asm = ModuleDefinition.ReadModule(file, parameters).Assembly;
if (throwOnError && asm == null)
throw new AssemblyResolutionException(name);
return asm;
}
default:
return ResolveInternal(name, parameters);
}
}
AssemblyDefinition ResolveInternal(AssemblyNameReference name, ReaderParameters parameters)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));
var assembly = SearchDirectory(name, directories, parameters);
if (assembly != null)
return assembly;
if (name.IsRetargetable) {
// if the reference is retargetable, zero it
name = new AssemblyNameReference(name.Name, ZeroVersion) {
PublicKeyToken = Empty<byte>.Array,
};
}
var framework_dir = Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName);
var framework_dirs = OnMono
? new[] { framework_dir, Path.Combine(framework_dir, "Facades") }
: new[] { framework_dir };
if (IsZero(name.Version)) {
assembly = SearchDirectory(name, framework_dirs, parameters);
if (assembly != null)
return assembly;
}
if (name.Name == "mscorlib") {
assembly = GetCorlib(name, parameters);
if (assembly != null)
return assembly;
}
assembly = GetAssemblyInGac(name, parameters);
if (assembly != null)
return assembly;
assembly = SearchDirectory(name, framework_dirs, parameters);
if (assembly != null)
return assembly;
if (ResolveFailed != null) {
assembly = ResolveFailed(this, name);
if (assembly != null)
return assembly;
}
if (throwOnError)
throw new AssemblyResolutionException(name);
return null;
}
#region .NET / mono GAC handling
AssemblyDefinition SearchDirectory(AssemblyNameReference name, IEnumerable<string> directories, ReaderParameters parameters)
{
var extensions = name.IsWindowsRuntime ? new[] { ".winmd", ".dll" } : new[] { ".exe", ".dll" };
foreach (var directory in directories) {
foreach (var extension in extensions) {
string file = Path.Combine(directory, name.Name + extension);
if (!File.Exists(file))
continue;
try {
return GetAssembly(file, parameters);
} catch (System.BadImageFormatException) {
continue;
}
}
}
return null;
}
static bool IsZero(Version version)
{
return version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0;
}
static Version ZeroVersion = new Version(0, 0, 0, 0);
AssemblyDefinition GetCorlib(AssemblyNameReference reference, ReaderParameters parameters)
{
var version = reference.Version;
var corlib = typeof(object).Assembly.GetName();
if (corlib.Version == version || IsZero(version))
return GetAssembly(typeof(object).Module.FullyQualifiedName, parameters);
var path = Directory.GetParent(
Directory.GetParent(
typeof(object).Module.FullyQualifiedName).FullName
).FullName;
if (OnMono) {
if (version.Major == 1)
path = Path.Combine(path, "1.0");
else if (version.Major == 2) {
if (version.MajorRevision == 5)
path = Path.Combine(path, "2.1");
else
path = Path.Combine(path, "2.0");
} else if (version.Major == 4)
path = Path.Combine(path, "4.0");
else
throw new NotSupportedException("Version not supported: " + version);
} else {
switch (version.Major) {
case 1:
if (version.MajorRevision == 3300)
path = Path.Combine(path, "v1.0.3705");
else
path = Path.Combine(path, "v1.0.5000.0");
break;
case 2:
path = Path.Combine(path, "v2.0.50727");
break;
case 4:
path = Path.Combine(path, "v4.0.30319");
break;
default:
throw new NotSupportedException("Version not supported: " + version);
}
}
var file = Path.Combine(path, "mscorlib.dll");
if (File.Exists(file))
return GetAssembly(file, parameters);
return null;
}
static List<string> GetGacPaths()
{
if (OnMono)
return GetDefaultMonoGacPaths();
var paths = new List<string>(2);
var windir = Environment.GetEnvironmentVariable("WINDIR");
if (windir == null)
return paths;
paths.Add(Path.Combine(windir, "assembly"));
paths.Add(Path.Combine(windir, Path.Combine("Microsoft.NET", "assembly")));
return paths;
}
static List<string> GetDefaultMonoGacPaths()
{
var paths = new List<string>(1);
var gac = GetCurrentMonoGac();
if (gac != null)
paths.Add(gac);
var gac_paths_env = Environment.GetEnvironmentVariable("MONO_GAC_PREFIX");
if (string.IsNullOrEmpty(gac_paths_env))
return paths;
var prefixes = gac_paths_env.Split(Path.PathSeparator);
foreach (var prefix in prefixes) {
if (string.IsNullOrEmpty(prefix))
continue;
var gac_path = Path.Combine(Path.Combine(Path.Combine(prefix, "lib"), "mono"), "gac");
if (Directory.Exists(gac_path) && !paths.Contains(gac))
paths.Add(gac_path);
}
return paths;
}
static string GetCurrentMonoGac()
{
return Path.Combine(
Directory.GetParent(
Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName)).FullName,
"gac");
}
AssemblyDefinition GetAssembly(string file, ReaderParameters parameters)
{
if (parameters.AssemblyResolver == null)
parameters.AssemblyResolver = this;
return ModuleDefinition.ReadModule(file, parameters).Assembly;
}
AssemblyDefinition GetAssemblyInGac(AssemblyNameReference reference, ReaderParameters parameters)
{
if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0)
return null;
if (OnMono)
return GetAssemblyInMonoGac(reference, parameters);
return GetAssemblyInNetGac(reference, parameters);
}
AssemblyDefinition GetAssemblyInMonoGac(AssemblyNameReference reference, ReaderParameters parameters)
{
for (int i = 0; i < gac_paths.Count; i++) {
var gac_path = gac_paths[i];
var file = GetAssemblyFile(reference, string.Empty, gac_path);
if (File.Exists(file))
return GetAssembly(file, parameters);
}
return null;
}
AssemblyDefinition GetAssemblyInNetGac(AssemblyNameReference reference, ReaderParameters parameters)
{
var gacs = new[] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" };
var prefixes = new[] { string.Empty, "v4.0_" };
for (int i = 0; i < 2; i++) {
for (int j = 0; j < gacs.Length; j++) {
var gac = Path.Combine(gac_paths[i], gacs[j]);
var file = GetAssemblyFile(reference, prefixes[i], gac);
if (Directory.Exists(gac) && File.Exists(file))
return GetAssembly(file, parameters);
}
}
return null;
}
static string GetAssemblyFile(AssemblyNameReference reference, string prefix, string gac)
{
var gac_folder = new StringBuilder()
.Append(prefix)
.Append(reference.Version)
.Append("__");
for (int i = 0; i < reference.PublicKeyToken.Length; i++)
gac_folder.Append(reference.PublicKeyToken[i].ToString("x2"));
return Path.Combine(
Path.Combine(
Path.Combine(gac, reference.Name), gac_folder.ToString()),
reference.Name + ".dll");
}
#endregion
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
}
}

22
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -24,21 +24,23 @@ @@ -24,21 +24,23 @@
<!-- HACK: Disable package generation on Unix due to tooling issues. -->
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IncludeSymbols>true</IncludeSymbols>
<IncludeSymbolsInPackage>true</IncludeSymbolsInPackage>
<NuspecFile>ICSharpCode.Decompiler.nuspec</NuspecFile>
<NuspecProperties>Configuration=$(Configuration)</NuspecProperties>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DebugType>full</DebugType>
<DebugType>portable</DebugType>
<DebugSymbols>true</DebugSymbols>
<EmbedSources>true</EmbedSources>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>$(DefineConstants);STEP</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugType>pdbonly</DebugType>
<DebugType>portable</DebugType>
<DebugSymbols>true</DebugSymbols>
<EmbedSources>true</EmbedSources>
</PropertyGroup>
<PropertyGroup>
@ -60,6 +62,7 @@ @@ -60,6 +62,7 @@
<ItemGroup>
<Compile Include="CSharp\Annotations.cs" />
<Compile Include="CSharp\CallBuilder.cs" />
<Compile Include="CSharp\SequencePointBuilder.cs" />
<Compile Include="CSharp\Syntax\AstNode.cs" />
<Compile Include="CSharp\Syntax\AstNodeCollection.cs" />
<Compile Include="CSharp\Syntax\AstType.cs" />
@ -202,7 +205,7 @@ @@ -202,7 +205,7 @@
<Compile Include="CSharp\OutputVisitor\InsertRequiredSpacesDecorator.cs" />
<Compile Include="CSharp\OutputVisitor\InsertSpecialsDecorator.cs" />
<Compile Include="CSharp\OutputVisitor\ITokenWriter.cs" />
<Compile Include="CSharp\OutputVisitor\TextWriterOutputFormatter.cs" />
<Compile Include="CSharp\OutputVisitor\TextWriterTokenWriter.cs" />
<Compile Include="CSharp\Resolver\AliasNamespaceResolveResult.cs" />
<Compile Include="CSharp\Resolver\AliasTypeResolveResult.cs" />
<Compile Include="CSharp\Resolver\AwaitResolveResult.cs" />
@ -271,8 +274,12 @@ @@ -271,8 +274,12 @@
<Compile Include="Documentation\XmlDocumentationProvider.cs" />
<Compile Include="DotNetCore\DotNetCorePathFinder.cs" />
<Compile Include="DotNetCore\DotNetCorePathFinderExtensions.cs" />
<Compile Include="DotNetCore\UniversalAssemblyResolver.cs" />
<Compile Include="DotNetCore\UnresolvedAssemblyNameReference.cs" />
<Compile Include="IL\ILAstWritingOptions.cs" />
<Compile Include="IL\SequencePoint.cs" />
<Compile Include="IL\Instructions\CallIndirect.cs" />
<Compile Include="IL\Instructions\DefaultValue.cs" />
<Compile Include="IL\Transforms\EarlyExpressionTransforms.cs" />
<Compile Include="IL\Transforms\ProxyCallReplacer.cs" />
<Compile Include="IL\Instructions\StringToInt.cs" />
@ -583,4 +590,11 @@ @@ -583,4 +590,11 @@
</PropertyGroup>
<Exec WorkingDirectory="$(SolutionDir)" Command="$(UpdateAssemblyInfo)" Timeout="60000" />
</Target>
<!-- Workaround for EmbedSources support, see https://github.com/dotnet/roslyn/issues/19127 -->
<Target Name="PopulateEmbeddedFiles" AfterTargets="BeforeCompile" BeforeTargets="CoreCompile">
<ItemGroup>
<EmbeddedFiles Include="@(Compile)" />
</ItemGroup>
</Target>
</Project>

15
ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec → ICSharpCode.Decompiler/ICSharpCode.Decompiler.nuspec.template

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>ICSharpCode.Decompiler</id>
<version>3.0.0-alpha3</version>
<version>$INSERTVERSION$$INSERTVERSIONNAMEPOSTFIX$</version>
<title>ILSpy Decompiler Engine</title>
<authors>Daniel Grunwald, David Srbecky, Ed Harvey, Siegfried Pammer</authors>
<owners>Daniel Grunwald, SharpDevelop</owners>
@ -12,12 +12,13 @@ @@ -12,12 +12,13 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>ICSharpCode.Decompiler is the decompiler engine used in ILSpy.</description>
<!--<releaseNotes></releaseNotes>-->
<copyright>Copyright 2011-2017 AlphaSierraPapa</copyright>
<copyright>Copyright 2011-$INSERTYEAR$ AlphaSierraPapa</copyright>
<tags>C# Decompiler ILSpy</tags>
<dependencies>
<dependency id="System.Collections.Immutable" version="1.3.0" />
<dependency id="System.ValueTuple" version="4.3.0" />
<dependency id="Newtonsoft.Json" version="10.0.3" />
<dependency id="Humanizer.Core" version="2.2.0" />
<dependency id="Newtonsoft.Json" version="10.0.3" />
<dependency id="System.Collections.Immutable" version="1.4.0" />
<dependency id="System.ValueTuple" version="4.4.0" />
</dependencies>
</metadata>
<files>
@ -30,9 +31,5 @@ @@ -30,9 +31,5 @@
<file src="bin\$Configuration$\netstandard2.0\ICSharpCode.Decompiler.pdb" target="lib\netstandard2.0" />
<file src="bin\$Configuration$\netstandard2.0\Mono.Cecil.dll" target="lib\netstandard2.0" />
<file src="bin\$Configuration$\netstandard2.0\Mono.Cecil.pdb" target="lib\netstandard2.0" />
<file src="**\*.cs" exclude="obj\**\*.cs" target="src\ICSharpCode.Decompiler" />
<file src="obj\$Configuration$\net461\**\*.cs" target="src\ICSharpCode.Decompiler\obj\$Configuration$\net461" />
<file src="obj\$Configuration$\netstandard2.0\**\*.cs" target="src\ICSharpCode.Decompiler\obj\$Configuration$\netstandard2.0" />
</files>
</package>

17
ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs

@ -172,10 +172,19 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -172,10 +172,19 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (DetectExitPoints.CompatibleExitInstruction(trueExitInst, falseExitInst)) {
// if (...) { ...; goto exitPoint; } goto nextBlock; nextBlock: ...; goto exitPoint;
// -> if (...) { ... } else { ... } goto exitPoint;
context.Step("Inline block as else-branch", ifInst);
targetBlock.Instructions.RemoveAt(targetBlock.Instructions.Count - 1);
targetBlock.Remove();
ifInst.FalseInst = targetBlock;
// the else block is not empty or nop-only:
if (targetBlock.Children.Any(inst => !(inst is Nop) && inst != falseExitInst)) {
context.Step("Inline block as else-branch", ifInst);
targetBlock.Instructions.RemoveAt(targetBlock.Instructions.Count - 1);
targetBlock.Remove();
ifInst.FalseInst = targetBlock;
} else {
// the else block is empty or nop-only and can be safely removed:
context.Step("Remove empty else-branch", ifInst);
targetBlock.Instructions.RemoveAt(targetBlock.Instructions.Count - 1);
targetBlock.Remove();
}
exitInst = block.Instructions[block.Instructions.Count - 1] = falseExitInst;
Block trueBlock = ifInst.TrueInst as Block;
if (trueBlock != null) {

20
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -44,9 +44,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -44,9 +44,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
foreach (var block in function.Descendants.OfType<Block>()) {
context.CancellationToken.ThrowIfCancellationRequested();
// Remove 'nop' instructions
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.Nop);
RemoveNopInstructions(block);
InlineVariableInReturnBlock(block, context);
// 1st pass SimplifySwitchInstruction before SimplifyBranchChains()
// starts duplicating return instructions.
@ -55,7 +54,20 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -55,7 +54,20 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
SimplifyBranchChains(function, context);
CleanUpEmptyBlocks(function, context);
}
private static void RemoveNopInstructions(Block block)
{
// Move ILRanges of special nop instructions to the previous non-nop instruction.
for (int i = block.Instructions.Count - 1; i > 0; i--) {
if (block.Instructions[i] is Nop nop && nop.Kind == NopKind.Pop) {
block.Instructions[i - 1].AddILRange(nop.ILRange);
}
}
// Remove 'nop' instructions
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.Nop);
}
void InlineVariableInReturnBlock(Block block, ILTransformContext context)
{
// In debug mode, the C#-compiler generates 'return blocks' that

81
ICSharpCode.Decompiler/IL/ILAstWritingOptions.cs

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
// Copyright (c) 2017 Daniel Grunwald
//
// 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.ComponentModel;
using System.Runtime.CompilerServices;
namespace ICSharpCode.Decompiler.IL
{
public class ILAstWritingOptions : INotifyPropertyChanged
{
private bool useLogicOperationSugar;
private bool useFieldSugar;
private bool showILRanges;
/// <summary>
/// Sugar for logic.not/and/or.
/// </summary>
public bool UseLogicOperationSugar {
get { return useLogicOperationSugar; }
set {
if (useLogicOperationSugar != value) {
useLogicOperationSugar = value;
OnPropertyChanged();
}
}
}
/// <summary>
/// Sugar for ldfld/stfld.
/// </summary>
public bool UseFieldSugar {
get { return useFieldSugar; }
set {
if (useFieldSugar != value) {
useFieldSugar = value;
OnPropertyChanged();
}
}
}
/// <summary>
/// Show IL ranges in ILAst output.
/// </summary>
public bool ShowILRanges {
get { return showILRanges; }
set {
if (showILRanges != value) {
showILRanges = value;
OnPropertyChanged();
}
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChanged?.Invoke(this, e);
}
public event PropertyChangedEventHandler PropertyChanged;
}
}

9
ICSharpCode.Decompiler/IL/ILReader.cs

@ -304,7 +304,8 @@ namespace ICSharpCode.Decompiler.IL @@ -304,7 +304,8 @@ namespace ICSharpCode.Decompiler.IL
inst.WriteTo(output, new ILAstWritingOptions());
output.WriteLine();
}
new Disassembler.MethodBodyDisassembler(output, false, cancellationToken).WriteExceptionHandlers(body);
new Disassembler.MethodBodyDisassembler(output, cancellationToken) { DetectControlStructure = false }
.WriteExceptionHandlers(body);
}
/// <summary>
@ -649,7 +650,7 @@ namespace ICSharpCode.Decompiler.IL @@ -649,7 +650,7 @@ namespace ICSharpCode.Decompiler.IL
return BinaryNumeric(BinaryNumericOperator.BitOr);
case Cil.Code.Pop:
Pop();
return new Nop();
return new Nop() { Kind = NopKind.Pop };
case Cil.Code.Rem:
return BinaryNumeric(BinaryNumericOperator.Rem, false, Sign.Signed);
case Cil.Code.Rem_Un:
@ -1010,7 +1011,9 @@ namespace ICSharpCode.Decompiler.IL @@ -1010,7 +1011,9 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction InitObj(ILInstruction target, IType type)
{
return new StObj(target, new DefaultValue(type), type);
var value = new DefaultValue(type);
value.ILStackWasEmpty = currentStack.IsEmpty;
return new StObj(target, value, type);
}
private ILInstruction DecodeConstrainedCall()

11
ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL
{
@ -50,5 +51,15 @@ namespace ICSharpCode.Decompiler.IL @@ -50,5 +51,15 @@ namespace ICSharpCode.Decompiler.IL
else
output.WriteReference(symbol.Name, symbol);
}
public static void WriteTo(this Interval interval, ITextOutput output, ILAstWritingOptions options)
{
if (!options.ShowILRanges)
return;
if (interval.IsEmpty)
output.Write("[empty] ");
else
output.Write($"[{interval.Start:x4}..{interval.InclusiveEnd:x4}] ");
}
}
}

37
ICSharpCode.Decompiler/IL/Instructions.cs

@ -297,6 +297,7 @@ namespace ICSharpCode.Decompiler.IL @@ -297,6 +297,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write('(');
this.argument.WriteTo(output, options);
@ -389,6 +390,7 @@ namespace ICSharpCode.Decompiler.IL @@ -389,6 +390,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write('(');
this.left.WriteTo(output, options);
@ -816,6 +818,7 @@ namespace ICSharpCode.Decompiler.IL @@ -816,6 +818,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
@ -2113,6 +2116,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2113,6 +2116,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
@ -2187,6 +2191,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2187,6 +2191,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
@ -2318,6 +2323,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2318,6 +2323,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
@ -2412,6 +2418,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2412,6 +2418,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write('(');
this.value.WriteTo(output, options);
@ -2505,6 +2512,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2505,6 +2512,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2541,6 +2549,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2541,6 +2549,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.I4; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2577,6 +2586,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2577,6 +2586,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.I8; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2613,6 +2623,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2613,6 +2623,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.F; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2649,6 +2660,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2649,6 +2660,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2715,6 +2727,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2715,6 +2727,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.I; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
method.WriteTo(output);
@ -2762,6 +2775,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2762,6 +2775,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
method.WriteTo(output);
@ -2803,6 +2817,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2803,6 +2817,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -2841,6 +2856,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2841,6 +2856,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
member.WriteTo(output);
@ -3009,6 +3025,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3009,6 +3025,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
@ -3149,6 +3166,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3149,6 +3166,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
@ -3254,6 +3272,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3254,6 +3272,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
field.WriteTo(output);
@ -3295,6 +3314,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3295,6 +3314,7 @@ namespace ICSharpCode.Decompiler.IL
public IField Field { get { return field; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
field.WriteTo(output);
@ -3342,6 +3362,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3342,6 +3362,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -3383,6 +3404,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3383,6 +3404,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -3485,6 +3507,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3485,6 +3507,7 @@ namespace ICSharpCode.Decompiler.IL
}
void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
@ -3609,6 +3632,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3609,6 +3632,7 @@ namespace ICSharpCode.Decompiler.IL
}
void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
@ -3665,6 +3689,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3665,6 +3689,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -3715,6 +3740,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3715,6 +3740,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -3765,6 +3791,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3765,6 +3791,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -3875,6 +3902,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3875,6 +3902,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -3920,6 +3948,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3920,6 +3948,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return type.GetStackType(); } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -4032,6 +4061,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4032,6 +4061,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.I4; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -4217,6 +4247,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4217,6 +4247,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
if (IsReadOnly)
output.Write("readonly.");
output.Write(OpCode);
@ -4318,6 +4349,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4318,6 +4349,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write('(');
this.array.WriteTo(output, options);
@ -4438,6 +4470,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4438,6 +4470,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -4516,6 +4549,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4516,6 +4549,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
@ -4610,6 +4644,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4610,6 +4644,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write('(');
this.value.WriteTo(output, options);
@ -4702,6 +4737,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4702,6 +4737,7 @@ namespace ICSharpCode.Decompiler.IL
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write('(');
this.value.WriteTo(output, options);
@ -4763,6 +4799,7 @@ namespace ICSharpCode.Decompiler.IL.Patterns @@ -4763,6 +4799,7 @@ namespace ICSharpCode.Decompiler.IL.Patterns
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write('(');
output.Write(')');

1
ICSharpCode.Decompiler/IL/Instructions.tt

@ -500,6 +500,7 @@ namespace ICSharpCode.Decompiler.IL @@ -500,6 +500,7 @@ namespace ICSharpCode.Decompiler.IL
public IEnumerable<string> WriteToBody {
get {
yield return "ILRange.WriteTo(output, options);";
foreach (string line in WriteOpCodePrefix)
yield return line;
yield return "output.Write(OpCode);";

1
ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs

@ -178,6 +178,7 @@ namespace ICSharpCode.Decompiler.IL @@ -178,6 +178,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write("." + GetOperatorName(Operator));
if (CheckForOverflow) {

1
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -129,6 +129,7 @@ namespace ICSharpCode.Decompiler.IL @@ -129,6 +129,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write("Block ");
output.WriteDefinition(Label, this);
if (Parent is BlockContainer)

1
ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs

@ -115,6 +115,7 @@ namespace ICSharpCode.Decompiler.IL @@ -115,6 +115,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.WriteDefinition("BlockContainer", this);
output.Write(' ');
if (entryPoint.IncomingEdgeCount > 1) {

1
ICSharpCode.Decompiler/IL/Instructions/Branch.cs

@ -113,6 +113,7 @@ namespace ICSharpCode.Decompiler.IL @@ -113,6 +113,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
output.WriteReference(TargetLabel, (object)targetBlock ?? TargetILOffset, isLocal: true);

1
ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs

@ -91,6 +91,7 @@ namespace ICSharpCode.Decompiler.IL @@ -91,6 +91,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write("call.indirect ");
ReturnType.WriteTo(output);
output.Write('(');

1
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -76,6 +76,7 @@ namespace ICSharpCode.Decompiler.IL @@ -76,6 +76,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
if (ConstrainedTo != null) {
output.Write("constrained[");
ConstrainedTo.WriteTo(output, ILNameSyntax.ShortTypeName);

1
ICSharpCode.Decompiler/IL/Instructions/Comp.cs

@ -175,6 +175,7 @@ namespace ICSharpCode.Decompiler.IL @@ -175,6 +175,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
if (options.UseLogicOperationSugar && MatchLogicNot(out var arg)) {
output.Write("logic.not(");
arg.WriteTo(output, options);

1
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -154,6 +154,7 @@ namespace ICSharpCode.Decompiler.IL @@ -154,6 +154,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write("." + GetOperatorName(Operator));
if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue)

1
ICSharpCode.Decompiler/IL/Instructions/Conv.cs

@ -260,6 +260,7 @@ namespace ICSharpCode.Decompiler.IL @@ -260,6 +260,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
if (CheckForOverflow) {
output.Write(".ovf");

33
ICSharpCode.Decompiler/IL/Instructions/DefaultValue.cs

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
// 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;
using System.Collections.Generic;
using System.Text;
namespace ICSharpCode.Decompiler.IL
{
partial class DefaultValue
{
/// <summary>
/// Gets whether the IL stack was empty at the point of this instruction.
/// (not counting the argument of the instruction itself)
/// </summary>
public bool ILStackWasEmpty;
}
}

32
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -85,6 +85,7 @@ namespace ICSharpCode.Decompiler.IL @@ -85,6 +85,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
if (Method != null) {
output.Write(' ');
@ -113,12 +114,41 @@ namespace ICSharpCode.Decompiler.IL @@ -113,12 +114,41 @@ namespace ICSharpCode.Decompiler.IL
}
body.WriteTo(output, options);
output.WriteLine();
if (options.ShowILRanges) {
var unusedILRanges = FindUnusedILRanges();
if (!unusedILRanges.IsEmpty) {
output.Write("// Unused IL Ranges: ");
output.Write(string.Join(", ", unusedILRanges.Intervals.Select(
range => $"[{range.Start:x4}..{range.InclusiveEnd:x4}]")));
output.WriteLine();
}
}
output.Unindent();
output.WriteLine("}");
}
LongSet FindUnusedILRanges()
{
var usedILRanges = new List<LongInterval>();
MarkUsedILRanges(body);
return new LongSet(new LongInterval(0, CecilMethod.Body.CodeSize)).ExceptWith(new LongSet(usedILRanges));
void MarkUsedILRanges(ILInstruction inst)
{
if (CSharp.SequencePointBuilder.HasUsableILRange(inst)) {
usedILRanges.Add(new LongInterval(inst.ILRange.Start, inst.ILRange.End));
}
if (!(inst is ILFunction)) {
foreach (var child in inst.Children) {
MarkUsedILRanges(child);
}
}
}
}
protected override InstructionFlags ComputeFlags()
{
// Creating a lambda may throw OutOfMemoryException

35
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -208,10 +208,26 @@ namespace ICSharpCode.Decompiler.IL @@ -208,10 +208,26 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public Interval ILRange;
public void AddILRange(Interval ilRange)
public void AddILRange(Interval newRange)
{
// TODO: try to combine the two ranges
this.ILRange = ilRange;
if (newRange.IsEmpty) {
return;
}
if (this.ILRange.IsEmpty) {
this.ILRange = newRange;
return;
}
if (newRange.Start <= this.ILRange.Start) {
if (newRange.End < this.ILRange.Start) {
this.ILRange = newRange; // use the earlier range
} else {
// join overlapping ranges
this.ILRange = new Interval(newRange.Start, Math.Max(newRange.End, this.ILRange.End));
}
} else if (newRange.Start <= this.ILRange.End) {
// join overlapping ranges
this.ILRange = new Interval(this.ILRange.Start, Math.Max(newRange.End, this.ILRange.End));
}
}
/// <summary>
@ -745,17 +761,4 @@ namespace ICSharpCode.Decompiler.IL @@ -745,17 +761,4 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
StackType UnderlyingResultType { get; }
}
public class ILAstWritingOptions
{
/// <summary>
/// Sugar for logic.not/and/or.
/// </summary>
public bool UseLogicOperationSugar { get; set; }
/// <summary>
/// Sugar for ldfld/stfld.
/// </summary>
public bool UseFieldSugar { get; set; }
}
}

20
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -78,6 +78,7 @@ namespace ICSharpCode.Decompiler.IL @@ -78,6 +78,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
if (options.UseLogicOperationSugar) {
if (MatchLogicAnd(out var lhs, out var rhs)) {
output.Write("logic.and(");
@ -106,5 +107,24 @@ namespace ICSharpCode.Decompiler.IL @@ -106,5 +107,24 @@ namespace ICSharpCode.Decompiler.IL
falseInst.WriteTo(output, options);
}
}
/// <summary>
/// Gets whether the input instruction occurs in a context where it is being compared with 0.
/// </summary>
internal static bool IsInConditionSlot(ILInstruction inst)
{
var slot = inst.SlotInfo;
if (slot == IfInstruction.ConditionSlot)
return true;
if (slot == IfInstruction.TrueInstSlot || slot == IfInstruction.FalseInstSlot || slot == NullCoalescingInstruction.FallbackInstSlot)
return IsInConditionSlot(inst.Parent);
if (inst.Parent is Comp comp) {
if (comp.Left == inst && comp.Right.MatchLdcI4(0))
return true;
if (comp.Right == inst && comp.Left.MatchLdcI4(0))
return true;
}
return false;
}
}
}

1
ICSharpCode.Decompiler/IL/Instructions/LdLen.cs

@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.IL @@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write('.');
output.Write(resultType);

1
ICSharpCode.Decompiler/IL/Instructions/Leave.cs

@ -111,6 +111,7 @@ namespace ICSharpCode.Decompiler.IL @@ -111,6 +111,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
if (targetContainer != null) {
output.Write(' ');

1
ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs

@ -28,6 +28,7 @@ namespace ICSharpCode.Decompiler.IL @@ -28,6 +28,7 @@ namespace ICSharpCode.Decompiler.IL
{
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write("lock (");
OnExpression.WriteTo(output, options);
output.WriteLine(") {");

4
ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.IL @@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.IL
{
if (options.UseFieldSugar) {
if (this.MatchLdFld(out var target, out var field)) {
ILRange.WriteTo(output, options);
output.Write("ldfld ");
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
@ -48,6 +49,7 @@ namespace ICSharpCode.Decompiler.IL @@ -48,6 +49,7 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')');
return;
} else if (this.MatchLdsFld(out field)) {
ILRange.WriteTo(output, options);
output.Write("ldsfld ");
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
return;
@ -63,6 +65,7 @@ namespace ICSharpCode.Decompiler.IL @@ -63,6 +65,7 @@ namespace ICSharpCode.Decompiler.IL
{
if (options.UseFieldSugar) {
if (this.MatchStFld(out var target, out var field, out var value)) {
ILRange.WriteTo(output, options);
output.Write("stfld ");
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
@ -72,6 +75,7 @@ namespace ICSharpCode.Decompiler.IL @@ -72,6 +75,7 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')');
return;
} else if (this.MatchStsFld(out field, out value)) {
ILRange.WriteTo(output, options);
output.Write("stsfld ");
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');

1
ICSharpCode.Decompiler/IL/Instructions/NullCoalescingInstruction.cs

@ -91,6 +91,7 @@ namespace ICSharpCode.Decompiler.IL @@ -91,6 +91,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write("(");
valueInst.WriteTo(output, options);

15
ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs

@ -26,18 +26,31 @@ namespace ICSharpCode.Decompiler.IL @@ -26,18 +26,31 @@ namespace ICSharpCode.Decompiler.IL
{
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
// the non-custom WriteTo would add useless parentheses
}
}
public enum NopKind
{
Normal,
Pop
}
partial class Nop
{
public string Comment;
public NopKind Kind;
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
if (Kind != NopKind.Normal) {
output.Write("." + Kind.ToString().ToLowerInvariant());
}
if (!string.IsNullOrEmpty(Comment)) {
output.Write(" // " + Comment);
}
@ -60,6 +73,7 @@ namespace ICSharpCode.Decompiler.IL @@ -60,6 +73,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
if (!string.IsNullOrEmpty(Message)) {
output.Write("(\"");
@ -86,6 +100,7 @@ namespace ICSharpCode.Decompiler.IL @@ -86,6 +100,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
if (!string.IsNullOrEmpty(Message)) {
output.Write("(\"");

1
ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs

@ -32,6 +32,7 @@ namespace ICSharpCode.Decompiler.IL @@ -32,6 +32,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write("string.to.int (");
Argument.WriteTo(output, options);
output.Write(", { ");

2
ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs

@ -76,6 +76,7 @@ namespace ICSharpCode.Decompiler.IL @@ -76,6 +76,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write("switch");
if (IsLifted)
output.Write(".lifted");
@ -180,6 +181,7 @@ namespace ICSharpCode.Decompiler.IL @@ -180,6 +181,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.WriteDefinition("case", this, isLocal: true);
output.Write(' ');
if (HasNullLabel) {

4
ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs

@ -67,6 +67,7 @@ namespace ICSharpCode.Decompiler.IL @@ -67,6 +67,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(".try ");
TryBlock.WriteTo(output, options);
foreach (var handler in Handlers) {
@ -161,6 +162,7 @@ namespace ICSharpCode.Decompiler.IL @@ -161,6 +162,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write("catch ");
if (variable != null) {
output.WriteDefinition(variable.Name, variable);
@ -202,6 +204,7 @@ namespace ICSharpCode.Decompiler.IL @@ -202,6 +204,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(".try ");
TryBlock.WriteTo(output, options);
output.Write(" finally ");
@ -297,6 +300,7 @@ namespace ICSharpCode.Decompiler.IL @@ -297,6 +300,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(".try ");
TryBlock.WriteTo(output, options);
output.Write(" fault ");

1
ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs

@ -51,6 +51,7 @@ namespace ICSharpCode.Decompiler.IL @@ -51,6 +51,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
if (IsLifted) {
output.Write(".lifted");

1
ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs

@ -38,6 +38,7 @@ namespace ICSharpCode.Decompiler.IL @@ -38,6 +38,7 @@ namespace ICSharpCode.Decompiler.IL
{
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write("using (");
Variable.WriteTo(output);
output.Write(" = ");

41
ICSharpCode.Decompiler/IL/SequencePoint.cs

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ICSharpCode.Decompiler.IL
{
/// <summary>
/// A sequence point produced by the decompiler.
/// </summary>
public struct SequencePoint
{
/// <summary>
/// IL start offset.
/// </summary>
public int Offset { get; set; }
/// <summary>
/// IL end offset.
/// </summary>
/// <remarks>
/// This does not get stored in debug information;
/// it is used internally to create hidden sequence points
/// for the IL fragments not covered by any sequence point.
/// </remarks>
public int EndOffset { get; set; }
public int StartLine { get; set; }
public int StartColumn { get; set; }
public int EndLine { get; set; }
public int EndColumn { get; set; }
public bool IsHidden {
get { return StartLine == 0xfeefee && StartLine == EndLine; }
}
internal void SetHidden()
{
StartLine = EndLine = 0xfeefee;
}
}
}

32
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -196,6 +196,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -196,6 +196,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
proposedName = proposedNameForLoads[0];
}
}
if (string.IsNullOrEmpty(proposedName) && variable.Kind == VariableKind.StackSlot) {
var proposedNameForStoresFromNewObj = variable.StoreInstructions.OfType<StLoc>()
.Select(expr => GetNameByType(GuessType(variable.Type, expr.Value, context)))
.Except(currentFieldNames).ToList();
if (proposedNameForStoresFromNewObj.Count == 1) {
proposedName = proposedNameForStoresFromNewObj[0];
}
}
if (string.IsNullOrEmpty(proposedName)) {
proposedName = GetNameByType(variable.Type);
}
@ -349,6 +357,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -349,6 +357,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return char.ToLower(name[0]) + name.Substring(1);
}
internal static IType GuessType(IType variableType, ILInstruction inst, ILTransformContext context)
{
if (!variableType.IsKnownType(KnownTypeCode.Object))
return variableType;
switch (inst) {
case NewObj newObj:
return newObj.Method.DeclaringType;
case Call call:
return call.Method.ReturnType;
case CallVirt callVirt:
return callVirt.Method.ReturnType;
case CallIndirect calli:
return calli.ReturnType;
default:
return context.TypeSystem.Compilation.FindType(inst.ResultType.ToKnownTypeCode());
}
}
internal static string GenerateForeachVariableName(ILFunction function, ILInstruction valueContext, ILVariable existingVariable = null)
{
if (function == null)
@ -362,6 +389,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -362,6 +389,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
AddExistingName(reservedVariableNames, f);
string baseName = GetNameFromInstruction(valueContext);
if (string.IsNullOrEmpty(baseName)) {
if (valueContext is LdLoc ldloc && ldloc.Variable.Kind == VariableKind.Parameter) {
baseName = ldloc.Variable.Name;
}
}
string proposedName = "item";
if (!string.IsNullOrEmpty(baseName)) {

5
ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs

@ -49,11 +49,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -49,11 +49,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (block.Instructions[i].MatchStLoc(out v, out copiedExpr)) {
if (v.IsSingleDefinition && v.LoadCount == 0 && v.Kind == VariableKind.StackSlot) {
// dead store to stack
if (copiedExpr.Flags == InstructionFlags.None) {
if (SemanticHelper.IsPure(copiedExpr.Flags)) {
// no-op -> delete
context.Step("remove dead store to stack: no-op -> delete", block.Instructions[i]);
block.Instructions.RemoveAt(i--);
} else {
// evaluate the value for its side-effects
context.Step("remove dead store to stack: evaluate the value for its side-effects", block.Instructions[i]);
copiedExpr.AddILRange(block.Instructions[i].ILRange);
block.Instructions[i] = copiedExpr;
}
} else if (v.IsSingleDefinition && CanPerformCopyPropagation(v, copiedExpr)) {

4
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -43,7 +43,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -43,7 +43,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
foreach (var call in block.Instructions[i].Descendants.OfType<NewObj>()) {
ILFunction f = TransformDelegateConstruction(call, out ILInstruction target);
if (f != null) {
call.Arguments[0].ReplaceWith(new Nop());
f.AddILRange(call.Arguments[0].ILRange);
f.AddILRange(call.Arguments[1].ILRange);
call.Arguments[0].ReplaceWith(new LdNull());
call.Arguments[1].ReplaceWith(f);
if (target is IInstructionWithVariableOperand && !target.MatchLdThis())
targetsToReplace.Add((IInstructionWithVariableOperand)target);

1
ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs

@ -104,6 +104,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -104,6 +104,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var newObj = new NewObj(inst.Method);
newObj.ILRange = inst.ILRange;
newObj.Arguments.AddRange(inst.Arguments.Skip(1));
newObj.ILStackWasEmpty = inst.ILStackWasEmpty;
var expr = new StObj(inst.Arguments[0], newObj, inst.Method.DeclaringType);
inst.ReplaceWith(expr);
return expr;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save