From a61a4c2245b3c531398786519ca4ab275393b34e Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 20 Feb 2011 16:55:19 +0100 Subject: [PATCH] Infer types for the temporary variables introduced in ILAst. --- ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs | 76 +++++++++++++++----- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index b5a17a782..6ed396d20 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -20,40 +20,69 @@ namespace Decompiler /// public class TypeAnalysis { - public static void Run(DecompilerContext context, ILNode node) + public static void Run(DecompilerContext context, ILBlock method) { TypeAnalysis ta = new TypeAnalysis(); ta.context = context; ta.module = context.CurrentMethod.Module; ta.typeSystem = ta.module.TypeSystem; - ta.InferTypes(node); + ta.method = method; + ta.InferTypes(method); + ta.InferRemainingStores(); } DecompilerContext context; TypeSystem typeSystem; + ILBlock method; ModuleDefinition module; List storedToGeneratedVariables = new List(); void InferTypes(ILNode node) { - foreach (ILNode child in node.GetChildren()) { - ILExpression expr = child as ILExpression; - if (expr != null) { - ILVariable v = expr.Operand as ILVariable; - if (v != null && v.IsGenerated && v.Type == null && expr.Code == ILCode.Stloc) { - // don't deal with this node or its children yet, - // wait for the expected type to be inferred first - storedToGeneratedVariables.Add(expr); - continue; - } - bool anyArgumentIsMissingType = expr.Arguments.Any(a => a.InferredType == null); - if (expr.InferredType == null || anyArgumentIsMissingType) - expr.InferredType = InferTypeForExpression(expr, null, forceInferChildren: anyArgumentIsMissingType); + ILExpression expr = node as ILExpression; + if (expr != null) { + ILVariable v = expr.Operand as ILVariable; + if (v != null && v.IsGenerated && v.Type == null && expr.Code == ILCode.Stloc && HasSingleLoad(v)) { + // don't deal with this node or its children yet, + // wait for the expected type to be inferred first + storedToGeneratedVariables.Add(expr); + return; } + bool anyArgumentIsMissingType = expr.Arguments.Any(a => a.InferredType == null); + if (expr.InferredType == null || anyArgumentIsMissingType) + expr.InferredType = InferTypeForExpression(expr, null, forceInferChildren: anyArgumentIsMissingType); + } + foreach (ILNode child in node.GetChildren()) { InferTypes(child); } } + bool HasSingleLoad(ILVariable v) + { + int loads = 0; + foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { + if (expr.Operand == v) { + if (expr.Code == ILCode.Ldloc) + loads++; + else if (expr.Code != ILCode.Stloc) + return false; + } + } + return loads == 1; + } + + void InferRemainingStores() + { + while (storedToGeneratedVariables.Count > 0) { + List stored = storedToGeneratedVariables; + storedToGeneratedVariables = new List(); + foreach (ILExpression expr in stored) + InferTypes(expr); + if (!(storedToGeneratedVariables.Count < stored.Count)) + throw new InvalidOperationException("Infinite loop in type analysis detected."); + } + } + /// /// Infers the C# type of . /// @@ -73,11 +102,22 @@ namespace Decompiler switch ((Code)expr.Code) { #region Variable load/store case Code.Stloc: - if (forceInferChildren) - InferTypeForExpression(expr.Arguments.Single(), ((ILVariable)expr.Operand).Type); + { + ILVariable v = (ILVariable)expr.Operand; + if (forceInferChildren || v.Type == null) { + TypeReference t = InferTypeForExpression(expr.Arguments.Single(), ((ILVariable)expr.Operand).Type); + if (v.Type == null) + v.Type = t; + } + } return null; case Code.Ldloc: - return ((ILVariable)expr.Operand).Type; + { + ILVariable v = (ILVariable)expr.Operand; + if (v.Type == null) + v.Type = expectedType; + return v.Type; + } case Code.Starg: if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), ((ParameterReference)expr.Operand).ParameterType);