From 3f5b8602f8e647915b6c2d09016769631b869e2c Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 4 Mar 2018 21:55:19 +0100 Subject: [PATCH] Add Language version dropdown --- ILSpy/Commands/DecompileAllCommand.cs | 2 +- ILSpy/DebugSteps.xaml.cs | 2 +- ILSpy/DecompilationOptions.cs | 19 +- ILSpy/FilterSettings.cs | 32 ++- ILSpy/Languages/CSharpLanguage.cs | 30 ++- ILSpy/Languages/Language.cs | 37 +++ ILSpy/MainWindow.xaml | 4 + ILSpy/MainWindow.xaml.cs | 15 +- ILSpy/Options/DecompilerSettingsPanel.xaml | 8 - ILSpy/Options/DecompilerSettingsPanel.xaml.cs | 240 ++++++++++-------- ILSpy/TreeNodes/AssemblyTreeNode.cs | 2 +- 11 files changed, 250 insertions(+), 141 deletions(-) diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index 2de1c24ef..3d3ecd24f 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.ILSpy Exception exception = null; using (var writer = new System.IO.StreamWriter("c:\\temp\\decompiled\\" + asm.ShortName + ".cs")) { try { - new CSharpLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), new DecompilationOptions { FullDecompilation = true, CancellationToken = ct }); + new CSharpLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), new DecompilationOptions(MainWindow.Instance.CurrentLanguageVersion, Options.DecompilerSettingsPanel.CurrentDecompilerSettings) { FullDecompilation = true, CancellationToken = ct }); } catch (Exception ex) { writer.WriteLine(ex.ToString()); diff --git a/ILSpy/DebugSteps.xaml.cs b/ILSpy/DebugSteps.xaml.cs index f3c3b7a7f..a15b2a198 100644 --- a/ILSpy/DebugSteps.xaml.cs +++ b/ILSpy/DebugSteps.xaml.cs @@ -127,7 +127,7 @@ namespace ICSharpCode.ILSpy var window = MainWindow.Instance; var state = window.TextView.GetState(); window.TextView.DecompileAsync(window.CurrentLanguage, window.SelectedNodes, - new DecompilationOptions() { + new DecompilationOptions(window.CurrentLanguageVersion, ILSpy.Options.DecompilerSettingsPanel.CurrentDecompilerSettings) { StepLimit = step, IsDebug = isDebug, TextViewState = state diff --git a/ILSpy/DecompilationOptions.cs b/ILSpy/DecompilationOptions.cs index 7c1bdaffd..e7da70a27 100644 --- a/ILSpy/DecompilationOptions.cs +++ b/ILSpy/DecompilationOptions.cs @@ -16,6 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; using System.Threading; using ICSharpCode.Decompiler; using ICSharpCode.ILSpy.Options; @@ -50,7 +51,7 @@ namespace ICSharpCode.ILSpy /// /// Gets the settings for the decompiler. /// - public DecompilerSettings DecompilerSettings { get; set; } + public Decompiler.DecompilerSettings DecompilerSettings { get; private set; } /// /// Gets/sets an optional state of a decompiler text view. @@ -66,9 +67,21 @@ namespace ICSharpCode.ILSpy internal int StepLimit = int.MaxValue; internal bool IsDebug = false; - public DecompilationOptions() + public DecompilationOptions(LanguageVersion version, Options.DecompilerSettings settings) { - this.DecompilerSettings = DecompilerSettingsPanel.CurrentDecompilerSettings; + if (!Enum.TryParse(version.Version, out Decompiler.CSharp.LanguageVersion languageVersion)) + languageVersion = Decompiler.CSharp.LanguageVersion.Latest; + this.DecompilerSettings = new Decompiler.DecompilerSettings(languageVersion) { + AlwaysUseBraces = settings.AlwaysUseBraces, + ExpandMemberDefinitions = settings.ExpandMemberDefinitions, + FoldBraces = settings.FoldBraces, + FullyQualifyAmbiguousTypeNames = settings.FullyQualifyAmbiguousTypeNames, + RemoveDeadCode = settings.RemoveDeadCode, + ShowDebugInfo = settings.ShowDebugInfo, + ShowXmlDocumentation = settings.ShowXmlDocumentation, + UseDebugSymbols = settings.UseDebugSymbols, + UsingDeclarations = settings.UsingDeclarations, + }; } } } diff --git a/ILSpy/FilterSettings.cs b/ILSpy/FilterSettings.cs index 910568c8c..9130eb30d 100644 --- a/ILSpy/FilterSettings.cs +++ b/ILSpy/FilterSettings.cs @@ -18,6 +18,8 @@ using System; using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; using System.Xml.Linq; namespace ICSharpCode.ILSpy @@ -36,6 +38,7 @@ namespace ICSharpCode.ILSpy { this.ShowInternalApi = (bool?)element.Element("ShowInternalAPI") ?? true; this.Language = Languages.GetLanguage((string)element.Element("Language")); + this.LanguageVersion = Language.LanguageVersions.FirstOrDefault(v => v.Version == (string)element.Element("LanguageVersion")); } public XElement SaveAsXml() @@ -43,7 +46,8 @@ namespace ICSharpCode.ILSpy return new XElement( "FilterSettings", new XElement("ShowInternalAPI", this.ShowInternalApi), - new XElement("Language", this.Language.Name) + new XElement("Language", this.Language.Name), + new XElement("LanguageVersion", this.LanguageVersion.Version) ); } @@ -102,14 +106,34 @@ namespace ICSharpCode.ILSpy set { if (language != value) { language = value; - OnPropertyChanged("Language"); + LanguageVersion = language.LanguageVersions.LastOrDefault(); + OnPropertyChanged(); } } } - + + LanguageVersion languageVersion; + + /// + /// Gets/Sets the current language version. + /// + /// + /// While this isn't related to filtering, having it as part of the FilterSettings + /// makes it easy to pass it down into all tree nodes. + /// + public LanguageVersion LanguageVersion { + get { return languageVersion; } + set { + if (languageVersion != value) { + languageVersion = value; + OnPropertyChanged(); + } + } + } + public event PropertyChangedEventHandler PropertyChanged; - protected virtual void OnPropertyChanged(string propertyName) + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index c66d72bc8..2f2624118 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -25,7 +25,6 @@ using System.Linq; using System.Resources; using ICSharpCode.Decompiler; -using ICSharpCode.ILSpy.Options; using Mono.Cecil; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.OutputVisitor; @@ -35,8 +34,6 @@ using System.Windows; using System.Windows.Controls; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.Decompiler.CSharp.Transforms; -using ICSharpCode.AvalonEdit.Highlighting; -using System.Windows.Media; namespace ICSharpCode.ILSpy { @@ -86,6 +83,27 @@ namespace ICSharpCode.ILSpy get { return ".csproj"; } } + IReadOnlyList versions; + + public override IReadOnlyList LanguageVersions { + get { + if (versions == null) { + versions = new List() { + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp1.ToString(), "C# 1.0"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp2.ToString(), "C# 2.0"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp3.ToString(), "C# 3.0"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp4.ToString(), "C# 4.0"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp5.ToString(), "C# 5.0"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp6.ToString(), "C# 6.0"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp7.ToString(), "C# 7.0"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp7_1.ToString(), "C# 7.1"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp7_2.ToString(), "C# 7.2"), + }; + } + return versions; + } + } + CSharpDecompiler CreateDecompiler(ModuleDefinition module, DecompilationOptions options) { CSharpDecompiler decompiler = new CSharpDecompiler(module, options.DecompilerSettings); @@ -478,14 +496,16 @@ namespace ICSharpCode.ILSpy return TypeToString(ConvertTypeOptions.DoNotUsePrimitiveTypeNames | ConvertTypeOptions.IncludeTypeParameterDefinitions, type); } + DecompilerSettings CurrentSettings => new DecompilationOptions(MainWindow.Instance.CurrentLanguageVersion, Options.DecompilerSettingsPanel.CurrentDecompilerSettings).DecompilerSettings; + public override bool ShowMember(MemberReference member) { - return showAllMembers || !CSharpDecompiler.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings); + return showAllMembers || !CSharpDecompiler.MemberIsHidden(member, CurrentSettings); } public override MemberReference GetOriginalCodeLocation(MemberReference member) { - if (showAllMembers || !DecompilerSettingsPanel.CurrentDecompilerSettings.AnonymousMethods) + if (showAllMembers || !CurrentSettings.AnonymousMethods) return member; else return TreeNodes.Analyzer.Helpers.GetOriginalCodeLocation(member); diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 7440f84b8..1c750f936 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -19,10 +19,41 @@ using System; using System.Collections.Generic; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Util; using Mono.Cecil; namespace ICSharpCode.ILSpy { + public struct LanguageVersion : IEquatable + { + public string Version { get; } + public string DisplayName { get; } + + public LanguageVersion(string version, string name = null) + { + this.Version = version ?? ""; + this.DisplayName = name ?? version.ToString(); + } + + public bool Equals(LanguageVersion other) + { + return other.Version == this.Version && other.DisplayName == this.DisplayName; + } + + public override bool Equals(object obj) + { + return obj is LanguageVersion version && Equals(version); + } + + public override int GetHashCode() + { + return unchecked(982451629 * Version.GetHashCode() + 982451653 * DisplayName.GetHashCode()); + } + + public static bool operator ==(LanguageVersion lhs, LanguageVersion rhs) => lhs.Equals(rhs); + public static bool operator !=(LanguageVersion lhs, LanguageVersion rhs) => !lhs.Equals(rhs); + } + /// /// Base class for language-specific decompiler implementations. /// @@ -43,6 +74,12 @@ namespace ICSharpCode.ILSpy get { return null; } } + public virtual IReadOnlyList LanguageVersions { + get { return EmptyList.Instance; } + } + + public bool HasLanguageVersions => LanguageVersions.Count > 0; + /// /// Gets the syntax highlighting used for this language. /// diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index 168af0a7e..9f958b4b9 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -81,6 +81,10 @@ + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 8a234cbeb..4c9a3a086 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -486,7 +486,7 @@ namespace ICSharpCode.ILSpy void filterSettings_PropertyChanged(object sender, PropertyChangedEventArgs e) { RefreshTreeViewFilter(); - if (e.PropertyName == "Language") { + if (e.PropertyName == "Language" || e.PropertyName == "LanguageVersion") { DecompileSelectedNodes(recordHistory: false); } } @@ -762,7 +762,7 @@ namespace ICSharpCode.ILSpy if (node != null && node.View(decompilerTextView)) return; } - decompilationTask = decompilerTextView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions { TextViewState = state }); + decompilationTask = decompilerTextView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions(CurrentLanguageVersion, Options.DecompilerSettingsPanel.CurrentDecompilerSettings) { TextViewState = state }); } void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e) @@ -773,7 +773,7 @@ namespace ICSharpCode.ILSpy } this.TextView.SaveToDisk(this.CurrentLanguage, this.SelectedNodes, - new DecompilationOptions { FullDecompilation = true }); + new DecompilationOptions(CurrentLanguageVersion, Options.DecompilerSettingsPanel.CurrentDecompilerSettings) { FullDecompilation = true }); } public void RefreshDecompiledView() @@ -784,12 +784,9 @@ namespace ICSharpCode.ILSpy public DecompilerTextView TextView { get { return decompilerTextView; } } - - public Language CurrentLanguage { - get { - return sessionSettings.FilterSettings.Language; - } - } + + public Language CurrentLanguage => sessionSettings.FilterSettings.Language; + public LanguageVersion CurrentLanguageVersion => sessionSettings.FilterSettings.LanguageVersion; public event SelectionChangedEventHandler SelectionChanged; diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml b/ILSpy/Options/DecompilerSettingsPanel.xaml index 6f79ae296..91fa85592 100644 --- a/ILSpy/Options/DecompilerSettingsPanel.xaml +++ b/ILSpy/Options/DecompilerSettingsPanel.xaml @@ -8,13 +8,6 @@ - Decompile anonymous methods/lambdas - Decompile anonymous types - Decompile enumerators (yield return) - Decompile async methods (async/await) - Decompile query expressions - Decompile expression trees - Decompile automatic properties Use variable names from debug symbols, if available Show info from debug symbols, if available Show XML documentation in decompiled code @@ -24,6 +17,5 @@ Fully qualify ambiguous type names Always use braces Expand member definitions after decompilation -