Browse Source

Add options dialog.

pull/70/head
Daniel Grunwald 15 years ago
parent
commit
7d1d168313
  1. 1
      ICSharpCode.Decompiler/Ast/DecompilerContext.cs
  2. 3
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  3. 55
      ICSharpCode.Decompiler/DecompilerSettings.cs
  4. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  5. 15
      ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
  6. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  7. 103
      ICSharpCode.Decompiler/Tests/YieldReturn.cs
  8. 3
      ILSpy/CSharpLanguage.cs
  9. 11
      ILSpy/DecompilationOptions.cs
  10. 9
      ILSpy/DecompilerSettingsPanel.xaml
  11. 57
      ILSpy/DecompilerSettingsPanel.xaml.cs
  12. 10
      ILSpy/ILSpy.csproj
  13. 5
      ILSpy/MainWindow.xaml.cs
  14. 21
      ILSpy/OptionsDialog.xaml
  15. 93
      ILSpy/OptionsDialog.xaml.cs

1
ICSharpCode.Decompiler/Ast/DecompilerContext.cs

@ -12,6 +12,7 @@ namespace ICSharpCode.Decompiler
public CancellationToken CancellationToken; public CancellationToken CancellationToken;
public TypeDefinition CurrentType; public TypeDefinition CurrentType;
public MethodDefinition CurrentMethod; public MethodDefinition CurrentMethod;
public DecompilerSettings Settings;
public DecompilerContext Clone() public DecompilerContext Clone()
{ {

3
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -105,6 +105,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef) bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef)
{ {
if (!context.Settings.AnonymousMethods)
return false; // anonymous method decompilation is disabled
// Anonymous methods are defined in the same assembly, so there's no need to Resolve(). // Anonymous methods are defined in the same assembly, so there's no need to Resolve().
MethodDefinition method = methodRef as MethodDefinition; MethodDefinition method = methodRef as MethodDefinition;
if (!IsAnonymousMethod(context, method)) if (!IsAnonymousMethod(context, method))

55
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -0,0 +1,55 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.ComponentModel;
namespace ICSharpCode.Decompiler
{
/// <summary>
/// Settings for the decompiler.
/// </summary>
public class DecompilerSettings : INotifyPropertyChanged
{
bool anonymousMethods = true;
/// <summary>
/// Decompile anonymous methods/lambdas.
/// </summary>
public bool AnonymousMethods {
get { return anonymousMethods; }
set {
if (anonymousMethods != value) {
anonymousMethods = value;
OnPropertyChanged("AnonymousMethods");
}
}
}
bool yieldReturn = true;
/// <summary>
/// Decompile enumerators.
/// </summary>
public bool YieldReturn {
get { return yieldReturn; }
set {
if (yieldReturn != value) {
yieldReturn = value;
OnPropertyChanged("YieldReturn");
}
}
}
public event EventHandler YieldReturnChanged;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -66,6 +66,7 @@
<Compile Include="Ast\Transforms\PatternStatementTransform.cs" /> <Compile Include="Ast\Transforms\PatternStatementTransform.cs" />
<Compile Include="CecilExtensions.cs" /> <Compile Include="CecilExtensions.cs" />
<Compile Include="DecompilerException.cs" /> <Compile Include="DecompilerException.cs" />
<Compile Include="DecompilerSettings.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" /> <Compile Include="Disassembler\DisassemblerHelpers.cs" />
<Compile Include="Disassembler\ILStructure.cs" /> <Compile Include="Disassembler\ILStructure.cs" />
<Compile Include="Disassembler\MethodBodyDisassembler.cs" /> <Compile Include="Disassembler\MethodBodyDisassembler.cs" />
@ -95,6 +96,7 @@
<Compile Include="ILAst\Pattern.cs" /> <Compile Include="ILAst\Pattern.cs" />
<Compile Include="ILAst\PeepholeTransform.cs" /> <Compile Include="ILAst\PeepholeTransform.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" /> <Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ILAst\YieldReturnDecompiler.cs" />
<Compile Include="ITextOutput.cs" /> <Compile Include="ITextOutput.cs" />
<Compile Include="PlainTextOutput.cs" /> <Compile Include="PlainTextOutput.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

15
ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

@ -0,0 +1,15 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.Decompiler.ILAst
{
public class YieldReturnDecompiler
{
// For a description on the code generated by the C# compiler for yield return:
// http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx
// not implemented yet...
}
}

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -53,6 +53,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="YieldReturn.cs" />
<None Include="Types\S_EnumSamples.cs" /> <None Include="Types\S_EnumSamples.cs" />
<None Include="CustomAttributes\S_AssemblyCustomAttribute.cs" /> <None Include="CustomAttributes\S_AssemblyCustomAttribute.cs" />
<Compile Include="Helpers\RemoveCompilerAttribute.cs" /> <Compile Include="Helpers\RemoveCompilerAttribute.cs" />

103
ICSharpCode.Decompiler/Tests/YieldReturn.cs

@ -0,0 +1,103 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
public static class YieldReturn
{
public static IEnumerable<string> SimpleYieldReturn()
{
yield return "A";
yield return "B";
yield return "C";
}
public static IEnumerable<int> YieldReturnInLoop()
{
for (int i = 0; i < 100; i++) {
yield return i;
}
}
public static IEnumerable<int> YieldReturnWithTryFinally()
{
yield return 0;
try {
yield return 1;
} finally {
Console.WriteLine("Finally!");
}
yield return 2;
}
public static IEnumerable<string> YieldReturnWithNestedTryFinally(bool breakInMiddle)
{
Console.WriteLine("Start of method - 1");
yield return "Start of method";
Console.WriteLine("Start of method - 2");
try {
Console.WriteLine("Within outer try - 1");
yield return "Within outer try";
Console.WriteLine("Within outer try - 2");
try {
Console.WriteLine("Within inner try - 1");
yield return "Within inner try";
Console.WriteLine("Within inner try - 2");
if (breakInMiddle)
yield break;
Console.WriteLine("End of inner try - 1");
yield return "End of inner try";
Console.WriteLine("End of inner try - 2");
} finally {
Console.WriteLine("Inner Finally");
}
Console.WriteLine("End of outer try - 1");
yield return "End of outer try";
Console.WriteLine("End of outer try - 2");
} finally {
Console.WriteLine("Outer Finally");
}
Console.WriteLine("End of method - 1");
yield return "End of method";
Console.WriteLine("End of method - 2");
}
public static IEnumerable<string> YieldReturnWithTwoNonNestedFinallyBlocks(IEnumerable<string> input)
{
// outer try-finally block
foreach (string line in input) {
// nested try-finally block
try {
yield return line;
} finally {
Console.WriteLine("Processed " + line);
}
}
yield return "A";
yield return "B";
yield return "C";
yield return "D";
yield return "E";
yield return "F";
// outer try-finally block
foreach (string line in input)
yield return line.ToUpper();
}
public static IEnumerable<Func<string>> YieldReturnWithAnonymousMethods1(IEnumerable<string> input)
{
foreach (string line in input) {
yield return () => line;
}
}
public static IEnumerable<Func<string>> YieldReturnWithAnonymousMethods2(IEnumerable<string> input)
{
foreach (string line in input) {
string copy = line;
yield return () => copy;
}
}
}

3
ILSpy/CSharpLanguage.cs

@ -376,7 +376,8 @@ namespace ICSharpCode.ILSpy
return new AstBuilder( return new AstBuilder(
new DecompilerContext { new DecompilerContext {
CancellationToken = options.CancellationToken, CancellationToken = options.CancellationToken,
CurrentType = currentType CurrentType = currentType,
Settings = options.DecompilerSettings
}); });
} }

11
ILSpy/DecompilationOptions.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
@ -45,5 +46,15 @@ namespace ICSharpCode.ILSpy
/// to allow for cooperative cancellation of the decompilation task. /// to allow for cooperative cancellation of the decompilation task.
/// </remarks> /// </remarks>
public CancellationToken CancellationToken { get; set; } public CancellationToken CancellationToken { get; set; }
/// <summary>
/// Gets the settings for the decompiler.
/// </summary>
public DecompilerSettings DecompilerSettings { get; set; }
public DecompilationOptions()
{
this.DecompilerSettings = DecompilerSettingsPanel.LoadDecompilerSettings(ILSpySettings.Load());
}
} }
} }

9
ILSpy/DecompilerSettingsPanel.xaml

@ -0,0 +1,9 @@
<UserControl x:Class="ICSharpCode.ILSpy.DecompilerSettingsPanel"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Margin="10">
<CheckBox IsChecked="{Binding AnonymousMethods}">Decompile anonymous methods/lambdas</CheckBox>
<CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</CheckBox>
</StackPanel>
</UserControl>

57
ILSpy/DecompilerSettingsPanel.xaml.cs

@ -0,0 +1,57 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Linq;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Interaction logic for DecompilerSettingsPanel.xaml
/// </summary>
[ExportOptionPage("Decompiler")]
partial class DecompilerSettingsPanel : UserControl, IOptionPage
{
public DecompilerSettingsPanel()
{
InitializeComponent();
}
public void Load(ILSpySettings settings)
{
this.DataContext = LoadDecompilerSettings(settings);
}
public static DecompilerSettings LoadDecompilerSettings(ILSpySettings settings)
{
XElement e = settings["DecompilerSettings"];
DecompilerSettings s = new DecompilerSettings();
s.AnonymousMethods = (bool?)e.Attribute("anonymousMethods") ?? s.AnonymousMethods;
s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn;
return s;
}
public void Save(XElement root)
{
DecompilerSettings s = (DecompilerSettings)this.DataContext;
XElement section = new XElement("DecompilerSettings");
section.SetAttributeValue("anonymousMethods", s.AnonymousMethods);
section.SetAttributeValue("yieldReturn", s.YieldReturn);
XElement existingElement = root.Element("DecompilerSettings");
if (existingElement != null)
existingElement.ReplaceWith(section);
else
root.Add(section);
}
}
}

10
ILSpy/ILSpy.csproj

@ -89,6 +89,10 @@
<Compile Include="AssemblyListManager.cs" /> <Compile Include="AssemblyListManager.cs" />
<Compile Include="BamlDecompiler.cs" /> <Compile Include="BamlDecompiler.cs" />
<Compile Include="Commands.cs" /> <Compile Include="Commands.cs" />
<Compile Include="DecompilerSettingsPanel.xaml.cs">
<DependentUpon>DecompilerSettingsPanel.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="ExportCommandAttribute.cs" /> <Compile Include="ExportCommandAttribute.cs" />
<Compile Include="Controls\SearchBox.cs" /> <Compile Include="Controls\SearchBox.cs" />
<Compile Include="Controls\SortableGridViewColumn.cs" /> <Compile Include="Controls\SortableGridViewColumn.cs" />
@ -111,6 +115,10 @@
<DependentUpon>OpenFromGacDialog.xaml</DependentUpon> <DependentUpon>OpenFromGacDialog.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="OptionsDialog.xaml.cs">
<DependentUpon>OptionsDialog.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="..\README.txt"> <EmbeddedResource Include="..\README.txt">
<Link>README.txt</Link> <Link>README.txt</Link>
@ -168,8 +176,10 @@
<Page Include="Controls\SearchBoxStyle.xaml"> <Page Include="Controls\SearchBoxStyle.xaml">
<DependentUpon>SearchBox.cs</DependentUpon> <DependentUpon>SearchBox.cs</DependentUpon>
</Page> </Page>
<Page Include="DecompilerSettingsPanel.xaml" />
<Page Include="MainWindow.xaml" /> <Page Include="MainWindow.xaml" />
<Page Include="OpenFromGacDialog.xaml" /> <Page Include="OpenFromGacDialog.xaml" />
<Page Include="OptionsDialog.xaml" />
<Page Include="TextView\DecompilerTextView.xaml"> <Page Include="TextView\DecompilerTextView.xaml">
<DependentUpon>DecompilerTextView.cs</DependentUpon> <DependentUpon>DecompilerTextView.cs</DependentUpon>
</Page> </Page>

5
ILSpy/MainWindow.xaml.cs

@ -429,6 +429,11 @@ namespace ICSharpCode.ILSpy
decompilerTextView.Decompile(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions()); decompilerTextView.Decompile(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions());
} }
public void RefreshDecompiledView()
{
TreeView_SelectionChanged(null, null);
}
public DecompilerTextView TextView { public DecompilerTextView TextView {
get { return decompilerTextView; } get { return decompilerTextView; }
} }

21
ILSpy/OptionsDialog.xaml

@ -0,0 +1,21 @@
<Window x:Class="ICSharpCode.ILSpy.OptionsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Style="{DynamicResource DialogWindow}"
WindowStartupLocation="CenterOwner"
ResizeMode="CanResizeWithGrip"
Title="Options" Height="400" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition
Height="1*" />
<RowDefinition
Height="Auto" />
</Grid.RowDefinitions>
<TabControl Name="tabControl" />
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="12,8">
<Button IsDefault="True" Margin="2,0" Name="okButton" Click="OKButton_Click">OK</Button>
<Button IsCancel="True" Margin="2,0">Cancel</Button>
</StackPanel>
</Grid>
</Window>

93
ILSpy/OptionsDialog.xaml.cs

@ -0,0 +1,93 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Linq;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Interaction logic for OptionsDialog.xaml
/// </summary>
public partial class OptionsDialog : Window
{
[ImportMany("OptionPages", typeof(UIElement), RequiredCreationPolicy = CreationPolicy.NonShared)]
Lazy<UIElement, IOptionsMetadata>[] optionPages = null;
public OptionsDialog()
{
InitializeComponent();
App.CompositionContainer.ComposeParts(this);
ILSpySettings settings = ILSpySettings.Load();
foreach (var optionPage in optionPages) {
TabItem tabItem = new TabItem();
tabItem.Header = optionPage.Metadata.Title;
tabItem.Content = optionPage.Value;
tabControl.Items.Add(tabItem);
IOptionPage page = optionPage.Value as IOptionPage;
if (page != null)
page.Load(settings);
}
}
void OKButton_Click(object sender, RoutedEventArgs e)
{
ILSpySettings.Update(
delegate (XElement root) {
foreach (var optionPage in optionPages) {
IOptionPage page = optionPage.Value as IOptionPage;
if (page != null)
page.Save(root);
}
});
this.DialogResult = true;
Close();
}
}
public interface IOptionsMetadata
{
string Title { get; }
}
public interface IOptionPage
{
void Load(ILSpySettings settings);
void Save(XElement root);
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class ExportOptionPageAttribute : ExportAttribute
{
public ExportOptionPageAttribute(string title)
: base("OptionPages", typeof(UIElement))
{
this.Title = title;
}
public string Title { get; private set; }
}
[ExportMainMenuCommand(Menu = "_View", Header = "_Options", MenuCategory = "Options", MenuOrder = 999)]
sealed class ShowOptionsCommand : SimpleCommand
{
public override void Execute(object parameter)
{
OptionsDialog dlg = new OptionsDialog();
dlg.Owner = MainWindow.Instance;
if (dlg.ShowDialog() == true)
MainWindow.Instance.RefreshDecompiledView();
}
}
}
Loading…
Cancel
Save