Add special handling for SingleModelItem

This commit is contained in:
Joshua "Yoshi" Askharoun
2025-11-24 01:22:19 -06:00
parent 8c63355a16
commit d8c073bd3d
3 changed files with 90 additions and 20 deletions
+43 -3
View File
@@ -1,9 +1,12 @@
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Iris.Asm; using Microsoft.Iris.Asm;
using Microsoft.Iris.Asm.Models;
using Microsoft.Iris.Markup; using Microsoft.Iris.Markup;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Microsoft.Iris.DecompXml.Mock; namespace Microsoft.Iris.DecompXml.Mock;
@@ -40,11 +43,30 @@ internal class IrisExpression
if (TryMapPredefinedType(type, out var kind)) if (TryMapPredefinedType(type, out var kind))
return PredefinedType(Token(kind)); return PredefinedType(Token(kind));
return IdentifierName(context.GetQualifiedName(type).ToString()); var typeName = context.GetQualifiedName(type);
if (type.Name.StartsWith("SingletonModelItem"))
{
// Special handling for this weird wrapper type
var genericName = ParseGenericType(typeName);
var innerFullTypeName = genericName.TypeArgumentList.Arguments[0].ToString();
// Resolve namespace to prefix
var nsEndIndex = innerFullTypeName.LastIndexOf('.');
var innerTypeName = innerFullTypeName[(nsEndIndex + 1)..];
var ns = innerFullTypeName[..nsEndIndex];
var innerType = context.ImportTables.TypeImports
.Where(t => t.Name == innerTypeName || t.AlternateName == innerTypeName)
.FirstOrDefault(t => (t.Owner as AssemblyLoadResult)?.Namespace == ns);
typeName = context.GetQualifiedName(innerType);
}
return IdentifierName(typeName.ToString());
} }
public static IdentifierNameSyntax ToSyntax(SymbolReference symbolRef) => public static IdentifierNameSyntax ToSyntax(SymbolReference symbolRef) => IdentifierName(symbolRef.Symbol);
IdentifierName(symbolRef.Symbol);
public static ExpressionSyntax ToSyntax(object obj, TypeSchema type, uint offset, DecompileContext context) public static ExpressionSyntax ToSyntax(object obj, TypeSchema type, uint offset, DecompileContext context)
{ {
@@ -90,4 +112,22 @@ internal class IrisExpression
return false; return false;
} }
private static GenericNameSyntax ParseGenericType(QualifiedTypeName typeName)
{
Regex rxGeneric = new(@"([A-z_:]\w*)`(\d+)\[(.+)\]");
var genericMatch = rxGeneric.Match(typeName.TypeName);
if (!genericMatch.Success)
throw new ArgumentException("Invalid generic");
var unqualifiedTypeName = genericMatch.Groups[1].Value;
var typeArgCount = int.Parse(genericMatch.Groups[2].Value);
var typeArgNames = genericMatch.Groups[3].Value
.Split(',')
.Select(IdentifierName);
// TODO: Handle nested generics
var trimmedTypeName = $"{typeName.NamespacePrefix}:{unqualifiedTypeName}";
return GenericName(Identifier(trimmedTypeName), TypeArgumentList([.. typeArgNames]));
}
} }
+31 -1
View File
@@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Iris.Asm; using Microsoft.Iris.Asm;
using Microsoft.Iris.Asm.Models; using Microsoft.Iris.Asm.Models;
using Microsoft.Iris.Markup; using Microsoft.Iris.Markup;
using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Microsoft.Iris.DecompXml.Mock; namespace Microsoft.Iris.DecompXml.Mock;
@@ -52,7 +53,7 @@ internal record IrisObject(object Object, TypeSchema Type)
if (expr is MemberAccessExpressionSyntax memberAccessExpression) if (expr is MemberAccessExpressionSyntax memberAccessExpression)
{ {
// TODO: Handle member access on instance methods // TODO: Handle member access on instances
try try
{ {
var sourceExpr = (IdentifierNameSyntax)memberAccessExpression.Expression; var sourceExpr = (IdentifierNameSyntax)memberAccessExpression.Expression;
@@ -90,6 +91,35 @@ internal record IrisObject(object Object, TypeSchema Type)
_ => throw new System.NotImplementedException(), _ => throw new System.NotImplementedException(),
}; };
} }
else if (expr is InvocationExpressionSyntax invocationExpression)
{
// TODO: Handle invocation of instance methods
try
{
var sourceExpr = invocationExpression.Expression;
List<NameSyntax> names = [];
while (sourceExpr is MemberAccessExpressionSyntax innerSourceExpr)
{
names.Add(innerSourceExpr.Name);
sourceExpr = innerSourceExpr.Expression;
}
var sourceTypeName = QualifiedTypeName.Parse(sourceExpr.ToString());
var sourceType = ctx.GetImportedType(sourceTypeName);
var memberName = names[^1].ToString();
// Try to disambiguate overloads using number of parameters
var parameterCount = invocationExpression.ArgumentList.Arguments.Count;
var method = sourceType.Methods.FirstOrDefault(
m => m.Name == memberName && m.ParameterTypes.Length == parameterCount);
return method?.ReturnType;
}
catch { }
}
return null; return null;
} }
+16 -16
View File
@@ -5,7 +5,7 @@
<Boolean Name="ShowZunePassTracks" Boolean="true" /> <Boolean Name="ShowZunePassTracks" Boolean="true" />
</Properties> </Properties>
<Locals> <Locals>
<zuneUI:TransportControls Name="TransportControls" TransportControls="{zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance}" /> <zuneUI:TransportControls Name="TransportControls" TransportControls="{zuneUI:TransportControls.Instance}" />
<zuneUI:SignIn Name="SignIn" SignIn="{zuneUI:SignIn.Instance}" /> <zuneUI:SignIn Name="SignIn" SignIn="{zuneUI:SignIn.Instance}" />
</Locals> </Locals>
<Scripts> <Scripts>
@@ -55,7 +55,7 @@ bool IsQuickMix()
</Properties> </Properties>
<Locals> <Locals>
<Window Name="Window" /> <Window Name="Window" />
<zuneUI:TransportControls Name="TransportControls" TransportControls="{zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance}" /> <zuneUI:TransportControls Name="TransportControls" TransportControls="{zuneUI:TransportControls.Instance}" />
<SelectionManager Name="SelectionManager" /> <SelectionManager Name="SelectionManager" />
<contentList:NavigateIntoIndexRequest Name="NavigateIntoArgs" /> <contentList:NavigateIntoIndexRequest Name="NavigateIntoArgs" />
<nowPlayingLand:NowPlayingListModel Name="NowPlayingListModel" Page="{Page}" /> <nowPlayingLand:NowPlayingListModel Name="NowPlayingListModel" Page="{Page}" />
@@ -126,8 +126,8 @@ UI.CreateInterestOnFocus = false;
ShowMPContent.Value = nowPlayingLand:NowPlayingPersistentState.ShowZunePassTracks; ShowMPContent.Value = nowPlayingLand:NowPlayingPersistentState.ShowZunePassTracks;
]]></Script> ]]></Script>
<Script><![CDATA[ <Script><![CDATA[
[DeclareTrigger(zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack)] [DeclareTrigger(zuneUI:TransportControls.Instance.CurrentTrack)]
CurrentTrack = #zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack #; CurrentTrack = #zuneUI:TransportControls.Instance.CurrentTrack #;
]]></Script> ]]></Script>
<Script><![CDATA[ <Script><![CDATA[
[DeclareTrigger(TransportControls.Playing), DeclareTrigger(TransportControls.PlayingVideo), DeclareTrigger(Page.SlideShowState.Play), DeclareTrigger(MiniMode.InCompactMode), DeclareTrigger(MiniMode.InPopupMode), DeclareTrigger(Window.WindowState)] [DeclareTrigger(TransportControls.Playing), DeclareTrigger(TransportControls.PlayingVideo), DeclareTrigger(Page.SlideShowState.Play), DeclareTrigger(MiniMode.InCompactMode), DeclareTrigger(MiniMode.InPopupMode), DeclareTrigger(Window.WindowState)]
@@ -272,7 +272,7 @@ ActionContainer.Visible = #SaveAsPlaylistButton.Visible # || #ShowMPContentCheck
]]></Script> ]]></Script>
<Script><![CDATA[ <Script><![CDATA[
[DeclareTrigger(CurrentlyPlayingTrackMixAvailability.Available)] [DeclareTrigger(CurrentlyPlayingTrackMixAvailability.Available)]
object track = zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack; object track = zuneUI:TransportControls.Instance.CurrentTrack;
if ((Page.ShowMixOnEntry && track != null) && (Page.InitialPlaybackID == track.PlaybackID) && #CurrentlyPlayingTrackMixAvailability.Available #) if ((Page.ShowMixOnEntry && track != null) && (Page.InitialPlaybackID == track.PlaybackID) && #CurrentlyPlayingTrackMixAvailability.Available #)
{ {
CurrentlyPlayingTrackMixAvailability.UpdateMixSeed.Invoke(); CurrentlyPlayingTrackMixAvailability.UpdateMixSeed.Invoke();
@@ -620,7 +620,7 @@ bool IsQuickMix()
</Properties> </Properties>
<Locals> <Locals>
<Window Name="Window" /> <Window Name="Window" />
<zuneUI:TransportControls Name="TransportControls" TransportControls="{zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance}" /> <zuneUI:TransportControls Name="TransportControls" TransportControls="{zuneUI:TransportControls.Instance}" />
<nonClientControls:WindowState Name="WindowState" /> <nonClientControls:WindowState Name="WindowState" />
<iris:Command Name="ZoomScale0" Description="{zuneUI:Shell.LoadString(zuneUI:StringId.IDS_VIDEO_ZOOM_FULL)}" /> <iris:Command Name="ZoomScale0" Description="{zuneUI:Shell.LoadString(zuneUI:StringId.IDS_VIDEO_ZOOM_FULL)}" />
<iris:Command Name="ZoomScale1" Description="{zuneUI:Shell.LoadString(zuneUI:StringId.IDS_VIDEO_ZOOM_NONE)}" /> <iris:Command Name="ZoomScale1" Description="{zuneUI:Shell.LoadString(zuneUI:StringId.IDS_VIDEO_ZOOM_NONE)}" />
@@ -678,7 +678,7 @@ if (playingVideo)
((float)(wndWidth)) / ((float)(naturalWidth)); ((float)(wndWidth)) / ((float)(naturalWidth));
object scaleY = (float)(wndHeight) / (float)(naturalHeight); object scaleY = (float)(wndHeight) / (float)(naturalHeight);
((float)(wndHeight)) / ((float)(naturalHeight)); ((float)(wndHeight)) / ((float)(naturalHeight));
object scale = system:Math.Min(scaleX, scaleY); int scale = system:Math.Min(scaleX, scaleY);
maxVideoSizeX = #TransportControls.ZoomScaleFactor # * naturalWidth; maxVideoSizeX = #TransportControls.ZoomScaleFactor # * naturalWidth;
maxVideoSizeY = TransportControls.ZoomScaleFactor * naturalHeight; maxVideoSizeY = TransportControls.ZoomScaleFactor * naturalHeight;
if (maxVideoSizeY + 50 > wndHeight || maxVideoSizeX + 50 > wndWidth) if (maxVideoSizeY + 50 > wndHeight || maxVideoSizeX + 50 > wndWidth)
@@ -875,7 +875,7 @@ else
{ {
SelectionManager selectionManager = (SelectionManager)value; SelectionManager selectionManager = (SelectionManager)value;
object insertAt = InsertIndex.Value; object insertAt = InsertIndex.Value;
zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.ReorderNowPlaying(selectionManager.SelectedIndices, insertAt); zuneUI:TransportControls.Instance.ReorderNowPlaying(selectionManager.SelectedIndices, insertAt);
} }
]]></Script> ]]></Script>
</Scripts> </Scripts>
@@ -936,8 +936,8 @@ else
</Properties> </Properties>
<Scripts> <Scripts>
<Script><![CDATA[ <Script><![CDATA[
[DeclareTrigger(zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.ErrorCount)] [DeclareTrigger(zuneUI:TransportControls.Instance.ErrorCount)]
ErrorCode = zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.GetLibraryErrorCode(Model); ErrorCode = zuneUI:TransportControls.Instance.GetLibraryErrorCode(Model);
]]></Script> ]]></Script>
<Script><![CDATA[ <Script><![CDATA[
[DeclareTrigger(RowModel.IsNowPlaying)] [DeclareTrigger(RowModel.IsNowPlaying)]
@@ -996,8 +996,8 @@ SignInButton.Visible = #RowModel.ButtonState #.ChosenValue # == "SignIn";
Upsell.Visible = util:FeatureEnablement.IsFeatureEnabled(zuneDBApi:Features.eSubscription) && RowModel.ButtonState.ChosenValue == "Upsell"; Upsell.Visible = util:FeatureEnablement.IsFeatureEnabled(zuneDBApi:Features.eSubscription) && RowModel.ButtonState.ChosenValue == "Upsell";
]]></Script> ]]></Script>
<Script><![CDATA[ <Script><![CDATA[
[DeclareTrigger(zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack)] [DeclareTrigger(zuneUI:TransportControls.Instance.CurrentTrack)]
RowModel.IsNowPlaying = Model == #zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack #; RowModel.IsNowPlaying = Model == #zuneUI:TransportControls.Instance.CurrentTrack #;
]]></Script> ]]></Script>
<Script><![CDATA[ <Script><![CDATA[
[DeclareTrigger(RowModel.IsNowPlaying), DeclareTrigger(RowModel.ForceNonMarketplace)] [DeclareTrigger(RowModel.IsNowPlaying), DeclareTrigger(RowModel.ForceNonMarketplace)]
@@ -1319,8 +1319,8 @@ if (ListModel.SelectionManager != null && ListModel.SelectionManager.IsSelected(
</Locals> </Locals>
<Scripts> <Scripts>
<Script><![CDATA[ <Script><![CDATA[
[DeclareTrigger(zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack)] [DeclareTrigger(zuneUI:TransportControls.Instance.CurrentTrack)]
object track = #zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack #; object track = #zuneUI:TransportControls.Instance.CurrentTrack #;
if (LibraryAlbumInfo != null) if (LibraryAlbumInfo != null)
{ {
Class.DisposeOwnedObject(LibraryAlbumInfo); Class.DisposeOwnedObject(LibraryAlbumInfo);
@@ -1513,7 +1513,7 @@ if (RotateInfo.Enabled)
[DeclareTrigger(NowPlayingBackgroundHelper.Visible)] [DeclareTrigger(NowPlayingBackgroundHelper.Visible)]
MPTrackQuery.Enabled = false; MPTrackQuery.Enabled = false;
MPTrackQuery.Id = null; MPTrackQuery.Id = null;
object currentTrack = zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack; object currentTrack = zuneUI:TransportControls.Instance.CurrentTrack;
if (#NowPlayingBackgroundHelper.Visible # && NowPlayingBackgroundHelper.Visible || !currentTrack.IsInVisibleCollection && util:FeatureEnablement.IsFeatureEnabled(zuneDBApi:Features.eMusic)) if (#NowPlayingBackgroundHelper.Visible # && NowPlayingBackgroundHelper.Visible || !currentTrack.IsInVisibleCollection && util:FeatureEnablement.IsFeatureEnabled(zuneDBApi:Features.eMusic))
{ {
MPTrackQuery.Id = TrackId.ToString(); MPTrackQuery.Id = TrackId.ToString();
@@ -1530,7 +1530,7 @@ ArtistQuery.Enabled = false;
ArtistQuery.Id = null; ArtistQuery.Id = null;
TopListenersQuery.Enabled = false; TopListenersQuery.Enabled = false;
TopListenersQuery.ArtistId = null; TopListenersQuery.ArtistId = null;
object currentTrack = zuneUI:SingletonModelItem`1[ZuneUI.TransportControls].Instance.CurrentTrack; object currentTrack = zuneUI:TransportControls.Instance.CurrentTrack;
if (((!zuneUI:GuidHelper.IsEmpty(ArtistId) && #NowPlayingBackgroundHelper.Visible # && util:FeatureEnablement.IsFeatureEnabled(zuneDBApi:Features.eMusic) && configuration:ClientConfiguration.Playback.ShowNowPlayingClipAnimations) && (iris:Application.RenderingQuality == iris:RenderingQuality.MaxQuality)) && (currentTrack != null) && currentTrack.IsMusic) if (((!zuneUI:GuidHelper.IsEmpty(ArtistId) && #NowPlayingBackgroundHelper.Visible # && util:FeatureEnablement.IsFeatureEnabled(zuneDBApi:Features.eMusic) && configuration:ClientConfiguration.Playback.ShowNowPlayingClipAnimations) && (iris:Application.RenderingQuality == iris:RenderingQuality.MaxQuality)) && (currentTrack != null) && currentTrack.IsMusic)
{ {
ArtistPhotosQuery.Id = ArtistId.ToString(); ArtistPhotosQuery.Id = ArtistId.ToString();