From 29ee42f2b014cb63537309ccfaffbb42c2770852 Mon Sep 17 00:00:00 2001 From: limuy Date: Sat, 31 May 2025 18:39:21 +0800 Subject: [PATCH] Add basic code of IL with C# --- .../Decompiler/DecompilerBackend.cs | 54 ++++++++++++++++++- backend/ILSpyX.Backend/Model/LanguageNames.cs | 1 + vscode-extension/package.json | 3 +- .../src/decompiler/languageInfos.ts | 1 + vscode-extension/src/protocol/LanguageName.ts | 1 + 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/backend/ILSpyX.Backend/Decompiler/DecompilerBackend.cs b/backend/ILSpyX.Backend/Decompiler/DecompilerBackend.cs index 08674623..b4ef7f73 100644 --- a/backend/ILSpyX.Backend/Decompiler/DecompilerBackend.cs +++ b/backend/ILSpyX.Backend/Decompiler/DecompilerBackend.cs @@ -6,6 +6,7 @@ using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Util; using ICSharpCode.ILSpyX; using ILSpyX.Backend.Application; using ILSpyX.Backend.Model; @@ -14,13 +15,15 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Threading; using System.Threading.Tasks; namespace ILSpyX.Backend.Decompiler; +using ICSharpCode.ILSpyX.Extensions; +using System.Reflection.Metadata; + public class DecompilerBackend( ILoggerFactory loggerFactory, ILSpyBackendSettings ilspyBackendSettings, @@ -165,6 +168,7 @@ public DecompileResult GetCode(string? assemblyPath, EntityHandle handle, string return outputLanguage switch { LanguageName.IL => DecompileResult.WithCode(GetILCode(assemblyPath, handle)), + LanguageName.ILCharp => DecompileResult.WithCode(GetIlWithCSharpCode(assemblyPath, handle, LanguageName.CSharpLatest)), _ => DecompileResult.WithCode(GetCSharpCode(assemblyPath, handle, outputLanguage)) }; } @@ -229,6 +233,54 @@ private string GetCSharpCode(string assemblyPath, EntityHandle handle, string ou return string.Empty; } + private string GetIlWithCSharpCode(string assemblyPath, EntityHandle handle, string outputLanguage) + { + if (handle.IsNil) + { + return string.Empty; + } + + var decompiler = CreateDecompiler(assemblyPath, outputLanguage); + if (decompiler is null) + { + return string.Empty; + } + + var module = decompiler.TypeSystem.MainModule; + var textOutput = new PlainTextOutput(); + var disassembler = CreateDisassembler(assemblyPath, module, textOutput); + string code; + + switch (handle.Kind) + { + case HandleKind.AssemblyDefinition: + code = GetAssemblyCode(assemblyPath, decompiler); + GetAssemblyILCode(disassembler, assemblyPath, module, textOutput); + return textOutput.ToString() + code; + case HandleKind.TypeDefinition: + var typeDefinition = module.GetDefinition((TypeDefinitionHandle) handle); + disassembler.DisassembleType(module.MetadataFile, (TypeDefinitionHandle) handle); + if (typeDefinition.DeclaringType == null) + code = decompiler.DecompileTypesAsString(new[] { (TypeDefinitionHandle) handle }); + else + code = decompiler.DecompileAsString(handle); + return textOutput.ToString() + code; + case HandleKind.FieldDefinition: + disassembler.DisassembleField(module.MetadataFile, (FieldDefinitionHandle) handle); + return textOutput.ToString() + decompiler.DecompileAsString(handle); + case HandleKind.MethodDefinition: + disassembler.DisassembleMethod(module.MetadataFile, (MethodDefinitionHandle) handle); + return textOutput.ToString() + decompiler.DecompileAsString(handle); + case HandleKind.PropertyDefinition: + disassembler.DisassembleProperty(module.MetadataFile, (PropertyDefinitionHandle) handle); + return textOutput.ToString() + decompiler.DecompileAsString(handle); + case HandleKind.EventDefinition: + disassembler.DisassembleEvent(module.MetadataFile, (EventDefinitionHandle) handle); + return textOutput.ToString() + decompiler.DecompileAsString(handle); + } + return string.Empty; + } + private string GetILCode(string assemblyPath, EntityHandle handle) { if (handle.IsNil) diff --git a/backend/ILSpyX.Backend/Model/LanguageNames.cs b/backend/ILSpyX.Backend/Model/LanguageNames.cs index 650d6590..5b039ec4 100644 --- a/backend/ILSpyX.Backend/Model/LanguageNames.cs +++ b/backend/ILSpyX.Backend/Model/LanguageNames.cs @@ -18,6 +18,7 @@ public class LanguageName public const string CSharp_10 = "cs-10"; public const string CSharp_11 = "cs-11"; public const string CSharp_12 = "cs-12"; + public const string ILCharp = "il-csharp"; public const string CSharpLatest = CSharp_12; } \ No newline at end of file diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 2bcf611e..69f8fb90 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -49,7 +49,8 @@ "C# 3.0 / VS 2008", "C# 2.0 / VS 2005", "C# 1.0 / VS .NET", - "IL" + "IL", + "IL with C#" ], "enumDescriptions": [ "Decompile to C# 12.0 by default", diff --git a/vscode-extension/src/decompiler/languageInfos.ts b/vscode-extension/src/decompiler/languageInfos.ts index b632d20b..1a99bf76 100644 --- a/vscode-extension/src/decompiler/languageInfos.ts +++ b/vscode-extension/src/decompiler/languageInfos.ts @@ -8,6 +8,7 @@ export interface LanguageInfo { export const languageInfos = createLanguageMap([ { name: LanguageName.IL, displayName: "IL", vsLanguageMode: "il" }, + { name: LanguageName.IL_CSharp, displayName: "IL With C#", vsLanguageMode: "il" }, { name: LanguageName.CSharp_1, displayName: "C# 1.0 / VS .NET", diff --git a/vscode-extension/src/protocol/LanguageName.ts b/vscode-extension/src/protocol/LanguageName.ts index 7128c961..92ff9aa4 100644 --- a/vscode-extension/src/protocol/LanguageName.ts +++ b/vscode-extension/src/protocol/LanguageName.ts @@ -5,6 +5,7 @@ export enum LanguageName { IL = "il", + IL_CSharp = "il-csharp", CSharp_1 = "cs-1", CSharp_2 = "cs-2", CSharp_3 = "cs-3",