Browse Source

First implementation of type inference.

pull/37/head
Daniel Grunwald 15 years ago
parent
commit
cd2c70a6b4
  1. 90
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 5
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  4. 41
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  5. 221
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  6. 18
      ILSpy/ILAstLanguage.cs

90
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -16,6 +16,7 @@ namespace Decompiler @@ -16,6 +16,7 @@ namespace Decompiler
public class AstMethodBodyBuilder
{
MethodDefinition methodDef;
TypeSystem typeSystem;
CancellationToken cancellationToken;
HashSet<ILVariable> definedLocalVars = new HashSet<ILVariable>();
@ -24,6 +25,7 @@ namespace Decompiler @@ -24,6 +25,7 @@ namespace Decompiler
AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
builder.cancellationToken = cancellationToken;
builder.methodDef = methodDef;
builder.typeSystem = methodDef.Module.TypeSystem;
if (Debugger.IsAttached) {
return builder.CreateMethodBody();
} else {
@ -65,7 +67,7 @@ namespace Decompiler @@ -65,7 +67,7 @@ namespace Decompiler
cancellationToken.ThrowIfCancellationRequested();
ILAstOptimizer bodyGraph = new ILAstOptimizer();
bodyGraph.Optimize(ilMethod);
bodyGraph.Optimize(methodDef, ilMethod);
cancellationToken.ThrowIfCancellationRequested();
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"});
@ -146,7 +148,7 @@ namespace Decompiler @@ -146,7 +148,7 @@ namespace Decompiler
yield return new Ast.ForStatement {
EmbeddedStatement = TransformBlock(((ILLoop)node).ContentBlock)
};
/*
/*
} else if (node is Branch) {
yield return new Ast.LabelStatement { Label = ((Branch)node).FirstBasicBlock.Label };
@ -163,7 +165,7 @@ namespace Decompiler @@ -163,7 +165,7 @@ namespace Decompiler
};
yield return ifElseStmt;
*/
*/
} else if (node is ILCondition) {
ILCondition conditionalNode = (ILCondition)node;
if (conditionalNode.FalseBlock.Body.Any()) {
@ -185,9 +187,9 @@ namespace Decompiler @@ -185,9 +187,9 @@ namespace Decompiler
SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition.Arguments[0]) };
for (int i = 0; i < ilSwitch.CaseBlocks.Count; i++) {
switchStmt.AddChild(new SwitchSection() {
CaseLabels = new[] { new CaseLabel() { Expression = new PrimitiveExpression(i) } },
Statements = new[] { TransformBlock(ilSwitch.CaseBlocks[i]) }
}, SwitchStatement.SwitchSectionRole);
CaseLabels = new[] { new CaseLabel() { Expression = new PrimitiveExpression(i) } },
Statements = new[] { TransformBlock(ilSwitch.CaseBlocks[i]) }
}, SwitchStatement.SwitchSectionRole);
}
yield return switchStmt;
} else if (node is ILTryCatchBlock) {
@ -195,10 +197,10 @@ namespace Decompiler @@ -195,10 +197,10 @@ namespace Decompiler
List<Ast.CatchClause> catchClauses = new List<CatchClause>();
foreach (var catchClause in tryCatchNode.CatchBlocks) {
catchClauses.Add(new Ast.CatchClause {
Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = "exception",
Body = TransformBlock(catchClause)
});
Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = "exception",
Body = TransformBlock(catchClause)
});
}
yield return new Ast.TryCatchStatement {
TryBlock = TransformBlock(tryCatchNode.TryBlock),
@ -225,7 +227,7 @@ namespace Decompiler @@ -225,7 +227,7 @@ namespace Decompiler
AstNode TransformExpression(ILExpression expr)
{
List<Ast.Expression> args = TransformExpressionArguments(expr);
return TransformByteCode(methodDef, expr, args);
return TransformByteCode(expr, args);
}
Ast.Expression MakeBranchCondition(ILExpression expr)
@ -234,19 +236,19 @@ namespace Decompiler @@ -234,19 +236,19 @@ namespace Decompiler
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
switch(expr.OpCode.Code) {
case Code.Brfalse: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case Code.Brtrue: return arg1;
case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
default: throw new Exception("Bad opcode");
case Code.Brfalse: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case Code.Brtrue: return arg1;
case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
default: throw new Exception("Bad opcode");
}
/*
} else if (branch is ShortCircuitBranch) {
@ -282,13 +284,13 @@ namespace Decompiler @@ -282,13 +284,13 @@ namespace Decompiler
} else {
throw new Exception("Bad type");
}
*/
*/
}
AstNode TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
AstNode TransformByteCode(ILExpression byteCode, List<Ast.Expression> args)
{
try {
AstNode ret = TransformByteCode_Internal(methodDef, byteCode, args);
AstNode ret = TransformByteCode_Internal(byteCode, args);
// ret.UserData["Type"] = byteCode.Type;
return ret;
} catch (NotImplementedException) {
@ -325,7 +327,7 @@ namespace Decompiler @@ -325,7 +327,7 @@ namespace Decompiler
}
}
AstNode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
AstNode TransformByteCode_Internal(ILExpression byteCode, List<Ast.Expression> args)
{
// throw new NotImplementedException();
@ -541,6 +543,20 @@ namespace Decompiler @@ -541,6 +543,20 @@ namespace Decompiler
return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name));
}
case Code.Ldc_I4:
if (byteCode.InferredType == typeSystem.Boolean && (int)operand == 0)
return new Ast.PrimitiveExpression(false);
else if (byteCode.InferredType == typeSystem.Boolean && (int)operand == 1)
return new Ast.PrimitiveExpression(true);
if (byteCode.InferredType != null && byteCode.InferredType.IsValueType) {
TypeDefinition enumDefinition = byteCode.InferredType.Resolve();
if (enumDefinition != null && enumDefinition.IsEnum) {
foreach (FieldDefinition field in enumDefinition.Fields) {
if (field.IsStatic && object.Equals(field.Constant, operand))
return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
}
}
}
return new Ast.PrimitiveExpression(operand);
case Code.Ldc_I8:
case Code.Ldc_R4:
case Code.Ldc_R8:
@ -724,26 +740,10 @@ namespace Decompiler @@ -724,26 +740,10 @@ namespace Decompiler
if (reqType == null) {
return expr;
} else {
return Convert(expr, reqType.FullName);
return expr;
}
}
static Ast.Expression Convert(Ast.Expression expr, string reqType)
{
// if (expr.UserData.ContainsKey("Type")) {
// Cecil.TypeReference exprType = (Cecil.TypeReference)expr.UserData["Type"];
// if (exprType == ByteCode.TypeZero &&
// reqType == ByteCode.TypeBool.FullName) {
// return new PrimitiveExpression(false, "false");
// }
// if (exprType == ByteCode.TypeOne &&
// reqType == ByteCode.TypeBool.FullName) {
// return new PrimitiveExpression(true, "true");
// }
// }
return expr;
}
static Ast.Expression ConvertIntToBool(Ast.Expression astInt)
{
return astInt;

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -87,6 +87,7 @@ @@ -87,6 +87,7 @@
<Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstOptimizer.cs" />
<Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="Mono.Cecil.Rocks\Constants.cs" />
<Compile Include="Mono.Cecil.Rocks\MethodBodyRocks.cs" />

5
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -16,6 +16,7 @@ namespace Decompiler.ControlFlow @@ -16,6 +16,7 @@ namespace Decompiler.ControlFlow
FlattenNestedMovableBlocks,
SimpleGotoRemoval,
RemoveDeadLabels,
TypeInference,
None
}
@ -23,7 +24,7 @@ namespace Decompiler.ControlFlow @@ -23,7 +24,7 @@ namespace Decompiler.ControlFlow
{
Dictionary<ILLabel, ControlFlowNode> labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
public void Optimize(ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
public void Optimize(MethodDefinition cecilMethod, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
{
if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
@ -55,6 +56,8 @@ namespace Decompiler.ControlFlow @@ -55,6 +56,8 @@ namespace Decompiler.ControlFlow
SimpleGotoRemoval(method);
if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return;
RemoveDeadLabels(method);
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
TypeAnalysis.Run(cecilMethod.Module.TypeSystem, method);
}
class ILMoveableBlock: ILBlock

41
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -55,7 +55,8 @@ namespace Decompiler @@ -55,7 +55,8 @@ namespace Decompiler
public override IEnumerable<ILNode> GetChildren()
{
yield return EntryPoint;
if (EntryPoint != null)
yield return EntryPoint;
foreach(ILNode child in this.Body) {
yield return child;
}
@ -157,7 +158,7 @@ namespace Decompiler @@ -157,7 +158,7 @@ namespace Decompiler
}
}
public class ILExpression: ILNode
public class ILExpression : ILNode
{
public OpCode OpCode { get; set; }
public object Operand { get; set; }
@ -165,6 +166,8 @@ namespace Decompiler @@ -165,6 +166,8 @@ namespace Decompiler
// Mapping to the original instructions (useful for debugging)
public List<ILRange> ILRanges { get; set; }
public TypeReference InferredType { get; set; }
public ILExpression(OpCode opCode, object operand, params ILExpression[] args)
{
this.OpCode = opCode;
@ -213,24 +216,39 @@ namespace Decompiler @@ -213,24 +216,39 @@ namespace Decompiler
public override void WriteTo(ITextOutput output)
{
if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) {
if (OpCode.Name == "stloc") {
output.Write(((ILVariable)Operand).Name + " = ");
if (OpCode == OpCodes.Stloc && this.InferredType == null) {
output.Write(((ILVariable)Operand).Name);
output.Write(" = ");
Arguments.First().WriteTo(output);
return;
} else if (OpCode.Name == "ldloc") {
} else if (OpCode == OpCodes.Ldloc) {
output.Write(((ILVariable)Operand).Name);
if (this.InferredType != null) {
output.Write(':');
this.InferredType.WriteTo(output, true, true);
}
return;
}
}
output.Write(OpCode.Name);
if (this.InferredType != null) {
output.Write(':');
this.InferredType.WriteTo(output, true, true);
}
output.Write('(');
bool first = true;
if (Operand != null) {
if (Operand is ILLabel)
output.Write(((ILLabel)Operand).Name);
else
if (Operand is ILLabel) {
output.WriteReference(((ILLabel)Operand).Name, Operand);
} else if (Operand is MethodReference) {
MethodReference method = (MethodReference)Operand;
method.DeclaringType.WriteTo(output, true, true);
output.Write("::");
output.WriteReference(method.Name, method);
} else {
DisassemblerHelpers.WriteOperand(output, Operand);
}
first = false;
}
foreach (ILExpression arg in this.Arguments) {
@ -242,7 +260,7 @@ namespace Decompiler @@ -242,7 +260,7 @@ namespace Decompiler
}
}
public class ILLoop: ILNode
public class ILLoop : ILNode
{
public ILBlock ContentBlock;
@ -261,7 +279,7 @@ namespace Decompiler @@ -261,7 +279,7 @@ namespace Decompiler
}
}
public class ILCondition: ILNode
public class ILCondition : ILNode
{
public ILExpression Condition;
public ILBlock TrueBlock; // Branch was taken
@ -271,7 +289,8 @@ namespace Decompiler @@ -271,7 +289,8 @@ namespace Decompiler
{
yield return Condition;
yield return TrueBlock;
yield return FalseBlock;
if (FalseBlock != null)
yield return FalseBlock;
}
public override void WriteTo(ITextOutput output)

221
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -0,0 +1,221 @@ @@ -0,0 +1,221 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Decompiler;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
/// <summary>
/// Assigns C# types to IL expressions.
/// </summary>
/// <remarks>
/// Types are inferred in a bidirectional manner:
/// The expected type flows from the outside to the inside, the actual inferred type flows from the inside to the outside.
/// </remarks>
public class TypeAnalysis
{
public static void Run(TypeSystem typeSystem, ILNode node)
{
TypeAnalysis ta = new TypeAnalysis();
ta.typeSystem = typeSystem;
ta.InferTypes(node);
}
TypeSystem typeSystem;
List<ILExpression> storedToGeneratedVariables = new List<ILExpression>();
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.OpCode == OpCodes.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);
}
InferTypes(child);
}
}
/// <summary>
/// Infers the C# type of <paramref name="expr"/>.
/// </summary>
/// <param name="expr">The expression</param>
/// <param name="expectedType">The expected type of the expression</param>
/// <param name="forceInferChildren">Whether direct children should be inferred even if its not necessary. (does not apply to nested children!)</param>
/// <returns>The inferred type</returns>
TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
{
if (forceInferChildren || expr.InferredType == null)
expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren);
return expr.InferredType;
}
TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
{
switch (expr.OpCode.Code) {
case Code.Stloc:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), ((ILVariable)expr.Operand).Type);
return null;
case Code.Ldloc:
return ((ILVariable)expr.Operand).Type;
case Code.Ldarg:
return ((ParameterDefinition)expr.Operand).ParameterType;
case Code.Call:
case Code.Callvirt:
{
MethodReference method = (MethodReference)expr.Operand;
if (forceInferChildren) {
for (int i = 0; i < expr.Arguments.Count; i++) {
if (i == 0 && method.HasThis)
InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
else
InferTypeForExpression(expr.Arguments[i], method.Parameters[method.HasThis ? i - 1: i].ParameterType);
}
}
return method.ReturnType;
}
case Code.Newobj:
{
MethodReference ctor = (MethodReference)expr.Operand;
if (forceInferChildren) {
for (int i = 0; i < ctor.Parameters.Count; i++) {
InferTypeForExpression(expr.Arguments[i], ctor.Parameters[i].ParameterType);
}
}
return ctor.DeclaringType;
}
case Code.Or:
return InferArgumentsInBinaryOperator(expr);
case Code.Shl:
case Code.Shr:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
return InferTypeForExpression(expr.Arguments[0], expectedType);
case Code.Ldc_I4:
return (IsSigned(expectedType) != null || expectedType == typeSystem.Boolean) ? expectedType : typeSystem.Int32;
case Code.Ldc_I8:
return (IsSigned(expectedType) != null) ? expectedType : typeSystem.Int64;
case Code.Conv_I8:
return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int64;
case Code.Dup:
return InferTypeForExpression(expr.Arguments.Single(), expectedType);
case Code.Ceq:
case Code.Clt:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr);
return typeSystem.Boolean;
case Code.Beq:
case Code.Blt:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr);
return null;
case Code.Brtrue:
case Code.Brfalse:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
return null;
default:
//throw new NotImplementedException("Can't handle " + expr.OpCode.Name);
return null;
}
}
TypeReference InferArgumentsInBinaryOperator(ILExpression expr)
{
ILExpression left = expr.Arguments[0];
ILExpression right = expr.Arguments[1];
TypeReference leftPreferred = DoInferTypeForExpression(left, null);
TypeReference rightPreferred = DoInferTypeForExpression(right, null);
if (leftPreferred == rightPreferred) {
return left.InferredType = right.InferredType = leftPreferred;
} else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
return left.InferredType = right.InferredType = rightPreferred;
} else if (leftPreferred == DoInferTypeForExpression(right, leftPreferred)) {
return left.InferredType = right.InferredType = leftPreferred;
} else {
return left.InferredType = right.InferredType = TypeWithMoreInformation(leftPreferred, rightPreferred);
}
}
TypeReference TypeWithMoreInformation(TypeReference leftPreferred, TypeReference rightPreferred)
{
int left = GetInformationAmount(typeSystem, leftPreferred);
int right = GetInformationAmount(typeSystem, rightPreferred);
if (left < right)
return rightPreferred;
else
return leftPreferred;
}
int GetInformationAmount(TypeReference type)
{
return GetInformationAmount(typeSystem, type);
}
static int GetInformationAmount(TypeSystem typeSystem, TypeReference type)
{
if (type == null)
return 0;
if (type.IsValueType) {
// value type might be an enum
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
return GetInformationAmount(typeDef.Module.TypeSystem, underlyingType);
}
}
if (type == typeSystem.Boolean)
return 1;
else if (type == typeSystem.Byte || type == typeSystem.SByte)
return 8;
else if (type == typeSystem.Int16 || type == typeSystem.UInt16)
return 16;
else if (type == typeSystem.Int32 || type == typeSystem.UInt32)
return 32;
else if (type == typeSystem.IntPtr || type == typeSystem.UIntPtr)
return 33; // treat native int as between int32 and int64
else if (type == typeSystem.Int64 || type == typeSystem.UInt64)
return 64;
return 100; // we consider structs/objects to have more information than any primitives
}
bool? IsSigned(TypeReference type)
{
return IsSigned(typeSystem, type);
}
static bool? IsSigned(TypeSystem typeSystem, TypeReference type)
{
if (type == null)
return null;
if (type.IsValueType) {
// value type might be an enum
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
return IsSigned(typeDef.Module.TypeSystem, underlyingType);
}
}
if (type == typeSystem.Byte || type == typeSystem.UInt16 || type == typeSystem.UInt32 || type == typeSystem.UInt64 || type == typeSystem.UIntPtr)
return false;
if (type == typeSystem.SByte || type == typeSystem.Int16 || type == typeSystem.Int32 || type == typeSystem.Int64 || type == typeSystem.IntPtr)
return true;
return null;
}
}
}

18
ILSpy/ILAstLanguage.cs

@ -24,6 +24,7 @@ using Decompiler; @@ -24,6 +24,7 @@ using Decompiler;
using Decompiler.ControlFlow;
using Decompiler.Transforms;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
@ -46,13 +47,26 @@ namespace ICSharpCode.ILSpy @@ -46,13 +47,26 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
ILAstBuilder astBuilder = new ILAstBuilder();
ILBlock ilMethod = new ILBlock();
ilMethod.Body = new ILAstBuilder().Build(method, inlineVariables);
ilMethod.Body = astBuilder.Build(method, inlineVariables);
if (abortBeforeStep != null) {
new ILAstOptimizer().Optimize(ilMethod, abortBeforeStep.Value);
new ILAstOptimizer().Optimize(method, ilMethod, abortBeforeStep.Value);
}
var allVariables = astBuilder.Variables
.Concat(ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable).Where(v => v != null)).Distinct();
foreach (ILVariable v in allVariables) {
output.Write(v.Name);
if (v.Type != null) {
output.Write(" : ");
v.Type.WriteTo(output, true, true);
}
output.WriteLine();
}
output.WriteLine();
foreach (ILNode node in ilMethod.Body) {
node.WriteTo(output);
output.WriteLine();

Loading…
Cancel
Save