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 @@ @@ -7,8 +7,70 @@
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
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
{
// 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 {}
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 @@ @@ -17,62 +17,197 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.Decompiler.IL;
namespace ICSharpCode.Decompiler.CSharp
{
/// <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>
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
{
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.Type = type;
this.ResolveResult = expression.Annotation<ResolveResult>() ?? ErrorResolveResult.UnknownError;
}
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 Expression ConvertTo(IType targetType, ExpressionBuilder expressionBuilder)
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))
return ConvertToBoolean();
if (Type.Equals(targetType))
return Expression;
if (Type.Kind == TypeKind.ByReference && targetType.Kind == TypeKind.Pointer && Expression is DirectionExpression) {
return ConvertToBoolean(expressionBuilder);
if (type.Equals(targetType))
return this;
if (type.Kind == TypeKind.ByReference && targetType.Kind == TypeKind.Pointer && Expression is DirectionExpression) {
// convert from reference to pointer
Expression arg = ((DirectionExpression)Expression).Expression.Detach();
var pointerExpr = new ConvertedExpression(
new UnaryOperatorExpression(UnaryOperatorType.AddressOf, arg),
new PointerType(((ByReferenceType)Type).ElementType));
var pointerType = new PointerType(((ByReferenceType)type).ElementType);
var pointerExpr = new UnaryOperatorExpression(UnaryOperatorType.AddressOf, arg)
.WithILInstruction(this.ILInstructions)
.WithRR(new ResolveResult(pointerType));
// perform remaining pointer cast, if necessary
return pointerExpr.ConvertTo(targetType, expressionBuilder);
}
if (Expression is PrimitiveExpression) {
object value = ((PrimitiveExpression)Expression).Value;
var rr = expressionBuilder.resolver.ResolveCast(targetType, new ConstantResolveResult(Type, value));
if (rr.IsCompileTimeConstant && !rr.IsError)
return expressionBuilder.astBuilder.ConvertConstantValue(rr);
var rr = expressionBuilder.resolver.ResolveCast(targetType, ResolveResult);
if (rr.IsCompileTimeConstant && !rr.IsError) {
return expressionBuilder.astBuilder.ConvertConstantValue(rr)
.WithILInstruction(this.ILInstructions)
.WithRR(rr);
}
return new CastExpression(
expressionBuilder.astBuilder.ConvertType(targetType),
Expression);
return Expression.CastTo(expressionBuilder.ConvertType(targetType))
.WithoutILInstruction().WithRR(rr);
}
public Expression ConvertToBoolean()
public ConvertedExpression ConvertToBoolean(ExpressionBuilder expressionBuilder)
{
if (Type.IsKnownType(KnownTypeCode.Boolean) || Type.Kind == TypeKind.Unknown)
return Expression;
else if (Expression is PrimitiveExpression && Type.IsKnownType(KnownTypeCode.Int32))
return new PrimitiveExpression((int)((PrimitiveExpression)Expression).Value != 0);
else if (Type.Kind == TypeKind.Pointer)
return new BinaryOperatorExpression(Expression, BinaryOperatorType.InEquality, new NullReferenceExpression());
else
return new BinaryOperatorExpression(Expression, BinaryOperatorType.InEquality, new PrimitiveExpression(0));
if (Type.IsKnownType(KnownTypeCode.Boolean) || Type.Kind == TypeKind.Unknown) {
return this;
}
IType boolType = expressionBuilder.compilation.FindType(KnownTypeCode.Boolean);
if (Expression is PrimitiveExpression && Type.IsKnownType(KnownTypeCode.Int32)) {
bool val = (int)((PrimitiveExpression)Expression).Value != 0;
return new PrimitiveExpression(val)
.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 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System.Diagnostics;
using ExpressionType = System.Linq.Expressions.ExpressionType;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
@ -36,153 +37,154 @@ namespace ICSharpCode.Decompiler.CSharp @@ -36,153 +37,154 @@ namespace ICSharpCode.Decompiler.CSharp
/// </summary>
class ExpressionBuilder : ILVisitor<ConvertedExpression>
{
private readonly ICompilation compilation;
readonly NRefactoryCecilMapper cecilMapper;
internal readonly ICompilation compilation;
internal readonly NRefactoryCecilMapper cecilMapper;
internal readonly CSharpResolver resolver;
internal readonly TypeSystemAstBuilder astBuilder;
public ExpressionBuilder(ICompilation compilation, NRefactoryCecilMapper cecilMapper)
{
Debug.Assert(compilation != null);
Debug.Assert(cecilMapper != null);
this.compilation = compilation;
this.cecilMapper = cecilMapper;
this.resolver = new CSharpResolver(compilation);
this.astBuilder = new TypeSystemAstBuilder(resolver);
}
public AstType ConvertType(Mono.Cecil.TypeReference type)
public AstType ConvertType(Mono.Cecil.TypeReference typeReference)
{
if (type == null)
return null;
return astBuilder.ConvertType(cecilMapper.GetType(type));
if (typeReference == null)
return AstType.Null;
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);
return expr.ConvertToBoolean();
var expr = Convert(condition);
return expr.ConvertToBoolean(this);
}
ConvertedExpression ConvertVariable(ILVariable variable)
ExpressionWithResolveResult ConvertVariable(ILVariable variable)
{
Expression expr;
if (variable.Kind == VariableKind.This)
expr = new ThisReferenceExpression();
else
expr = new IdentifierExpression(variable.Name);
expr.AddAnnotation(variable);
if (variable.Type.SkipModifiers().MetadataType == Mono.Cecil.MetadataType.ByReference)
{
// When loading a by-ref parameter, use 'ref paramName'.
// We'll strip away the 'ref' when dereferencing.
expr = new DirectionExpression(FieldDirection.Ref, expr);
}
return new ConvertedExpression(expr, cecilMapper.GetType(variable.Type));
}
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;
return expr
.WithRR(new ResolveResult(cecilMapper.GetType(variable.Type))); // TODO: use LocalResolveResult instead
}
ConvertedExpression IsType(IsInst inst)
{
var arg = ConvertArgument(inst.Argument);
return new ConvertedExpression(
new IsExpression(arg.Expression, ConvertType(inst.Type)),
compilation.FindType(TypeCode.Boolean));
var arg = Convert(inst.Argument);
var type = cecilMapper.GetType(inst.Type);
return new IsExpression(arg.Expression, ConvertType(type))
.WithILInstruction(inst)
.WithRR(new TypeIsResolveResult(arg.ResolveResult, type, compilation.FindType(TypeCode.Boolean)));
}
protected internal override ConvertedExpression VisitIsInst(IsInst inst)
{
var arg = ConvertArgument(inst.Argument);
return new ConvertedExpression(
new AsExpression(arg.Expression, ConvertType(inst.Type)),
cecilMapper.GetType(inst.Type));
var arg = Convert(inst.Argument);
var type = cecilMapper.GetType(inst.Type);
return new AsExpression(arg.Expression, ConvertType(type))
.WithILInstruction(inst)
.WithRR(new ConversionResolveResult(type, arg.ResolveResult, Conversion.TryCast));
}
protected internal override ConvertedExpression VisitNewObj(NewObj inst)
{
var oce = new ObjectCreateExpression(ConvertType(inst.Method.DeclaringType));
oce.Arguments.AddRange(inst.Arguments.Select(i => ConvertArgument(i).Expression));
return new ConvertedExpression(oce, cecilMapper.GetType(inst.Method.DeclaringType));
return HandleCallInstruction(inst);
}
protected internal override ConvertedExpression VisitLdcI4(LdcI4 inst)
{
return new ConvertedExpression(
new PrimitiveExpression(inst.Value),
compilation.FindType(KnownTypeCode.Int32));
return new PrimitiveExpression(inst.Value)
.WithILInstruction(inst)
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), inst.Value));
}
protected internal override ConvertedExpression VisitLdcI8(LdcI8 inst)
{
return new ConvertedExpression(
new PrimitiveExpression(inst.Value),
compilation.FindType(KnownTypeCode.Int64));
return new PrimitiveExpression(inst.Value)
.WithILInstruction(inst)
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int64), inst.Value));
}
protected internal override ConvertedExpression VisitLdcF(LdcF inst)
{
return new ConvertedExpression(
new PrimitiveExpression(inst.Value),
compilation.FindType(KnownTypeCode.Double));
return new PrimitiveExpression(inst.Value)
.WithILInstruction(inst)
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Double), inst.Value));
}
protected internal override ConvertedExpression VisitLdStr(LdStr inst)
{
return new ConvertedExpression(
new PrimitiveExpression(inst.Value),
compilation.FindType(KnownTypeCode.String));
return new PrimitiveExpression(inst.Value)
.WithILInstruction(inst)
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.String), inst.Value));
}
protected internal override ConvertedExpression VisitLdNull(LdNull inst)
{
return new ConvertedExpression(
new NullReferenceExpression(),
SpecialType.UnknownType);
return new NullReferenceExpression()
.WithILInstruction(inst)
.WithRR(new ConstantResolveResult(SpecialType.UnknownType, null));
}
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(
new UnaryOperatorExpression(UnaryOperatorType.Not, expr.Expression),
compilation.FindType(KnownTypeCode.Boolean));
return new UnaryOperatorExpression(UnaryOperatorType.Not, expr.Expression)
.WithRR(new OperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), ExpressionType.Not));
}
protected internal override ConvertedExpression VisitLdLoc(LdLoc inst)
{
return ConvertVariable(inst.Variable);
return ConvertVariable(inst.Variable).WithILInstruction(inst);
}
protected internal override ConvertedExpression VisitLdLoca(LdLoca inst)
{
var expr = ConvertVariable(inst.Variable);
return new ConvertedExpression(
new DirectionExpression(FieldDirection.Ref, expr.Expression),
new ByReferenceType(expr.Type));
var expr = ConvertVariable(inst.Variable).WithILInstruction(inst);
// Note that we put the instruction on the IdentifierExpression instead of the DirectionExpression,
// because the DirectionExpression might get removed by dereferencing instructions such as LdObj
return new DirectionExpression(FieldDirection.Ref, expr.Expression)
.WithoutILInstruction()
.WithRR(new ByReferenceResolveResult(expr.ResolveResult, isOut: false));
}
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)
@ -190,15 +192,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -190,15 +192,15 @@ namespace ICSharpCode.Decompiler.CSharp
// Translate 'e as T == null' to 'e is T'.
// This is necessary for correctness when T is a value type.
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) {
return LogicNot(IsType((IsInst)inst.Right));
return LogicNot(IsType((IsInst)inst.Right)).WithILInstruction(inst);
}
var left = ConvertArgument(inst.Left);
var right = ConvertArgument(inst.Right);
return new ConvertedExpression(
new BinaryOperatorExpression(left.Expression, BinaryOperatorType.Equality, right.Expression),
compilation.FindType(TypeCode.Boolean));
var left = Convert(inst.Left);
var right = Convert(inst.Right);
return new BinaryOperatorExpression(left.Expression, BinaryOperatorType.Equality, right.Expression)
.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), ExpressionType.Equal, left.ResolveResult, right.ResolveResult));
}
protected internal override ConvertedExpression VisitClt(Clt inst)
@ -223,19 +225,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -223,19 +225,22 @@ namespace ICSharpCode.Decompiler.CSharp
ConvertedExpression Comparison(BinaryComparisonInstruction inst, BinaryOperatorType op, bool un = false)
{
var left = ConvertArgument(inst.Left);
var right = ConvertArgument(inst.Right);
var left = Convert(inst.Left);
var right = Convert(inst.Right);
// TODO: ensure the arguments are signed
// or with _Un: ensure the arguments are unsigned; and that float comparisons are performed unordered
return new ConvertedExpression(
new BinaryOperatorExpression(left.Expression, op, right.Expression),
compilation.FindType(TypeCode.Boolean));
return new BinaryOperatorExpression(left.Expression, op, right.Expression)
.WithILInstruction(inst)
.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))
.WithTypeInfo(left.Type);
right = right.ConvertTo(left.Type, this);
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)
@ -290,20 +295,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -290,20 +295,22 @@ namespace ICSharpCode.Decompiler.CSharp
ConvertedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op)
{
var left = ConvertArgument(inst.Left);
var right = ConvertArgument(inst.Right);
var rr = resolver.ResolveBinaryOperator(op, new ResolveResult(left.Type), new ResolveResult(right.Type));
if (!rr.IsError && rr.Type.GetStackType() == inst.ResultType
&& IsCompatibleWithSign(left.Type, inst.Sign) && IsCompatibleWithSign(right.Type, inst.Sign))
var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow);
var left = Convert(inst.Left);
var right = Convert(inst.Right);
var rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
if (rr.IsError || rr.Type.GetStackType() != inst.ResultType
|| !IsCompatibleWithSign(left.Type, inst.Sign) || !IsCompatibleWithSign(right.Type, inst.Sign))
{
return new ConvertedExpression(
new BinaryOperatorExpression(left.Expression, op, right.Expression),
rr.Type);
}
// Left and right operands are incompatible, so convert them to a common type
IType targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode(inst.Sign));
return new ConvertedExpression(
new BinaryOperatorExpression(left.ConvertTo(targetType, this), op, right.ConvertTo(targetType, this)),
targetType);
left = left.ConvertTo(targetType, this);
right = right.ConvertTo(targetType, this);
rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
}
return new BinaryOperatorExpression(left.Expression, op, right.Expression)
.WithILInstruction(inst)
.WithRR(rr);
}
/// <summary>
@ -317,17 +324,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -317,17 +324,17 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override ConvertedExpression VisitConv(Conv inst)
{
var arg = ConvertArgument(inst.Argument);
Expression input = arg.Expression;
var arg = Convert(inst.Argument);
if (arg.Type.GetSign() != inst.Sign) {
// we need to cast the input to a type of appropriate 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());
return new ConvertedExpression(
new CastExpression(astBuilder.ConvertType(targetType), input),
targetType);
var rr = resolver.WithCheckForOverflow(inst.CheckForOverflow).ResolveCast(targetType, arg.ResolveResult);
return new CastExpression(ConvertType(targetType), arg.Expression)
.WithILInstruction(inst)
.WithRR(rr);
}
protected internal override ConvertedExpression VisitCall(Call inst)
@ -342,54 +349,85 @@ namespace ICSharpCode.Decompiler.CSharp @@ -342,54 +349,85 @@ namespace ICSharpCode.Decompiler.CSharp
ConvertedExpression HandleCallInstruction(CallInstruction inst)
{
Expression target;
if (inst.Method.HasThis) {
// Used for Call, CallVirt and NewObj
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];
if (inst.OpCode == OpCode.Call && argInstruction.MatchLdThis())
target = new BaseReferenceExpression().WithAnnotation(argInstruction);
else
if (inst.OpCode == OpCode.Call && argInstruction.MatchLdThis()) {
target = new BaseReferenceExpression()
.WithILInstruction(argInstruction)
.WithRR(new ThisResolveResult(cecilMapper.GetType(inst.Method.DeclaringType), causesNonVirtualInvocation: true));
} else {
target = Convert(argInstruction);
}
} 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));
}
var arguments = inst.Arguments.SelectArray(Convert);
int firstParamIndex = inst.Method.HasThis && inst.OpCode != OpCode.NewObj ? 1 : 0;
Debug.Assert(arguments.Length == firstParamIndex + inst.Method.Parameters.Count);
ResolveResult rr;
if (method != null) {
// 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);
}
InvocationExpression invocation = target.Invoke(inst.Method.Name);
int firstParamIndex = inst.Method.HasThis ? 1 : 0;
for (int i = firstParamIndex; i < inst.Arguments.Count; i++) {
var p = inst.Method.Parameters[i - firstParamIndex];
var arg = ConvertArgument(inst.Arguments[i]);
var type = cecilMapper.GetType(p.ParameterType);
invocation.Arguments.Add(arg.ConvertTo(type, 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)
{
var target = ConvertArgument(inst.Target);
var target = Convert(inst.Target);
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'
return new ConvertedExpression(
((DirectionExpression)target.Expression).Expression.Detach(),
type);
var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
result = result.ConvertTo(type, this);
}
return new ConvertedExpression(
new UnaryOperatorExpression(
UnaryOperatorType.Dereference, target.ConvertTo(new PointerType(type), this)),
type);
// Cast pointer type if necessary:
target = target.ConvertTo(new PointerType(type), this);
return new UnaryOperatorExpression(UnaryOperatorType.Dereference, target.Expression)
.WithILInstruction(inst)
.WithRR(new ResolveResult(type));
}
protected internal override ConvertedExpression VisitUnboxAny(UnboxAny inst)
{
var arg = ConvertArgument(inst.Argument);
Expression expr = arg.Expression;
var arg = Convert(inst.Argument);
if (arg.Type.IsReferenceType != true) {
// 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 ConvertedExpression(expr, cecilMapper.GetType(inst.Type));
return new CastExpression(ConvertType(inst.Type), arg.Expression)
.WithILInstruction(inst)
.WithRR(new ConversionResolveResult(cecilMapper.GetType(inst.Type), arg.ResolveResult, Conversion.UnboxingConversion));
}
protected override ConvertedExpression Default(ILInstruction inst)
@ -401,7 +439,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -401,7 +439,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
var e = new ErrorExpression();
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 @@ -25,11 +25,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
static class NRefactoryExtensions
{
public static ConvertedExpression WithTypeInfo(this Expression expr, IType type)
{
return new ConvertedExpression(expr, type);
}
[Obsolete("Use the more concrete With...()-methods in AnnotationExtensions, so that we maintain a centralised list of the possible annotation types")]
public static T WithAnnotation<T>(this T node, object annotation) where T : AstNode
{
if (annotation != null)

2
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -86,7 +86,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -86,7 +86,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (inst.ReturnValue == null)
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)

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

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

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

@ -21,7 +21,7 @@ using System.Diagnostics; @@ -21,7 +21,7 @@ using System.Diagnostics;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
/// <summary>
/// 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; @@ -23,7 +23,7 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
/// <summary>
/// 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 @@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
invocation.Arguments.MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>());
constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(invocation);
// Remove the statement:
stmt.Remove();
}

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

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

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

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

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

@ -27,7 +27,7 @@ using ICSharpCode.NRefactory.CSharp; @@ -27,7 +27,7 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
/// <summary>
/// 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; @@ -26,7 +26,7 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
public class ExpressionTreeConverter
{

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

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

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

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

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

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

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

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

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

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

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

@ -27,7 +27,7 @@ using ICSharpCode.NRefactory.CSharp.Analysis; @@ -27,7 +27,7 @@ using ICSharpCode.NRefactory.CSharp.Analysis;
using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
/// <summary>
/// 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; @@ -22,7 +22,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.Decompiler.Ast.Transforms
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform
{

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

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

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

@ -20,46 +20,28 @@ using System; @@ -20,46 +20,28 @@ using System;
using System.Threading;
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 IAstTransform[] CreatePipeline(DecompilerContext context)
public static IAstTransform[] CreatePipeline()
{
return new IAstTransform[] {
new PushNegation(),
new DelegateConstruction(context),
new PatternStatementTransform(context),
new ReplaceMethodCallsWithOperators(context),
//new PushNegation(),
//new DelegateConstruction(context),
//new PatternStatementTransform(context),
new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(),
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 DecimalConstantTransform(),
new IntroduceUsingDeclarations(context),
new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods
new CombineQueryExpressions(context),
new FlattenSwitchBlocks(),
//new DecimalConstantTransform(),
//new IntroduceUsingDeclarations(context),
//new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
//new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods
//new CombineQueryExpressions(context),
//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 @@ @@ -70,9 +70,12 @@
<Compile Include="CSharp\NRefactoryExtensions.cs" />
<Compile Include="CSharp\StatementBuilder.cs" />
<Compile Include="CSharp\Transforms\AddCheckedBlocks.cs" />
<Compile Include="CSharp\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="CSharp\Transforms\CustomPatterns.cs" />
<Compile Include="CSharp\Transforms\IAstTransform.cs" />
<Compile Include="CSharp\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="CSharp\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="CSharp\Transforms\TransformationPipeline.cs" />
<Compile Include="IL\Instructions.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>

14
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -27,5 +27,19 @@ namespace ICSharpCode.Decompiler @@ -27,5 +27,19 @@ namespace ICSharpCode.Decompiler
foreach (T item in input)
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 @@ @@ -1,7 +1,7 @@

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

Loading…
Cancel
Save