From d2b66515074b039be4ef38bb62ddfa675a96101f Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 14 Oct 2017 18:58:41 +0200 Subject: [PATCH] ILAst: show unused IL ranges --- .../CSharp/SequencePointBuilder.cs | 20 ++++++++++-- .../IL/ILAstWritingOptions.cs | 21 +++++++++++-- .../IL/Instructions/Block.cs | 1 + .../IL/Instructions/BlockContainer.cs | 1 + .../IL/Instructions/ILFunction.cs | 31 ++++++++++++++++++- 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs b/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs index e86825bc5..a4528113f 100644 --- a/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs @@ -171,9 +171,11 @@ namespace ICSharpCode.Decompiler.CSharp return; } // Add the IL range associated with this instruction to the current sequence point. - if (!inst.ILRange.IsEmpty && current.Intervals != null) { + if (HasUsableILRange(inst) && current.Intervals != null) { current.Intervals.Add(inst.ILRange); - current.Function = inst.Parent.Ancestors.OfType().FirstOrDefault(); + var function = inst.Parent.Ancestors.OfType().FirstOrDefault(); + Debug.Assert(current.Function == null || current.Function == function); + current.Function = function; } // Do not add instructions of lambdas/delegates. @@ -187,6 +189,13 @@ namespace ICSharpCode.Decompiler.CSharp } } + internal static bool HasUsableILRange(ILInstruction inst) + { + if (inst.ILRange.IsEmpty) + return false; + return !(inst is BlockContainer || inst is Block); + } + /// /// Called after the visitor is done to return the results. /// @@ -227,6 +236,13 @@ namespace ICSharpCode.Decompiler.CSharp newList.Add(sequencePoint); pos = sequencePoint.EndOffset; } + if (pos < function.CecilMethod.Body.CodeSize) { + var hidden = new SequencePoint(); + hidden.Offset = pos; + hidden.EndOffset = function.CecilMethod.Body.CodeSize; + hidden.SetHidden(); + newList.Add(hidden); + } dict[function] = newList; } return dict; diff --git a/ICSharpCode.Decompiler/IL/ILAstWritingOptions.cs b/ICSharpCode.Decompiler/IL/ILAstWritingOptions.cs index 42b8ddf66..3b6098d1c 100644 --- a/ICSharpCode.Decompiler/IL/ILAstWritingOptions.cs +++ b/ICSharpCode.Decompiler/IL/ILAstWritingOptions.cs @@ -1,8 +1,23 @@ -using System; -using System.Collections.Generic; +// Copyright (c) 2017 Daniel Grunwald +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + using System.ComponentModel; using System.Runtime.CompilerServices; -using System.Text; namespace ICSharpCode.Decompiler.IL { diff --git a/ICSharpCode.Decompiler/IL/Instructions/Block.cs b/ICSharpCode.Decompiler/IL/Instructions/Block.cs index 0c5f9b7cc..8548717bc 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Block.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Block.cs @@ -129,6 +129,7 @@ namespace ICSharpCode.Decompiler.IL public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { + ILRange.WriteTo(output, options); output.Write("Block "); output.WriteDefinition(Label, this); if (Parent is BlockContainer) diff --git a/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs b/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs index b70056841..099f553a4 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs @@ -107,6 +107,7 @@ namespace ICSharpCode.Decompiler.IL public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { + ILRange.WriteTo(output, options); output.WriteDefinition("BlockContainer", this); output.Write(' '); output.MarkFoldStart("{...}"); diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs index 523f6218e..4424ba4f5 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs @@ -114,12 +114,41 @@ namespace ICSharpCode.Decompiler.IL } body.WriteTo(output, options); - output.WriteLine(); + + if (options.ShowILRanges) { + var unusedILRanges = FindUnusedILRanges(); + if (!unusedILRanges.IsEmpty) { + output.Write("// Unused IL Ranges: "); + output.Write(string.Join(", ", unusedILRanges.Intervals.Select( + range => $"[{range.Start:x4}..{range.InclusiveEnd:x4}]"))); + output.WriteLine(); + } + } + output.Unindent(); output.WriteLine("}"); } + LongSet FindUnusedILRanges() + { + var usedILRanges = new List(); + MarkUsedILRanges(body); + return new LongSet(new LongInterval(0, CecilMethod.Body.CodeSize)).ExceptWith(new LongSet(usedILRanges)); + + void MarkUsedILRanges(ILInstruction inst) + { + if (CSharp.SequencePointBuilder.HasUsableILRange(inst)) { + usedILRanges.Add(new LongInterval(inst.ILRange.Start, inst.ILRange.End)); + } + if (!(inst is ILFunction)) { + foreach (var child in inst.Children) { + MarkUsedILRanges(child); + } + } + } + } + protected override InstructionFlags ComputeFlags() { // Creating a lambda may throw OutOfMemoryException