ILSpy resolves an assembly's references against the target framework it
detects from the TargetFrameworkAttribute. When that attribute is missing,
wrong, or the user wants to force a different framework, there was no way to
hint the correct one, so references could resolve against the wrong runtime
pack or framework directory.
A LoadedAssembly can now carry a TargetFrameworkIdOverride that short-circuits
detection (it is the single value every LoadedAssembly-based resolution path
reads), is persisted in the assembly-list XML, and is carried across a reload
so a runtime change re-resolves against the new framework. The "Set Target
Framework" context-menu entry edits it through a dialog with a free-form text
box and an always-visible list of common monikers to pick from (the app forces
overlay popups, so a dropdown would be clamped inside the small dialog); input
is validated and converted from the short TFM users know (net48) to the long
FrameworkName form the resolver consumes (.NETFramework,Version=v4.8) via
NuGet. The direct DetectTargetFrameworkId callers in the decompiler core
(project export, language version) intentionally keep reading the real
attribute; only reference resolution is overridden.
Resurrects a 2020 prototype (branch tfmoverride) re-implemented against the
current ILSpyX/Avalonia code, whose surrounding structures no longer matched.
Assisted-by: Claude:claude-opus-4-8:Claude Code
* Migrate ILSpy.AddIn.VS2022 to SDK-style VSIX project
* Retire the legacy VS2017/2019 ILSpy add-in
* Build the VS extension via dotnet build on the slnx
* Inline ILSpy.AddIn.Shared into ILSpy.AddIn.VS2022
* Restore the VS add-in menus broken by the SDK-style migration
The Avalonia port had placed the UI app in an ILSpy.* namespace tree,
while the csproj RootNamespace and every prior release (through 10.1)
use ICSharpCode.ILSpy.*. Restoring the historical namespace reduces the
public API diff against release/10.1 for plugin authors and removes the
shadowing that forced global:: qualifiers in the test project. The
Images class and AccessOverlayIcon enum move back into the root
namespace (as in 10.1), since an ICSharpCode.ILSpy.Images namespace
would shadow the Images class for all code inside ICSharpCode.ILSpy.
Assisted-by: Claude:claude-fable-5:Claude Code
Opening a package from a feed previously meant downloading the .nupkg by
hand and using File > Open (#2313). The new File menu command searches any
public V3 feed (editable package-source list, persisted as an MRU in the
ILSpy settings), offers the latest 100 versions in a dropdown, and downloads
into the NuGet global packages folder so the cache is shared with every
other NuGet consumer on the machine and nothing is fetched twice. The cached
.nupkg is then opened exactly like the regular Open command. Feed access
sits behind INuGetFeedClient so the headless test suite covers search,
paging, version selection, download, cancellation, and error surfacing
without touching the network.
Assisted-by: Claude:claude-fable-5:Claude Code
These three project settings were present in the WPF build but lost in the
move to Avalonia. RollForward=major matters most: the default publish is
framework-dependent (publish.ps1 uses --no-self-contained) and the app targets
net10.0, so without it a machine that only has a newer major runtime installed
fails to start the app. DynamicAdaptationMode (DATAS) lets server GC shrink its
heap count to the live load for a smaller idle working set, and Debug-only
CheckForOverflowUnderflow traps arithmetic wrap during development.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The SortResX target only set its command on Windows (powershell), so the
resx-sorting build step was a silent no-op on Linux/macOS even though
pwsh (PowerShell 7+) is available there -- mirror the PowerShell cmdlet
project's powershell/pwsh split. The included Resources.resx change is
that step catching up one entry (ExportProjectSolution) that had drifted
out of order while the target was disabled. The script is EOL-preserving,
so this stays LF with no cross-OS churn.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The WPF host carried two ILSpy.csproj build steps the Avalonia port left
behind. ApplyStackExtension runs editbin /stack:16777216 on the apphost so
deeply nested types/expressions don't overflow the 1 MB main-thread stack
during decompilation (the managed runtime can't grow the main thread's
stack at run time on Windows). SortResX keeps the .resx entries sorted so
localisation diffs stay clean; its script was still in BuildTools but no
target invoked it.
Both are gated to do nothing off Windows / without the MSVC tools / on CI,
so they only act in the same local-Windows scenario they did before. The
VC-tools props import is restored alongside, since it is what populates
$(VCToolsVersion) for the editbin gate.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The Pdb2Xml command (ILSpy) and the PDB round-trip tests (Decompiler.Tests)
reference Microsoft.DiaSymReader*, previously gated on the build host being
Windows. That made dotnet restore resolve a different graph on Windows than
on Linux -- the packages (and their transitive tail: DiaSymReader.PortablePdb,
the legacy NETCore.Platforms/Win32 packages) appear only on Windows, and
DiaSymReader.Native flips between Direct and CentralTransitive. So a checkout
could not be developed across OSes without the committed packages.lock.json
churning on every Windows restore.
Drop the OS gate (keep Debug-only) so the restored graph, and the committed
lock, are identical on every OS. The consuming code is still gated by DEBUG
and WINDOWS, so on non-Windows the packages are restored but never compiled
in; the native asset only resolves for win-* RIDs.
The "Verify package contents" step (which checks the committed *.filelist
snapshots still match the built VSIX/MSI contents) had been excluding
packages.lock.json from its git diff to tolerate that per-OS churn. With the
locks now identical across OSes the carve-out is unnecessary, so it goes back
to a plain git diff --exit-code.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Three comments described the old WPF host: the NoWarn rationale and the
DiaSymReader-gating note in ILSpy.csproj, and the no-[Shared] note in
DecompilerSettingsViewModel. Reword them to describe the current
System.Composition / build behavior directly. No code or suppression changes;
the TomsToolbox.Composition.Analyzer (MEF002/MEF004 source) stays.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Rename Avalonia.Xaml.Behaviors to its successor Xaml.Behaviors.Avalonia
(12.0.0.1), and bump Dock (12.0.0.2), Svg.Controls.Skia.Avalonia,
AvaloniaUI.DiagnosticsSupport, CliWrap, coverlet.MTP, and NUnit to their
latest releases.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Avalonia 12 dropped the in-process Avalonia.Diagnostics package (its last
release is 11.3.x), so AttachDevTools no longer shows a window. Move to the
AvaloniaUI.DiagnosticsSupport bridge driven by WithDeveloperTools() in
BuildAvaloniaApp -- it attaches internally, so a separate App-level
AttachDeveloperTools call would double-attach and throw. The inspector is the
AvaloniaUI.DeveloperTools global tool (avdt) connecting over the bridge.
DEBUG-only: the assets are dropped from Release builds.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Master's manual ILSpy/Properties/AssemblyInfo.cs was dropped during
the Avalonia port; the SDK's auto-generated AssemblyInfo took over
with default-zero versions. As a result the built ILSpy.dll's
assembly metadata read 1.0.0.0 even though DecompilerVersionInfo
(the static class generated from the .template by the build pipeline)
had the right values. Anything that queried Assembly.GetName().Version
or AssemblyInformationalVersionAttribute -- update checks, crash
report context, the title-bar version line we still need to wire --
got the SDK default, not the real revision.
Port the cross-platform-safe slice of master's AssemblyInfo.cs:
Title/Description/Company/Product/Copyright, ComVisible(false), the
two version attributes pointing at DecompilerVersionInfo,
NeutralResourcesLanguage, InternalsVisibleTo("ILSpy.Tests"), and the
CA2243 suppression. Deliberately skipped: [SupportedOSPlatform(
"Windows7.0")] and [TargetPlatform("Windows10.0")] (would re-make the
assembly Windows-only at metadata level and emit CA1416 noise for
cross-platform code paths), [InternalsVisibleTo("ILSpy.AddIn")] (the
AddIn project isn't in the avalonia build path), and the WPF-only
Properties/WPFAssemblyInfo.cs ThemeInfo (System.Windows-typed).
The single-line ILSpy/AssemblyInfo.cs stub that only carried the
ILSpy.Tests InternalsVisibleTo gets folded into the new file and
removed, matching master's layout.
GenerateAssemblyInfo=false in the csproj is the required companion --
without it the SDK emits a second AssemblyVersion attribute and
compilation fails with CS0579.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Avalonia's Window.Icon doesn't reach the macOS Dock, so the app needs a
proper .app bundle: an ILSpy.icns produced from the existing artwork, an
Info.plist with CFBundleIconFile=ILSpy and CFBundleIdentifier
net.sharpdevelop.ilspy, and a BuildMacAppBundle target that runs
AfterTargets="Publish" for any osx-* RuntimeIdentifier. The target lays
out the standard Contents/MacOS + Contents/Resources structure under
bin/<config>/<tfm>/<rid>/ILSpy.app/ and chmods the apphost executable
so macOS LaunchServices will accept it.
The Avalonia resource glob ('Assets/**') is told to skip the bundle
inputs since they're consumed by the OS loader rather than at runtime
via avares://. The lock files pick up RID-specific runtime asset entries
that NuGet adds when an osx RID is in the project's RuntimeIdentifiers.
Workstation GC pauses every managed thread on Gen-1/2 collections,
so background allocations (decompiler work, layout deserialise,
search streaming) stall the UI thread for the duration of the pause.
Server GC spawns one heap per CPU core with dedicated GC threads;
collections of one heap don't pause the others. Concurrent stays on
so even server collections don't stop-the-world for long.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Without per-dockable view resolution the dock chrome caches one view per
slot and reuses it for every dockable that lands there, so a second pane
sharing an Alignment (Analyzer + Debug Steps both Bottom) renders the
first pane's content under the second pane's tab. Each dockable instead
owns its view (IDockableViewOwner) and DockableViewRecycling hands that
instance back keyed by dockable identity -- there is no app-lifetime
global view cache to leak every transient document tab's view subtree.
Resolution runs through the single application-wide ViewLocator (its
dispatch map is introduced here rather than in the later DataTemplate
cleanup) so the dock never re-resolves an owned view through the template
machinery on a cache hit.
Assisted-by: Claude:claude-opus-4-8:Claude Code
WPF ships Pdb2XmlCommand behind `#if DEBUG && WINDOWS` because
Microsoft.DiaSymReader uses native COM interop. Avalonia parity uses the
same gate, with the package references conditional on the build host being
Windows + Debug, and the consuming command file `#if DEBUG && WINDOWS`.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds ICSharpCode.BamlDecompiler as a ProjectReference, ports IResourceFileHandler +
ResourceFileHandlerContext from WPF, and plumbs both through:
Assisted-by: Claude:claude-opus-4-7:Claude Code
Brings the WPF decompiler-pipeline-stepper feature across. Available only
in Debug builds — the entire feature set is gated behind `#if DEBUG`, so
Release users see neither the pane nor the ILAst languages in the picker.
The renamed Avalonia csproj was referencing the localized strings file
via a sibling-project relative path (..\ILSpy\Properties\Resources.resx)
that resolved into the WPF host's tree. The host is gone now, so the
reference is dangling.
Selecting a node in the assembly tree now opens (or refocuses) a
DecompilerTabPageModel document tab and renders the C# decompilation in
an AvaloniaEdit TextEditor with XSHD-driven syntax highlighting.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The Fluent theme combined with the Inter font made the app feel like a
modern UWP/WinUI surface, not the WPF/native Windows look the project
wants. Switching to Avalonia's Simple theme (and Dock's matching
DockSimpleTheme + DataGrid Simple.v2.xaml) gives flatter chrome with
denser default control padding. Dropping WithInterFont() lets Avalonia
fall back to the OS font (Segoe UI on Windows).
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the Language abstraction so tree-node labels render through the
active output language instead of raw metadata names.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the temporary 3-column Grid placeholder in MainWindow with a
Dock.Avalonia DockControl driven by an ILSpyDockFactory and orchestrated
by a [Shared] DockWorkspace exported via MEF.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Strip the WPF ILSpy/, ILSpy.Tests/, and ILSpy.BamlDecompiler/ projects
and their solution entries so this commit can serve as the base for
replaying the rewritten Avalonia history on top. The BAML plugin needed
UseWpf + AvalonEdit and had a ProjectReference to ILSpy/ILSpy.csproj;
once both are gone it cannot build and would block bisect for every
intermediate commit. The Avalonia main app will absorb its three exports
(factory, file handler, entry node) in the later "BAML to XAML
decompiler integration" commit.
* Changes necessary for making SharpTreeNode cross platform by proxying System.Windows dependencies
* Add ITreeNodeImagesProvider for node icons
* Move InternalsVisibleTo to csproj (possible since net50)
* Move view models and other xplat class for SharpTreeView to ILSpyX, Windows-dependent classes to ILSpy/Controls/TreeView
* Move GetDoubleClickTime to NativeMethods
* Use NaturalSort.Extension instead of Interop
* Update to latest NaturalSort.Extensions and update 3rd party notices
* Remove old interop implementation