|
|
|
@ -16,68 +16,69 @@ using ICSharpCode.Decompiler.IL;
@@ -16,68 +16,69 @@ using ICSharpCode.Decompiler.IL;
|
|
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
|
using ICSharpCode.Decompiler.Util; |
|
|
|
|
using Mono.Cecil; |
|
|
|
|
using Mono.Cecil.Cil; |
|
|
|
|
|
|
|
|
|
namespace ICSharpCode.ILSpy |
|
|
|
|
{ |
|
|
|
|
[Export(typeof(Language))] |
|
|
|
|
class CSharpILMixedLanguage : Language |
|
|
|
|
class CSharpILMixedLanguage : ILLanguage |
|
|
|
|
{ |
|
|
|
|
private readonly bool detectControlStructure = true; |
|
|
|
|
|
|
|
|
|
public override string Name => "IL with C#"; |
|
|
|
|
|
|
|
|
|
public override string FileExtension => ".il"; |
|
|
|
|
protected override ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) |
|
|
|
|
{ |
|
|
|
|
return new ReflectionDisassembler(output, |
|
|
|
|
new MixedMethodBodyDisassembler(output, detectControlStructure, options), |
|
|
|
|
options.CancellationToken); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CSharpDecompiler CreateDecompiler(ModuleDefinition module, DecompilationOptions options) |
|
|
|
|
static CSharpDecompiler CreateDecompiler(ModuleDefinition module, DecompilationOptions options) |
|
|
|
|
{ |
|
|
|
|
CSharpDecompiler decompiler = new CSharpDecompiler(module, options.DecompilerSettings); |
|
|
|
|
decompiler.CancellationToken = options.CancellationToken; |
|
|
|
|
return decompiler; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void WriteCode(TextWriter output, DecompilerSettings settings, SyntaxTree syntaxTree, IDecompilerTypeSystem typeSystem) |
|
|
|
|
static void WriteCode(TextWriter output, DecompilerSettings settings, SyntaxTree syntaxTree, IDecompilerTypeSystem typeSystem) |
|
|
|
|
{ |
|
|
|
|
syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }); |
|
|
|
|
TokenWriter tokenWriter = new TextWriterTokenWriter(output); |
|
|
|
|
tokenWriter = TokenWriter.WrapInWriterThatSetsLocationsInAST(tokenWriter); |
|
|
|
|
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, settings.CSharpFormattingOptions)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) |
|
|
|
|
{ |
|
|
|
|
//AddReferenceWarningMessage(method.Module.Assembly, output);
|
|
|
|
|
var csharpOutput = new StringWriter(); |
|
|
|
|
CSharpDecompiler decompiler = CreateDecompiler(method.Module, options); |
|
|
|
|
var st = decompiler.Decompile(method); |
|
|
|
|
WriteCode(csharpOutput, options.DecompilerSettings, st, decompiler.TypeSystem); |
|
|
|
|
var sequencePoints = (IList<SequencePoint>)decompiler.CreateSequencePoints(st).FirstOrDefault(kvp => kvp.Key.CecilMethod == method).Value ?? EmptyList<SequencePoint>.Instance; |
|
|
|
|
var codeLines = csharpOutput.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None); |
|
|
|
|
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true)); |
|
|
|
|
var methodDisassembler = new MixedMethodBodyDisassembler(output, codeLines, sequencePoints, detectControlStructure, options.CancellationToken); |
|
|
|
|
var dis = new ReflectionDisassembler(output, methodDisassembler, options.CancellationToken); |
|
|
|
|
dis.DisassembleMethod(method); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MixedMethodBodyDisassembler : MethodBodyDisassembler |
|
|
|
|
{ |
|
|
|
|
readonly DecompilationOptions options; |
|
|
|
|
// list sorted by IL offset
|
|
|
|
|
IList<SequencePoint> sequencePoints; |
|
|
|
|
IList<Decompiler.IL.SequencePoint> sequencePoints; |
|
|
|
|
// lines of raw c# source code
|
|
|
|
|
string[] codeLines; |
|
|
|
|
|
|
|
|
|
public MixedMethodBodyDisassembler(ITextOutput output, string[] codeLines, IList<SequencePoint> sequencePoints, bool detectControlStructure, CancellationToken cancellationToken) |
|
|
|
|
: base(output, detectControlStructure, cancellationToken) |
|
|
|
|
public MixedMethodBodyDisassembler(ITextOutput output, bool detectControlStructure, DecompilationOptions options) |
|
|
|
|
: base(output, detectControlStructure, options.CancellationToken) |
|
|
|
|
{ |
|
|
|
|
if (codeLines == null) |
|
|
|
|
throw new ArgumentNullException(nameof(codeLines)); |
|
|
|
|
if (sequencePoints == null) |
|
|
|
|
throw new ArgumentNullException(nameof(sequencePoints)); |
|
|
|
|
this.options = options; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.codeLines = codeLines; |
|
|
|
|
this.sequencePoints = sequencePoints; |
|
|
|
|
public override void Disassemble(MethodBody body) |
|
|
|
|
{ |
|
|
|
|
var method = body.Method; |
|
|
|
|
try { |
|
|
|
|
var csharpOutput = new StringWriter(); |
|
|
|
|
CSharpDecompiler decompiler = CreateDecompiler(method.Module, options); |
|
|
|
|
var st = decompiler.Decompile(method); |
|
|
|
|
WriteCode(csharpOutput, options.DecompilerSettings, st, decompiler.TypeSystem); |
|
|
|
|
this.sequencePoints = decompiler.CreateSequencePoints(st).FirstOrDefault(kvp => kvp.Key.CecilMethod == method).Value ?? (IList<Decompiler.IL.SequencePoint>)EmptyList<Decompiler.IL.SequencePoint>.Instance; |
|
|
|
|
this.codeLines = csharpOutput.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None); |
|
|
|
|
base.Disassemble(body); |
|
|
|
|
} finally { |
|
|
|
|
this.sequencePoints = null; |
|
|
|
|
this.codeLines = null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected override void WriteInstruction(ITextOutput output, Mono.Cecil.Cil.Instruction instruction) |
|
|
|
|
protected override void WriteInstruction(ITextOutput output, Instruction instruction) |
|
|
|
|
{ |
|
|
|
|
int index = sequencePoints.BinarySearch(instruction.Offset, seq => seq.Offset); |
|
|
|
|
if (index >= 0) { |
|
|
|
|