Browse Source

Implement basic mixed view in CSharpILMixedLanguage

pull/923/head
Siegfried Pammer 8 years ago
parent
commit
a663b5b0df
  1. 25
      ILSpy/ExtensionMethods.cs
  2. 103
      ILSpy/Languages/CSharpILMixedLanguage.cs

25
ILSpy/ExtensionMethods.cs

@ -64,6 +64,31 @@ namespace ICSharpCode.ILSpy @@ -64,6 +64,31 @@ namespace ICSharpCode.ILSpy
return ~start;
}
public static int BinarySearch<T, TKey>(this IList<T> instance, TKey itemKey, Func<T, TKey> keySelector)
where TKey : IComparable<TKey>, IComparable
{
if (instance == null)
throw new ArgumentNullException(nameof(instance));
if (keySelector == null)
throw new ArgumentNullException(nameof(keySelector));
int start = 0;
int end = instance.Count - 1;
while (start <= end) {
int m = (start + end) / 2;
TKey key = keySelector(instance[m]);
int result = key.CompareTo(itemKey);
if (result == 0)
return m;
if (result < 0)
start = m + 1;
else
end = m - 1;
}
return ~start;
}
public static bool IsCustomAttribute(this TypeDefinition type)
{
while (type.FullName != "System.Object") {

103
ILSpy/Languages/CSharpILMixedLanguage.cs

@ -1,9 +1,20 @@ @@ -1,9 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
namespace ICSharpCode.ILSpy
@ -17,10 +28,100 @@ namespace ICSharpCode.ILSpy @@ -17,10 +28,100 @@ namespace ICSharpCode.ILSpy
public override string FileExtension => ".il";
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)
{
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)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
//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
{
// list sorted by IL offset
IList<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)
{
if (codeLines == null)
throw new ArgumentNullException(nameof(codeLines));
if (sequencePoints == null)
throw new ArgumentNullException(nameof(sequencePoints));
this.codeLines = codeLines;
this.sequencePoints = sequencePoints;
}
protected override void WriteInstruction(ITextOutput output, Mono.Cecil.Cil.Instruction instruction)
{
int index = sequencePoints.BinarySearch(instruction.Offset, seq => seq.Offset);
if (index >= 0) {
var info = sequencePoints[index];
if (!info.IsHidden) {
for (int line = info.StartLine; line <= info.EndLine; line++) {
if (output is ISmartTextOutput highlightingOutput) {
string text = codeLines[line - 1];
int startColumn = 1;
int endColumn = text.Length + 1;
if (line == info.StartLine)
startColumn = info.StartColumn;
if (line == info.EndLine)
endColumn = info.EndColumn;
WriteHighlightedCommentLine(highlightingOutput, text, startColumn - 1, endColumn - 1);
} else
WriteCommentLine(output, codeLines[line - 1]);
}
} else {
WriteCommentLine(output, "no code");
}
}
base.WriteInstruction(output, instruction);
}
HighlightingColor gray = new HighlightingColor { Foreground = new SimpleHighlightingBrush(Colors.DarkGray) };
HighlightingColor black = new HighlightingColor { Foreground = new SimpleHighlightingBrush(Colors.Black) };
void WriteHighlightedCommentLine(ISmartTextOutput output, string text, int startColumn, int endColumn)
{
output.BeginSpan(gray);
output.Write("// " + text.Substring(0, startColumn));
output.BeginSpan(black);
output.Write(text.Substring(startColumn, endColumn - startColumn));
output.EndSpan();
output.Write(text.Substring(endColumn));
output.EndSpan();
output.WriteLine();
}
void WriteCommentLine(ITextOutput output, string text)
{
output.WriteLine("// " + text);
}
}
}
}

Loading…
Cancel
Save