Browse Source

Merge branch 'master' of https://github.com/icsharpcode/ILSpy into metadata-explorer

pull/1716/head
Siegfried Pammer 6 years ago
parent
commit
84d5d7e68c
  1. 2
      DecompilerNuGetDemos.workbook
  2. 20
      ICSharpCode.Decompiler.Console/ICSharpCode.Decompiler.Console.csproj
  3. 23
      ICSharpCode.Decompiler.Console/IlspyCmdProgram.cs
  4. 23
      ICSharpCode.Decompiler.Console/ValidationAttributes.cs
  5. 2
      ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs
  6. 15
      ICSharpCode.Decompiler.PowerShell/GetDecompilerCmdlet.cs
  7. 10
      ICSharpCode.Decompiler.PowerShell/ICSharpCode.Decompiler.PowerShell.csproj
  8. 23
      ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs
  9. 5
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  10. 3
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  11. 22
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS73_StackAllocInitializers.cs
  12. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs
  13. 9
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/PropertiesAndEvents.cs
  14. 26
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  15. 37
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/Select.cs
  16. 24
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/Select.vb
  17. 10
      ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs
  18. 9
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  19. 3
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  20. 13
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  21. 43
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  22. 71
      ICSharpCode.Decompiler/DecompilerSettings.cs
  23. 10
      ICSharpCode.Decompiler/Documentation/XmlDocumentationElement.cs
  24. 14
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  25. 6
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  26. 82
      ICSharpCode.Decompiler/IL/Instructions.cs
  27. 8
      ICSharpCode.Decompiler/IL/Instructions.tt
  28. 2
      ICSharpCode.Decompiler/IL/PointerArithmeticOffset.cs
  29. 8
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  30. 2
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  31. 5
      ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs
  32. 2
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  33. 147
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
  34. 4
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs
  35. 78
      ICSharpCode.Decompiler/TypeSystem/Accessibility.cs
  36. 29
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs
  37. 100
      ILSpy/Analyzers/AnalyzerScope.cs
  38. 2
      ILSpy/Analyzers/AnalyzerTreeView.cs
  39. 9
      ILSpy/AssemblyList.cs
  40. 21
      ILSpy/AssemblyListManager.cs
  41. 41
      ILSpy/Commands/DelegateCommand.cs
  42. 1
      ILSpy/Commands/ILSpyCommands.cs
  43. 9
      ILSpy/Commands/ManageAssemblyListsCommand.cs
  44. 2
      ILSpy/Commands/ShowDebugSteps.cs
  45. 113
      ILSpy/DebugInfo/DebugInfoUtils.cs
  46. 3
      ILSpy/DebugInfo/PortableDebugInfoProvider.cs
  47. 28
      ILSpy/ILSpy.csproj
  48. 3
      ILSpy/Languages/ILAstLanguage.cs
  49. 69
      ILSpy/LoadedAssembly.cs
  50. 8
      ILSpy/MainWindow.xaml
  51. 32
      ILSpy/MainWindow.xaml.cs
  52. 46
      ILSpy/OpenListDialog.xaml
  53. 6
      ILSpy/Options/DecompilerSettingsPanel.xaml.cs
  54. 7
      ILSpy/Options/DisplaySettings.cs
  55. 6
      ILSpy/Options/DisplaySettingsPanel.xaml.cs
  56. 5
      ILSpy/Options/MiscSettings.cs
  57. 6
      ILSpy/Options/MiscSettingsPanel.xaml.cs
  58. 5
      ILSpy/Options/OptionsDialog.xaml
  59. 10
      ILSpy/Options/OptionsDialog.xaml.cs
  60. 162
      ILSpy/Properties/Resources.Designer.cs
  61. 48
      ILSpy/Properties/Resources.resx
  62. 17
      ILSpy/SessionSettings.cs
  63. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  64. 1
      ILSpy/TreeNodes/TypeTreeNode.cs
  65. 174
      ILSpy/ViewModels/ManageAssemblyListsViewModel.cs
  66. 6
      ILSpy/ViewModels/ToolPaneModel.cs
  67. 20
      ILSpy/ViewModels/ViewModelBase.cs
  68. 0
      ILSpy/Views/CreateListDialog.xaml
  69. 0
      ILSpy/Views/CreateListDialog.xaml.cs
  70. 0
      ILSpy/Views/DebugSteps.xaml
  71. 5
      ILSpy/Views/DebugSteps.xaml.cs
  72. 35
      ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs
  73. 39
      ILSpy/Views/ManageAssemblyListsDialog.xaml
  74. 0
      ILSpy/Views/NugetPackageBrowserDialog.xaml
  75. 0
      ILSpy/Views/NugetPackageBrowserDialog.xaml.cs
  76. 0
      ILSpy/Views/OpenFromGacDialog.xaml
  77. 0
      ILSpy/Views/OpenFromGacDialog.xaml.cs
  78. 10
      README.md
  79. 5
      TestPlugin/CustomOptionPage.xaml.cs
  80. 8
      azure-pipelines.yml
  81. 10
      debugbuild.bat
  82. 2
      global.json
  83. 29
      preparerelease.bat
  84. 10
      releasebuild.bat

2
DecompilerNuGetDemos.workbook

@ -6,7 +6,7 @@ platforms: @@ -6,7 +6,7 @@ platforms:
- DotNetCore
packages:
- id: ICSharpCode.Decompiler
version: 5.0.0.5124
version: 6.0.0.5420-preview1
---
Setup: load the references required to work with the decompiler

20
ICSharpCode.Decompiler.Console/ICSharpCode.Decompiler.Console.csproj

@ -2,21 +2,22 @@ @@ -2,21 +2,22 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>true</IsPackable>
<PackAsTool>true</PackAsTool>
<AssemblyName>ilspycmd</AssemblyName>
<ToolCommandName>ilspycmd</ToolCommandName>
<Version>5.0.0.5124</Version>
<Version>6.0.0.5420-preview1</Version>
<Description>Command-line decompiler using the ILSpy decompilation engine</Description>
<Copyright>Copyright 2011-2019 AlphaSierraPapa</Copyright>
<PackageProjectUrl>https://github.com/icsharpcode/ILSpy/</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>ILSpyCmdNuGetPackageIcon.png</PackageIcon>
<PackageIcon>ILSpyCmdNuGetPackageIcon.png</PackageIcon>
<RepositoryUrl>https://github.com/icsharpcode/ILSpy/</RepositoryUrl>
<Company />
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<FileVersion>5.0.0.0</FileVersion>
<AssemblyVersion>6.0.0.0</AssemblyVersion>
<FileVersion>6.0.0.0</FileVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>ILSpy Team</Authors>
</PropertyGroup>
@ -26,6 +27,12 @@ @@ -26,6 +27,12 @@
<WarningsAsErrors>NU1605</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\ICSharpCode.Decompiler.PdbProvider.Cecil\MonoCecilDebugInfoProvider.cs" Link="MonoCecilDebugInfoProvider.cs" />
<Compile Include="..\ILSpy\DebugInfo\PortableDebugInfoProvider.cs" Link="PortableDebugInfoProvider.cs" />
<Compile Include="..\ILSpy\DebugInfo\DebugInfoUtils.cs" Link="DebugInfoUtils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="ILSpyCmdNuGetPackageIcon.png" Pack="true" PackagePath="\" />
</ItemGroup>
@ -35,7 +42,7 @@ @@ -35,7 +42,7 @@
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.0.5124" />
<PackageReference Include="ICSharpCode.Decompiler" Version="6.0.0.5420-preview1" />
</ItemGroup>
<ItemGroup>
@ -45,6 +52,7 @@ @@ -45,6 +52,7 @@
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.3.0" />
<PackageReference Include="Mono.Cecil" Version="0.10.3" />
</ItemGroup>
</Project>

23
ICSharpCode.Decompiler.Console/IlspyCmdProgram.cs

@ -12,6 +12,7 @@ using System.Threading; @@ -12,6 +12,7 @@ using System.Threading;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.PdbProvider;
// ReSharper disable All
namespace ICSharpCode.Decompiler.Console
@ -45,9 +46,13 @@ Remarks: @@ -45,9 +46,13 @@ Remarks:
[Option("-il|--ilcode", "Show IL code.", CommandOptionType.NoValue)]
public bool ShowILCodeFlag { get; }
[Option("-d|--debuginfo", "Generate PDB.", CommandOptionType.NoValue)]
[Option("-genpdb", "Generate PDB.", CommandOptionType.NoValue)]
public bool CreateDebugInfoFlag { get; }
[FileExistsOrNull]
[Option("-usepdb", "Use PDB.", CommandOptionType.SingleOrNoValue)]
public (bool IsSet, string Value) InputPDBFile { get; }
[Option("-l|--list <entity-type(s)>", "Lists all entities of the specified type(s). Valid types: c(lass), i(interface), s(truct), d(elegate), e(num)", CommandOptionType.MultipleValue)]
public string[] EntityTypes { get; } = new string[0];
@ -142,7 +147,9 @@ Remarks: @@ -142,7 +147,9 @@ Remarks:
foreach (var path in ReferencePaths) {
resolver.AddSearchDirectory(path);
}
return new CSharpDecompiler(assemblyFileName, resolver, GetSettings());
return new CSharpDecompiler(assemblyFileName, resolver, GetSettings()) {
DebugInfoProvider = TryLoadPDB(module)
};
}
int ListContent(string assemblyFileName, TextWriter output, ISet<TypeKind> kinds)
@ -175,6 +182,7 @@ Remarks: @@ -175,6 +182,7 @@ Remarks:
resolver.AddSearchDirectory(path);
}
decompiler.AssemblyResolver = resolver;
decompiler.DebugInfoProvider = TryLoadPDB(module);
decompiler.DecompileProject(module, outputDirectory);
return 0;
}
@ -211,5 +219,16 @@ Remarks: @@ -211,5 +219,16 @@ Remarks:
return 0;
}
IDebugInfoProvider TryLoadPDB(PEFile module)
{
if (InputPDBFile.IsSet) {
if (InputPDBFile.Value == null)
return DebugInfoUtils.LoadSymbols(module);
return DebugInfoUtils.FromFile(module, InputPDBFile.Value);
}
return null;
}
}
}

23
ICSharpCode.Decompiler.Console/ValidationAttributes.cs

@ -1,19 +1,38 @@ @@ -1,19 +1,38 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.IO;
namespace ICSharpCode.Decompiler.Console
{
[AttributeUsage(AttributeTargets.Class)]
public class ProjectOptionRequiresOutputDirectoryValidationAttribute : ValidationAttribute
public sealed class ProjectOptionRequiresOutputDirectoryValidationAttribute : ValidationAttribute
{
public ProjectOptionRequiresOutputDirectoryValidationAttribute()
{
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (value is ILSpyCmdProgram obj) {
if (obj.CreateCompilableProjectFlag && String.IsNullOrEmpty(obj.OutputDirectory)) {
if (obj.CreateCompilableProjectFlag && string.IsNullOrEmpty(obj.OutputDirectory)) {
return new ValidationResult("--project cannot be used unless --outputdir is also specified");
}
}
return ValidationResult.Success;
}
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class FileExistsOrNullAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
var s = value as string;
if (string.IsNullOrEmpty(s))
return ValidationResult.Success;
if (File.Exists(s))
return ValidationResult.Success;
return new ValidationResult($"File '{s}' does not exist!");
}
}
}

2
ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs

@ -30,7 +30,7 @@ using Mono.Cecil; @@ -30,7 +30,7 @@ using Mono.Cecil;
using Mono.Cecil.Pdb;
using SRM = System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.PdbProvider.Cecil
namespace ICSharpCode.Decompiler.PdbProvider
{
public class MonoCecilDebugInfoProvider : IDebugInfoProvider
{

15
ICSharpCode.Decompiler.PowerShell/GetDecompilerCmdlet.cs

@ -1,8 +1,12 @@ @@ -1,8 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Reflection.PortableExecutable;
using System.Text;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.PdbProvider;
namespace ICSharpCode.Decompiler.PowerShell
{
@ -24,18 +28,25 @@ namespace ICSharpCode.Decompiler.PowerShell @@ -24,18 +28,25 @@ namespace ICSharpCode.Decompiler.PowerShell
[Parameter(HelpMessage = "Remove dead code")]
public bool RemoveDeadCode { get; set; }
[Parameter(HelpMessage = "Use PDB")]
public string PDBFilePath { get; set; }
protected override void ProcessRecord()
{
string path = GetUnresolvedProviderPathFromPSPath(LiteralPath);
try {
var module = new PEFile(LiteralPath, new FileStream(LiteralPath, FileMode.Open, FileAccess.Read), PEStreamOptions.Default);
var debugInfo = DebugInfoUtils.FromFile(module, PDBFilePath);
var decompiler = new CSharpDecompiler(path, new DecompilerSettings(LanguageVersion) {
ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = RemoveDeadCode,
RemoveDeadStores = RemoveDeadStores
RemoveDeadStores = RemoveDeadStores,
UseDebugSymbols = debugInfo != null,
ShowDebugInfo = debugInfo != null,
});
decompiler.DebugInfoProvider = debugInfo;
WriteObject(decompiler);
} catch (Exception e) {
WriteVerbose(e.ToString());
WriteError(new ErrorRecord(e, ErrorIds.AssemblyLoadFailed, ErrorCategory.OperationStopped, null));

10
ICSharpCode.Decompiler.PowerShell/ICSharpCode.Decompiler.PowerShell.csproj

@ -2,13 +2,21 @@ @@ -2,13 +2,21 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RootNamespace>ICSharpCode.Decompiler.PowerShell</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0" />
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.0.5124" />
<PackageReference Include="ICSharpCode.Decompiler" Version="6.0.0.5420-preview1" />
<PackageReference Include="Mono.Cecil" Version="0.10.3" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\ICSharpCode.Decompiler.PdbProvider.Cecil\MonoCecilDebugInfoProvider.cs" Link="MonoCecilDebugInfoProvider.cs" />
<Compile Include="..\ILSpy\DebugInfo\PortableDebugInfoProvider.cs" Link="PortableDebugInfoProvider.cs" />
<Compile Include="..\ILSpy\DebugInfo\DebugInfoUtils.cs" Link="DebugInfoUtils.cs" />
</ItemGroup>
</Project>

23
ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs

@ -13,14 +13,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -13,14 +13,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var section = (AttributeSection)attribute.Parent;
SimpleType type = attribute.Type as SimpleType;
if (section.AttributeTarget == "assembly" &&
(type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "PermissionSet" || type.Identifier == "AssemblyVersion" || type.Identifier == "Debuggable" || type.Identifier == "TargetFramework"))
{
(type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "PermissionSet" || type.Identifier == "AssemblyVersion" || type.Identifier == "Debuggable" || type.Identifier == "TargetFramework")) {
attribute.Remove();
if (section.Attributes.Count == 0)
section.Remove();
}
if (section.AttributeTarget == "module" && type.Identifier == "UnverifiableCode")
{
if (section.AttributeTarget == "module" && type.Identifier == "UnverifiableCode") {
attribute.Remove();
if (section.Attributes.Count == 0)
section.Remove();
@ -60,4 +58,21 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -60,4 +58,21 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
rootNode.AcceptVisitor(this);
}
}
public class RemoveNamespaceMy : DepthFirstAstVisitor, IAstTransform
{
public override void VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
{
if (namespaceDeclaration.Name == "My") {
namespaceDeclaration.Remove();
} else {
base.VisitNamespaceDeclaration(namespaceDeclaration);
}
}
public void Run(AstNode rootNode, TransformContext context)
{
rootNode.AcceptVisitor(this);
}
}
}

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

@ -183,7 +183,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -183,7 +183,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
return Regex.Replace(il, @"'<PrivateImplementationDetails>\{[0-9A-F-]+\}'", "'<PrivateImplementationDetails>'");
}
static readonly string coreRefAsmPath = new DotNetCorePathFinder(new Version(3, 0)).GetReferenceAssemblyPath(".NETCoreApp, Version = v3.0");
static readonly string coreRefAsmPath = new DotNetCorePathFinder(new Version(3, 1)).GetReferenceAssemblyPath(".NETCoreApp, Version = v3.1");
static readonly string refAsmPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2");
@ -209,7 +209,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -209,7 +209,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
const string targetFrameworkAttributeSnippet = @"
[assembly: System.Runtime.Versioning.TargetFramework("".NETCoreApp, Version = v3.0"", FrameworkDisplayName = """")]
[assembly: System.Runtime.Versioning.TargetFramework("".NETCoreApp, Version = v3.1"", FrameworkDisplayName = """")]
";
@ -482,6 +482,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -482,6 +482,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, settings);
decompiler.AstTransforms.Insert(0, new RemoveEmbeddedAttributes());
decompiler.AstTransforms.Insert(0, new RemoveCompilerAttribute());
decompiler.AstTransforms.Insert(0, new RemoveNamespaceMy());
decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers());
var syntaxTree = decompiler.DecompileWholeModuleAsSingleFile(sortTypes: true);

3
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -81,6 +81,7 @@ @@ -81,6 +81,7 @@
<ItemGroup>
<Compile Include="DisassemblerPrettyTestRunner.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" />
<Compile Include="TestCases\VBPretty\Select.cs" />
<None Include="TestCases\ILPretty\WeirdEnums.cs" />
<Compile Include="TestCases\ILPretty\ConstantBlobs.cs" />
<None Include="TestCases\Pretty\AsyncStreams.cs" />
@ -91,6 +92,7 @@ @@ -91,6 +92,7 @@
<Compile Include="TestCases\Ugly\NoForEachStatement.cs" />
<None Include="TestCases\Ugly\NoExtensionMethods.Expected.cs" />
<Compile Include="TestCases\Ugly\NoExtensionMethods.cs" />
<None Include="TestCases\VBPretty\Select.vb" />
<None Include="TestCases\VBPretty\VBCompoundAssign.cs" />
<Compile Include="TestCases\Pretty\ThrowExpressions.cs" />
<None Include="TestCases\ILPretty\Issue1145.cs" />
@ -261,6 +263,7 @@ @@ -261,6 +263,7 @@
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualBasic" />
</ItemGroup>
<ItemGroup>

22
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS73_StackAllocInitializers.cs

@ -379,11 +379,33 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -379,11 +379,33 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return UseSpan(span);
}
public string GetSpan3()
{
Span<decimal> span = stackalloc decimal[GetSize()];
return UseSpan(span);
}
public string GetSpan4()
{
Span<decimal> span = stackalloc decimal[4] {
1m,
2m,
3m,
4m
};
return UseSpan(span);
}
public string UseSpan(Span<int> span)
{
throw new NotImplementedException();
}
public string UseSpan(Span<decimal> span)
{
throw new NotImplementedException();
}
public int GetSize()
{
throw new NotImplementedException();

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs

@ -1038,7 +1038,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1038,7 +1038,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
await Task.Delay(100);
if (string.IsNullOrEmpty(str)) {
#if ROSLYN
#if CS70
if (int.TryParse(str, out int id)) {
#else
int id;
@ -1050,6 +1050,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1050,6 +1050,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
}
public void NullCoalescing()
{
Test<Func<string, string, string>>((string a, string b) => a ?? b, (string a, string b) => a ?? b);
Test<Func<int?, int>>((int? a) => a ?? 1, (int? a) => a ?? 1);
}
}
internal static class Extensions

9
ICSharpCode.Decompiler.Tests/TestCases/Pretty/PropertiesAndEvents.cs

@ -191,6 +191,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -191,6 +191,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public event EventHandler AutomaticEventWithInitializer = delegate {
};
#if ROSLYN
// Legacy csc has a bug where EventHandler<dynamic> is only used for the backing field
public event EventHandler<dynamic> DynamicAutoEvent;
public event EventHandler<(int A, string B)> AutoEventWithTuple;
#endif
#if CS80
public event EventHandler<(int a, dynamic? b)> ComplexAutoEvent;
#endif
public event EventHandler CustomEvent {
add {
AutomaticEvent += value;

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

@ -65,6 +65,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -65,6 +65,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
#if CS73
public class CustomPinnable
{
public ref int GetPinnableReference()
{
throw new NotImplementedException();
}
}
#endif
public unsafe delegate void UnsafeDelegate(byte* ptr);
private UnsafeDelegate unsafeDelegate;
@ -354,6 +364,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -354,6 +364,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return ptr->ToString();
}
#if CS73
public unsafe void PinSpan(Span<int> span)
{
fixed (int* ptr = span) {
UsePointer(ptr);
}
}
//public unsafe void CustomPinReferenceType(CustomPinnable mem)
//{
// fixed (int* ptr = mem) {
// UsePointer(ptr);
// }
//}
#endif
public unsafe string StackAlloc(int count)
{
char* ptr = stackalloc char[count];

37
ICSharpCode.Decompiler.Tests/TestCases/VBPretty/Select.cs

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
using Microsoft.VisualBasic.CompilerServices;
using System;
[StandardModule]
internal sealed class Program
{
public static void SelectOnString()
{
switch (Environment.CommandLine) {
case "123":
Console.WriteLine("a");
break;
case "444":
Console.WriteLine("b");
break;
case "222":
Console.WriteLine("c");
break;
case "11":
Console.WriteLine("d");
break;
case "dd":
Console.WriteLine("e");
break;
case "sss":
Console.WriteLine("f");
break;
case "aa":
Console.WriteLine("g");
break;
case null:
case "":
Console.WriteLine("empty");
break;
}
}
}

24
ICSharpCode.Decompiler.Tests/TestCases/VBPretty/Select.vb

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
Imports System
Module Program
Sub SelectOnString()
Select Case Environment.CommandLine
Case "123"
Console.WriteLine("a")
Case "444"
Console.WriteLine("b")
Case "222"
Console.WriteLine("c")
Case "11"
Console.WriteLine("d")
Case "dd"
Console.WriteLine("e")
Case "sss"
Console.WriteLine("f")
Case "aa"
Console.WriteLine("g")
Case ""
Console.WriteLine("empty")
End Select
End Sub
End Module

10
ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs

@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.Tests
}
static readonly CompilerOptions[] defaultOptions =
{
{
CompilerOptions.None,
CompilerOptions.Optimize,
CompilerOptions.UseRoslyn,
@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests
};
static readonly CompilerOptions[] roslynOnlyOptions =
{
{
CompilerOptions.UseRoslyn,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn,
};
@ -72,6 +72,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -72,6 +72,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(options: options | CompilerOptions.Library);
}
[Test]
public void Select([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
Run(options: options | CompilerOptions.Library);
}
void Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null)
{
var vbFile = Path.Combine(TestCasePath, testName + ".vb");

9
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -819,8 +819,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -819,8 +819,13 @@ namespace ICSharpCode.Decompiler.CSharp
var fixedStmt = new FixedStatement();
fixedStmt.Type = exprBuilder.ConvertType(inst.Variable.Type);
Expression initExpr;
if (inst.Init.OpCode == OpCode.ArrayToPointer) {
initExpr = exprBuilder.Translate(((ArrayToPointer)inst.Init).Array);
if (inst.Init is GetPinnableReference gpr) {
if (gpr.Method != null) {
IType expectedType = gpr.Method.IsStatic ? gpr.Method.Parameters[0].Type : gpr.Method.DeclaringType;
initExpr = exprBuilder.Translate(gpr.Argument, typeHint: expectedType).ConvertTo(expectedType, exprBuilder);
} else {
initExpr = exprBuilder.Translate(gpr.Argument);
}
} else {
initExpr = exprBuilder.Translate(inst.Init, typeHint: inst.Variable.Type).ConvertTo(inst.Variable.Type, exprBuilder);
}

3
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -1362,6 +1362,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1362,6 +1362,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
ClassType classType;
switch (typeDefinition.Kind) {
case TypeKind.Struct:
case TypeKind.Void:
classType = ClassType.Struct;
modifiers &= ~Modifiers.Sealed;
if (ShowModifiers) {
@ -1420,7 +1421,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1420,7 +1421,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.BaseTypes.Add(ConvertType(typeDefinition.EnumUnderlyingType));
}
// if the declared type is a struct, ignore System.ValueType
} else if (typeDefinition.Kind == TypeKind.Struct && baseType.IsKnownType(KnownTypeCode.ValueType)) {
} else if ((typeDefinition.Kind == TypeKind.Struct || typeDefinition.Kind == TypeKind.Void) && baseType.IsKnownType(KnownTypeCode.ValueType)) {
continue;
// always ignore System.Object
} else if (baseType.IsKnownType(KnownTypeCode.Object)) {

13
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -432,6 +432,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -432,6 +432,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
&& identExpr.TypeArguments.Count == 0;
}
bool CombineDeclarationAndInitializer(VariableToDeclare v, TransformContext context)
{
if (v.Type.IsByRefLike)
return true; // by-ref-like variables always must be initialized at their declaration.
if (v.InsertionPoint.nextNode.Role == ForStatement.InitializerRole)
return true; // for-statement initializers always should combine declaration and initialization.
return !context.Settings.SeparateLocalVariableDeclarations;
}
void InsertVariableDeclarations(TransformContext context)
{
var replacements = new List<(AstNode, AstNode)>();
@ -439,7 +450,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -439,7 +450,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (v.RemovedDueToCollision)
continue;
if (IsMatchingAssignment(v, out AssignmentExpression assignment)) {
if (CombineDeclarationAndInitializer(v, context) && IsMatchingAssignment(v, out AssignmentExpression assignment)) {
// 'int v; v = expr;' can be combined to 'int v = expr;'
AstType type;
if (context.Settings.AnonymousTypes && v.Type.ContainsAnonymousType()) {

43
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -165,6 +165,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -165,6 +165,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public ForStatement TransformFor(ExpressionStatement node)
{
if (!context.Settings.ForStatement)
return null;
Match m1 = variableAssignPattern.Match(node);
if (!m1.Success) return null;
var variable = m1.Get<IdentifierExpression>("variable").Single().GetILVariable();
@ -810,16 +812,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -810,16 +812,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
default:
return false;
}
if (!ev.ReturnType.IsMatch(m.Get("type").Single())) {
// Variable types must match event type,
// except that the event type may have an additional nullability annotation
if (ev.ReturnType is ComposedType ct && ct.HasOnlyNullableSpecifier) {
if (!ct.BaseType.IsMatch(m.Get("type").Single()))
return false;
} else {
return false;
}
}
var returnType = ev.ReturnType.GetResolveResult().Type;
var eventType = m.Get<AstType>("type").Single().GetResolveResult().Type;
// ignore tuple element names, dynamic and nullability
if (!NormalizeTypeVisitor.TypeErasure.EquivalentTypes(returnType, eventType))
return false;
var combineMethod = m.Get<AstNode>("delegateCombine").Single().Parent.GetSymbol() as IMethod;
if (combineMethod == null || combineMethod.Name != (isAddAccessor ? "Combine" : "Remove"))
return false;
@ -890,8 +887,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -890,8 +887,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
ed.Variables.Add(new VariableInitializer(ev.Name));
ed.CopyAnnotationsFrom(ev);
IEvent eventDef = ev.GetSymbol() as IEvent;
if (eventDef != null) {
if (ev.GetSymbol() is IEvent eventDef) {
IField field = eventDef.DeclaringType.GetFields(f => f.Name == ev.Name, GetMemberOptions.IgnoreInheritedMembers).SingleOrDefault();
if (field != null) {
ed.AddAnnotation(field);
@ -1040,5 +1036,28 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1040,5 +1036,28 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return base.VisitBinaryOperatorExpression(expr);
}
#endregion
#region C# 7.3 pattern based fixed
static readonly Expression addressOfPinnableReference = new UnaryOperatorExpression {
Operator = UnaryOperatorType.AddressOf,
Expression = new InvocationExpression {
Target = new MemberReferenceExpression(new AnyNode("target"), "GetPinnableReference"),
Arguments = { }
}
};
public override AstNode VisitFixedStatement(FixedStatement fixedStatement)
{
if (context.Settings.PatternBasedFixedStatement) {
foreach (var v in fixedStatement.Variables) {
var m = addressOfPinnableReference.Match(v.Initializer);
if (m.Success) {
v.Initializer = m.Get<Expression>("target").Single().Detach();
}
}
}
return base.VisitFixedStatement(fixedStatement);
}
#endregion
}
}

71
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -104,6 +104,7 @@ namespace ICSharpCode.Decompiler @@ -104,6 +104,7 @@ namespace ICSharpCode.Decompiler
introduceUnmanagedConstraint = false;
stackAllocInitializers = false;
tupleComparisons = false;
patternBasedFixedStatement = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp8_0) {
nullableReferenceTypes = false;
@ -117,7 +118,7 @@ namespace ICSharpCode.Decompiler @@ -117,7 +118,7 @@ namespace ICSharpCode.Decompiler
{
if (nullableReferenceTypes || readOnlyMethods || asyncEnumerator || asyncUsingAndForEachStatement)
return CSharp.LanguageVersion.CSharp8_0;
if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers)
if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers || patternBasedFixedStatement)
return CSharp.LanguageVersion.CSharp7_3;
if (introduceRefModifiersOnStructs || introduceReadonlyAndInModifiers || nonTrailingNamedArguments || refExtensionMethods)
return CSharp.LanguageVersion.CSharp7_2;
@ -926,6 +927,23 @@ namespace ICSharpCode.Decompiler @@ -926,6 +927,23 @@ namespace ICSharpCode.Decompiler
}
}
bool patternBasedFixedStatement = true;
/// <summary>
/// Gets/Sets whether C# 7.3 pattern based fixed statement should be used.
/// </summary>
[Category("C# 7.3 / VS 2017.7")]
[Description("DecompilerSettings.UsePatternBasedFixedStatement")]
public bool PatternBasedFixedStatement {
get { return patternBasedFixedStatement; }
set {
if (patternBasedFixedStatement != value) {
patternBasedFixedStatement = value;
OnPropertyChanged();
}
}
}
bool tupleTypes = true;
/// <summary>
@ -1224,6 +1242,57 @@ namespace ICSharpCode.Decompiler @@ -1224,6 +1242,57 @@ namespace ICSharpCode.Decompiler
#endregion
bool forStatement = true;
/// <summary>
/// Gets/sets whether the decompiler should produce for loops.
/// </summary>
[Category("C# 1.0 / VS .NET")]
[Description("DecompilerSettings.ForStatement")]
public bool ForStatement {
get { return forStatement; }
set {
if (forStatement != value) {
forStatement = value;
OnPropertyChanged();
}
}
}
bool doWhileStatement = true;
/// <summary>
/// Gets/sets whether the decompiler should produce do-while loops.
/// </summary>
[Category("C# 1.0 / VS .NET")]
[Description("DecompilerSettings.DoWhileStatement")]
public bool DoWhileStatement {
get { return doWhileStatement; }
set {
if (doWhileStatement != value) {
doWhileStatement = value;
OnPropertyChanged();
}
}
}
bool separateLocalVariableDeclarations = false;
/// <summary>
/// Gets/sets whether the decompiler should separate local variable declarations from their initialization.
/// </summary>
[Category("DecompilerSettings.Other")]
[Description("DecompilerSettings.SeparateLocalVariableDeclarations")]
public bool SeparateLocalVariableDeclarations {
get { return separateLocalVariableDeclarations; }
set {
if (separateLocalVariableDeclarations != value) {
separateLocalVariableDeclarations = value;
OnPropertyChanged();
}
}
}
CSharpFormattingOptions csharpFormattingOptions;
[Browsable(false)]

10
ICSharpCode.Decompiler/Documentation/XmlDocumentationElement.cs

@ -91,8 +91,12 @@ namespace ICSharpCode.Decompiler.Documentation @@ -91,8 +91,12 @@ namespace ICSharpCode.Decompiler.Documentation
get {
if (!referencedEntityInitialized) {
string cref = GetAttribute("cref");
if (!string.IsNullOrEmpty(cref) && crefResolver != null)
referencedEntity = crefResolver(cref);
try {
if (!string.IsNullOrEmpty(cref) && crefResolver != null)
referencedEntity = crefResolver(cref);
} catch {
referencedEntity = null;
}
referencedEntityInitialized = true;
}
return referencedEntity;
@ -113,7 +117,7 @@ namespace ICSharpCode.Decompiler.Documentation @@ -113,7 +117,7 @@ namespace ICSharpCode.Decompiler.Documentation
/// </summary>
public string GetAttribute(string name)
{
return element?.Attribute(name)?.Value ?? string.Empty;
return element?.Attribute(name)?.Value;
}
/// <summary>

14
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -139,11 +139,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -139,11 +139,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
bool modified = false;
for (int i = 0; i < container.Blocks.Count; i++) {
var block = container.Blocks[i];
ILVariable v, p;
Block targetBlock;
if (IsNullSafeArrayToPointerPattern(block, out v, out p, out targetBlock)) {
if (IsNullSafeArrayToPointerPattern(block, out ILVariable v, out ILVariable p, out Block targetBlock)) {
context.Step("NullSafeArrayToPointerPattern", block);
ILInstruction arrayToPointer = new ArrayToPointer(new LdLoc(v));
ILInstruction arrayToPointer = new GetPinnableReference(new LdLoc(v), null);
if (p.StackType != StackType.Ref) {
arrayToPointer = new Conv(arrayToPointer, p.StackType.ToPrimitiveType(), false, Sign.None);
}
@ -432,7 +430,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -432,7 +430,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return; // variable access that is not LdLoc
}
}
if (!(ldloc.Parent is ArrayToPointer arrayToPointer))
if (!(ldloc.Parent is GetPinnableReference arrayToPointer))
return;
if (!(arrayToPointer.Parent is Conv conv && conv.Kind == ConversionKind.StopGCTracking))
return;
@ -446,7 +444,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -446,7 +444,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
newVar.HasGeneratedName = oldVar.HasGeneratedName;
oldVar.Function.Variables.Add(newVar);
pinnedRegion.Variable = newVar;
pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init).WithILRange(arrayToPointer);
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, arrayToPointer.Method).WithILRange(arrayToPointer);
conv.ReplaceWith(new LdLoc(newVar).WithILRange(conv));
}
@ -514,7 +512,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -514,7 +512,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
newVar.HasGeneratedName = pinnedRegion.Variable.HasGeneratedName;
pinnedRegion.Variable.Function.Variables.Add(newVar);
pinnedRegion.Variable = newVar;
pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init);
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, null);
}
return;
}
@ -542,7 +540,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -542,7 +540,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// make targetBlock the new entry point
body.Blocks.RemoveAt(targetBlock.ChildIndex);
body.Blocks.Insert(0, targetBlock);
pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init);
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, null);
ILVariable otherVar;
ILInstruction otherVarInit;

6
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -131,7 +131,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -131,7 +131,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
AnalyzeCurrentProperty();
ResolveIEnumerableIEnumeratorFieldMapping();
ConstructExceptionTable();
newBody = AnalyzeMoveNext();
newBody = AnalyzeMoveNext(function);
} catch (SymbolicAnalysisFailedException) {
return;
}
@ -525,12 +525,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -525,12 +525,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
#endregion
#region Analyze MoveNext() and generate new body
BlockContainer AnalyzeMoveNext()
BlockContainer AnalyzeMoveNext(ILFunction function)
{
context.StepStartGroup("AnalyzeMoveNext");
MethodDefinitionHandle moveNextMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(m => metadata.GetString(metadata.GetMethodDefinition(m).Name) == "MoveNext");
ILFunction moveNextFunction = CreateILAst(moveNextMethod, context);
function.MoveNextMethod = moveNextFunction.Method;
// Copy-propagate temporaries holding a copy of 'this'.
// This is necessary because the old (pre-Roslyn) C# compiler likes to store 'this' in temporary variables.
foreach (var stloc in moveNextFunction.Descendants.OfType<StLoc>().Where(s => s.Variable.IsSingleDefinition && s.Value.MatchLdThis()).ToList()) {

82
ICSharpCode.Decompiler/IL/Instructions.cs

@ -184,9 +184,12 @@ namespace ICSharpCode.Decompiler.IL @@ -184,9 +184,12 @@ namespace ICSharpCode.Decompiler.IL
LdLen,
/// <summary>Load address of array element.</summary>
LdElema,
/// <summary>Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty.
/// Also used to convert a string to a reference to the first character.</summary>
ArrayToPointer,
/// <summary>Retrieves a pinnable reference for the input object.
/// The input must be an object reference (O).
/// If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty.
/// Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null.
/// </summary>
GetPinnableReference,
/// <summary>Maps a string value to an integer. This is used in switch(string).</summary>
StringToInt,
/// <summary>ILAst representation of Expression.Convert.</summary>
@ -4756,21 +4759,25 @@ namespace ICSharpCode.Decompiler.IL @@ -4756,21 +4759,25 @@ namespace ICSharpCode.Decompiler.IL
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty.
/// Also used to convert a string to a reference to the first character.</summary>
public sealed partial class ArrayToPointer : ILInstruction
/// <summary>Retrieves a pinnable reference for the input object.
/// The input must be an object reference (O).
/// If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty.
/// Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null.
/// </summary>
public sealed partial class GetPinnableReference : ILInstruction, IInstructionWithMethodOperand
{
public ArrayToPointer(ILInstruction array) : base(OpCode.ArrayToPointer)
public GetPinnableReference(ILInstruction argument, IMethod method) : base(OpCode.GetPinnableReference)
{
this.Array = array;
this.Argument = argument;
this.method = method;
}
public static readonly SlotInfo ArraySlot = new SlotInfo("Array", canInlineInto: true);
ILInstruction array;
public ILInstruction Array {
get { return this.array; }
public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true);
ILInstruction argument;
public ILInstruction Argument {
get { return this.argument; }
set {
ValidateChild(value);
SetChildInstruction(ref this.array, value, 0);
SetChildInstruction(ref this.argument, value, 0);
}
}
protected sealed override int GetChildCount()
@ -4781,7 +4788,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4781,7 +4788,7 @@ namespace ICSharpCode.Decompiler.IL
{
switch (index) {
case 0:
return this.array;
return this.argument;
default:
throw new IndexOutOfRangeException();
}
@ -4790,7 +4797,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4790,7 +4797,7 @@ namespace ICSharpCode.Decompiler.IL
{
switch (index) {
case 0:
this.Array = value;
this.Argument = value;
break;
default:
throw new IndexOutOfRangeException();
@ -4800,21 +4807,24 @@ namespace ICSharpCode.Decompiler.IL @@ -4800,21 +4807,24 @@ namespace ICSharpCode.Decompiler.IL
{
switch (index) {
case 0:
return ArraySlot;
return ArgumentSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (ArrayToPointer)ShallowClone();
clone.Array = this.array.Clone();
var clone = (GetPinnableReference)ShallowClone();
clone.Argument = this.argument.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.Ref; } }
readonly IMethod method;
/// <summary>Returns the method operand.</summary>
public IMethod Method { get { return method; } }
protected override InstructionFlags ComputeFlags()
{
return array.Flags;
return argument.Flags;
}
public override InstructionFlags DirectFlags {
get {
@ -4825,31 +4835,33 @@ namespace ICSharpCode.Decompiler.IL @@ -4825,31 +4835,33 @@ namespace ICSharpCode.Decompiler.IL
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
method.WriteTo(output);
output.Write('(');
this.array.WriteTo(output, options);
this.argument.WriteTo(output, options);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitArrayToPointer(this);
visitor.VisitGetPinnableReference(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitArrayToPointer(this);
return visitor.VisitGetPinnableReference(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitArrayToPointer(this, context);
return visitor.VisitGetPinnableReference(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as ArrayToPointer;
return o != null && this.array.PerformMatch(o.array, ref match);
var o = other as GetPinnableReference;
return o != null && this.argument.PerformMatch(o.argument, ref match) && method.Equals(o.method);
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(array.ResultType == StackType.O);
Debug.Assert(argument.ResultType == StackType.O);
}
}
}
@ -6717,7 +6729,7 @@ namespace ICSharpCode.Decompiler.IL @@ -6717,7 +6729,7 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitArrayToPointer(ArrayToPointer inst)
protected internal virtual void VisitGetPinnableReference(GetPinnableReference inst)
{
Default(inst);
}
@ -7103,7 +7115,7 @@ namespace ICSharpCode.Decompiler.IL @@ -7103,7 +7115,7 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitArrayToPointer(ArrayToPointer inst)
protected internal virtual T VisitGetPinnableReference(GetPinnableReference inst)
{
return Default(inst);
}
@ -7489,7 +7501,7 @@ namespace ICSharpCode.Decompiler.IL @@ -7489,7 +7501,7 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
protected internal virtual T VisitArrayToPointer(ArrayToPointer inst, C context)
protected internal virtual T VisitGetPinnableReference(GetPinnableReference inst, C context)
{
return Default(inst, context);
}
@ -7651,7 +7663,7 @@ namespace ICSharpCode.Decompiler.IL @@ -7651,7 +7663,7 @@ namespace ICSharpCode.Decompiler.IL
"sizeof",
"ldlen",
"ldelema",
"array.to.pointer",
"get.pinnable.reference",
"string.to.int",
"expression.tree.cast",
"user.logic.operator",
@ -8202,14 +8214,16 @@ namespace ICSharpCode.Decompiler.IL @@ -8202,14 +8214,16 @@ namespace ICSharpCode.Decompiler.IL
array = default(ILInstruction);
return false;
}
public bool MatchArrayToPointer(out ILInstruction array)
public bool MatchGetPinnableReference(out ILInstruction argument, out IMethod method)
{
var inst = this as ArrayToPointer;
var inst = this as GetPinnableReference;
if (inst != null) {
array = inst.Array;
argument = inst.Argument;
method = inst.Method;
return true;
}
array = default(ILInstruction);
argument = default(ILInstruction);
method = default(IMethod);
return false;
}
public bool MatchUserDefinedLogicOperator(out IMethod method, out ILInstruction left, out ILInstruction right)

8
ICSharpCode.Decompiler/IL/Instructions.tt

@ -279,9 +279,11 @@ @@ -279,9 +279,11 @@
new OpCode("ldelema", "Load address of array element.",
CustomClassName("LdElema"), HasTypeOperand, CustomChildren(new [] { new ArgumentInfo("array"), new ArgumentInfo("indices") { IsCollection = true } }, true),
MayThrowIfNotDelayed, ResultType("Ref"), SupportsReadonlyPrefix),
new OpCode("array.to.pointer", "Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty." + Environment.NewLine
+ "Also used to convert a string to a reference to the first character.",
CustomArguments(("array", new[] { "O" })), ResultType("Ref")),
new OpCode("get.pinnable.reference", "Retrieves a pinnable reference for the input object." + Environment.NewLine
+ "The input must be an object reference (O)." + Environment.NewLine
+ "If the input is an array/string, evaluates to a reference to the first element/character, or to a null reference if the array is null or empty." + Environment.NewLine
+ "Otherwise, uses the GetPinnableReference method to get the reference, or evaluates to a null reference if the input is null." + Environment.NewLine,
CustomArguments(("argument", new[] { "O" })), ResultType("Ref"), HasMethodOperand),
new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).",
CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo, ResultType("I4")),

2
ICSharpCode.Decompiler/IL/PointerArithmeticOffset.cs

@ -77,6 +77,8 @@ namespace ICSharpCode.Decompiler.IL @@ -77,6 +77,8 @@ namespace ICSharpCode.Decompiler.IL
case KnownTypeCode.UInt64:
case KnownTypeCode.Double:
return 8;
case KnownTypeCode.Decimal:
return 16;
}
return null;
}

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

@ -140,7 +140,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -140,7 +140,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// remove unused variables before assigning names
function.Variables.RemoveDead();
int numDisplayClassLocals = 0;
foreach (var v in function.Variables) {
foreach (var v in function.Variables.OrderBy(v => v.Name)) {
switch (v.Kind) {
case VariableKind.Parameter: // ignore
break;
@ -243,8 +243,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -243,8 +243,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
reservedVariableNames.Add(nameWithoutDigits, number - 1);
}
int count = ++reservedVariableNames[nameWithoutDigits];
string nameWithDigits = nameWithoutDigits + count.ToString();
if (oldVariableName == nameWithDigits) {
return oldVariableName;
}
if (count != 1) {
return nameWithoutDigits + count.ToString();
return nameWithDigits;
} else {
return nameWithoutDigits;
}

2
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -405,7 +405,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -405,7 +405,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
var pointerType = new PointerType(elementType);
var elementCountInstr = PointerArithmeticOffset.Detect(sizeInBytesInstr, pointerType.ElementType, checkForOverflow: true, unwrapZeroExtension: true);
if (!elementCountInstr.Match(elementCountInstr2).Success)
if (elementCountInstr == null || !elementCountInstr.Match(elementCountInstr2).Success)
return false;
return true;
}

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

@ -42,10 +42,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -42,10 +42,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (loop.Kind != ContainerKind.Loop)
continue;
if (MatchWhileLoop(loop, out var condition, out var loopBody)) {
MatchForLoop(loop, condition, loopBody);
if (context.Settings.ForStatement)
MatchForLoop(loop, condition, loopBody);
continue;
}
if (MatchDoWhileLoop(loop))
if (context.Settings.DoWhileStatement && MatchDoWhileLoop(loop))
continue;
}
}

2
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -459,7 +459,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -459,7 +459,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
break;
case OpCode.DynamicCompoundAssign:
return true;
case OpCode.ArrayToPointer:
case OpCode.GetPinnableReference:
case OpCode.LocAllocSpan:
return true; // inline size-expressions into localloc.span
case OpCode.Call:

147
ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

@ -160,6 +160,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -160,6 +160,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// if (comp(ldloc switchValueVar == ldnull)) br defaultBlock
if (!instructions[i].MatchIfInstruction(out var condition, out var firstBlockOrDefaultJump))
return false;
var nextCaseJump = instructions[i + 1];
while (condition.MatchLogicNot(out var arg)) {
condition = arg;
ExtensionMethods.Swap(ref firstBlockOrDefaultJump, ref nextCaseJump);
}
// match call to operator ==(string, string)
if (!MatchStringEqualityComparison(condition, out var switchValueVar, out string firstBlockValue, out bool isVBCompareString))
return false;
if (isVBCompareString) {
ExtensionMethods.Swap(ref firstBlockOrDefaultJump, ref nextCaseJump);
}
if (firstBlockOrDefaultJump.MatchBranch(out var firstBlock)) {
// success
@ -172,11 +183,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -172,11 +183,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
List<(string, ILInstruction)> values = new List<(string, ILInstruction)>();
ILInstruction switchValue = null;
// match call to operator ==(string, string)
if (!MatchStringEqualityComparison(condition, out var switchValueVar, out string firstBlockValue))
return false;
values.Add((firstBlockValue, firstBlock ?? firstBlockOrDefaultJump));
if (isVBCompareString && string.IsNullOrEmpty(firstBlockValue)) {
values.Add((null, firstBlock ?? firstBlockOrDefaultJump));
values.Add((string.Empty, firstBlock ?? firstBlockOrDefaultJump));
} else {
values.Add((firstBlockValue, firstBlock ?? firstBlockOrDefaultJump));
}
bool extraLoad = false;
bool keepAssignmentBefore = false;
@ -215,13 +227,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -215,13 +227,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switchValue = new LdLoc(switchValueVar);
}
// if instruction must be followed by a branch to the next case
if (!(instructions.ElementAtOrDefault(i + 1) is Branch nextCaseJump))
if (!nextCaseJump.MatchBranch(out Block currentCaseBlock))
return false;
// extract all cases and add them to the values list.
Block currentCaseBlock = nextCaseJump.TargetBlock;
ILInstruction nextCaseBlock;
while ((nextCaseBlock = MatchCaseBlock(currentCaseBlock, switchValueVar, out string value, out Block block)) != null) {
values.Add((value, block));
while ((nextCaseBlock = MatchCaseBlock(currentCaseBlock, switchValueVar, out string value, out bool emptyStringEqualsNull, out Block block)) != null) {
if (emptyStringEqualsNull && string.IsNullOrEmpty(value)) {
values.Add((null, block));
values.Add((string.Empty, block));
} else {
values.Add((value, block));
}
currentCaseBlock = nextCaseBlock as Block;
if (currentCaseBlock == null)
break;
@ -367,37 +383,34 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -367,37 +383,34 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// The <paramref name="switchVariable"/> is updated if the value gets copied to a different variable.
/// See comments below for more info.
/// </summary>
ILInstruction MatchCaseBlock(Block currentBlock, ILVariable switchVariable, out string value, out Block caseBlock)
ILInstruction MatchCaseBlock(Block currentBlock, ILVariable switchVariable, out string value, out bool emptyStringEqualsNull, out Block caseBlock)
{
value = null;
caseBlock = null;
emptyStringEqualsNull = false;
if (currentBlock.IncomingEdgeCount != 1 || currentBlock.Instructions.Count != 2)
return null;
if (!currentBlock.Instructions[0].MatchIfInstruction(out var condition, out var caseBlockBranch))
if (!currentBlock.MatchIfAtEndOfBlock(out var condition, out var caseBlockBranch, out var nextBlockBranch))
return null;
if (!MatchStringEqualityComparison(condition, switchVariable, out value, out bool isVBCompareString)) {
return null;
}
if (isVBCompareString) {
ExtensionMethods.Swap(ref caseBlockBranch, ref nextBlockBranch);
emptyStringEqualsNull = true;
}
if (!caseBlockBranch.MatchBranch(out caseBlock))
return null;
Block nextBlock;
BlockContainer blockContainer = null;
if (condition.MatchLogicNot(out var inner)) {
condition = inner;
nextBlock = caseBlock;
if (!currentBlock.Instructions[1].MatchBranch(out caseBlock))
return null;
if (nextBlockBranch.MatchBranch(out Block nextBlock)) {
// success
return nextBlock;
} else if (nextBlockBranch.MatchLeave(out BlockContainer blockContainer)) {
// success
return blockContainer;
} else {
if (currentBlock.Instructions[1].MatchBranch(out nextBlock)) {
// success
} else if (currentBlock.Instructions[1].MatchLeave(out blockContainer)) {
// success
} else {
return null;
}
}
if (!MatchStringEqualityComparison(condition, switchVariable, out value)) {
return null;
}
return nextBlock ?? (ILInstruction)blockContainer;
}
/// <summary>
@ -836,8 +849,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -836,8 +849,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
MatchComputeStringHashCall(switchBlockInstructions[switchBlockInstructionsOffset], switchValueVar, out LdLoc switchValueLoad)))
return false;
var stringValues = new List<(int Index, string Value, ILInstruction TargetBlockOrLeave)>();
int index = 0;
var stringValues = new List<(string Value, ILInstruction TargetBlockOrLeave)>();
SwitchSection defaultSection = switchInst.Sections.MaxBy(s => s.Labels.Count());
Block exitOrDefaultBlock = null;
foreach (var section in switchInst.Sections) {
@ -846,20 +858,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -846,20 +858,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!section.Body.MatchBranch(out Block target))
return false;
string stringValue;
bool emptyStringEqualsNull;
if (MatchRoslynEmptyStringCaseBlockHead(target, switchValueLoad.Variable, out ILInstruction targetOrLeave, out Block currentExitBlock)) {
stringValue = "";
} else if (!MatchRoslynCaseBlockHead(target, switchValueLoad.Variable, out targetOrLeave, out currentExitBlock, out stringValue)) {
emptyStringEqualsNull = false;
} else if (!MatchRoslynCaseBlockHead(target, switchValueLoad.Variable, out targetOrLeave, out currentExitBlock, out stringValue, out emptyStringEqualsNull)) {
return false;
}
if (exitOrDefaultBlock != null && exitOrDefaultBlock != currentExitBlock)
return false;
exitOrDefaultBlock = currentExitBlock;
stringValues.Add((index++, stringValue, targetOrLeave));
if (emptyStringEqualsNull && string.IsNullOrEmpty(stringValue)) {
stringValues.Add((null, targetOrLeave));
stringValues.Add((string.Empty, targetOrLeave));
} else {
stringValues.Add((stringValue, targetOrLeave));
}
}
if (nullValueCaseBlock != null && exitOrDefaultBlock != nullValueCaseBlock) {
stringValues.Add((index++, null, nullValueCaseBlock));
stringValues.Add((null, nullValueCaseBlock));
}
ILInstruction switchValueInst = switchValueLoad;
@ -914,13 +933,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -914,13 +933,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
SwitchInstruction ReplaceWithSwitchInstruction(int offset)
{
var defaultLabel = new LongSet(new LongInterval(0, index)).Invert();
var defaultLabel = new LongSet(new LongInterval(0, stringValues.Count)).Invert();
var values = new string[stringValues.Count];
var sections = new SwitchSection[stringValues.Count];
foreach (var (idx, (label, value, bodyInstruction)) in stringValues.WithIndex()) {
foreach (var (idx, (value, bodyInstruction)) in stringValues.WithIndex()) {
values[idx] = value;
var body = bodyInstruction is Block b ? new Branch(b) : bodyInstruction;
sections[idx] = new SwitchSection { Labels = new LongSet(label), Body = body };
sections[idx] = new SwitchSection { Labels = new LongSet(idx), Body = body };
}
var newSwitch = new SwitchInstruction(new StringToInt(switchValueInst, values));
newSwitch.Sections.AddRange(sections);
@ -935,26 +954,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -935,26 +954,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// if (call op_Equality(ldloc switchValueVar, stringValue)) br body
/// br exit
/// </summary>
bool MatchRoslynCaseBlockHead(Block target, ILVariable switchValueVar, out ILInstruction bodyOrLeave, out Block defaultOrExitBlock, out string stringValue)
bool MatchRoslynCaseBlockHead(Block target, ILVariable switchValueVar, out ILInstruction bodyOrLeave, out Block defaultOrExitBlock, out string stringValue, out bool emptyStringEqualsNull)
{
bodyOrLeave = null;
defaultOrExitBlock = null;
stringValue = null;
emptyStringEqualsNull = false;
if (target.Instructions.Count != 2)
return false;
if (!target.Instructions[0].MatchIfInstruction(out var condition, out var bodyBranch))
return false;
ILInstruction exitBranch;
ILInstruction exitBranch = target.Instructions[1];
// Handle negated conditions first:
if (condition.MatchLogicNot(out var expr)) {
exitBranch = bodyBranch;
bodyBranch = target.Instructions[1];
while (condition.MatchLogicNot(out var expr)) {
ExtensionMethods.Swap(ref exitBranch, ref bodyBranch);
condition = expr;
} else {
exitBranch = target.Instructions[1];
}
if (!MatchStringEqualityComparison(condition, switchValueVar, out stringValue))
if (!MatchStringEqualityComparison(condition, switchValueVar, out stringValue, out bool isVBCompareString))
return false;
if (isVBCompareString) {
ExtensionMethods.Swap(ref exitBranch, ref bodyBranch);
emptyStringEqualsNull = true;
}
if (!(exitBranch.MatchBranch(out defaultOrExitBlock) || exitBranch.MatchLeave(out _)))
return false;
if (bodyBranch.MatchLeave(out _)) {
@ -1054,25 +1075,45 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1054,25 +1075,45 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Matches 'call string.op_Equality(ldloc(variable), ldstr(stringValue))'
/// or 'comp(ldloc(variable) == ldnull)'
/// </summary>
bool MatchStringEqualityComparison(ILInstruction condition, ILVariable variable, out string stringValue)
bool MatchStringEqualityComparison(ILInstruction condition, ILVariable variable, out string stringValue, out bool isVBCompareString)
{
return MatchStringEqualityComparison(condition, out var v, out stringValue) && v == variable;
return MatchStringEqualityComparison(condition, out var v, out stringValue, out isVBCompareString) && v == variable;
}
/// <summary>
/// Matches 'call string.op_Equality(ldloc(variable), ldstr(stringValue))'
/// or 'comp(ldloc(variable) == ldnull)'
/// </summary>
bool MatchStringEqualityComparison(ILInstruction condition, out ILVariable variable, out string stringValue)
bool MatchStringEqualityComparison(ILInstruction condition, out ILVariable variable, out string stringValue, out bool isVBCompareString)
{
stringValue = null;
variable = null;
ILInstruction left, right;
if (condition is Call c && c.Method.IsOperator && c.Method.Name == "op_Equality"
&& c.Method.DeclaringType.IsKnownType(KnownTypeCode.String) && c.Arguments.Count == 2)
{
left = c.Arguments[0];
right = c.Arguments[1];
isVBCompareString = false;
while (condition is Comp comp && comp.Kind == ComparisonKind.Inequality && comp.Right.MatchLdcI4(0)) {
// if (x != 0) == if (x)
condition = comp.Left;
}
if (condition is Call c) {
ILInstruction left, right;
if (c.Method.IsOperator && c.Method.Name == "op_Equality"
&& c.Method.DeclaringType.IsKnownType(KnownTypeCode.String) && c.Arguments.Count == 2) {
left = c.Arguments[0];
right = c.Arguments[1];
} else if (c.Method.IsStatic && c.Method.Name == "CompareString"
&& c.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators"
&& c.Arguments.Count == 3) {
left = c.Arguments[0];
right = c.Arguments[1];
// VB CompareString(): return 0 on equality -> condition is effectively negated.
// Also, the empty string is considered equal to null.
isVBCompareString = true;
if (!c.Arguments[2].MatchLdcI4(0)) {
// Option Compare Text: case insensitive comparison is not supported in C#
return false;
}
} else {
return false;
}
return left.MatchLdLoc(out variable) && right.MatchLdStr(out stringValue);
} else if (condition.MatchCompEqualsNull(out var arg)) {
stringValue = null;

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

@ -604,7 +604,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -604,7 +604,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else {
targetType = fallbackInstType;
}
return (new NullCoalescingInstruction(kind, trueInst, fallbackInst), targetType);
return (new NullCoalescingInstruction(kind, trueInst, fallbackInst) {
UnderlyingResultType = trueInstTypeNonNullable.GetStackType()
}, targetType);
}
(ILInstruction, IType) ConvertComparison(CallInstruction invocation, ComparisonKind kind)

78
ICSharpCode.Decompiler/TypeSystem/Accessibility.cs

@ -16,6 +16,9 @@ @@ -16,6 +16,9 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Diagnostics;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.TypeSystem
{
/// <summary>
@ -23,7 +26,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -23,7 +26,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
public enum Accessibility : byte
{
// note: some code depends on the fact that these values are within the range 0-7
// Note: some code depends on the fact that these values are within the range 0-7
/// <summary>
/// The entity is completely inaccessible. This is used for C# explicit interface implementations.
@ -34,26 +37,83 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -34,26 +37,83 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
Private,
/// <summary>
/// The entity is accessible everywhere.
/// The entity is accessible in derived classes within the same assembly.
/// This corresponds to C# <c>private protected</c>.
/// </summary>
Public,
ProtectedAndInternal,
/// <summary>
/// The entity is only accessible within the same class and in derived classes.
/// </summary>
Protected,
/// <summary>
/// The entity is accessible within the same project content.
/// The entity is accessible within the same assembly.
/// </summary>
Internal,
/// <summary>
/// The entity is accessible both everywhere in the project content, and in all derived classes.
/// The entity is accessible both everywhere in the assembly, and in all derived classes.
/// This corresponds to C# <c>protected internal</c>.
/// </summary>
/// <remarks>This corresponds to C# 'protected internal'.</remarks>
ProtectedOrInternal,
/// <summary>
/// The entity is accessible in derived classes within the same project content.
/// The entity is accessible everywhere.
/// </summary>
/// <remarks>This corresponds to C# 'private protected'.</remarks>
ProtectedAndInternal,
Public,
}
public static class AccessibilityExtensions
{
// This code depends on the fact that the enum values are sorted similar to the partial order
// where an accessibility is smaller than another if it makes an entity visibible to a subset of the code:
// digraph Accessibilities {
// none -> private -> protected_and_internal -> protected -> protected_or_internal -> public;
// none -> private -> protected_and_internal -> internal -> protected_or_internal -> public;
// }
/// <summary>
/// Gets whether a &lt;= b in the partial order of accessibilities:
/// return true if b is accessible everywhere where a is accessible.
/// </summary>
public static bool LessThanOrEqual(this Accessibility a, Accessibility b)
{
// Exploit the enum order being similar to the partial order to dramatically simplify the logic here:
// protected vs. internal is the only pair for which the enum value order doesn't match the partial order
return a <= b && !(a == Accessibility.Protected && b == Accessibility.Internal);
}
/// <summary>
/// Computes the intersection of the two accessibilities:
/// The result is accessible from any given point in the code
/// iff both a and b are accessible from that point.
/// </summary>
public static Accessibility Intersect(this Accessibility a, Accessibility b)
{
if (a > b) {
ExtensionMethods.Swap(ref a, ref b);
}
if (a == Accessibility.Protected && b == Accessibility.Internal) {
return Accessibility.ProtectedAndInternal;
} else {
Debug.Assert(!(a == Accessibility.Internal && b == Accessibility.Protected));
return a;
}
}
/// <summary>
/// Computes the union of the two accessibilities:
/// The result is accessible from any given point in the code
/// iff at least one of a or b is accessible from that point.
/// </summary>
public static Accessibility Union(this Accessibility a, Accessibility b)
{
if (a > b) {
ExtensionMethods.Swap(ref a, ref b);
}
if (a == Accessibility.Protected && b == Accessibility.Internal) {
return Accessibility.ProtectedOrInternal;
} else {
Debug.Assert(!(a == Accessibility.Internal && b == Accessibility.Protected));
return b;
}
}
}
}

29
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs

@ -196,37 +196,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -196,37 +196,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return baseMember.Accessibility;
}
}
return MergePropertyAccessibility(
return AccessibilityExtensions.Union(
this.Getter?.Accessibility ?? Accessibility.None,
this.Setter?.Accessibility ?? Accessibility.None);
}
static internal Accessibility MergePropertyAccessibility(Accessibility left, Accessibility right)
{
if (left == Accessibility.Public || right == Accessibility.Public)
return Accessibility.Public;
if (left == Accessibility.ProtectedOrInternal || right == Accessibility.ProtectedOrInternal)
return Accessibility.ProtectedOrInternal;
if (left == Accessibility.Protected && right == Accessibility.Internal ||
left == Accessibility.Internal && right == Accessibility.Protected)
return Accessibility.ProtectedOrInternal;
if (left == Accessibility.Protected || right == Accessibility.Protected)
return Accessibility.Protected;
if (left == Accessibility.Internal || right == Accessibility.Internal)
return Accessibility.Internal;
if (left == Accessibility.ProtectedAndInternal || right == Accessibility.ProtectedAndInternal)
return Accessibility.ProtectedAndInternal;
if (left == Accessibility.Private || right == Accessibility.Private)
return Accessibility.Private;
return left;
}
#endregion
public bool IsStatic => AnyAccessor?.IsStatic ?? false;

100
ILSpy/Analyzers/AnalyzerScope.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy.Analyzers
public ITypeDefinition TypeScope => typeScope;
Accessibility memberAccessibility, typeAccessibility;
Accessibility effectiveAccessibility;
public AnalyzerScope(AssemblyList assemblyList, IEntity entity)
{
@ -53,13 +53,12 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -53,13 +53,12 @@ namespace ICSharpCode.ILSpy.Analyzers
AnalyzedSymbol = entity;
if (entity is ITypeDefinition type) {
typeScope = type;
memberAccessibility = Accessibility.None;
effectiveAccessibility = DetermineEffectiveAccessibility(ref typeScope);
} else {
typeScope = entity.DeclaringTypeDefinition;
memberAccessibility = entity.Accessibility;
effectiveAccessibility = DetermineEffectiveAccessibility(ref typeScope, entity.Accessibility);
}
typeAccessibility = DetermineTypeAccessibility(ref typeScope);
IsLocal = memberAccessibility == Accessibility.Private || typeAccessibility == Accessibility.Private;
IsLocal = effectiveAccessibility.LessThanOrEqual(Accessibility.Private);
}
public IEnumerable<PEFile> GetModulesInScope(CancellationToken ct)
@ -67,10 +66,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -67,10 +66,7 @@ namespace ICSharpCode.ILSpy.Analyzers
if (IsLocal)
return new[] { TypeScope.ParentModule.PEFile };
if (memberAccessibility == Accessibility.Internal ||
memberAccessibility == Accessibility.ProtectedOrInternal ||
typeAccessibility == Accessibility.Internal ||
typeAccessibility == Accessibility.ProtectedAndInternal)
if (effectiveAccessibility.LessThanOrEqual(Accessibility.Internal))
return GetModuleAndAnyFriends(TypeScope, ct);
return GetReferencingModules(TypeScope.ParentModule.PEFile, ct);
@ -89,11 +85,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -89,11 +85,7 @@ namespace ICSharpCode.ILSpy.Analyzers
{
if (IsLocal) {
var typeSystem = new DecompilerTypeSystem(TypeScope.ParentModule.PEFile, TypeScope.ParentModule.PEFile.GetAssemblyResolver());
ITypeDefinition scope = typeScope;
if (memberAccessibility != Accessibility.Private && typeScope.DeclaringTypeDefinition != null) {
scope = typeScope.DeclaringTypeDefinition;
}
foreach (var type in TreeTraversal.PreOrder(scope, t => t.NestedTypes)) {
foreach (var type in TreeTraversal.PreOrder(typeScope, t => t.NestedTypes)) {
yield return type;
}
} else {
@ -106,23 +98,17 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -106,23 +98,17 @@ namespace ICSharpCode.ILSpy.Analyzers
}
}
Accessibility DetermineTypeAccessibility(ref ITypeDefinition typeScope)
static Accessibility DetermineEffectiveAccessibility(ref ITypeDefinition typeScope, Accessibility memberAccessibility = Accessibility.Public)
{
var typeAccessibility = typeScope.Accessibility;
while (typeScope.DeclaringType != null) {
Accessibility accessibility = typeScope.Accessibility;
if ((int)typeAccessibility > (int)accessibility) {
typeAccessibility = accessibility;
if (typeAccessibility == Accessibility.Private)
break;
}
Accessibility accessibility = memberAccessibility;
while (typeScope.DeclaringTypeDefinition != null && !accessibility.LessThanOrEqual(Accessibility.Private)) {
accessibility = accessibility.Intersect(typeScope.Accessibility);
typeScope = typeScope.DeclaringTypeDefinition;
}
if ((int)typeAccessibility > (int)Accessibility.Internal) {
typeAccessibility = Accessibility.Internal;
}
return typeAccessibility;
// Once we reach a private entity, we leave the loop with typeScope set to the class that
// contains the private entity = the scope that needs to be searched.
// Otherwise (if we don't find a private entity) we return the top-level class.
return accessibility;
}
#region Find modules
@ -134,24 +120,39 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -134,24 +120,39 @@ namespace ICSharpCode.ILSpy.Analyzers
if (typeScope.TypeParameterCount > 0)
reflectionTypeScopeName += "`" + typeScope.TypeParameterCount;
foreach (var assembly in AssemblyList.GetAssemblies()) {
ct.ThrowIfCancellationRequested();
bool found = false;
var module = assembly.GetPEFileOrNull();
if (module == null || !module.IsAssembly)
continue;
var resolver = assembly.GetAssemblyResolver();
foreach (var reference in module.AssemblyReferences) {
using (LoadedAssembly.DisableAssemblyLoad()) {
if (resolver.Resolve(reference) == self) {
found = true;
break;
var toWalkFiles = new Stack<PEFile>();
var checkedFiles = new HashSet<PEFile>();
toWalkFiles.Push(self);
checkedFiles.Add(self);
do {
PEFile curFile = toWalkFiles.Pop();
foreach (var assembly in AssemblyList.GetAssemblies()) {
ct.ThrowIfCancellationRequested();
bool found = false;
var module = assembly.GetPEFileOrNull();
if (module == null || !module.IsAssembly)
continue;
if (checkedFiles.Contains(module))
continue;
var resolver = assembly.GetAssemblyResolver();
foreach (var reference in module.AssemblyReferences) {
using (LoadedAssembly.DisableAssemblyLoad()) {
if (resolver.Resolve(reference) == curFile) {
found = true;
break;
}
}
}
if (found && checkedFiles.Add(module)) {
if (ModuleReferencesScopeType(module.Metadata, reflectionTypeScopeName, typeScope.Namespace))
yield return module;
if (ModuleForwardsScopeType(module.Metadata, reflectionTypeScopeName, typeScope.Namespace))
toWalkFiles.Push(module);
}
}
if (found && ModuleReferencesScopeType(module.Metadata, reflectionTypeScopeName, typeScope.Namespace))
yield return module;
}
} while (toWalkFiles.Count > 0);
}
IEnumerable<PEFile> GetModuleAndAnyFriends(ITypeDefinition typeScope, CancellationToken ct)
@ -198,6 +199,19 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -198,6 +199,19 @@ namespace ICSharpCode.ILSpy.Analyzers
}
return hasRef;
}
bool ModuleForwardsScopeType(MetadataReader metadata, string typeScopeName, string typeScopeNamespace)
{
bool hasForward = false;
foreach (var h in metadata.ExportedTypes) {
var exportedType = metadata.GetExportedType(h);
if (exportedType.IsForwarder && metadata.StringComparer.Equals(exportedType.Name, typeScopeName) && metadata.StringComparer.Equals(exportedType.Namespace, typeScopeNamespace)) {
hasForward = true;
break;
}
}
return hasForward;
}
#endregion
}
}

2
ILSpy/Analyzers/AnalyzerTreeView.cs

@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy.Analyzers
public void Show()
{
AnalyzerPaneModel.Instance.IsVisible = true;
AnalyzerPaneModel.Instance.Show();
}
public void Show(AnalyzerTreeNode node)

9
ILSpy/AssemblyList.cs

@ -71,6 +71,15 @@ namespace ICSharpCode.ILSpy @@ -71,6 +71,15 @@ namespace ICSharpCode.ILSpy
this.dirty = false; // OpenAssembly() sets dirty, so reset it afterwards
}
/// <summary>
/// Creates a copy of an assembly list.
/// </summary>
public AssemblyList(AssemblyList list, string newName)
: this(newName)
{
this.assemblies.AddRange(list.assemblies);
}
/// <summary>
/// Gets the loaded assemblies. This method is thread-safe.
/// </summary>

21
ILSpy/AssemblyListManager.cs

@ -30,22 +30,26 @@ namespace ICSharpCode.ILSpy @@ -30,22 +30,26 @@ namespace ICSharpCode.ILSpy
/// </summary>
sealed class AssemblyListManager
{
ILSpySettings spySettings;
public AssemblyListManager(ILSpySettings spySettings)
{
this.spySettings = spySettings;
XElement doc = spySettings["AssemblyLists"];
foreach (var list in doc.Elements("List")) {
AssemblyLists.Add((string)list.Attribute("name"));
}
}
public readonly ObservableCollection<string> AssemblyLists = new ObservableCollection<string>();
public ObservableCollection<string> AssemblyLists { get; } = new ObservableCollection<string>();
/// <summary>
/// Loads an assembly list from the ILSpySettings.
/// If no list with the specified name is found, the default list is loaded instead.
/// </summary>
public AssemblyList LoadList(ILSpySettings spySettings, string listName)
public AssemblyList LoadList(ILSpySettings settings, string listName)
{
this.spySettings = settings;
AssemblyList list = DoLoadList(spySettings, listName);
if (!AssemblyLists.Contains(list.ListName))
AssemblyLists.Add(list.ListName);
@ -62,11 +66,14 @@ namespace ICSharpCode.ILSpy @@ -62,11 +66,14 @@ namespace ICSharpCode.ILSpy
}
}
}
XElement firstList = doc.Elements("List").FirstOrDefault();
if (firstList != null)
return new AssemblyList(firstList);
else
return new AssemblyList(listName ?? DefaultListName);
return new AssemblyList(listName ?? DefaultListName);
}
public bool CloneList(string selectedAssemblyList, string newListName)
{
var list = DoLoadList(spySettings, selectedAssemblyList);
var newList = new AssemblyList(list, newListName);
return CreateList(newList);
}
public const string DefaultListName = "(Default)";

41
ILSpy/Commands/DelegateCommand.cs

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace ICSharpCode.ILSpy.Commands
{
public class DelegateCommand<T> : ICommand
{
private readonly Action<T> action;
private readonly Func<T, bool> canExecute;
public event EventHandler CanExecuteChanged {
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public DelegateCommand(Action<T> action)
: this(action, _ => true)
{
}
public DelegateCommand(Action<T> action, Func<T, bool> canExecute)
{
this.action = action;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute((T)parameter);
}
public void Execute(object parameter)
{
action((T)parameter);
}
}
}

1
ILSpy/Commands/ILSpyCommands.cs

@ -29,5 +29,6 @@ namespace ICSharpCode.ILSpy @@ -29,5 +29,6 @@ namespace ICSharpCode.ILSpy
static class ILSpyCommands
{
public static readonly AnalyzeCommand Analyze = new AnalyzeCommand();
public static readonly ManageAssemblyListsCommand ManageAssemblyListsCommand = new ManageAssemblyListsCommand();
}
}

9
ILSpy/Commands/OpenListCommand.cs → ILSpy/Commands/ManageAssemblyListsCommand.cs

@ -21,15 +21,14 @@ using ICSharpCode.ILSpy.Properties; @@ -21,15 +21,14 @@ using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy
{
[ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.Open_List), MenuIcon = "Images/AssemblyList", MenuCategory = nameof(Resources.Open), MenuOrder = 1.7)]
sealed class OpenListCommand : SimpleCommand
[ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.ManageAssemblyLists), MenuIcon = "Images/AssemblyList", MenuCategory = nameof(Resources.Open), MenuOrder = 1.7)]
sealed class ManageAssemblyListsCommand : SimpleCommand
{
public override void Execute(object parameter)
{
OpenListDialog dlg = new OpenListDialog();
ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog();
dlg.Owner = MainWindow.Instance;
if (dlg.ShowDialog() == true)
MainWindow.Instance.ShowAssemblyList(dlg.SelectedListName);
dlg.ShowDialog();
}
}
}

2
ILSpy/Commands/ShowDebugSteps.cs

@ -11,7 +11,7 @@ namespace ICSharpCode.ILSpy.Commands @@ -11,7 +11,7 @@ namespace ICSharpCode.ILSpy.Commands
{
public override void Execute(object parameter)
{
DebugStepsPaneModel.Instance.IsVisible = true;
DebugStepsPaneModel.Instance.Show();
}
}
}

113
ILSpy/DebugInfo/DebugInfoUtils.cs

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
// Copyright (c) 2018 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.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.Decompiler.PdbProvider
{
static class DebugInfoUtils
{
public static IDebugInfoProvider LoadSymbols(PEFile module)
{
try {
var reader = module.Reader;
// try to open portable pdb file/embedded pdb info:
if (TryOpenPortablePdb(module, out var provider, out var pdbFileName)) {
return new PortableDebugInfoProvider(pdbFileName, provider);
} else {
// search for pdb in same directory as dll
pdbFileName = Path.Combine(Path.GetDirectoryName(module.FileName), Path.GetFileNameWithoutExtension(module.FileName) + ".pdb");
if (File.Exists(pdbFileName)) {
return new MonoCecilDebugInfoProvider(module, pdbFileName);
}
}
} catch (Exception ex) when (ex is BadImageFormatException || ex is COMException) {
// Ignore PDB load errors
}
return null;
}
public static IDebugInfoProvider FromFile(PEFile module, string pdbFileName)
{
if (string.IsNullOrEmpty(pdbFileName))
return null;
Stream stream = OpenStream(pdbFileName);
if (stream == null)
return null;
if (stream.Read(buffer, 0, buffer.Length) == LegacyPDBPrefix.Length
&& System.Text.Encoding.ASCII.GetString(buffer) == LegacyPDBPrefix) {
stream.Position = 0;
return new MonoCecilDebugInfoProvider(module, pdbFileName);
} else {
stream.Position = 0;
var provider = MetadataReaderProvider.FromPortablePdbStream(stream);
return new PortableDebugInfoProvider(pdbFileName, provider);
}
}
const string LegacyPDBPrefix = "Microsoft C/C++ MSF 7.00";
static readonly byte[] buffer = new byte[LegacyPDBPrefix.Length];
static bool TryOpenPortablePdb(PEFile module, out MetadataReaderProvider provider, out string pdbFileName)
{
provider = null;
pdbFileName = null;
var reader = module.Reader;
foreach (var entry in reader.ReadDebugDirectory()) {
if (entry.IsPortableCodeView) {
return reader.TryOpenAssociatedPortablePdb(module.FileName, OpenStream, out provider, out pdbFileName);
}
if (entry.Type == DebugDirectoryEntryType.CodeView) {
string pdbDirectory = Path.GetDirectoryName(module.FileName);
pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(module.FileName) + ".pdb");
if (File.Exists(pdbFileName)) {
Stream stream = OpenStream(pdbFileName);
if (stream.Read(buffer, 0, buffer.Length) == LegacyPDBPrefix.Length
&& System.Text.Encoding.ASCII.GetString(buffer) == LegacyPDBPrefix) {
return false;
}
stream.Position = 0;
provider = MetadataReaderProvider.FromPortablePdbStream(stream);
return true;
}
}
}
return false;
}
static Stream OpenStream(string fileName)
{
if (!File.Exists(fileName))
return null;
var memory = new MemoryStream();
using (var stream = File.OpenRead(fileName))
stream.CopyTo(memory);
memory.Position = 0;
return memory;
}
}
}

3
ILSpy/DebugInfo/PortableDebugInfoProvider.cs

@ -20,9 +20,8 @@ using System; @@ -20,9 +20,8 @@ using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy.DebugInfo
namespace ICSharpCode.Decompiler.PdbProvider
{
class PortableDebugInfoProvider : IDebugInfoProvider
{

28
ILSpy/ILSpy.csproj

@ -108,12 +108,13 @@ @@ -108,12 +108,13 @@
<Compile Include="Commands\BrowseBackCommand.cs" />
<Compile Include="Commands\BrowseForwardCommand.cs" />
<Compile Include="CommandLineArguments.cs" />
<Compile Include="Commands\DelegateCommand.cs" />
<Compile Include="Commands\DecompileCommand.cs" />
<Compile Include="Commands\DisassembleAllCommand.cs" />
<Compile Include="Commands\ExitCommand.cs" />
<Compile Include="Commands\CommandWrapper.cs" />
<Compile Include="Commands\ILSpyCommands.cs" />
<Compile Include="Commands\OpenListCommand.cs" />
<Compile Include="Commands\ManageAssemblyListsCommand.cs" />
<Compile Include="Commands\Pdb2XmlCommand.cs" />
<Compile Include="Commands\RemoveAssembliesWithLoadErrors.cs" />
<Compile Include="Commands\ShowCFGContextMenuEntry.cs" />
@ -135,11 +136,14 @@ @@ -135,11 +136,14 @@
<Compile Include="Controls\SearchBox.cs" />
<Compile Include="Controls\SortableGridViewColumn.cs" />
<Compile Include="Controls\XamlResourceExtension.cs" />
<Compile Include="CreateListDialog.xaml.cs">
<Compile Include="ViewModels\ManageAssemblyListsViewModel.cs" />
<Compile Include="ViewModels\ViewModelBase.cs" />
<Compile Include="Views\CreateListDialog.xaml.cs">
<DependentUpon>CreateListDialog.xaml</DependentUpon>
</Compile>
<Compile Include="DebugInfo\DebugInfoUtils.cs" />
<Compile Include="DebugInfo\PortableDebugInfoProvider.cs" />
<Compile Include="DebugSteps.xaml.cs">
<Compile Include="Views\DebugSteps.xaml.cs">
<DependentUpon>DebugSteps.xaml</DependentUpon>
</Compile>
<Compile Include="Docking\ActiveTabPageConverter.cs" />
@ -313,18 +317,16 @@ @@ -313,18 +317,16 @@
<Compile Include="NavigationState.cs" />
<Compile Include="Commands\OpenCommand.cs" />
<Compile Include="Commands\OpenFromGacCommand.cs" />
<Compile Include="NugetPackageBrowserDialog.xaml.cs">
<Compile Include="Views\NugetPackageBrowserDialog.xaml.cs">
<DependentUpon>NugetPackageBrowserDialog.xaml</DependentUpon>
</Compile>
<Compile Include="OpenFromGacDialog.xaml.cs">
<Compile Include="Views\OpenFromGacDialog.xaml.cs">
<DependentUpon>OpenFromGacDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ResourceStringTable.xaml.cs">
<DependentUpon>ResourceStringTable.xaml</DependentUpon>
</Compile>
<Compile Include="OpenListDialog.xaml.cs">
<DependentUpon>OpenListDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ManageAssemblyListsDialog.xaml.cs" />
<Compile Include="Options\DisplaySettings.cs" />
<Compile Include="Options\DisplaySettingsPanel.xaml.cs">
<DependentUpon>DisplaySettingsPanel.xaml</DependentUpon>
@ -438,8 +440,8 @@ @@ -438,8 +440,8 @@
<Page Include="Controls\ResourceObjectTable.xaml" />
<Page Include="Controls\ResourceStringTable.xaml" />
<Page Include="Controls\SearchBoxStyle.xaml" />
<Page Include="CreateListDialog.xaml" />
<Page Include="DebugSteps.xaml" />
<Page Include="Views\CreateListDialog.xaml" />
<Page Include="Views\DebugSteps.xaml" />
<Page Include="Images\Assembly.xaml" />
<Page Include="Images\AssemblyList.xaml" />
<Page Include="Images\AssemblyListGAC.xaml" />
@ -504,9 +506,9 @@ @@ -504,9 +506,9 @@
<Page Include="Images\Warning.xaml" />
<Page Include="MainWindow.xaml" />
<Page Include="Metadata\MetadataTableViews.xaml" />
<Page Include="OpenFromGacDialog.xaml" />
<Page Include="OpenListDialog.xaml" />
<Page Include="NugetPackageBrowserDialog.xaml" />
<Page Include="Views\OpenFromGacDialog.xaml" />
<Page Include="Views\ManageAssemblyListsDialog.xaml" />
<Page Include="Views\NugetPackageBrowserDialog.xaml" />
<Page Include="Options\DecompilerSettingsPanel.xaml" />
<Page Include="Options\DisplaySettingsPanel.xaml" />
<Page Include="Options\MiscSettingsPanel.xaml" />

3
ILSpy/Languages/ILAstLanguage.cs

@ -31,6 +31,7 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -31,6 +31,7 @@ using ICSharpCode.Decompiler.TypeSystem;
using SRM = System.Reflection.Metadata;
using static System.Reflection.Metadata.PEReaderExtensions;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy
{
@ -140,7 +141,7 @@ namespace ICSharpCode.ILSpy @@ -140,7 +141,7 @@ namespace ICSharpCode.ILSpy
}
}
(output as ISmartTextOutput)?.AddButton(Images.ViewCode, "Show Steps", delegate {
DebugSteps.Show();
DebugStepsPaneModel.Instance.Show();
});
output.WriteLine();
il.WriteTo(output, DebugSteps.Options);

69
ILSpy/LoadedAssembly.cs

@ -28,10 +28,9 @@ using System.Threading; @@ -28,10 +28,9 @@ using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.PdbProvider.Cecil;
using ICSharpCode.Decompiler.PdbProvider;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.ILSpy.DebugInfo;
using ICSharpCode.ILSpy.Options;
namespace ICSharpCode.ILSpy
@ -167,7 +166,7 @@ namespace ICSharpCode.ILSpy @@ -167,7 +166,7 @@ namespace ICSharpCode.ILSpy
if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) {
try {
LoadSymbols(module);
debugInfoProvider = DebugInfoUtils.LoadSymbols(module);
} catch (IOException) {
} catch (UnauthorizedAccessException) {
} catch (InvalidOperationException) {
@ -180,70 +179,6 @@ namespace ICSharpCode.ILSpy @@ -180,70 +179,6 @@ namespace ICSharpCode.ILSpy
return module;
}
void LoadSymbols(PEFile module)
{
try {
var reader = module.Reader;
// try to open portable pdb file/embedded pdb info:
if (TryOpenPortablePdb(module, out var provider, out var pdbFileName)) {
debugInfoProvider = new PortableDebugInfoProvider(pdbFileName, provider);
} else {
// search for pdb in same directory as dll
string pdbDirectory = Path.GetDirectoryName(fileName);
pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(fileName) + ".pdb");
if (File.Exists(pdbFileName)) {
debugInfoProvider = new MonoCecilDebugInfoProvider(module, pdbFileName);
return;
}
// TODO: use symbol cache, get symbols from microsoft
}
} catch (Exception ex) when (ex is BadImageFormatException || ex is COMException) {
// Ignore PDB load errors
}
}
const string LegacyPDBPrefix = "Microsoft C/C++ MSF 7.00";
byte[] buffer = new byte[LegacyPDBPrefix.Length];
bool TryOpenPortablePdb(PEFile module, out MetadataReaderProvider provider, out string pdbFileName)
{
provider = null;
pdbFileName = null;
var reader = module.Reader;
foreach (var entry in reader.ReadDebugDirectory()) {
if (entry.IsPortableCodeView) {
return reader.TryOpenAssociatedPortablePdb(fileName, OpenStream, out provider, out pdbFileName);
}
if (entry.Type == DebugDirectoryEntryType.CodeView) {
string pdbDirectory = Path.GetDirectoryName(fileName);
pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(fileName) + ".pdb");
if (File.Exists(pdbFileName)) {
Stream stream = OpenStream(pdbFileName);
if (stream.Read(buffer, 0, buffer.Length) == LegacyPDBPrefix.Length
&& System.Text.Encoding.ASCII.GetString(buffer) == LegacyPDBPrefix) {
return false;
}
stream.Position = 0;
provider = MetadataReaderProvider.FromPortablePdbStream(stream);
return true;
}
}
}
return false;
}
Stream OpenStream(string fileName)
{
if (!File.Exists(fileName))
return null;
var memory = new MemoryStream();
using (var stream = File.OpenRead(fileName))
stream.CopyTo(memory);
memory.Position = 0;
return memory;
}
[ThreadStatic]
static int assemblyLoadDisableCount;

8
ILSpy/MainWindow.xaml

@ -6,7 +6,6 @@ @@ -6,7 +6,6 @@
xmlns:local="clr-namespace:ICSharpCode.ILSpy"
xmlns:avalondock="http://schemas.xceed.com/wpf/xaml/avalondock"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
xmlns:avalondockproperties="clr-namespace:Xceed.Wpf.AvalonDock.Properties;assembly=Xceed.Wpf.AvalonDock"
xmlns:docking="clr-namespace:ICSharpCode.ILSpy.Docking"
xmlns:textview="clr-namespace:ICSharpCode.ILSpy.TextView"
xmlns:analyzers="clr-namespace:ICSharpCode.ILSpy.Analyzers"
@ -121,6 +120,13 @@ @@ -121,6 +120,13 @@
<Separator />
<!-- 'Open' toolbar category is inserted here -->
<Separator />
<ComboBox Name="assemblyListComboBox" Width="100" MaxDropDownHeight="Auto"
ItemsSource="{Binding AssemblyListManager.AssemblyLists}" ToolTip="{x:Static properties:Resources.SelectAssemblyListDropdownTooltip}"
SelectedItem="{Binding SessionSettings.ActiveAssemblyList}"/>
<Button Command="{x:Static local:ILSpyCommands.ManageAssemblyListsCommand}" ToolTip="{x:Static properties:Resources.ManageAssemblyLists}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/AssemblyList}" />
</Button>
<Separator />
<CheckBox IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicOnly}" ToolTip="{x:Static properties:Resources.ShowPublicOnlyTypesMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowPublicOnly}" />
</CheckBox>

32
ILSpy/MainWindow.xaml.cs

@ -24,6 +24,7 @@ using System.Diagnostics; @@ -24,6 +24,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
@ -56,6 +57,7 @@ namespace ICSharpCode.ILSpy @@ -56,6 +57,7 @@ namespace ICSharpCode.ILSpy
{
public DockWorkspace Workspace { get; set; }
public SessionSettings SessionSettings { get; set; }
public AssemblyListManager AssemblyListManager { get; set; }
}
/// <summary>
@ -68,8 +70,6 @@ namespace ICSharpCode.ILSpy @@ -68,8 +70,6 @@ namespace ICSharpCode.ILSpy
readonly NavigationHistory<NavigationState> history = new NavigationHistory<NavigationState>();
ILSpySettings spySettingsForMainWindow_Loaded;
internal SessionSettings sessionSettings;
internal AssemblyListManager assemblyListManager;
AssemblyList assemblyList;
AssemblyListTreeNode assemblyListTreeNode;
@ -83,6 +83,8 @@ namespace ICSharpCode.ILSpy @@ -83,6 +83,8 @@ namespace ICSharpCode.ILSpy
get { return sessionSettings; }
}
internal AssemblyListManager AssemblyListManager { get; }
public SharpTreeView treeView {
get {
return FindResource("TreeView") as SharpTreeView;
@ -107,19 +109,21 @@ namespace ICSharpCode.ILSpy @@ -107,19 +109,21 @@ namespace ICSharpCode.ILSpy
var spySettings = ILSpySettings.Load();
this.spySettingsForMainWindow_Loaded = spySettings;
this.sessionSettings = new SessionSettings(spySettings);
this.assemblyListManager = new AssemblyListManager(spySettings);
this.AssemblyListManager = new AssemblyListManager(spySettings);
this.Icon = new BitmapImage(new Uri("pack://application:,,,/ILSpy;component/images/ILSpy.ico"));
this.DataContext = new MainWindowDataContext {
Workspace = DockWorkspace.Instance,
SessionSettings = sessionSettings
SessionSettings = sessionSettings,
AssemblyListManager = AssemblyListManager
};
DockWorkspace.Instance.LoadSettings(sessionSettings);
InitializeComponent();
DockWorkspace.Instance.InitializeLayout(DockManager);
sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged;
sessionSettings.PropertyChanged += SessionSettings_PropertyChanged;
InitMainMenu();
InitToolbar();
@ -128,6 +132,13 @@ namespace ICSharpCode.ILSpy @@ -128,6 +132,13 @@ namespace ICSharpCode.ILSpy
this.Loaded += MainWindow_Loaded;
}
private void SessionSettings_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "ActiveAssemblyList") {
ShowAssemblyList(sessionSettings.ActiveAssemblyList);
}
}
void SetWindowBounds(Rect bounds)
{
this.Left = bounds.Left;
@ -376,7 +387,7 @@ namespace ICSharpCode.ILSpy @@ -376,7 +387,7 @@ namespace ICSharpCode.ILSpy
} else if (spySettings != null) {
SharpTreeNode node = null;
if (activeTreeViewPath?.Length > 0) {
foreach (var asm in assemblyList.GetAssemblies()) {
foreach (var asm in CurrentAssemblyList.GetAssemblies()) {
if (asm.FileName == activeTreeViewPath[0]) {
// FindNodeByPath() blocks the UI if the assembly is not yet loaded,
// so use an async wait instead.
@ -466,10 +477,10 @@ namespace ICSharpCode.ILSpy @@ -466,10 +477,10 @@ namespace ICSharpCode.ILSpy
if (loadPreviousAssemblies) {
// Load AssemblyList only in Loaded event so that WPF is initialized before we start the CPU-heavy stuff.
// This makes the UI come up a bit faster.
this.assemblyList = assemblyListManager.LoadList(spySettings, sessionSettings.ActiveAssemblyList);
this.assemblyList = AssemblyListManager.LoadList(spySettings, sessionSettings.ActiveAssemblyList);
} else {
this.assemblyList = new AssemblyList(AssemblyListManager.DefaultListName);
assemblyListManager.ClearAll();
AssemblyListManager.ClearAll();
}
HandleCommandLineArguments(App.CommandLineArguments);
@ -584,8 +595,7 @@ namespace ICSharpCode.ILSpy @@ -584,8 +595,7 @@ namespace ICSharpCode.ILSpy
public void ShowAssemblyList(string name)
{
ILSpySettings settings = ILSpySettings.Load();
AssemblyList list = this.assemblyListManager.LoadList(settings, name);
AssemblyList list = this.AssemblyListManager.LoadList(ILSpySettings.Load(), name);
//Only load a new list when it is a different one
if (list.ListName != CurrentAssemblyList.ListName) {
ShowAssemblyList(list);
@ -906,7 +916,7 @@ namespace ICSharpCode.ILSpy @@ -906,7 +916,7 @@ namespace ICSharpCode.ILSpy
try {
refreshInProgress = true;
var path = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
ShowAssemblyList(assemblyListManager.LoadList(ILSpySettings.Load(), assemblyList.ListName));
ShowAssemblyList(AssemblyListManager.LoadList(ILSpySettings.Load(), assemblyList.ListName));
SelectNode(FindNodeByPath(path, true));
} finally {
refreshInProgress = false;
@ -915,7 +925,7 @@ namespace ICSharpCode.ILSpy @@ -915,7 +925,7 @@ namespace ICSharpCode.ILSpy
void SearchCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
SearchPaneModel.Instance.IsVisible = true;
SearchPaneModel.Instance.Show();
}
#endregion

46
ILSpy/OpenListDialog.xaml

@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
<Window
x:Class="ICSharpCode.ILSpy.OpenListDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
Title="{x:Static properties:Resources.OpenList}"
Style="{DynamicResource DialogWindow}"
WindowStartupLocation="CenterOwner"
ResizeMode="CanResizeWithGrip"
MinWidth="480"
MinHeight="250"
Height="350"
Width="480"
FocusManager.FocusedElement="{Binding ElementName=listView}">
<Grid Margin="12,8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel>
<Label Content="{x:Static properties:Resources.SelectList}"/>
</StackPanel>
<ListView Name="listView" Grid.Row="1" Margin="0, 8" controls:SortableGridViewColumn.SortMode="Automatic" SelectionChanged="ListView_SelectionChanged"
Loaded="listView_Loaded" SelectionMode="Single" MouseDoubleClick="listView_MouseDoubleClick">
<ListView.View>
<GridView>
<controls:SortableGridViewColumn x:Name="nameColumn" Header="{x:Static properties:Resources.Name}" DisplayMemberBinding="{Binding .}" />
</GridView>
</ListView.View>
</ListView>
<DockPanel Grid.Row="2">
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right">
<Button IsDefault="True" Margin="2,0" IsEnabled="False" Name="okButton" Click="OKButton_Click" Content="{x:Static properties:Resources.OpenListDialog__Open}"/>
<Button IsCancel="True" Margin="2,0" Content="Cancel"/>
</StackPanel>
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" HorizontalAlignment="Left">
<Button Margin="2,0" Click="CreateButton_Click" Content="{x:Static properties:Resources._Create}"/>
<Button Margin="2,0" IsEnabled="False" Name="deleteButton" Click="DeleteButton_Click" Content="{x:Static properties:Resources.OpenListDialog__Delete}"/>
<Button Margin="2,0" Click="ResetButton_Click" Content="{x:Static properties:Resources._Reset}"/>
</StackPanel>
</DockPanel>
</Grid>
</Window>

6
ILSpy/Options/DecompilerSettingsPanel.xaml.cs

@ -128,6 +128,12 @@ namespace ICSharpCode.ILSpy.Options @@ -128,6 +128,12 @@ namespace ICSharpCode.ILSpy.Options
CheckBox checkBox = (CheckBox)sender;
checkBox.IsChecked = IsGroupChecked((CollectionViewGroup)checkBox.DataContext);
}
public void LoadDefaults()
{
currentDecompilerSettings = new Decompiler.DecompilerSettings();
this.DataContext = new DecompilerSettings(currentDecompilerSettings);
}
}
public class DecompilerSettings : INotifyPropertyChanged

7
ILSpy/Options/DisplaySettings.cs

@ -29,6 +29,13 @@ namespace ICSharpCode.ILSpy.Options @@ -29,6 +29,13 @@ namespace ICSharpCode.ILSpy.Options
{
public DisplaySettings()
{
this.selectedFont = new FontFamily("Consolas");
this.selectedFontSize = 10.0 * 4 / 3;
this.sortResults = true;
this.indentationUseTabs = true;
this.indentationSize = 4;
this.indentationTabSize = 4;
this.highlightMatchingBraces = true;
}
#region INotifyPropertyChanged implementation

6
ILSpy/Options/DisplaySettingsPanel.xaml.cs

@ -164,6 +164,12 @@ namespace ICSharpCode.ILSpy.Options @@ -164,6 +164,12 @@ namespace ICSharpCode.ILSpy.Options
if (!text.All(char.IsDigit))
e.CancelCommand();
}
public void LoadDefaults()
{
currentDisplaySettings = new DisplaySettings();
this.DataContext = currentDisplaySettings;
}
}
public class FontSizeConverter : IValueConverter

5
ILSpy/Options/MiscSettings.cs

@ -26,6 +26,11 @@ namespace ICSharpCode.ILSpy.Options @@ -26,6 +26,11 @@ namespace ICSharpCode.ILSpy.Options
bool allowMultipleInstances;
bool loadPreviousAssemblies;
public MiscSettings()
{
this.loadPreviousAssemblies = true;
}
/// <summary>
/// Allow multiple instances.
/// </summary>

6
ILSpy/Options/MiscSettingsPanel.xaml.cs

@ -71,5 +71,11 @@ namespace ICSharpCode.ILSpy.Options @@ -71,5 +71,11 @@ namespace ICSharpCode.ILSpy.Options
currentMiscSettings = null; // invalidate cached settings
}
public void LoadDefaults()
{
currentMiscSettings = new MiscSettings();
this.DataContext = currentMiscSettings;
}
}
}

5
ILSpy/Options/OptionsDialog.xaml

@ -15,8 +15,9 @@ @@ -15,8 +15,9 @@
</Grid.RowDefinitions>
<TabControl Name="tabControl" />
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="12,8">
<Button IsDefault="True" Margin="2,0" Name="okButton" Click="OKButton_Click" Content="{x:Static properties:Resources.OK}"></Button>
<Button IsCancel="True" Margin="2,0" Content="{x:Static properties:Resources.Cancel}"></Button>
<Button Margin="2,0" Name="defaultsButton" Click="DefaultsButton_Click" Content="{x:Static properties:Resources.ResetToDefaults}" />
<Button IsDefault="True" Margin="2,0" Name="okButton" Click="OKButton_Click" Content="{x:Static properties:Resources.OK}" />
<Button IsCancel="True" Margin="2,0" Content="{x:Static properties:Resources.Cancel}" />
</StackPanel>
</Grid>
</Window>

10
ILSpy/Options/OptionsDialog.xaml.cs

@ -68,6 +68,15 @@ namespace ICSharpCode.ILSpy.Options @@ -68,6 +68,15 @@ namespace ICSharpCode.ILSpy.Options
this.DialogResult = true;
Close();
}
private void DefaultsButton_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show(Properties.Resources.ResetToDefaultsConfirmationMessage, "ILSpy", MessageBoxButton.YesNo) == MessageBoxResult.Yes) {
var page = ((TabItem)tabControl.SelectedItem).Content as IOptionPage;
if (page != null)
page.LoadDefaults();
}
}
}
public interface IOptionsMetadata
@ -80,6 +89,7 @@ namespace ICSharpCode.ILSpy.Options @@ -80,6 +89,7 @@ namespace ICSharpCode.ILSpy.Options
{
void Load(ILSpySettings settings);
void Save(XElement root);
void LoadDefaults();
}
[MetadataAttribute]

162
ILSpy/Properties/Resources.Designer.cs generated

@ -96,15 +96,6 @@ namespace ICSharpCode.ILSpy.Properties { @@ -96,15 +96,6 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to _Create.
/// </summary>
public static string _Create {
get {
return ResourceManager.GetString("_Create", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _File.
/// </summary>
@ -132,6 +123,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -132,6 +123,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to _New.
/// </summary>
public static string _New {
get {
return ResourceManager.GetString("_New", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Open....
/// </summary>
@ -376,6 +376,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -376,6 +376,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to C_lone.
/// </summary>
public static string C_lone {
get {
return ResourceManager.GetString("C_lone", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cancel.
/// </summary>
@ -421,6 +430,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -421,6 +430,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Close.
/// </summary>
public static string Close {
get {
return ResourceManager.GetString("Close", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Collapse all tree nodes.
/// </summary>
@ -763,6 +781,24 @@ namespace ICSharpCode.ILSpy.Properties { @@ -763,6 +781,24 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Transform to do-while, if possible..
/// </summary>
public static string DecompilerSettings_DoWhileStatement {
get {
return ResourceManager.GetString("DecompilerSettings.DoWhileStatement", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Transform to for, if possible..
/// </summary>
public static string DecompilerSettings_ForStatement {
get {
return ResourceManager.GetString("DecompilerSettings.ForStatement", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to F#-specific options.
/// </summary>
@ -891,6 +927,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -891,6 +927,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Separate local variable declarations and initializers (int x = 5; -&gt; int x; x = 5;), if possible..
/// </summary>
public static string DecompilerSettings_SeparateLocalVariableDeclarations {
get {
return ResourceManager.GetString("DecompilerSettings.SeparateLocalVariableDeclarations", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Show info from debug symbols, if available.
/// </summary>
@ -999,6 +1044,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -999,6 +1044,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Use pattern-based fixed statement.
/// </summary>
public static string DecompilerSettings_UsePatternBasedFixedStatement {
get {
return ResourceManager.GetString("DecompilerSettings.UsePatternBasedFixedStatement", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use stackalloc initializer syntax.
/// </summary>
@ -1305,6 +1359,33 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1305,6 +1359,33 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Are you sure that you want to delete the selected assembly list?.
/// </summary>
public static string ListDeleteConfirmation {
get {
return ResourceManager.GetString("ListDeleteConfirmation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A list with the same name was found..
/// </summary>
public static string ListExistsAlready {
get {
return ResourceManager.GetString("ListExistsAlready", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Are you sure that you want to remove all assembly lists and recreate the default assembly lists?.
/// </summary>
public static string ListsResetConfirmation {
get {
return ResourceManager.GetString("ListsResetConfirmation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Load assemblies that were loaded in the last instance..
/// </summary>
@ -1332,6 +1413,24 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1332,6 +1413,24 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Manage assembly _lists....
/// </summary>
public static string ManageAssembly_Lists {
get {
return ResourceManager.GetString("ManageAssembly_Lists", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Manage Assembly Lists.
/// </summary>
public static string ManageAssemblyLists {
get {
return ResourceManager.GetString("ManageAssemblyLists", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Misc.
/// </summary>
@ -1386,15 +1485,6 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1386,15 +1485,6 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Open _List....
/// </summary>
public static string Open_List {
get {
return ResourceManager.GetString("Open_List", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open Explorer.
/// </summary>
@ -1422,15 +1512,6 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1422,15 +1512,6 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Open List.
/// </summary>
public static string OpenList {
get {
return ResourceManager.GetString("OpenList", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Delete.
/// </summary>
@ -1557,6 +1638,24 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1557,6 +1638,24 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Reset to defaults.
/// </summary>
public static string ResetToDefaults {
get {
return ResourceManager.GetString("ResetToDefaults", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Do you really want to load the default settings for the active page?.
/// </summary>
public static string ResetToDefaultsConfirmationMessage {
get {
return ResourceManager.GetString("ResetToDefaultsConfirmationMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Resources file (*.resources)|*.resources|Resource XML file|*.resx.
/// </summary>
@ -1656,6 +1755,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1656,6 +1755,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Select a list of assemblies.
/// </summary>
public static string SelectAssemblyListDropdownTooltip {
get {
return ResourceManager.GetString("SelectAssemblyListDropdownTooltip", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Select language to decompile to.
/// </summary>

48
ILSpy/Properties/Resources.resx

@ -156,8 +156,8 @@ @@ -156,8 +156,8 @@
<data name="OpenFrom_GAC" xml:space="preserve">
<value>Open from _GAC...</value>
</data>
<data name="Open_List" xml:space="preserve">
<value>Open _List...</value>
<data name="ManageAssembly_Lists" xml:space="preserve">
<value>Manage assembly _lists...</value>
</data>
<data name="ReloadAssemblies" xml:space="preserve">
<value>Reload all assemblies</value>
@ -450,14 +450,14 @@ @@ -450,14 +450,14 @@
<data name="PublicToken" xml:space="preserve">
<value>Public Key Token</value>
</data>
<data name="OpenList" xml:space="preserve">
<value>Open List</value>
<data name="ManageAssemblyLists" xml:space="preserve">
<value>Manage Assembly Lists</value>
</data>
<data name="SelectList" xml:space="preserve">
<value>Select a list:</value>
</data>
<data name="_Create" xml:space="preserve">
<value>_Create</value>
<data name="_New" xml:space="preserve">
<value>_New</value>
</data>
<data name="OpenListDialog__Open" xml:space="preserve">
<value>_Open</value>
@ -790,4 +790,40 @@ Are you sure you want to continue?</value> @@ -790,4 +790,40 @@ Are you sure you want to continue?</value>
<data name="_Window" xml:space="preserve">
<value>_Window</value>
</data>
<data name="DecompilerSettings.UsePatternBasedFixedStatement" xml:space="preserve">
<value>Use pattern-based fixed statement</value>
</data>
<data name="DecompilerSettings.DoWhileStatement" xml:space="preserve">
<value>Transform to do-while, if possible.</value>
</data>
<data name="DecompilerSettings.ForStatement" xml:space="preserve">
<value>Transform to for, if possible.</value>
</data>
<data name="DecompilerSettings.SeparateLocalVariableDeclarations" xml:space="preserve">
<value>Separate local variable declarations and initializers (int x = 5; -&gt; int x; x = 5;), if possible.</value>
</data>
<data name="ResetToDefaults" xml:space="preserve">
<value>Reset to defaults</value>
</data>
<data name="ResetToDefaultsConfirmationMessage" xml:space="preserve">
<value>Do you really want to load the default settings for the active page?</value>
</data>
<data name="SelectAssemblyListDropdownTooltip" xml:space="preserve">
<value>Select a list of assemblies</value>
</data>
<data name="Close" xml:space="preserve">
<value>Close</value>
</data>
<data name="C_lone" xml:space="preserve">
<value>C_lone</value>
</data>
<data name="ListDeleteConfirmation" xml:space="preserve">
<value>Are you sure that you want to delete the selected assembly list?</value>
</data>
<data name="ListExistsAlready" xml:space="preserve">
<value>A list with the same name was found.</value>
</data>
<data name="ListsResetConfirmation" xml:space="preserve">
<value>Are you sure that you want to remove all assembly lists and recreate the default assembly lists?</value>
</data>
</root>

17
ILSpy/SessionSettings.cs

@ -20,6 +20,7 @@ using System; @@ -20,6 +20,7 @@ using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
@ -63,10 +64,9 @@ namespace ICSharpCode.ILSpy @@ -63,10 +64,9 @@ namespace ICSharpCode.ILSpy
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public FilterSettings FilterSettings { get; private set; }
@ -75,7 +75,15 @@ namespace ICSharpCode.ILSpy @@ -75,7 +75,15 @@ namespace ICSharpCode.ILSpy
public string[] ActiveTreeViewPath;
public string ActiveAutoLoadedAssembly;
public string ActiveAssemblyList;
public string ActiveAssemblyList {
get => activeAssemblyList;
set {
if (value != activeAssemblyList) {
activeAssemblyList = value;
OnPropertyChanged();
}
}
}
public WindowState WindowState = WindowState.Normal;
public Rect WindowBounds;
@ -118,6 +126,7 @@ namespace ICSharpCode.ILSpy @@ -118,6 +126,7 @@ namespace ICSharpCode.ILSpy
}
static Regex regex = new Regex("\\\\x(?<num>[0-9A-f]{4})");
private string activeAssemblyList;
static string Escape(string p)
{

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -127,8 +127,6 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -127,8 +127,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
RaisePropertyChanged("Tooltip");
if (moduleTask.IsFaulted) {
RaisePropertyChanged("ShowExpander"); // cannot expand assemblies with load error
// observe the exception so that the Task's finalizer doesn't re-throw it
try { moduleTask.Wait(); } catch (AggregateException) { }
} else {
RaisePropertyChanged("Text"); // shortname might have changed
}

1
ILSpy/TreeNodes/TypeTreeNode.cs

@ -122,6 +122,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -122,6 +122,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
case TypeKind.Interface:
return TypeIcon.Interface;
case TypeKind.Struct:
case TypeKind.Void:
return TypeIcon.Struct;
case TypeKind.Delegate:
return TypeIcon.Delegate;

174
ILSpy/OpenListDialog.xaml.cs → ILSpy/ViewModels/ManageAssemblyListsViewModel.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
// Copyright (c) 2019 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
@ -16,61 +16,117 @@ @@ -16,61 +16,117 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Commands;
namespace ICSharpCode.ILSpy
namespace ICSharpCode.ILSpy.ViewModels
{
/// <summary>
/// Interaction logic for OpenListDialog.xaml
/// </summary>
public partial class OpenListDialog : Window
public class ManageAssemblyListsViewModel : ViewModelBase
{
public const string DotNet4List = ".NET 4 (WPF)";
public const string DotNet35List = ".NET 3.5";
public const string ASPDotNetMVC3List = "ASP.NET (MVC3)";
readonly AssemblyListManager manager;
private readonly AssemblyListManager manager;
public OpenListDialog()
public ManageAssemblyListsViewModel()
{
InitializeComponent();
manager = MainWindow.Instance.assemblyListManager;
this.manager = MainWindow.Instance.AssemblyListManager;
CreateDefaultAssemblyLists();
NewCommand = new DelegateCommand<ManageAssemblyListsDialog>(ExecuteNew);
CloneCommand = new DelegateCommand<ManageAssemblyListsDialog>(ExecuteClone, CanExecuteClone);
ResetCommand = new DelegateCommand<ManageAssemblyListsDialog>(ExecuteReset);
DeleteCommand = new DelegateCommand<ManageAssemblyListsDialog>(ExecuteDelete, CanExecuteDelete);
}
private void listView_Loaded(object sender, RoutedEventArgs e)
{
listView.ItemsSource = manager.AssemblyLists;
CreateDefaultAssemblyLists();
public ObservableCollection<string> AssemblyLists => manager.AssemblyLists;
private string selectedAssemblyList;
public string SelectedAssemblyList {
get => selectedAssemblyList;
set {
if (selectedAssemblyList != value) {
selectedAssemblyList = value;
RaisePropertyChanged();
}
}
}
void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
public ICommand NewCommand { get; }
public ICommand CloneCommand { get; }
public ICommand ResetCommand { get; }
public ICommand DeleteCommand { get; }
private void ExecuteNew(ManageAssemblyListsDialog dialog)
{
okButton.IsEnabled = listView.SelectedItem != null;
deleteButton.IsEnabled = listView.SelectedItem != null;
CreateListDialog dlg = new CreateListDialog();
dlg.Owner = dialog;
dlg.Closing += (s, args) => {
if (dlg.DialogResult == true) {
if (manager.AssemblyLists.Contains(dlg.NewListName)) {
args.Cancel = true;
MessageBox.Show(Properties.Resources.ListExistsAlready, null, MessageBoxButton.OK);
}
}
};
if (dlg.ShowDialog() == true) {
manager.CreateList(new AssemblyList(dlg.NewListName));
}
}
void OKButton_Click(object sender, RoutedEventArgs e)
private bool CanExecuteClone(ManageAssemblyListsDialog _)
{
this.DialogResult = true;
return selectedAssemblyList != null;
}
public string SelectedListName
private void ExecuteClone(ManageAssemblyListsDialog dialog)
{
get
{
return listView.SelectedItem.ToString();
CreateListDialog dlg = new CreateListDialog();
dlg.Owner = dialog;
dlg.Closing += (s, args) => {
if (dlg.DialogResult == true) {
if (manager.AssemblyLists.Contains(dlg.NewListName)) {
args.Cancel = true;
MessageBox.Show(Properties.Resources.ListExistsAlready, null, MessageBoxButton.OK);
}
}
};
if (dlg.ShowDialog() == true) {
manager.CloneList(SelectedAssemblyList, dlg.NewListName);
}
}
private void ExecuteReset(ManageAssemblyListsDialog dialog)
{
if (MessageBox.Show(dialog, Properties.Resources.ListsResetConfirmation,
"ILSpy", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No, MessageBoxOptions.None) != MessageBoxResult.Yes)
return;
manager.ClearAll();
CreateDefaultAssemblyLists();
MainWindow.Instance.SessionSettings.ActiveAssemblyList = manager.AssemblyLists[0];
}
private void ExecuteDelete(ManageAssemblyListsDialog dialog)
{
if (MessageBox.Show(dialog, Properties.Resources.ListDeleteConfirmation,
"ILSpy", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No, MessageBoxOptions.None) != MessageBoxResult.Yes)
return;
manager.DeleteList(SelectedAssemblyList);
}
private bool CanExecuteDelete(ManageAssemblyListsDialog _)
{
return selectedAssemblyList != null;
}
private void CreateDefaultAssemblyLists()
{
if (!manager.AssemblyLists.Contains(DotNet4List))
{
if (!manager.AssemblyLists.Contains(DotNet4List)) {
AssemblyList dotnet4 = new AssemblyList(DotNet4List);
AddToList(dotnet4, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
@ -85,14 +141,12 @@ namespace ICSharpCode.ILSpy @@ -85,14 +141,12 @@ namespace ICSharpCode.ILSpy
AddToList(dotnet4, "PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(dotnet4, "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
if (dotnet4.assemblies.Count > 0)
{
if (dotnet4.assemblies.Count > 0) {
manager.CreateList(dotnet4);
}
}
if (!manager.AssemblyLists.Contains(DotNet35List))
{
if (!manager.AssemblyLists.Contains(DotNet35List)) {
AssemblyList dotnet35 = new AssemblyList(DotNet35List);
AddToList(dotnet35, "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet35, "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
@ -105,14 +159,12 @@ namespace ICSharpCode.ILSpy @@ -105,14 +159,12 @@ namespace ICSharpCode.ILSpy
AddToList(dotnet35, "PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(dotnet35, "WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
if (dotnet35.assemblies.Count > 0)
{
if (dotnet35.assemblies.Count > 0) {
manager.CreateList(dotnet35);
}
}
if (!manager.AssemblyLists.Contains(ASPDotNetMVC3List))
{
if (!manager.AssemblyLists.Contains(ASPDotNetMVC3List)) {
AssemblyList mvc = new AssemblyList(ASPDotNetMVC3List);
AddToList(mvc, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
@ -139,8 +191,7 @@ namespace ICSharpCode.ILSpy @@ -139,8 +191,7 @@ namespace ICSharpCode.ILSpy
AddToList(mvc, "System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
if (mvc.assemblies.Count > 0)
{
if (mvc.assemblies.Count > 0) {
manager.CreateList(mvc);
}
}
@ -153,52 +204,5 @@ namespace ICSharpCode.ILSpy @@ -153,52 +204,5 @@ namespace ICSharpCode.ILSpy
if (file != null)
list.OpenAssembly(file);
}
private void CreateButton_Click(object sender, RoutedEventArgs e)
{
CreateListDialog dlg = new CreateListDialog();
dlg.Owner = this;
dlg.Closing += (s, args) =>
{
if (dlg.DialogResult == true)
{
if (manager.AssemblyLists.Contains(dlg.NewListName))
{
args.Cancel = true;
MessageBox.Show("A list with the same name was found.", null, MessageBoxButton.OK);
}
}
};
if (dlg.ShowDialog() == true)
{
manager.CreateList(new AssemblyList(dlg.NewListName));
}
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
if (listView.SelectedItem == null)
return;
if (MessageBox.Show(this, "Are you sure that you want to delete the selected assembly list?",
"ILSpy", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No, MessageBoxOptions.None) != MessageBoxResult.Yes)
return;
manager.DeleteList(listView.SelectedItem.ToString());
}
private void ResetButton_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show(this, "Are you sure that you want to remove all assembly lists and recreate the default assembly lists?",
"ILSpy", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No, MessageBoxOptions.None) != MessageBoxResult.Yes)
return;
manager.ClearAll();
CreateDefaultAssemblyLists();
}
private void listView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left && listView.SelectedItem != null)
this.DialogResult = true;
}
}
}

6
ILSpy/ViewModels/ToolPaneModel.cs

@ -20,6 +20,10 @@ namespace ICSharpCode.ILSpy.ViewModels @@ -20,6 +20,10 @@ namespace ICSharpCode.ILSpy.ViewModels
{
public abstract class ToolPaneModel : PaneModel
{
public void Show()
{
this.IsActive = true;
this.IsVisible = true;
}
}
}

20
ILSpy/ViewModels/ViewModelBase.cs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.ILSpy.ViewModels
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

0
ILSpy/CreateListDialog.xaml → ILSpy/Views/CreateListDialog.xaml

0
ILSpy/CreateListDialog.xaml.cs → ILSpy/Views/CreateListDialog.xaml.cs

0
ILSpy/DebugSteps.xaml → ILSpy/Views/DebugSteps.xaml

5
ILSpy/DebugSteps.xaml.cs → ILSpy/Views/DebugSteps.xaml.cs

@ -79,11 +79,6 @@ namespace ICSharpCode.ILSpy @@ -79,11 +79,6 @@ namespace ICSharpCode.ILSpy
#endif
}
public static void Show()
{
DebugStepsPaneModel.Instance.IsVisible = true;
}
void IPane.Closed()
{
#if DEBUG

35
ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
// Copyright (c) 2011 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.Windows;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Interaction logic for ManageAssemblyListsDialog.xaml
/// </summary>
public partial class ManageAssemblyListsDialog : Window
{
public ManageAssemblyListsDialog()
{
InitializeComponent();
DataContext = new ManageAssemblyListsViewModel();
}
}
}

39
ILSpy/Views/ManageAssemblyListsDialog.xaml

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
<Window
x:Class="ICSharpCode.ILSpy.ManageAssemblyListsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
Title="{x:Static properties:Resources.ManageAssemblyLists}"
Style="{DynamicResource DialogWindow}"
WindowStartupLocation="CenterOwner"
ResizeMode="CanResizeWithGrip"
MinWidth="480"
MinHeight="250"
Height="350"
Width="480"
FocusManager.FocusedElement="{Binding ElementName=listView}">
<Grid Margin="12,8">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ListBox Name="listView" Margin="0 8" Grid.ColumnSpan="4" SelectedItem="{Binding SelectedAssemblyList}"
SelectionMode="Single" ItemsSource="{Binding AssemblyLists}" />
<StackPanel Grid.Column="5" Grid.RowSpan="2" Margin="4, 8">
<Button Margin="2 2 2 10" Command="{Binding NewCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources._New}"/>
<Button Margin="2" Command="{Binding CloneCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources.C_lone}"/>
<Button Margin="2" Command="{Binding DeleteCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources.OpenListDialog__Delete}"/>
<Button Margin="2 10 2 2" Command="{Binding ResetCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources._Reset}"/>
</StackPanel>
<Button IsCancel="True" Grid.Row="2" Margin="2,0" Content="{x:Static properties:Resources.Close}" />
</Grid>
</Window>

0
ILSpy/NugetPackageBrowserDialog.xaml → ILSpy/Views/NugetPackageBrowserDialog.xaml

0
ILSpy/NugetPackageBrowserDialog.xaml.cs → ILSpy/Views/NugetPackageBrowserDialog.xaml.cs

0
ILSpy/OpenFromGacDialog.xaml → ILSpy/Views/OpenFromGacDialog.xaml

0
ILSpy/OpenFromGacDialog.xaml.cs → ILSpy/Views/OpenFromGacDialog.xaml.cs

10
README.md

@ -48,8 +48,8 @@ How to build @@ -48,8 +48,8 @@ How to build
------------
Windows:
- Install Visual Studio (documented version: 16.3) with the following components:
- Workload ".NET Desktop Development". This includes by default .NET Framework 4.8 SDK and the .NET Framework 4.7.2 targeting pack, as well as the [.NET Core 3.0 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.0) (ILSpy.csproj targets .NET 4.7.2, and ILSpy.sln uses SDK-style projects).
- Install Visual Studio (documented version: 16.4) with the following components:
- Workload ".NET Desktop Development". This includes by default .NET Framework 4.8 SDK and the .NET Framework 4.7.2 targeting pack, as well as the [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.1) (ILSpy.csproj targets .NET 4.7.2, and ILSpy.sln uses SDK-style projects).
- Workload "Visual Studio extension development" (ILSpy.sln contains a VS extension project)
- Individual Component "MSVC v142 - VS 2019 C++ x64/x86 build tools (v14.23)" (or similar)
- The VC++ toolset is optional; if present it is used for `editbin.exe` to modify the stack size used by ILSpy.exe from 1MB to 16MB, because the decompiler makes heavy use of recursion, where small stack sizes lead to problems in very complex methods.
@ -60,11 +60,13 @@ Windows: @@ -60,11 +60,13 @@ Windows:
- Run project "ILSpy" for the ILSpy UI
- Use the Visual Studio "Test Explorer" to see/run the tests
**Note:** Visual Studio 16.3 and later include a version of the .NET Core SDK that is managed by the Visual Studio installer, once you update to 16.4 it may get upgraded to version 3.1. Please note that ILSpy is not compatible with the .NET Core 3.1 SDK and Visual Studio will refuse to load some projects in the solution. If this problem occurs, please manually install the .NET Core 3.0 SDK from [here](https://dotnet.microsoft.com/download/dotnet-core/3.0).
**Note:** Visual Studio 16.3 and later include a version of the .NET Core SDK that is managed by the Visual Studio installer - once you update, it may get upgraded too.
Please note that ILSpy is only compatible with the .NET Core 3.1 SDK and Visual Studio will refuse to load some projects in the solution (and unit tests will fail).
If this problem occurs, please manually install the .NET Core 3.1 SDK from [here](https://dotnet.microsoft.com/download/dotnet-core/3.1).
Unix / Mac:
- Make sure .NET Core 2.1 LTS Runtime is installed (you can get it here: https://get.dot.net).
- Make sure [.NET Core 3.0 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.0) is installed.
- Make sure [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.1) is installed.
- Check out the repository using git.
- Execute `git submodule update --init --recursive` to download the ILSpy-Tests submodule (used by some test cases).
- Use `dotnet build Frontends.sln` to build the non-Windows flavors of ILSpy (.NET Core Global Tool and PowerShell Core).

5
TestPlugin/CustomOptionPage.xaml.cs

@ -31,6 +31,11 @@ namespace TestPlugin @@ -31,6 +31,11 @@ namespace TestPlugin
this.DataContext = s;
}
public void LoadDefaults()
{
this.DataContext = new Options();
}
public void Save(XElement root)
{
Options s = (Options)this.DataContext;

8
azure-pipelines.yml

@ -37,9 +37,13 @@ jobs: @@ -37,9 +37,13 @@ jobs:
- checkout: self
submodules: recursive
- task: DotNetCoreInstaller@0
- task: UseDotNet@2
displayName: 'Install .NET Core 3.1'
inputs:
version: '3.0.100'
packageType: sdk
version: '3.1.100'
installationPath: $(Agent.ToolsDirectory)/dotnet
- powershell: .\BuildTools\pipelines-install.ps1
displayName: Install

10
debugbuild.bat

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
@setlocal enabledelayedexpansion
@set MSBUILD=
@for /D %%M in ("%ProgramFiles(x86)%\Microsoft Visual Studio\2019"\*) do (
@for /D %%M in ("%ProgramFiles(x86)%\Microsoft Visual Studio\2019"\*) do @(
@if exist "%%M\MSBuild\Current\Bin\MSBuild.exe" (
@set "MSBUILD=%%M\MSBuild\Current\Bin\MSBuild.exe"
)
@ -9,9 +9,5 @@ @@ -9,9 +9,5 @@
@echo Could not find VS2019 MSBuild
@exit /b 1
)
"%MSBUILD%" ILSpy.sln /p:Configuration=Debug "/p:Platform=Any CPU"
@IF %ERRORLEVEL% NEQ 0 (
@pause
@exit /b 1
)
@exit /b 0
@nuget restore ILSpy.sln || (pause && exit /b 1)
"%MSBUILD%" ILSpy.sln /p:Configuration=Debug "/p:Platform=Any CPU" || (pause && exit /b 1)

2
global.json

@ -3,6 +3,6 @@ @@ -3,6 +3,6 @@
"MSBuild.Sdk.Extras": "2.0.54"
},
"sdk": {
"version": "3.0.100"
"version": "3.1.100"
}
}

29
preparerelease.bat

@ -1,29 +0,0 @@ @@ -1,29 +0,0 @@
@setlocal enabledelayedexpansion
@set MSBUILD=
@for /D %%M in ("%ProgramFiles(x86)%\Microsoft Visual Studio\2019"\*) do (
@if exist "%%M\MSBuild\Current\Bin\MSBuild.exe" (
@set "MSBUILD=%%M\MSBuild\Current\Bin\MSBuild.exe"
)
)
@if "%MSBUILD%" == "" (
@echo Could not find VS2019 MSBuild
@exit /b 1
)
@del ICSharpCode.Decompiler\bin\Release\*.nupkg
"%MSBUILD%" ILSpy.sln /p:Configuration=Release "/p:Platform=Any CPU"
@IF %ERRORLEVEL% NEQ 0 (
@pause
@exit /b 1
)
@if not exist "%ProgramFiles%\7-zip\7z.exe" (
@echo Could not find 7zip
@exit /b 1
)
@del artifacts.zip
@rmdir /Q /S artifacts
@mkdir artifacts
"%ProgramFiles%\7-zip\7z.exe" a artifacts\ILSpy_binaries.zip %cd%\ILSpy\bin\Release\net46\*.dll %cd%\ILSpy\bin\Release\net46\*.exe %cd%\ILSpy\bin\Release\net46\*.config
@copy ILSpy.AddIn\bin\Release\net46\ILSpy.AddIn.vsix artifacts\
@copy ICSharpCode.Decompiler\bin\Release\*.nupkg artifacts\
"%ProgramFiles%\7-zip\7z.exe" a artifacts.zip %cd%\artifacts\*
@exit /b 0

10
releasebuild.bat

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
@setlocal enabledelayedexpansion
@set MSBUILD=
@for /D %%M in ("%ProgramFiles(x86)%\Microsoft Visual Studio\2019"\*) do (
@for /D %%M in ("%ProgramFiles(x86)%\Microsoft Visual Studio\2019"\*) do @(
@if exist "%%M\MSBuild\Current\Bin\MSBuild.exe" (
@set "MSBUILD=%%M\MSBuild\Current\Bin\MSBuild.exe"
)
@ -9,9 +9,5 @@ @@ -9,9 +9,5 @@
@echo Could not find VS2019 MSBuild
@exit /b 1
)
"%MSBUILD%" ILSpy.sln /p:Configuration=Release "/p:Platform=Any CPU"
@IF %ERRORLEVEL% NEQ 0 (
@pause
@exit /b 1
)
@exit /b 0
@nuget restore ILSpy.sln || (pause && exit /b 1)
"%MSBUILD%" ILSpy.sln /p:Configuration=Release "/p:Platform=Any CPU" || (pause && exit /b 1)

Loading…
Cancel
Save