Browse Source

Merge pull request #3505 from icsharpcode/fix/3494/ilspycmd-settings

Add dynamic ILSpy settings options to ILSpyCmd
pull/3508/head
Siegfried Pammer 2 weeks ago committed by GitHub
parent
commit
96cba4a994
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 88
      ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs
  2. 21
      ICSharpCode.ILSpyX/Settings/DecompilerSettings.cs
  3. 75
      ICSharpCode.ILSpyX/Settings/SettingsServiceBase.cs
  4. 2
      ILSpy.ReadyToRun/ReadyToRunOptions.cs
  5. 2
      ILSpy/DecompilationOptions.cs
  6. 1
      ILSpy/LanguageSettings.cs
  7. 1
      ILSpy/Options/DecompilerSettingsViewModel.cs
  8. 2
      ILSpy/Options/DisplaySettings.cs
  9. 1
      ILSpy/SessionSettings.cs
  10. 2
      ILSpy/Updates/UpdateSettings.cs
  11. 57
      ILSpy/Util/SettingsService.cs
  12. 1
      TestPlugin/CustomOptionPage.xaml.cs

88
ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs

@ -91,7 +91,7 @@ Examples: @@ -91,7 +91,7 @@ Examples:
public (bool IsSet, string Value) InputPDBFile { get; }
[Option("-l|--list <entity-type(s)>", "Lists all entities of the specified type(s). Valid types: c(lass), i(nterface), s(truct), d(elegate), e(num)", CommandOptionType.MultipleValue)]
public string[] EntityTypes { get; } = new string[0];
public string[] EntityTypes { get; } = Array.Empty<string>();
public string DecompilerVersion => "ilspycmd: " + typeof(ILSpyCmdProgram).Assembly.GetName().Version.ToString() +
Environment.NewLine
@ -100,9 +100,16 @@ Examples: @@ -100,9 +100,16 @@ Examples:
[Option("-lv|--languageversion <version>", "C# Language version: CSharp1, CSharp2, CSharp3, " +
"CSharp4, CSharp5, CSharp6, CSharp7, CSharp7_1, CSharp7_2, CSharp7_3, CSharp8_0, CSharp9_0, " +
"CSharp10_0, Preview or Latest", CommandOptionType.SingleValue)]
"CSharp10_0, CSharp11_0, CSharp12_0, CSharp13_0, Preview or Latest", CommandOptionType.SingleValue)]
public LanguageVersion LanguageVersion { get; } = LanguageVersion.Latest;
[FileExists]
[Option("--ilspy-settingsfile <path>", "Path to an ILSpy settings file.", CommandOptionType.SingleValue)]
public string ILSpySettingsFile { get; }
[Option("-ds|--decompiler-setting <name>=<value>", "Set a decompiler setting. Use multiple times to set multiple settings.", CommandOptionType.MultipleValue)]
public string[] DecompilerSettingOverrides { get; set; } = Array.Empty<string>();
[DirectoryExists]
[Option("-r|--referencepath <path>", "Path to a directory containing dependencies of the assembly that is being decompiled.", CommandOptionType.MultipleValue)]
public string[] ReferencePaths { get; }
@ -325,13 +332,76 @@ Examples: @@ -325,13 +332,76 @@ Examples:
DecompilerSettings GetSettings(PEFile module)
{
return new DecompilerSettings(LanguageVersion) {
ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = RemoveDeadCode,
RemoveDeadStores = RemoveDeadStores,
UseSdkStyleProjectFormat = WholeProjectDecompiler.CanUseSdkStyleProjectFormat(module),
UseNestedDirectoriesForNamespaces = NestedDirectories,
};
DecompilerSettings decompilerSettings = null;
if (ILSpySettingsFile != null)
{
try
{
ILSpyX.Settings.ILSpySettings.SettingsFilePathProvider = new ILSpyX.Settings.DefaultSettingsFilePathProvider(ILSpySettingsFile);
var settingsService = new ILSpyX.Settings.SettingsServiceBase(ILSpyX.Settings.ILSpySettings.Load());
decompilerSettings = settingsService.GetSettings<ILSpyX.Settings.DecompilerSettings>();
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error loading ILSpy settings file '{ILSpySettingsFile}': {ex.Message}");
}
}
if (decompilerSettings == null)
{
decompilerSettings = new DecompilerSettings(LanguageVersion) {
ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = RemoveDeadCode,
RemoveDeadStores = RemoveDeadStores,
UseSdkStyleProjectFormat = WholeProjectDecompiler.CanUseSdkStyleProjectFormat(module),
UseNestedDirectoriesForNamespaces = NestedDirectories,
};
}
if (DecompilerSettingOverrides is { Length: > 0 })
{
foreach (var entry in DecompilerSettingOverrides)
{
int equals = entry.IndexOf('=');
if (equals <= 0)
{
Console.Error.WriteLine($"Decompiler setting '{entry}' is invalid; use '<Name>=<Value>'");
continue;
}
string name = entry[..equals].Trim();
string value = entry[(equals + 1)..].Trim();
if (!ILSpyX.Settings.DecompilerSettings.IsKnownOption(name, out var property))
{
Console.Error.WriteLine($"Decompiler setting '{name}' is unknown.");
continue;
}
object typedValue;
try
{
typedValue = Convert.ChangeType(value, property.PropertyType);
}
catch (Exception)
{
Console.Error.WriteLine($"Decompiler setting '{name}': Value '{value}' could not be converted to '{property.PropertyType.FullName}'.");
continue;
}
if (typedValue == null && property.PropertyType.IsValueType)
{
Console.Error.WriteLine($"Decompiler setting '{name}': Value '{value}' could not be converted to '{property.PropertyType.FullName}'.");
continue;
}
property.SetValue(decompilerSettings, typedValue);
}
}
return decompilerSettings;
}
CSharpDecompiler GetDecompiler(string assemblyFileName)

21
ILSpy/Options/DecompilerSettings.cs → ICSharpCode.ILSpyX/Settings/DecompilerSettings.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
// Copyright (c) 2024 Tom Englert for the SharpDevelop Team
// Copyright (c) 2024 Tom Englert
//
// 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
@ -17,13 +17,12 @@ @@ -17,13 +17,12 @@
// DEALINGS IN THE SOFTWARE.
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
#nullable enable
namespace ICSharpCode.ILSpy.Options
namespace ICSharpCode.ILSpyX.Settings
{
public class DecompilerSettings : Decompiler.DecompilerSettings, ISettingsSection
{
@ -59,5 +58,19 @@ namespace ICSharpCode.ILSpy.Options @@ -59,5 +58,19 @@ namespace ICSharpCode.ILSpy.Options
{
return (DecompilerSettings)base.Clone();
}
public static bool IsKnownOption(string name, [NotNullWhen(true)] out PropertyInfo? property)
{
property = null;
foreach (var item in properties)
{
if (item.Name != name)
continue;
property = item;
return true;
}
return false;
}
}
}

75
ICSharpCode.ILSpyX/Settings/SettingsServiceBase.cs

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
// Copyright (c) 2024 Tom Englert
//
// 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;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Xml.Linq;
namespace ICSharpCode.ILSpyX.Settings
{
public interface IChildSettings
{
ISettingsSection Parent { get; }
}
public interface ISettingsSection : INotifyPropertyChanged
{
XName SectionName { get; }
void LoadFromXml(XElement section);
XElement SaveToXml();
}
public class SettingsServiceBase(ISettingsProvider spySettings)
{
protected readonly ConcurrentDictionary<Type, ISettingsSection> sections = new();
protected ISettingsProvider SpySettings { get; set; } = spySettings;
public T GetSettings<T>() where T : ISettingsSection, new()
{
return (T)sections.GetOrAdd(typeof(T), _ => {
T section = new T();
var sectionElement = SpySettings[section.SectionName];
section.LoadFromXml(sectionElement);
section.PropertyChanged += Section_PropertyChanged;
return section;
});
}
protected static void SaveSection(ISettingsSection section, XElement root)
{
var element = section.SaveToXml();
var existingElement = root.Element(section.SectionName);
if (existingElement != null)
existingElement.ReplaceWith(element);
else
root.Add(element);
}
protected virtual void Section_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
}
}
}

2
ILSpy.ReadyToRun/ReadyToRunOptions.cs

@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
using System.Xml.Linq;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpyX.Settings;
using TomsToolbox.Wpf;

2
ILSpy/DecompilationOptions.cs

@ -23,7 +23,7 @@ using ICSharpCode.Decompiler; @@ -23,7 +23,7 @@ using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpyX;
using DecompilerSettings = ICSharpCode.ILSpy.Options.DecompilerSettings;
using DecompilerSettings = ICSharpCode.ILSpyX.Settings.DecompilerSettings;
namespace ICSharpCode.ILSpy
{

1
ILSpy/LanguageSettings.cs

@ -20,6 +20,7 @@ using System.Collections.Generic; @@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.Xml.Linq;
using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Settings;
using TomsToolbox.Wpf;

1
ILSpy/Options/DecompilerSettingsViewModel.cs

@ -24,6 +24,7 @@ using System.Reflection; @@ -24,6 +24,7 @@ using System.Reflection;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpyX.Settings;
using TomsToolbox.Wpf;

2
ILSpy/Options/DisplaySettings.cs

@ -19,6 +19,8 @@ @@ -19,6 +19,8 @@
using System.Windows.Media;
using System.Xml.Linq;
using ICSharpCode.ILSpyX.Settings;
using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy.Options

1
ILSpy/SessionSettings.cs

@ -30,6 +30,7 @@ using System.Xml.Linq; @@ -30,6 +30,7 @@ using System.Xml.Linq;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Themes;
using ICSharpCode.ILSpyX.Search;
using ICSharpCode.ILSpyX.Settings;
namespace ICSharpCode.ILSpy
{

2
ILSpy/Updates/UpdateSettings.cs

@ -19,6 +19,8 @@ @@ -19,6 +19,8 @@
using System;
using System.Xml.Linq;
using ICSharpCode.ILSpyX.Settings;
using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy.Updates

57
ILSpy/Util/SettingsService.cs

@ -16,71 +16,18 @@ @@ -16,71 +16,18 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Xml.Linq;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Settings;
using DecompilerSettings = ICSharpCode.ILSpy.Options.DecompilerSettings;
using DecompilerSettings = ICSharpCode.ILSpyX.Settings.DecompilerSettings;
#nullable enable
namespace ICSharpCode.ILSpy.Util
{
public interface IChildSettings
{
ISettingsSection Parent { get; }
}
public interface ISettingsSection : INotifyPropertyChanged
{
XName SectionName { get; }
void LoadFromXml(XElement section);
XElement SaveToXml();
}
public abstract class SettingsServiceBase(ISettingsProvider spySettings)
{
protected readonly ConcurrentDictionary<Type, ISettingsSection> sections = new();
protected ISettingsProvider SpySettings { get; set; } = spySettings;
public T GetSettings<T>() where T : ISettingsSection, new()
{
return (T)sections.GetOrAdd(typeof(T), _ => {
T section = new T();
var sectionElement = SpySettings[section.SectionName];
section.LoadFromXml(sectionElement);
section.PropertyChanged += Section_PropertyChanged;
return section;
});
}
protected static void SaveSection(ISettingsSection section, XElement root)
{
var element = section.SaveToXml();
var existingElement = root.Element(section.SectionName);
if (existingElement != null)
existingElement.ReplaceWith(element);
else
root.Add(element);
}
protected virtual void Section_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
}
}
public class SettingsSnapshot(SettingsService parent, ISettingsProvider spySettings) : SettingsServiceBase(spySettings)
{
public void Save()
@ -173,7 +120,7 @@ namespace ICSharpCode.ILSpy.Util @@ -173,7 +120,7 @@ namespace ICSharpCode.ILSpy.Util
SpySettings.Update(root => {
SaveSection(section, root);
});
};
}
}
if (sender is DecompilerSettings decompilerSettings && assemblyListManager != null)

1
TestPlugin/CustomOptionPage.xaml.cs

@ -6,6 +6,7 @@ using System.Xml.Linq; @@ -6,6 +6,7 @@ using System.Xml.Linq;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpyX.Settings;
using TomsToolbox.Wpf;
using TomsToolbox.Wpf.Composition.AttributedModel;

Loading…
Cancel
Save