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.Syntax;
using Microsoft.Iris.Asm;
using Microsoft.Iris.Asm.Models;
using Microsoft.Iris.Markup;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Microsoft.Iris.DecompXml.Mock;
@@ -40,11 +43,30 @@ internal class IrisExpression
if (TryMapPredefinedType(type, out var 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) =>
IdentifierName(symbolRef.Symbol);
public static IdentifierNameSyntax ToSyntax(SymbolReference symbolRef) => IdentifierName(symbolRef.Symbol);
public static ExpressionSyntax ToSyntax(object obj, TypeSchema type, uint offset, DecompileContext context)
{
@@ -90,4 +112,22 @@ internal class IrisExpression
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.Models;
using Microsoft.Iris.Markup;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Iris.DecompXml.Mock;
@@ -52,7 +53,7 @@ internal record IrisObject(object Object, TypeSchema Type)
if (expr is MemberAccessExpressionSyntax memberAccessExpression)
{
// TODO: Handle member access on instance methods
// TODO: Handle member access on instances
try
{
var sourceExpr = (IdentifierNameSyntax)memberAccessExpression.Expression;
@@ -90,6 +91,35 @@ internal record IrisObject(object Object, TypeSchema Type)
_ => 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;
}