Add type guessing for property and local symbol references

This commit is contained in:
Yoshi Askharoun
2025-09-21 21:25:28 -05:00
parent d6d3aabdcb
commit 768f14c46f
3 changed files with 44 additions and 11 deletions
+7 -2
View File
@@ -354,10 +354,15 @@ public class Disassembler
}
}
public static TypeSchema GuessTypeSchema(Type runtimeType, MarkupLoadResult loadResult)
public static TypeSchema TryGuessTypeSchema(Type runtimeType, MarkupLoadResult loadResult)
{
return loadResult.ImportTables.TypeImports.FirstOrDefault(t => t.RuntimeType == runtimeType)
?? loadResult.ImportTables.TypeImports.FirstOrDefault(t => t.RuntimeType == runtimeType.BaseType)
?? loadResult.ImportTables.TypeImports.FirstOrDefault(t => t.RuntimeType == runtimeType.BaseType);
}
public static TypeSchema GuessTypeSchema(Type runtimeType, MarkupLoadResult loadResult)
{
return TryGuessTypeSchema(runtimeType, loadResult)
?? throw new Exception($"Failed to find type schema for '{runtimeType.Name}' in {loadResult.Uri}");
}
+1 -1
View File
@@ -112,7 +112,7 @@ partial class Decompiler
if (symbolRef.Origin is SymbolOrigin.ScopedLocal && !scopedLocals.Contains(symbolRef.Symbol))
{
// Scoped locals need to be declared the first time they're assigned
var newSymbolIrisObj = IrisObject.Create(newSymbolValue, null, _context);
var newSymbolIrisObj = IrisObject.Create(newSymbolValue, null, _context, export);
var typeSchema = newSymbolIrisObj.Type ?? UIXTypes.MapIDToType(UIXTypeID.Object);
symbolWriteExpr = LocalDeclarationStatement(VariableDeclaration(
+36 -8
View File
@@ -3,12 +3,13 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Iris.Asm;
using Microsoft.Iris.Asm.Models;
using Microsoft.Iris.Markup;
using System.Linq;
namespace Microsoft.Iris.DecompXml.Mock;
internal record IrisObject(object Object, TypeSchema Type)
{
public static IrisObject Create(object objIn, TypeSchema type, DecompileContext context)
public static IrisObject Create(object objIn, TypeSchema type, DecompileContext context, MarkupTypeSchema parentSchema = null)
{
object obj = objIn;
@@ -27,6 +28,11 @@ internal record IrisObject(object Object, TypeSchema Type)
type ??= GuessExpressionReturnType(expr, context);
return new(obj, type);
}
else if (objIn is SymbolReference symRef && type is null && parentSchema is not null)
{
if (symRef.Origin is SymbolOrigin.Properties or SymbolOrigin.Locals)
type = parentSchema.InheritableSymbolsTable.First(sr => sr.Name == symRef.Symbol).Type;
}
if (objIn is Disassembler.RawConstantInfo constantInfo)
{
@@ -47,21 +53,43 @@ internal record IrisObject(object Object, TypeSchema Type)
if (expr is MemberAccessExpressionSyntax memberAccessExpression)
{
// TODO: Handle member access on instance methods
var sourceExpr = (IdentifierNameSyntax)memberAccessExpression.Expression;
var sourceTypeName = QualifiedTypeName.Parse(sourceExpr.ToString());
var sourceType = ctx.GetImportedType(sourceTypeName);
try
{
var sourceExpr = (IdentifierNameSyntax)memberAccessExpression.Expression;
var sourceTypeName = QualifiedTypeName.Parse(sourceExpr.ToString());
var sourceType = ctx.GetImportedType(sourceTypeName);
var memberName = memberAccessExpression.TryGetInferredMemberName();
var memberName = memberAccessExpression.TryGetInferredMemberName();
var property = sourceType.FindPropertyDeep(memberName);
if (property is not null)
return property.PropertyType;
var property = sourceType.FindPropertyDeep(memberName);
if (property is not null)
return property.PropertyType;
}
catch { }
}
else if (expr is CastExpressionSyntax castExpr)
{
var castTargetName = QualifiedTypeName.Parse(castExpr.Type.ToString());
return ctx.GetImportedType(castTargetName);
}
else if (expr is LiteralExpressionSyntax literalExpr)
{
return literalExpr.Kind() switch
{
// FIXME: This should be more specific. Detect the best numeric type.
SyntaxKind.NumericLiteralExpression => UIXTypes.MapIDToType(UIXTypeID.Int32),
SyntaxKind.Utf8StringLiteralExpression or
SyntaxKind.StringLiteralExpression => UIXTypes.MapIDToType(UIXTypeID.String),
SyntaxKind.CharacterLiteralExpression => UIXTypes.MapIDToType(UIXTypeID.Char),
SyntaxKind.TrueLiteralExpression or
SyntaxKind.FalseLiteralExpression => UIXTypes.MapIDToType(UIXTypeID.Boolean),
SyntaxKind.NullLiteralExpression => UIXTypes.MapIDToType(UIXTypeID.Null),
SyntaxKind.ArgListExpression or
SyntaxKind.DefaultLiteralExpression or
_ => throw new System.NotImplementedException(),
};
}
return null;
}