From f0f067759adf21cb741643fe40a4630bf3a9d321 Mon Sep 17 00:00:00 2001 From: "Joshua \"Yoshi\" Askharoun" Date: Mon, 24 Nov 2025 02:10:55 -0600 Subject: [PATCH] Unify invocation and member access type inference, add support for chained accesses --- libs/UIX.DecompXml/Mock/IrisObject.cs | 86 +++++++++++++++------------ 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/libs/UIX.DecompXml/Mock/IrisObject.cs b/libs/UIX.DecompXml/Mock/IrisObject.cs index 077abca..2e4ac26 100644 --- a/libs/UIX.DecompXml/Mock/IrisObject.cs +++ b/libs/UIX.DecompXml/Mock/IrisObject.cs @@ -51,20 +51,61 @@ internal record IrisObject(object Object, TypeSchema Type) if (expr is ParenthesizedExpressionSyntax parenExpr) expr = parenExpr.Expression; - if (expr is MemberAccessExpressionSyntax memberAccessExpression) + if (expr is InvocationExpressionSyntax or MemberAccessExpressionSyntax) { - // TODO: Handle member access on instances + // TODO: Handle invocation of instance methods try { - var sourceExpr = (IdentifierNameSyntax)memberAccessExpression.Expression; - var sourceTypeName = QualifiedTypeName.Parse(sourceExpr.ToString()); + ExpressionSyntax sourceExpr = expr; + + Stack argumentLists = []; + List names = []; + + while (sourceExpr is not NameSyntax) + { + if (sourceExpr is MemberAccessExpressionSyntax innerSourceExpr) + { + names.Add(innerSourceExpr.Name); + sourceExpr = innerSourceExpr.Expression; + } + else if (sourceExpr is InvocationExpressionSyntax innerInvocationExpr) + { + argumentLists.Push(innerInvocationExpr.ArgumentList); + sourceExpr = innerInvocationExpr.Expression; + } + } + + if (sourceExpr is not NameSyntax sourceName) + return null; + + names.Reverse(); + + var sourceTypeName = QualifiedTypeName.Parse(sourceName.ToString()); var sourceType = ctx.GetImportedType(sourceTypeName); - var memberName = memberAccessExpression.TryGetInferredMemberName(); + foreach (var name in names) + { + var memberName = name.ToString(); - var property = sourceType.FindPropertyDeep(memberName); - if (property is not null) - return property.PropertyType; + var prop = sourceType.FindPropertyDeep(memberName); + if (prop is not null) + { + sourceType = prop.PropertyType; + continue; + } + + var argumentList = argumentLists.Pop(); + + // Try to disambiguate overloads using number of parameters + var parameterCount = argumentList.Arguments.Count; + + var method = sourceType.Methods.FirstOrDefault( + m => m.Name == memberName && m.ParameterTypes.Length == parameterCount); + + sourceType = method.ReturnType; + } + + return sourceType; } catch { } } @@ -91,35 +132,6 @@ 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 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; }