From d2f2a139823eb2991c0150e8c196d5c7095a6108 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Wed, 1 Nov 2017 19:54:11 +0100 Subject: [PATCH] Add RemoveDeadCode option --- ICSharpCode.Decompiler/DecompilerSettings.cs | 90 +++++++++++-------- .../IL/Transforms/RemoveDeadVariableInit.cs | 34 +++---- ILSpy/Options/DecompilerSettingsPanel.xaml | 1 + 3 files changed, 71 insertions(+), 54 deletions(-) diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index 5e8858356..62247af52 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -29,7 +29,7 @@ namespace ICSharpCode.Decompiler public class DecompilerSettings : INotifyPropertyChanged { bool anonymousMethods = true; - + /// /// Decompile anonymous methods/lambdas. /// @@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler } bool expressionTrees = true; - + /// /// Decompile expression trees. /// @@ -72,9 +72,9 @@ namespace ICSharpCode.Decompiler } } } - + bool yieldReturn = true; - + /// /// Decompile enumerators. /// @@ -87,9 +87,9 @@ namespace ICSharpCode.Decompiler } } } - + bool asyncAwait = true; - + /// /// Decompile async methods. /// @@ -134,7 +134,7 @@ namespace ICSharpCode.Decompiler } bool automaticProperties = true; - + /// /// Decompile automatic properties /// @@ -147,9 +147,9 @@ namespace ICSharpCode.Decompiler } } } - + bool automaticEvents = true; - + /// /// Decompile automatic events /// @@ -162,9 +162,9 @@ namespace ICSharpCode.Decompiler } } } - + bool usingStatement = true; - + /// /// Decompile using statements. /// @@ -177,9 +177,9 @@ namespace ICSharpCode.Decompiler } } } - + bool forEachStatement = true; - + /// /// Decompile foreach statements. /// @@ -192,9 +192,9 @@ namespace ICSharpCode.Decompiler } } } - + bool lockStatement = true; - + /// /// Decompile lock statements. /// @@ -207,9 +207,9 @@ namespace ICSharpCode.Decompiler } } } - + bool switchStatementOnString = true; - + public bool SwitchStatementOnString { get { return switchStatementOnString; } set { @@ -219,9 +219,9 @@ namespace ICSharpCode.Decompiler } } } - + bool usingDeclarations = true; - + public bool UsingDeclarations { get { return usingDeclarations; } set { @@ -231,9 +231,9 @@ namespace ICSharpCode.Decompiler } } } - + bool queryExpressions = true; - + public bool QueryExpressions { get { return queryExpressions; } set { @@ -262,7 +262,7 @@ namespace ICSharpCode.Decompiler } bool fullyQualifyAmbiguousTypeNames = true; - + public bool FullyQualifyAmbiguousTypeNames { get { return fullyQualifyAmbiguousTypeNames; } set { @@ -272,9 +272,9 @@ namespace ICSharpCode.Decompiler } } } - + bool useDebugSymbols = true; - + /// /// Gets/Sets whether to use variable names from debug symbols, if available. /// @@ -287,9 +287,9 @@ namespace ICSharpCode.Decompiler } } } - + bool objectCollectionInitializers = true; - + /// /// Gets/Sets whether to use C# 3.0 object/collection initializers /// @@ -302,9 +302,9 @@ namespace ICSharpCode.Decompiler } } } - + bool showXmlDocumentation = true; - + /// /// Gets/Sets whether to include XML documentation comments in the decompiled code /// @@ -319,7 +319,7 @@ namespace ICSharpCode.Decompiler } bool foldBraces = false; - + public bool FoldBraces { get { return foldBraces; } set { @@ -329,10 +329,10 @@ namespace ICSharpCode.Decompiler } } } - + #region Options to aid VB decompilation bool introduceIncrementAndDecrement = true; - + /// /// Gets/Sets whether to use increment and decrement operators /// @@ -345,9 +345,9 @@ namespace ICSharpCode.Decompiler } } } - + bool makeAssignmentExpressions = true; - + /// /// Gets/Sets whether to use assignment expressions such as in while ((count = Do()) != 0) ; /// @@ -360,9 +360,9 @@ namespace ICSharpCode.Decompiler } } } - + bool alwaysGenerateExceptionVariableForCatchBlocks = false; - + /// /// Gets/Sets whether to always generate exception variables in catch blocks /// @@ -390,6 +390,20 @@ namespace ICSharpCode.Decompiler #endregion + #region Options to aid F# decompilation + bool removeDeadCode = false; + + public bool RemoveDeadCode { + get { return removeDeadCode; } + set { + if (removeDeadCode != value) { + removeDeadCode = value; + OnPropertyChanged(); + } + } + } + #endregion + #region Assembly Load and Resolve options bool loadInMemory = false; @@ -419,7 +433,7 @@ namespace ICSharpCode.Decompiler #endregion CSharpFormattingOptions csharpFormattingOptions; - + public CSharpFormattingOptions CSharpFormattingOptions { get { if (csharpFormattingOptions == null) { @@ -440,14 +454,14 @@ namespace ICSharpCode.Decompiler } public event PropertyChangedEventHandler PropertyChanged; - + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } - + public DecompilerSettings Clone() { DecompilerSettings settings = (DecompilerSettings)MemberwiseClone(); diff --git a/ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs b/ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs index e5d1831bf..91ed54025 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs @@ -44,22 +44,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms // This is necessary to remove useless stores generated by some compilers, e.g., the F# compiler. // In yield return + async, the C# compiler tends to store null/default(T) to variables // when the variable goes out of scope. - var variableQueue = new Queue(function.Variables); - while (variableQueue.Count > 0) { - var v = variableQueue.Dequeue(); - if (v.Kind != VariableKind.Local && v.Kind != VariableKind.StackSlot) - continue; - if (v.LoadCount != 0 || v.AddressCount != 0) - continue; - foreach (var stloc in v.StoreInstructions.OfType().ToArray()) { - if (stloc.Parent is Block block) { - if (SemanticHelper.IsPure(stloc.Value.Flags)) { - block.Instructions.Remove(stloc); - } else { - stloc.ReplaceWith(stloc.Value); - } - if (stloc.Value is LdLoc ldloc) { - variableQueue.Enqueue(ldloc.Variable); + if (function.IsAsync || function.IsIterator || context.Settings.RemoveDeadCode) { + var variableQueue = new Queue(function.Variables); + while (variableQueue.Count > 0) { + var v = variableQueue.Dequeue(); + if (v.Kind != VariableKind.Local && v.Kind != VariableKind.StackSlot) + continue; + if (v.LoadCount != 0 || v.AddressCount != 0) + continue; + foreach (var stloc in v.StoreInstructions.OfType().ToArray()) { + if (stloc.Parent is Block block) { + if (SemanticHelper.IsPure(stloc.Value.Flags)) { + block.Instructions.Remove(stloc); + } else { + stloc.ReplaceWith(stloc.Value); + } + if (stloc.Value is LdLoc ldloc) { + variableQueue.Enqueue(ldloc.Variable); + } } } } diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml b/ILSpy/Options/DecompilerSettingsPanel.xaml index e43c553d3..4d76de14e 100644 --- a/ILSpy/Options/DecompilerSettingsPanel.xaml +++ b/ILSpy/Options/DecompilerSettingsPanel.xaml @@ -14,5 +14,6 @@ Show info from debug symbols, if available Show XML documentation in decompiled code Enable folding on all blocks in braces + Remove dead and side effect free code. \ No newline at end of file