Browse Source

Port ILSpy.ReadyToRun plugin

R2R was the only legacy plugin still keeping the solution-level build red
(27 errors against the Avalonia tree). Port mirrors the four-corner
substitution used for the rest of the rewrite:

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 2 months ago
parent
commit
6dbd8429b7
  1. 15
      ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj
  2. 3
      ILSpy.ReadyToRun/ReadyToRunDisassembler.cs
  3. 15
      ILSpy.ReadyToRun/ReadyToRunLanguage.cs
  4. 29
      ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml
  5. 6
      ILSpy.ReadyToRun/ReadyToRunOptions.cs
  6. 33
      ILSpy.ReadyToRun/ReadyToRunOptionsView.axaml
  7. 33
      ILSpy.ReadyToRun/ReadyToRunOptionsView.axaml.cs
  8. 36
      ILSpy.ReadyToRun/ReadyToRunOptionsViewModel.cs
  9. 15
      ILSpy.sln
  10. 16
      ILSpy/ViewLocator.cs

15
ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj

@ -3,14 +3,13 @@
<PropertyGroup> <PropertyGroup>
<AssemblyName>ILSpy.ReadyToRun.Plugin</AssemblyName> <AssemblyName>ILSpy.ReadyToRun.Plugin</AssemblyName>
<TargetFramework>net10.0-windows</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo> <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<NeutralResourcesLanguage>en-US</NeutralResourcesLanguage> <NeutralResourcesLanguage>en-US</NeutralResourcesLanguage>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<UseWpf>true</UseWpf>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<EnableWindowsTargeting>true</EnableWindowsTargeting> <Nullable>disable</Nullable>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'"> <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
@ -31,16 +30,18 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ILSpy\ILSpy.csproj" /> <ProjectReference Include="..\ILSpy\ILSpy.csproj" />
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" /> <ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" />
<ProjectReference Include="..\ICSharpCode.ILSpyX\ICSharpCode.ILSpyX.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="Iced" /> <PackageReference Include="Iced" />
<PackageReference Include="ILCompiler.Reflection.ReadyToRun.Experimental" /> <PackageReference Include="ILCompiler.Reflection.ReadyToRun.Experimental" />
<!-- ILCompiler.Reflection.ReadyToRun has dependencies on System.Reflection.Metadata and <!-- ILCompiler.Reflection.ReadyToRun has dependencies on System.Reflection.Metadata and
System.Runtime.CompilerServices.Unsafe. Because the AddIn compiles into ILSpy's output System.Runtime.CompilerServices.Unsafe. Because the plugin compiles into ILSpy's output
directory, we're at risk of overwriting our dependencies with different versions. directory, we're at risk of overwriting our dependencies with different versions.
So ensure NuGet uses consistent versions (from our packages.props) for these. So ensure NuGet uses consistent versions (from Directory.Packages.props) for these. -->
-->
<PackageReference Include="System.Reflection.Metadata" /> <PackageReference Include="System.Reflection.Metadata" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" /> <PackageReference Include="System.Runtime.CompilerServices.Unsafe" />
</ItemGroup> </ItemGroup>

3
ILSpy.ReadyToRun/ReadyToRunDisassembler.cs

@ -26,11 +26,12 @@ using Iced.Intel;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Util;
using ILCompiler.Reflection.ReadyToRun; using ILCompiler.Reflection.ReadyToRun;
using ILCompiler.Reflection.ReadyToRun.Amd64; using ILCompiler.Reflection.ReadyToRun.Amd64;
using ILSpy;
namespace ICSharpCode.ILSpy.ReadyToRun namespace ICSharpCode.ILSpy.ReadyToRun
{ {
internal class ReadyToRunDisassembler internal class ReadyToRunDisassembler

15
ILSpy.ReadyToRun/ReadyToRunLanguage.cs

@ -30,18 +30,20 @@ using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using ICSharpCode.AvalonEdit.Highlighting; using AvaloniaEdit.Highlighting;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ILCompiler.Reflection.ReadyToRun; using ILCompiler.Reflection.ReadyToRun;
using TomsToolbox.Composition; using ILSpy;
using ILSpy.Languages;
using MetadataReader = System.Reflection.Metadata.MetadataReader; using MetadataReader = System.Reflection.Metadata.MetadataReader;
@ -108,7 +110,10 @@ namespace ICSharpCode.ILSpy.ReadyToRun
[Export(typeof(Language))] [Export(typeof(Language))]
[Shared] [Shared]
internal class ReadyToRunLanguage(SettingsService settingsService, IExportProvider exportProvider) : Language [method: ImportingConstructor]
// LanguageService is taken Lazy because it imports Language[] -- a direct LanguageService
// dependency creates a constructor-injection cycle that System.Composition refuses.
internal class ReadyToRunLanguage(SettingsService settingsService, Lazy<LanguageService> languageService) : Language
{ {
private static readonly ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry> readyToRunReaders = new ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry>(); private static readonly ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry> readyToRunReaders = new ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry>();
@ -229,7 +234,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public override RichText GetRichTextTooltip(IEntity entity) public override RichText GetRichTextTooltip(IEntity entity)
{ {
return exportProvider.GetExportedValue<LanguageService>().ILLanguage.GetRichTextTooltip(entity); return languageService.Value.GetLanguage("IL").GetRichTextTooltip(entity);
} }
private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, MetadataFile file) private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, MetadataFile file)

29
ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml

@ -1,29 +0,0 @@
<UserControl x:Class="ICSharpCode.ILSpy.ReadyToRun.ReadyToRunOptionPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:properties="clr-namespace:ILSpy.ReadyToRun.Properties"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d:DesignHeight="500" d:DesignWidth="500" mc:Ignorable="d"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:readyToRun="clr-namespace:ICSharpCode.ILSpy.ReadyToRun"
d:DataContext="{d:DesignInstance readyToRun:ReadyToRunOptionsViewModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Margin="3" Text="{x:Static properties:Resources.DisassemblyFormat}" />
<ComboBox Grid.Row="0" Grid.Column="1" Margin="3" ItemsSource="{Binding Options.DisassemblyFormats}" SelectedItem="{Binding Options.DisassemblyFormat}" />
<TextBlock Grid.Row="1" Grid.Column="0" Margin="3" Text="{x:Static properties:Resources.ShowStackUnwindInfo}"/>
<CheckBox Grid.Row="1" Grid.Column="1" Margin="3" IsChecked="{Binding Options.IsShowUnwindInfo}" />
<TextBlock Grid.Row="2" Margin="3" Text="{x:Static properties:Resources.ShowDebugInfo}"/>
<CheckBox Grid.Row="2" Grid.Column="1" Margin="3" IsChecked="{Binding Options.IsShowDebugInfo}" />
<TextBlock Grid.Row="3" Margin="3" Text="{x:Static properties:Resources.ShowGCInfo}"/>
<CheckBox Grid.Row="3" Grid.Column="1" Margin="3" IsChecked="{Binding Options.IsShowGCInfo}" />
</Grid>
</UserControl>

6
ILSpy.ReadyToRun/ReadyToRunOptions.cs

@ -18,13 +18,13 @@
using System.Xml.Linq; using System.Xml.Linq;
using ICSharpCode.ILSpyX.Settings; using CommunityToolkit.Mvvm.ComponentModel;
using TomsToolbox.Wpf; using ICSharpCode.ILSpyX.Settings;
namespace ICSharpCode.ILSpy.ReadyToRun namespace ICSharpCode.ILSpy.ReadyToRun
{ {
internal partial class ReadyToRunOptions : ObservableObjectBase, ISettingsSection internal partial class ReadyToRunOptions : ObservableObject, ISettingsSection
{ {
private static readonly XNamespace ns = "http://www.ilspy.net/ready-to-run"; private static readonly XNamespace ns = "http://www.ilspy.net/ready-to-run";

33
ILSpy.ReadyToRun/ReadyToRunOptionsView.axaml

@ -0,0 +1,33 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:ICSharpCode.ILSpy.ReadyToRun"
xmlns:res="using:ILSpy.ReadyToRun.Properties"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="300"
x:Class="ICSharpCode.ILSpy.ReadyToRun.ReadyToRunOptionsView"
x:DataType="vm:ReadyToRunOptionsViewModel">
<Grid Margin="6" ColumnDefinitions="Auto,*" RowSpacing="6" ColumnSpacing="6"
RowDefinitions="Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"
Text="{x:Static res:Resources.DisassemblyFormat}" />
<ComboBox Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch"
ItemsSource="{Binding Options.DisassemblyFormats}"
SelectedItem="{Binding Options.DisassemblyFormat, Mode=TwoWay}" />
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"
Text="{x:Static res:Resources.ShowStackUnwindInfo}" />
<CheckBox Grid.Row="1" Grid.Column="1"
IsChecked="{Binding Options.IsShowUnwindInfo, Mode=TwoWay}" />
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"
Text="{x:Static res:Resources.ShowDebugInfo}" />
<CheckBox Grid.Row="2" Grid.Column="1"
IsChecked="{Binding Options.IsShowDebugInfo, Mode=TwoWay}" />
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center"
Text="{x:Static res:Resources.ShowGCInfo}" />
<CheckBox Grid.Row="3" Grid.Column="1"
IsChecked="{Binding Options.IsShowGCInfo, Mode=TwoWay}" />
</Grid>
</UserControl>

33
ILSpy.ReadyToRun/ReadyToRunOptionsView.axaml.cs

@ -0,0 +1,33 @@
// Copyright (c) 2018 Siegfried Pammer
//
// 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 global::Avalonia.Controls;
using global::Avalonia.Markup.Xaml;
namespace ICSharpCode.ILSpy.ReadyToRun
{
public partial class ReadyToRunOptionsView : UserControl
{
public ReadyToRunOptionsView()
{
InitializeComponent();
}
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}
}

36
ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml.cs → ILSpy.ReadyToRun/ReadyToRunOptionsViewModel.cs

@ -17,46 +17,32 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Composition; using System.Composition;
using System.Xml.Linq;
using ICSharpCode.ILSpy.Options; using CommunityToolkit.Mvvm.ComponentModel;
using ICSharpCode.ILSpy.Util;
using TomsToolbox.Wpf; using ILSpy;
using TomsToolbox.Wpf.Composition.AttributedModel; using ILSpy.Options;
namespace ICSharpCode.ILSpy.ReadyToRun namespace ICSharpCode.ILSpy.ReadyToRun
{ {
[DataTemplate(typeof(ReadyToRunOptionsViewModel))]
[NonShared]
partial class ReadyToRunOptionPage
{
public ReadyToRunOptionPage()
{
InitializeComponent();
}
}
[ExportOptionPage(Order = 40)] [ExportOptionPage(Order = 40)]
[NonShared] [Shared]
class ReadyToRunOptionsViewModel : ObservableObjectBase, IOptionPage internal sealed partial class ReadyToRunOptionsViewModel : ObservableObject, IOptionPage
{ {
private ReadyToRunOptions options; [ObservableProperty]
ReadyToRunOptions options = null!;
public ReadyToRunOptions Options {
get => options;
set => SetProperty(ref options, value);
}
public string Title => global::ILSpy.ReadyToRun.Properties.Resources.ReadyToRun; public string Title => global::ILSpy.ReadyToRun.Properties.Resources.ReadyToRun;
public void Load(SettingsSnapshot snapshot) public void Load(SettingsService service)
{ {
Options = snapshot.GetSettings<ReadyToRunOptions>(); Options = service.GetSettings<ReadyToRunOptions>();
} }
public void LoadDefaults() public void LoadDefaults()
{ {
Options.LoadFromXml(new("empty")); Options.LoadFromXml(new XElement("ReadyToRunOptions"));
} }
} }
} }

15
ILSpy.sln

@ -1,3 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18 # Visual Studio Version 18
VisualStudioVersion = 18.4.11620.152 VisualStudioVersion = 18.4.11620.152
@ -38,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.Tests", "ILSpy.Tests\
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.Tests.Windows", "ILSpy.Tests.Windows\ILSpy.Tests.Windows.csproj", "{20AF56FB-DC0F-4048-B75D-83FEE0D669B2}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.Tests.Windows", "ILSpy.Tests.Windows\ILSpy.Tests.Windows.csproj", "{20AF56FB-DC0F-4048-B75D-83FEE0D669B2}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.ReadyToRun", "ILSpy.ReadyToRun\ILSpy.ReadyToRun.csproj", "{AF43A431-AAF7-4758-A180-42C378AE0FB2}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -168,6 +171,18 @@ Global
{20AF56FB-DC0F-4048-B75D-83FEE0D669B2}.Release|x64.Build.0 = Release|Any CPU {20AF56FB-DC0F-4048-B75D-83FEE0D669B2}.Release|x64.Build.0 = Release|Any CPU
{20AF56FB-DC0F-4048-B75D-83FEE0D669B2}.Release|x86.ActiveCfg = Release|Any CPU {20AF56FB-DC0F-4048-B75D-83FEE0D669B2}.Release|x86.ActiveCfg = Release|Any CPU
{20AF56FB-DC0F-4048-B75D-83FEE0D669B2}.Release|x86.Build.0 = Release|Any CPU {20AF56FB-DC0F-4048-B75D-83FEE0D669B2}.Release|x86.Build.0 = Release|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Debug|x64.ActiveCfg = Debug|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Debug|x64.Build.0 = Debug|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Debug|x86.ActiveCfg = Debug|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Debug|x86.Build.0 = Debug|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Release|Any CPU.Build.0 = Release|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Release|x64.ActiveCfg = Release|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Release|x64.Build.0 = Release|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Release|x86.ActiveCfg = Release|Any CPU
{AF43A431-AAF7-4758-A180-42C378AE0FB2}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

16
ILSpy/ViewLocator.cs

@ -28,6 +28,7 @@ using Dock.Model.Core;
using ILSpy.Analyzers; using ILSpy.Analyzers;
using ILSpy.AssemblyTree; using ILSpy.AssemblyTree;
using ILSpy.Compare; using ILSpy.Compare;
using ILSpy.Options;
using ILSpy.Search; using ILSpy.Search;
using ILSpy.TextView; using ILSpy.TextView;
using ILSpy.ViewModels; using ILSpy.ViewModels;
@ -77,9 +78,21 @@ namespace ILSpy
return null; return null;
if (s_views.TryGetValue(param.GetType(), out var ctor)) if (s_views.TryGetValue(param.GetType(), out var ctor))
return ctor(); return ctor();
// Convention fallback for ViewModelBase-derived VMs not in the explicit map. // Convention fallback: SomeViewModel -> SomeView. Type.GetType only searches the
// calling assembly + corelib, so a plugin viewmodel (loaded into the AppDomain
// at runtime by AppComposition.LoadPlugins) wouldn't be found via that path
// alone. Walk every loaded assembly to find the matching View type.
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal); var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name); var type = Type.GetType(name);
if (type == null)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
type = asm.GetType(name);
if (type != null)
break;
}
}
if (type != null) if (type != null)
return (Control)Activator.CreateInstance(type)!; return (Control)Activator.CreateInstance(type)!;
return new TextBlock { Text = "Not Found: " + name }; return new TextBlock { Text = "Not Found: " + name };
@ -91,6 +104,7 @@ namespace ILSpy
return false; return false;
return data is IDockable return data is IDockable
|| data is ViewModelBase || data is ViewModelBase
|| data is IOptionPage
|| s_views.ContainsKey(data.GetType()); || s_views.ContainsKey(data.GetType());
} }
} }

Loading…
Cancel
Save