Browse Source

Use ResolveResults as annotations.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
fffa297b8f
  1. 62
      ICSharpCode.Decompiler/CSharp/Annotations.cs
  2. 193
      ICSharpCode.Decompiler/CSharp/ConvertedExpression.cs
  3. 286
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  4. 6
      ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs
  5. 2
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  6. 2
      ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs
  7. 2
      ICSharpCode.Decompiler/CSharp/Transforms/ContextTrackingVisitor.cs
  8. 4
      ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs
  9. 2
      ICSharpCode.Decompiler/CSharp/Transforms/DecimalConstantTransform.cs
  10. 2
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  11. 2
      ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs
  12. 2
      ICSharpCode.Decompiler/CSharp/Transforms/ExpressionTreeConverter.cs
  13. 2
      ICSharpCode.Decompiler/CSharp/Transforms/FlattenSwitchBlocks.cs
  14. 10
      ICSharpCode.Decompiler/CSharp/Transforms/IAstTransform.cs
  15. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  16. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs
  17. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
  18. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs
  19. 2
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  20. 2
      ICSharpCode.Decompiler/CSharp/Transforms/PushNegation.cs
  21. 7
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  22. 44
      ICSharpCode.Decompiler/CSharp/Transforms/TransformationPipeline.cs
  23. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  24. 14
      ICSharpCode.Decompiler/Util/CollectionExtensions.cs
  25. 2
      ILSpy.sln

62
ICSharpCode.Decompiler/CSharp/Annotations.cs

@ -7,8 +7,70 @@
* To change this template use Tools | Options | Coding | Edit Standard Headers. * To change this template use Tools | Options | Coding | Edit Standard Headers.
*/ */
using System; using System;
using System.Collections;
using System.Collections.Generic;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.Decompiler.IL;
namespace ICSharpCode.Decompiler.CSharp namespace ICSharpCode.Decompiler.CSharp
{ {
// Annotations:
// * AstNodes should be annotated with the corresponding ILInstruction
// * AstNodes referring to other entities should be annotated with the IEntity
// * Expression type information is currently only available in the ExpressionBuilder, but we might change 'WithTypeInfo()'
// to use an annotation in the future
// * IntroduceUnsafeModifier.PointerArithmeticAnnotation is placed on arithmetic operators that operate on pointers.
// TODO: actually, we could use the type info instead?
// * AddCheckedBlocks.CheckedAnnotation / AddCheckedBlocks.UnCheckedAnnotation is used on checked/unchecked integer arithmetic
// TODO: here the info is also redundant, we could peek at the BinaryNumericInstruction instead
/// <summary>
/// Currently unused; we'll probably use the LdToken ILInstruction as annotation instead when LdToken support gets reimplemented.
/// </summary>
public class LdTokenAnnotation {} public class LdTokenAnnotation {}
static class AnnotationExtensions
{
public static ExpressionWithILInstruction WithILInstruction(this Expression expression, ILInstruction instruction)
{
expression.AddAnnotation(instruction);
return new ExpressionWithILInstruction(expression);
}
public static ExpressionWithILInstruction WithILInstruction(this Expression expression, IEnumerable<ILInstruction> instructions)
{
foreach (var inst in instructions)
expression.AddAnnotation(inst);
return new ExpressionWithILInstruction(expression);
}
public static ExpressionWithILInstruction WithoutILInstruction(this Expression expression)
{
return new ExpressionWithILInstruction(expression);
}
public static ConvertedExpression WithILInstruction(this ExpressionWithResolveResult expression, ILInstruction instruction)
{
expression.Expression.AddAnnotation(instruction);
return new ConvertedExpression(expression.Expression, expression.ResolveResult);
}
public static ConvertedExpression WithoutILInstruction(this ExpressionWithResolveResult expression)
{
return new ConvertedExpression(expression.Expression, expression.ResolveResult);
}
public static ExpressionWithResolveResult WithRR(this Expression expression, ResolveResult resolveResult)
{
expression.AddAnnotation(resolveResult);
return new ExpressionWithResolveResult(expression, resolveResult);
}
public static ConvertedExpression WithRR(this ExpressionWithILInstruction expression, ResolveResult resolveResult)
{
expression.Expression.AddAnnotation(resolveResult);
return new ConvertedExpression(expression, resolveResult);
}
}
} }

193
ICSharpCode.Decompiler/CSharp/ConvertedExpression.cs

@ -17,62 +17,197 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.Decompiler.IL;
namespace ICSharpCode.Decompiler.CSharp namespace ICSharpCode.Decompiler.CSharp
{ {
/// <summary> /// <summary>
/// Output of C# ExpressionBuilder -- a pair of decompiled C# expression and its type /// Helper struct so that the compiler can ensure we don't forget both the ILInstruction annotation and the ResolveResult annotation.
/// Use '.WithILInstruction(...)' or '.WithoutILInstruction()' to create an instance of this struct.
/// </summary> /// </summary>
struct ExpressionWithILInstruction
{
public readonly Expression Expression;
public IEnumerable<ILInstruction> ILInstructions {
get { return Expression.Annotations.OfType<ILInstruction>(); }
}
internal ExpressionWithILInstruction(Expression expression)
{
Debug.Assert(expression != null);
this.Expression = expression;
}
public static implicit operator Expression(ExpressionWithILInstruction expression)
{
return expression.Expression;
}
}
/// <summary>
/// Helper struct so that the compiler can ensure we don't forget both the ILInstruction annotation and the ResolveResult annotation.
/// Use '.WithRR(...)'.
/// </summary>
struct ExpressionWithResolveResult
{
public readonly Expression Expression;
// Because ResolveResult is frequently accessed within the ExpressionBuilder, we put it directly
// in this struct instead of accessing it through the list of annotations.
public readonly ResolveResult ResolveResult;
public IType Type {
get { return ResolveResult.Type; }
}
internal ExpressionWithResolveResult(Expression expression, ResolveResult resolveResult)
{
Debug.Assert(expression != null && resolveResult != null);
Debug.Assert(expression.Annotation<ResolveResult>() == resolveResult);
this.Expression = expression;
this.ResolveResult = resolveResult;
}
public static implicit operator Expression(ExpressionWithResolveResult expression)
{
return expression.Expression;
}
}
/// <summary>
/// Output of C# ExpressionBuilder -- a decompiled C# expression that has both a resolve result and ILInstruction annotation.
/// </summary>
/// <remarks>
/// The resolve result is also always available as annotation on the expression, but having
/// ConvertedExpression as a separate type is still useful to ensure that no case in the expression builder
/// forgets to add the annotation.
/// </remarks>
struct ConvertedExpression struct ConvertedExpression
{ {
public readonly Expression Expression; public readonly Expression Expression;
public readonly IType Type;
public ConvertedExpression(Expression expression, IType type) // Because ResolveResult is frequently accessed within the ExpressionBuilder, we put it directly
// in this struct instead of accessing it through the list of annotations.
public readonly ResolveResult ResolveResult;
public IEnumerable<ILInstruction> ILInstructions {
get { return Expression.Annotations.OfType<ILInstruction>(); }
}
public IType Type {
get { return ResolveResult.Type; }
}
internal ConvertedExpression(Expression expression)
{ {
Debug.Assert(expression != null);
this.Expression = expression; this.Expression = expression;
this.Type = type; this.ResolveResult = expression.Annotation<ResolveResult>() ?? ErrorResolveResult.UnknownError;
} }
public Expression ConvertTo(IType targetType, ExpressionBuilder expressionBuilder) internal ConvertedExpression(Expression expression, ResolveResult resolveResult)
{ {
Debug.Assert(expression != null && resolveResult != null);
Debug.Assert(expression.Annotation<ResolveResult>() == resolveResult);
this.ResolveResult = resolveResult;
this.Expression = expression;
}
public static implicit operator Expression(ConvertedExpression expression)
{
return expression.Expression;
}
public static implicit operator ExpressionWithResolveResult(ConvertedExpression expression)
{
return new ExpressionWithResolveResult(expression.Expression, expression.ResolveResult);
}
public static implicit operator ExpressionWithILInstruction(ConvertedExpression expression)
{
return new ExpressionWithILInstruction(expression.Expression);
}
/// <summary>
/// Returns a new ConvertedExpression that represents the specified descendant expression.
/// All ILInstruction annotations from the current expression are copied to the descendant expression.
/// The descendant expression is detached from the AST.
/// </summary>
public ConvertedExpression UnwrapChild(Expression descendant)
{
if (descendant == Expression)
return this;
for (AstNode parent = descendant.Parent; parent != null; parent = parent.Parent) {
foreach (var inst in parent.Annotations.OfType<ILInstruction>())
descendant.AddAnnotation(inst);
if (parent == Expression)
return new ConvertedExpression(descendant);
}
throw new ArgumentException("descendant must be a descendant of the current node");
}
public ConvertedExpression ConvertTo(IType targetType, ExpressionBuilder expressionBuilder)
{
var type = this.Type;
if (targetType.IsKnownType(KnownTypeCode.Boolean)) if (targetType.IsKnownType(KnownTypeCode.Boolean))
return ConvertToBoolean(); return ConvertToBoolean(expressionBuilder);
if (Type.Equals(targetType)) if (type.Equals(targetType))
return Expression; return this;
if (Type.Kind == TypeKind.ByReference && targetType.Kind == TypeKind.Pointer && Expression is DirectionExpression) { if (type.Kind == TypeKind.ByReference && targetType.Kind == TypeKind.Pointer && Expression is DirectionExpression) {
// convert from reference to pointer // convert from reference to pointer
Expression arg = ((DirectionExpression)Expression).Expression.Detach(); Expression arg = ((DirectionExpression)Expression).Expression.Detach();
var pointerExpr = new ConvertedExpression( var pointerType = new PointerType(((ByReferenceType)type).ElementType);
new UnaryOperatorExpression(UnaryOperatorType.AddressOf, arg), var pointerExpr = new UnaryOperatorExpression(UnaryOperatorType.AddressOf, arg)
new PointerType(((ByReferenceType)Type).ElementType)); .WithILInstruction(this.ILInstructions)
.WithRR(new ResolveResult(pointerType));
// perform remaining pointer cast, if necessary // perform remaining pointer cast, if necessary
return pointerExpr.ConvertTo(targetType, expressionBuilder); return pointerExpr.ConvertTo(targetType, expressionBuilder);
} }
if (Expression is PrimitiveExpression) { var rr = expressionBuilder.resolver.ResolveCast(targetType, ResolveResult);
object value = ((PrimitiveExpression)Expression).Value; if (rr.IsCompileTimeConstant && !rr.IsError) {
var rr = expressionBuilder.resolver.ResolveCast(targetType, new ConstantResolveResult(Type, value)); return expressionBuilder.astBuilder.ConvertConstantValue(rr)
if (rr.IsCompileTimeConstant && !rr.IsError) .WithILInstruction(this.ILInstructions)
return expressionBuilder.astBuilder.ConvertConstantValue(rr); .WithRR(rr);
} }
return new CastExpression( return Expression.CastTo(expressionBuilder.ConvertType(targetType))
expressionBuilder.astBuilder.ConvertType(targetType), .WithoutILInstruction().WithRR(rr);
Expression);
} }
public Expression ConvertToBoolean() public ConvertedExpression ConvertToBoolean(ExpressionBuilder expressionBuilder)
{ {
if (Type.IsKnownType(KnownTypeCode.Boolean) || Type.Kind == TypeKind.Unknown) if (Type.IsKnownType(KnownTypeCode.Boolean) || Type.Kind == TypeKind.Unknown) {
return Expression; return this;
else if (Expression is PrimitiveExpression && Type.IsKnownType(KnownTypeCode.Int32)) }
return new PrimitiveExpression((int)((PrimitiveExpression)Expression).Value != 0); IType boolType = expressionBuilder.compilation.FindType(KnownTypeCode.Boolean);
else if (Type.Kind == TypeKind.Pointer) if (Expression is PrimitiveExpression && Type.IsKnownType(KnownTypeCode.Int32)) {
return new BinaryOperatorExpression(Expression, BinaryOperatorType.InEquality, new NullReferenceExpression()); bool val = (int)((PrimitiveExpression)Expression).Value != 0;
else return new PrimitiveExpression(val)
return new BinaryOperatorExpression(Expression, BinaryOperatorType.InEquality, new PrimitiveExpression(0)); .WithILInstruction(this.ILInstructions)
.WithRR(new ConstantResolveResult(boolType, val));
} else if (Type.Kind == TypeKind.Pointer) {
var nullRef = new NullReferenceExpression()
.WithoutILInstruction()
.WithRR(new ConstantResolveResult(this.Type, null));
return new BinaryOperatorExpression(Expression, BinaryOperatorType.InEquality, nullRef.Expression)
.WithoutILInstruction()
.WithRR(new OperatorResolveResult(boolType, System.Linq.Expressions.ExpressionType.NotEqual,
this.ResolveResult, nullRef.ResolveResult));
} else {
var zero = new PrimitiveExpression(0)
.WithoutILInstruction()
.WithRR(new ConstantResolveResult(expressionBuilder.compilation.FindType(KnownTypeCode.Int32), 0));
return new BinaryOperatorExpression(Expression, BinaryOperatorType.InEquality, zero.Expression)
.WithoutILInstruction()
.WithRR(new OperatorResolveResult(boolType, System.Linq.Expressions.ExpressionType.NotEqual,
this.ResolveResult, zero.ResolveResult));
}
} }
} }
} }

286
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Diagnostics; using System.Diagnostics;
using ExpressionType = System.Linq.Expressions.ExpressionType;
using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
@ -36,153 +37,154 @@ namespace ICSharpCode.Decompiler.CSharp
/// </summary> /// </summary>
class ExpressionBuilder : ILVisitor<ConvertedExpression> class ExpressionBuilder : ILVisitor<ConvertedExpression>
{ {
private readonly ICompilation compilation; internal readonly ICompilation compilation;
readonly NRefactoryCecilMapper cecilMapper; internal readonly NRefactoryCecilMapper cecilMapper;
internal readonly CSharpResolver resolver; internal readonly CSharpResolver resolver;
internal readonly TypeSystemAstBuilder astBuilder; internal readonly TypeSystemAstBuilder astBuilder;
public ExpressionBuilder(ICompilation compilation, NRefactoryCecilMapper cecilMapper) public ExpressionBuilder(ICompilation compilation, NRefactoryCecilMapper cecilMapper)
{ {
Debug.Assert(compilation != null);
Debug.Assert(cecilMapper != null);
this.compilation = compilation; this.compilation = compilation;
this.cecilMapper = cecilMapper; this.cecilMapper = cecilMapper;
this.resolver = new CSharpResolver(compilation); this.resolver = new CSharpResolver(compilation);
this.astBuilder = new TypeSystemAstBuilder(resolver); this.astBuilder = new TypeSystemAstBuilder(resolver);
} }
public AstType ConvertType(Mono.Cecil.TypeReference type) public AstType ConvertType(Mono.Cecil.TypeReference typeReference)
{ {
if (type == null) if (typeReference == null)
return null; return AstType.Null;
return astBuilder.ConvertType(cecilMapper.GetType(type)); var type = cecilMapper.GetType(typeReference);
return ConvertType(type);
} }
public Expression Convert(ILInstruction inst) public AstType ConvertType(IType type)
{ {
return ConvertArgument(inst).Expression; var astType = astBuilder.ConvertType(type);
astType.AddAnnotation(new TypeResolveResult(type));
return astType;
} }
public Expression Convert(ILInstruction inst, IType expectedType) public ConvertedExpression Convert(ILInstruction inst)
{ {
return ConvertArgument(inst).ConvertTo(expectedType, this); Debug.Assert(inst != null);
var cexpr = inst.AcceptVisitor(this);
Debug.Assert(cexpr.Type.GetStackType() == inst.ResultType || cexpr.Type.Kind == TypeKind.Unknown || inst.ResultType == StackType.Void);
return cexpr;
} }
public Expression ConvertCondition(ILInstruction condition) public ConvertedExpression ConvertCondition(ILInstruction condition)
{ {
var expr = ConvertArgument(condition); var expr = Convert(condition);
return expr.ConvertToBoolean(); return expr.ConvertToBoolean(this);
} }
ConvertedExpression ConvertVariable(ILVariable variable) ExpressionWithResolveResult ConvertVariable(ILVariable variable)
{ {
Expression expr; Expression expr;
if (variable.Kind == VariableKind.This) if (variable.Kind == VariableKind.This)
expr = new ThisReferenceExpression(); expr = new ThisReferenceExpression();
else else
expr = new IdentifierExpression(variable.Name); expr = new IdentifierExpression(variable.Name);
expr.AddAnnotation(variable);
if (variable.Type.SkipModifiers().MetadataType == Mono.Cecil.MetadataType.ByReference) if (variable.Type.SkipModifiers().MetadataType == Mono.Cecil.MetadataType.ByReference)
{ {
// When loading a by-ref parameter, use 'ref paramName'. // When loading a by-ref parameter, use 'ref paramName'.
// We'll strip away the 'ref' when dereferencing. // We'll strip away the 'ref' when dereferencing.
expr = new DirectionExpression(FieldDirection.Ref, expr); expr = new DirectionExpression(FieldDirection.Ref, expr);
} }
return new ConvertedExpression(expr, cecilMapper.GetType(variable.Type)); return expr
} .WithRR(new ResolveResult(cecilMapper.GetType(variable.Type))); // TODO: use LocalResolveResult instead
ConvertedExpression ConvertArgument(ILInstruction inst)
{
var cexpr = inst.AcceptVisitor(this);
Debug.Assert(cexpr.Type.GetStackType() == inst.ResultType || cexpr.Type.Kind == TypeKind.Unknown || inst.ResultType == StackType.Void);
cexpr.Expression.AddAnnotation(inst);
return cexpr;
} }
ConvertedExpression IsType(IsInst inst) ConvertedExpression IsType(IsInst inst)
{ {
var arg = ConvertArgument(inst.Argument); var arg = Convert(inst.Argument);
return new ConvertedExpression( var type = cecilMapper.GetType(inst.Type);
new IsExpression(arg.Expression, ConvertType(inst.Type)), return new IsExpression(arg.Expression, ConvertType(type))
compilation.FindType(TypeCode.Boolean)); .WithILInstruction(inst)
.WithRR(new TypeIsResolveResult(arg.ResolveResult, type, compilation.FindType(TypeCode.Boolean)));
} }
protected internal override ConvertedExpression VisitIsInst(IsInst inst) protected internal override ConvertedExpression VisitIsInst(IsInst inst)
{ {
var arg = ConvertArgument(inst.Argument); var arg = Convert(inst.Argument);
return new ConvertedExpression( var type = cecilMapper.GetType(inst.Type);
new AsExpression(arg.Expression, ConvertType(inst.Type)), return new AsExpression(arg.Expression, ConvertType(type))
cecilMapper.GetType(inst.Type)); .WithILInstruction(inst)
.WithRR(new ConversionResolveResult(type, arg.ResolveResult, Conversion.TryCast));
} }
protected internal override ConvertedExpression VisitNewObj(NewObj inst) protected internal override ConvertedExpression VisitNewObj(NewObj inst)
{ {
var oce = new ObjectCreateExpression(ConvertType(inst.Method.DeclaringType)); return HandleCallInstruction(inst);
oce.Arguments.AddRange(inst.Arguments.Select(i => ConvertArgument(i).Expression));
return new ConvertedExpression(oce, cecilMapper.GetType(inst.Method.DeclaringType));
} }
protected internal override ConvertedExpression VisitLdcI4(LdcI4 inst) protected internal override ConvertedExpression VisitLdcI4(LdcI4 inst)
{ {
return new ConvertedExpression( return new PrimitiveExpression(inst.Value)
new PrimitiveExpression(inst.Value), .WithILInstruction(inst)
compilation.FindType(KnownTypeCode.Int32)); .WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), inst.Value));
} }
protected internal override ConvertedExpression VisitLdcI8(LdcI8 inst) protected internal override ConvertedExpression VisitLdcI8(LdcI8 inst)
{ {
return new ConvertedExpression( return new PrimitiveExpression(inst.Value)
new PrimitiveExpression(inst.Value), .WithILInstruction(inst)
compilation.FindType(KnownTypeCode.Int64)); .WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int64), inst.Value));
} }
protected internal override ConvertedExpression VisitLdcF(LdcF inst) protected internal override ConvertedExpression VisitLdcF(LdcF inst)
{ {
return new ConvertedExpression( return new PrimitiveExpression(inst.Value)
new PrimitiveExpression(inst.Value), .WithILInstruction(inst)
compilation.FindType(KnownTypeCode.Double)); .WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Double), inst.Value));
} }
protected internal override ConvertedExpression VisitLdStr(LdStr inst) protected internal override ConvertedExpression VisitLdStr(LdStr inst)
{ {
return new ConvertedExpression( return new PrimitiveExpression(inst.Value)
new PrimitiveExpression(inst.Value), .WithILInstruction(inst)
compilation.FindType(KnownTypeCode.String)); .WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.String), inst.Value));
} }
protected internal override ConvertedExpression VisitLdNull(LdNull inst) protected internal override ConvertedExpression VisitLdNull(LdNull inst)
{ {
return new ConvertedExpression( return new NullReferenceExpression()
new NullReferenceExpression(), .WithILInstruction(inst)
SpecialType.UnknownType); .WithRR(new ConstantResolveResult(SpecialType.UnknownType, null));
} }
protected internal override ConvertedExpression VisitLogicNot(LogicNot inst) protected internal override ConvertedExpression VisitLogicNot(LogicNot inst)
{ {
return LogicNot(new ConvertedExpression(ConvertCondition(inst.Argument), compilation.FindType(KnownTypeCode.Boolean))); return LogicNot(ConvertCondition(inst.Argument)).WithILInstruction(inst);
} }
ConvertedExpression LogicNot(ConvertedExpression expr) ExpressionWithResolveResult LogicNot(ConvertedExpression expr)
{ {
return new ConvertedExpression( return new UnaryOperatorExpression(UnaryOperatorType.Not, expr.Expression)
new UnaryOperatorExpression(UnaryOperatorType.Not, expr.Expression), .WithRR(new OperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), ExpressionType.Not));
compilation.FindType(KnownTypeCode.Boolean));
} }
protected internal override ConvertedExpression VisitLdLoc(LdLoc inst) protected internal override ConvertedExpression VisitLdLoc(LdLoc inst)
{ {
return ConvertVariable(inst.Variable); return ConvertVariable(inst.Variable).WithILInstruction(inst);
} }
protected internal override ConvertedExpression VisitLdLoca(LdLoca inst) protected internal override ConvertedExpression VisitLdLoca(LdLoca inst)
{ {
var expr = ConvertVariable(inst.Variable); var expr = ConvertVariable(inst.Variable).WithILInstruction(inst);
return new ConvertedExpression( // Note that we put the instruction on the IdentifierExpression instead of the DirectionExpression,
new DirectionExpression(FieldDirection.Ref, expr.Expression), // because the DirectionExpression might get removed by dereferencing instructions such as LdObj
new ByReferenceType(expr.Type)); return new DirectionExpression(FieldDirection.Ref, expr.Expression)
.WithoutILInstruction()
.WithRR(new ByReferenceResolveResult(expr.ResolveResult, isOut: false));
} }
protected internal override ConvertedExpression VisitStLoc(StLoc inst) protected internal override ConvertedExpression VisitStLoc(StLoc inst)
{ {
return Assignment(ConvertVariable(inst.Variable), ConvertArgument(inst.Value)); return Assignment(ConvertVariable(inst.Variable).WithoutILInstruction(), Convert(inst.Value)).WithILInstruction(inst);
} }
protected internal override ConvertedExpression VisitCeq(Ceq inst) protected internal override ConvertedExpression VisitCeq(Ceq inst)
@ -190,15 +192,15 @@ namespace ICSharpCode.Decompiler.CSharp
// Translate 'e as T == null' to 'e is T'. // Translate 'e as T == null' to 'e is T'.
// This is necessary for correctness when T is a value type. // This is necessary for correctness when T is a value type.
if (inst.Left.OpCode == OpCode.IsInst && inst.Right.OpCode == OpCode.LdNull) { if (inst.Left.OpCode == OpCode.IsInst && inst.Right.OpCode == OpCode.LdNull) {
return LogicNot(IsType((IsInst)inst.Left)); return LogicNot(IsType((IsInst)inst.Left)).WithILInstruction(inst);
} else if (inst.Right.OpCode == OpCode.IsInst && inst.Left.OpCode == OpCode.LdNull) { } else if (inst.Right.OpCode == OpCode.IsInst && inst.Left.OpCode == OpCode.LdNull) {
return LogicNot(IsType((IsInst)inst.Right)); return LogicNot(IsType((IsInst)inst.Right)).WithILInstruction(inst);
} }
var left = ConvertArgument(inst.Left); var left = Convert(inst.Left);
var right = ConvertArgument(inst.Right); var right = Convert(inst.Right);
return new ConvertedExpression( return new BinaryOperatorExpression(left.Expression, BinaryOperatorType.Equality, right.Expression)
new BinaryOperatorExpression(left.Expression, BinaryOperatorType.Equality, right.Expression), .WithILInstruction(inst)
compilation.FindType(TypeCode.Boolean)); .WithRR(new OperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), ExpressionType.Equal, left.ResolveResult, right.ResolveResult));
} }
protected internal override ConvertedExpression VisitClt(Clt inst) protected internal override ConvertedExpression VisitClt(Clt inst)
@ -223,19 +225,22 @@ namespace ICSharpCode.Decompiler.CSharp
ConvertedExpression Comparison(BinaryComparisonInstruction inst, BinaryOperatorType op, bool un = false) ConvertedExpression Comparison(BinaryComparisonInstruction inst, BinaryOperatorType op, bool un = false)
{ {
var left = ConvertArgument(inst.Left); var left = Convert(inst.Left);
var right = ConvertArgument(inst.Right); var right = Convert(inst.Right);
// TODO: ensure the arguments are signed // TODO: ensure the arguments are signed
// or with _Un: ensure the arguments are unsigned; and that float comparisons are performed unordered // or with _Un: ensure the arguments are unsigned; and that float comparisons are performed unordered
return new ConvertedExpression( return new BinaryOperatorExpression(left.Expression, op, right.Expression)
new BinaryOperatorExpression(left.Expression, op, right.Expression), .WithILInstruction(inst)
compilation.FindType(TypeCode.Boolean)); .WithRR(new OperatorResolveResult(compilation.FindType(TypeCode.Boolean),
BinaryOperatorExpression.GetLinqNodeType(op, false),
left.ResolveResult, right.ResolveResult));
} }
ConvertedExpression Assignment(ConvertedExpression left, ConvertedExpression right) ExpressionWithResolveResult Assignment(ConvertedExpression left, ConvertedExpression right)
{ {
return new AssignmentExpression(left.Expression, right.ConvertTo(left.Type, this)) right = right.ConvertTo(left.Type, this);
.WithTypeInfo(left.Type); return new AssignmentExpression(left.Expression, right.Expression)
.WithRR(new OperatorResolveResult(left.Type, ExpressionType.Assign, left.ResolveResult, right.ResolveResult));
} }
protected internal override ConvertedExpression VisitAdd(Add inst) protected internal override ConvertedExpression VisitAdd(Add inst)
@ -290,20 +295,22 @@ namespace ICSharpCode.Decompiler.CSharp
ConvertedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op) ConvertedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op)
{ {
var left = ConvertArgument(inst.Left); var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow);
var right = ConvertArgument(inst.Right); var left = Convert(inst.Left);
var rr = resolver.ResolveBinaryOperator(op, new ResolveResult(left.Type), new ResolveResult(right.Type)); var right = Convert(inst.Right);
if (!rr.IsError && rr.Type.GetStackType() == inst.ResultType var rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
&& IsCompatibleWithSign(left.Type, inst.Sign) && IsCompatibleWithSign(right.Type, inst.Sign)) if (rr.IsError || rr.Type.GetStackType() != inst.ResultType
|| !IsCompatibleWithSign(left.Type, inst.Sign) || !IsCompatibleWithSign(right.Type, inst.Sign))
{ {
return new ConvertedExpression( // Left and right operands are incompatible, so convert them to a common type
new BinaryOperatorExpression(left.Expression, op, right.Expression), IType targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode(inst.Sign));
rr.Type); left = left.ConvertTo(targetType, this);
right = right.ConvertTo(targetType, this);
rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
} }
IType targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode(inst.Sign)); return new BinaryOperatorExpression(left.Expression, op, right.Expression)
return new ConvertedExpression( .WithILInstruction(inst)
new BinaryOperatorExpression(left.ConvertTo(targetType, this), op, right.ConvertTo(targetType, this)), .WithRR(rr);
targetType);
} }
/// <summary> /// <summary>
@ -317,17 +324,17 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override ConvertedExpression VisitConv(Conv inst) protected internal override ConvertedExpression VisitConv(Conv inst)
{ {
var arg = ConvertArgument(inst.Argument); var arg = Convert(inst.Argument);
Expression input = arg.Expression;
if (arg.Type.GetSign() != inst.Sign) { if (arg.Type.GetSign() != inst.Sign) {
// we need to cast the input to a type of appropriate sign // we need to cast the input to a type of appropriate sign
var inputType = inst.Argument.ResultType.ToKnownTypeCode(inst.Sign); var inputType = inst.Argument.ResultType.ToKnownTypeCode(inst.Sign);
input = arg.ConvertTo(compilation.FindType(inputType), this); arg = arg.ConvertTo(compilation.FindType(inputType), this);
} }
var targetType = compilation.FindType(inst.TargetType.ToKnownTypeCode()); var targetType = compilation.FindType(inst.TargetType.ToKnownTypeCode());
return new ConvertedExpression( var rr = resolver.WithCheckForOverflow(inst.CheckForOverflow).ResolveCast(targetType, arg.ResolveResult);
new CastExpression(astBuilder.ConvertType(targetType), input), return new CastExpression(ConvertType(targetType), arg.Expression)
targetType); .WithILInstruction(inst)
.WithRR(rr);
} }
protected internal override ConvertedExpression VisitCall(Call inst) protected internal override ConvertedExpression VisitCall(Call inst)
@ -342,54 +349,85 @@ namespace ICSharpCode.Decompiler.CSharp
ConvertedExpression HandleCallInstruction(CallInstruction inst) ConvertedExpression HandleCallInstruction(CallInstruction inst)
{ {
Expression target; // Used for Call, CallVirt and NewObj
if (inst.Method.HasThis) { var method = cecilMapper.GetMethod(inst.Method);
ConvertedExpression target;
if (inst.OpCode == OpCode.NewObj) {
target = default(ConvertedExpression); // no target
} else if (inst.Method.HasThis) {
var argInstruction = inst.Arguments[0]; var argInstruction = inst.Arguments[0];
if (inst.OpCode == OpCode.Call && argInstruction.MatchLdThis()) if (inst.OpCode == OpCode.Call && argInstruction.MatchLdThis()) {
target = new BaseReferenceExpression().WithAnnotation(argInstruction); target = new BaseReferenceExpression()
else .WithILInstruction(argInstruction)
.WithRR(new ThisResolveResult(cecilMapper.GetType(inst.Method.DeclaringType), causesNonVirtualInvocation: true));
} else {
target = Convert(argInstruction); target = Convert(argInstruction);
}
} else { } else {
target = new TypeReferenceExpression(ConvertType(inst.Method.DeclaringType)); var declaringType = cecilMapper.GetType(inst.Method.DeclaringType);
target = new TypeReferenceExpression(ConvertType(declaringType))
.WithoutILInstruction()
.WithRR(new TypeResolveResult(declaringType));
} }
InvocationExpression invocation = target.Invoke(inst.Method.Name);
int firstParamIndex = inst.Method.HasThis ? 1 : 0; var arguments = inst.Arguments.SelectArray(Convert);
for (int i = firstParamIndex; i < inst.Arguments.Count; i++) { int firstParamIndex = inst.Method.HasThis && inst.OpCode != OpCode.NewObj ? 1 : 0;
var p = inst.Method.Parameters[i - firstParamIndex]; Debug.Assert(arguments.Length == firstParamIndex + inst.Method.Parameters.Count);
var arg = ConvertArgument(inst.Arguments[i]); ResolveResult rr;
var type = cecilMapper.GetType(p.ParameterType); if (method != null) {
invocation.Arguments.Add(arg.ConvertTo(type, this)); // Convert arguments to the expected parameter types
Debug.Assert(arguments.Length == method.Parameters.Count);
for (int i = firstParamIndex; i < arguments.Length; i++) {
var parameter = method.Parameters[i - firstParamIndex];
arguments[i] = arguments[i].ConvertTo(parameter.Type, this);
}
rr = new CSharpInvocationResolveResult(target.ResolveResult, method, arguments.SelectArray(arg => arg.ResolveResult));
} else {
// no IMethod found -- determine the target types from the cecil parameter collection instead
for (int i = firstParamIndex; i < arguments.Length; i++) {
var parameterDefinition = inst.Method.Parameters[i - firstParamIndex];
var parameterType = cecilMapper.GetType(parameterDefinition.ParameterType);
arguments[i] = arguments[i].ConvertTo(parameterType, this);
}
rr = new ResolveResult(cecilMapper.GetType(inst.Method.DeclaringType));
}
if (inst.OpCode == OpCode.NewObj) {
return new ObjectCreateExpression(ConvertType(inst.Method.DeclaringType), arguments.Select(arg => arg.Expression))
.WithILInstruction(inst).WithRR(rr);
} else {
var mre = new MemberReferenceExpression(target.Expression, inst.Method.Name);
return new InvocationExpression(mre, arguments.Select(arg => arg.Expression))
.WithILInstruction(inst).WithRR(rr);
} }
return new ConvertedExpression(invocation, cecilMapper.GetType(inst.Method.ReturnType));
} }
protected internal override ConvertedExpression VisitLdObj(LdObj inst) protected internal override ConvertedExpression VisitLdObj(LdObj inst)
{ {
var target = ConvertArgument(inst.Target); var target = Convert(inst.Target);
var type = cecilMapper.GetType(inst.Type); var type = cecilMapper.GetType(inst.Type);
if (target.Type.Equals(new ByReferenceType(type)) && target.Expression is DirectionExpression) if (target.Type.Equals(new ByReferenceType(type)) && target.Expression is DirectionExpression) {
{
// we can deference the managed reference by stripping away the 'ref' // we can deference the managed reference by stripping away the 'ref'
return new ConvertedExpression( var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
((DirectionExpression)target.Expression).Expression.Detach(), result = result.ConvertTo(type, this);
type);
} }
return new ConvertedExpression( // Cast pointer type if necessary:
new UnaryOperatorExpression( target = target.ConvertTo(new PointerType(type), this);
UnaryOperatorType.Dereference, target.ConvertTo(new PointerType(type), this)), return new UnaryOperatorExpression(UnaryOperatorType.Dereference, target.Expression)
type); .WithILInstruction(inst)
.WithRR(new ResolveResult(type));
} }
protected internal override ConvertedExpression VisitUnboxAny(UnboxAny inst) protected internal override ConvertedExpression VisitUnboxAny(UnboxAny inst)
{ {
var arg = ConvertArgument(inst.Argument); var arg = Convert(inst.Argument);
Expression expr = arg.Expression;
if (arg.Type.IsReferenceType != true) { if (arg.Type.IsReferenceType != true) {
// ensure we treat the input as a reference type // ensure we treat the input as a reference type
expr = arg.ConvertTo(compilation.FindType(KnownTypeCode.Object), this); arg = arg.ConvertTo(compilation.FindType(KnownTypeCode.Object), this);
} }
expr = new CastExpression(ConvertType(inst.Type), expr); return new CastExpression(ConvertType(inst.Type), arg.Expression)
return new ConvertedExpression(expr, cecilMapper.GetType(inst.Type)); .WithILInstruction(inst)
.WithRR(new ConversionResolveResult(cecilMapper.GetType(inst.Type), arg.ResolveResult, Conversion.UnboxingConversion));
} }
protected override ConvertedExpression Default(ILInstruction inst) protected override ConvertedExpression Default(ILInstruction inst)
@ -401,7 +439,7 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
var e = new ErrorExpression(); var e = new ErrorExpression();
e.AddChild(new Comment(message, CommentType.MultiLine), Roles.Comment); e.AddChild(new Comment(message, CommentType.MultiLine), Roles.Comment);
return new ConvertedExpression(e, SpecialType.UnknownType); return e.WithoutILInstruction().WithRR(ErrorResolveResult.UnknownError);
} }
} }
} }

6
ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs

@ -25,11 +25,7 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
static class NRefactoryExtensions static class NRefactoryExtensions
{ {
public static ConvertedExpression WithTypeInfo(this Expression expr, IType type) [Obsolete("Use the more concrete With...()-methods in AnnotationExtensions, so that we maintain a centralised list of the possible annotation types")]
{
return new ConvertedExpression(expr, type);
}
public static T WithAnnotation<T>(this T node, object annotation) where T : AstNode public static T WithAnnotation<T>(this T node, object annotation) where T : AstNode
{ {
if (annotation != null) if (annotation != null)

2
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -86,7 +86,7 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
if (inst.ReturnValue == null) if (inst.ReturnValue == null)
return new ReturnStatement(); return new ReturnStatement();
return new ReturnStatement(exprBuilder.Convert(inst.ReturnValue, currentMethod.ReturnType)); return new ReturnStatement(exprBuilder.Convert(inst.ReturnValue).ConvertTo(currentMethod.ReturnType, exprBuilder));
} }
TryCatchStatement MakeTryCatch(ILInstruction tryBlock) TryCatchStatement MakeTryCatch(ILInstruction tryBlock)

2
ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs

@ -21,7 +21,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Combines query expressions and removes transparent identifiers. /// Combines query expressions and removes transparent identifiers.

2
ICSharpCode.Decompiler/CSharp/Transforms/ContextTrackingVisitor.cs

@ -21,7 +21,7 @@ using System.Diagnostics;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Base class for AST visitors that need the current type/method context info. /// Base class for AST visitors that need the current type/method context info.

4
ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -23,7 +23,7 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// If the first element of a constructor is a chained constructor call, convert it into a constructor initializer. /// If the first element of a constructor is a chained constructor call, convert it into a constructor initializer.
@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
invocation.Arguments.MoveTo(ci.Arguments); invocation.Arguments.MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()') // Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0)) if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>()); constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(invocation);
// Remove the statement: // Remove the statement:
stmt.Remove(); stmt.Remove();
} }

2
ICSharpCode.Decompiler/CSharp/Transforms/DecimalConstantTransform.cs

@ -21,7 +21,7 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Transforms decimal constant fields. /// Transforms decimal constant fields.

2
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -25,7 +25,7 @@ using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Analysis; using ICSharpCode.NRefactory.CSharp.Analysis;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Moves variable declarations to improved positions. /// Moves variable declarations to improved positions.

2
ICSharpCode.Decompiler/CSharp/Transforms/DelegateConstruction.cs

@ -27,7 +27,7 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)". /// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)".

2
ICSharpCode.Decompiler/CSharp/Transforms/ExpressionTreeConverter.cs

@ -26,7 +26,7 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
public class ExpressionTreeConverter public class ExpressionTreeConverter
{ {

2
ICSharpCode.Decompiler/CSharp/Transforms/FlattenSwitchBlocks.cs

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
class FlattenSwitchBlocks : IAstTransform class FlattenSwitchBlocks : IAstTransform
{ {

10
ICSharpCode.Decompiler/CSharp/Transforms/IAstTransform.cs

@ -26,14 +26,4 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
void Run(AstNode compilationUnit); void Run(AstNode compilationUnit);
} }
public static class TransformationPipeline
{
public static IAstTransform[] CreatePipeline()
{
return new IAstTransform[] {
new AddCheckedBlocks()
};
}
}
} }

2
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs

@ -21,7 +21,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Converts extension method calls into infix syntax. /// Converts extension method calls into infix syntax.

2
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs

@ -21,7 +21,7 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Decompiles query expressions. /// Decompiles query expressions.

2
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs

@ -19,7 +19,7 @@
using System; using System;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
public class IntroduceUnsafeModifier : DepthFirstAstVisitor<object, bool>, IAstTransform public class IntroduceUnsafeModifier : DepthFirstAstVisitor<object, bool>, IAstTransform
{ {

2
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

@ -22,7 +22,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Introduces using declarations. /// Introduces using declarations.

2
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -27,7 +27,7 @@ using ICSharpCode.NRefactory.CSharp.Analysis;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Finds the expanded form of using statements using pattern matching and replaces it with a UsingStatement. /// Finds the expanded form of using statements using pattern matching and replaces it with a UsingStatement.

2
ICSharpCode.Decompiler/CSharp/Transforms/PushNegation.cs

@ -22,7 +22,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform
{ {

7
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -202,9 +202,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
/// <summary> /// <summary>
/// This annotation is used to convert a compound assignment "a += 2;" or increment operator "a++;" /// This annotation is used to allow later pipeline steps to convert a compound assignment "a += 2;" or
/// back to the original "a = a + 2;". This is sometimes necessary when the checked/unchecked semantics /// increment operator "a++;" back to the original "a = a + 2;".
/// cannot be guaranteed otherwise (see CheckedUnchecked.ForWithCheckedInitializerAndUncheckedIterator test) /// This is sometimes necessary when the checked/unchecked semantics cannot be guaranteed otherwise
/// (see CheckedUnchecked.ForWithCheckedInitializerAndUncheckedIterator test).
/// </summary> /// </summary>
public class RestoreOriginalAssignOperatorAnnotation public class RestoreOriginalAssignOperatorAnnotation
{ {

44
ICSharpCode.Decompiler/CSharp/Transforms/TransformationPipeline.cs

@ -20,46 +20,28 @@ using System;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
public interface IAstTransform
{
void Run(AstNode compilationUnit);
}
public static class TransformationPipeline public static class TransformationPipeline
{ {
public static IAstTransform[] CreatePipeline(DecompilerContext context) public static IAstTransform[] CreatePipeline()
{ {
return new IAstTransform[] { return new IAstTransform[] {
new PushNegation(), //new PushNegation(),
new DelegateConstruction(context), //new DelegateConstruction(context),
new PatternStatementTransform(context), //new PatternStatementTransform(context),
new ReplaceMethodCallsWithOperators(context), new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(), new IntroduceUnsafeModifier(),
new AddCheckedBlocks(), new AddCheckedBlocks(),
new DeclareVariables(context), // should run after most transforms that modify statements //new DeclareVariables(context), // should run after most transforms that modify statements
new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables
new DecimalConstantTransform(), //new DecimalConstantTransform(),
new IntroduceUsingDeclarations(context), //new IntroduceUsingDeclarations(context),
new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations //new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods //new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods
new CombineQueryExpressions(context), //new CombineQueryExpressions(context),
new FlattenSwitchBlocks(), //new FlattenSwitchBlocks(),
}; };
} }
public static void RunTransformationsUntil(AstNode node, Predicate<IAstTransform> abortCondition, DecompilerContext context)
{
if (node == null)
return;
foreach (var transform in CreatePipeline(context)) {
context.CancellationToken.ThrowIfCancellationRequested();
if (abortCondition != null && abortCondition(transform))
return;
transform.Run(node);
}
}
} }
} }

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -70,9 +70,12 @@
<Compile Include="CSharp\NRefactoryExtensions.cs" /> <Compile Include="CSharp\NRefactoryExtensions.cs" />
<Compile Include="CSharp\StatementBuilder.cs" /> <Compile Include="CSharp\StatementBuilder.cs" />
<Compile Include="CSharp\Transforms\AddCheckedBlocks.cs" /> <Compile Include="CSharp\Transforms\AddCheckedBlocks.cs" />
<Compile Include="CSharp\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="CSharp\Transforms\CustomPatterns.cs" /> <Compile Include="CSharp\Transforms\CustomPatterns.cs" />
<Compile Include="CSharp\Transforms\IAstTransform.cs" /> <Compile Include="CSharp\Transforms\IAstTransform.cs" />
<Compile Include="CSharp\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="CSharp\Transforms\ReplaceMethodCallsWithOperators.cs" /> <Compile Include="CSharp\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="CSharp\Transforms\TransformationPipeline.cs" />
<Compile Include="IL\Instructions.cs"> <Compile Include="IL\Instructions.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>

14
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -27,5 +27,19 @@ namespace ICSharpCode.Decompiler
foreach (T item in input) foreach (T item in input)
collection.Add(item); collection.Add(item);
} }
/// <summary>
/// Equivalent to <code>collection.Select(func).ToArray()</code>, but more efficient as it makes
/// use of the input collection's known size.
/// </summary>
public static U[] SelectArray<T, U>(this ICollection<T> collection, Func<T, U> func)
{
U[] result = new U[collection.Count];
int index = 0;
foreach (var element in collection) {
result[index++] = func(element);
}
return result;
}
} }
} }

2
ILSpy.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012 # Visual Studio 2012
# SharpDevelop 5.0 # SharpDevelop 5.1
VisualStudioVersion = 14.0.21730.1 VisualStudioVersion = 14.0.21730.1
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}"

Loading…
Cancel
Save