Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: icsharpcode/ILSpy
base: 18fde48
...
head fork: icsharpcode/ILSpy
compare: fe4b3d4
  • 11 commits
  • 29 files changed
  • 0 commit comments
  • 1 contributor
Showing with 1,285 additions and 293 deletions.
  1. +52 −14 ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. +6 −0 ICSharpCode.Decompiler/Ast/NameVariables.cs
  3. +50 −10 ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs
  4. +1 −1  ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  5. +3 −0  ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
  6. +7 −3 ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  7. +76 −41 ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
  8. +12 −0 ICSharpCode.Decompiler/DecompilerSettings.cs
  9. +7 −1 ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  10. +66 −0 ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  11. +31 −8 ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  12. +35 −27 ICSharpCode.Decompiler/ILAst/ILCodes.cs
  13. +0 −10 ICSharpCode.Decompiler/ILAst/PatternMatching.cs
  14. +348 −11 ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  15. +5 −4 ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
  16. +66 −18 ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  17. +28 −21 ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs
  18. +14 −3 ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
  19. +29 −11 ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
  20. +2 −2 ICSharpCode.Decompiler/Tests/Generics.cs
  21. +6 −0 ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs
  22. +3 −3 ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  23. +217 −0 ICSharpCode.Decompiler/Tests/IncrementDecrement.cs
  24. +10 −6 ICSharpCode.Decompiler/Tests/Loops.cs
  25. +19 −8 ICSharpCode.Decompiler/Tests/MultidimensionalArray.cs
  26. +38 −25 ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs
  27. +82 −12 ICSharpCode.Decompiler/Tests/TestRunner.cs
  28. +43 −26 ICSharpCode.Decompiler/Tests/UnsafeCode.cs
  29. +29 −28 ICSharpCode.Decompiler/Tests/ValueTypes.cs
View
66 ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
@@ -280,6 +280,17 @@ AstNode TransformByteCode(ILExpression byteCode)
case ILCode.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case ILCode.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1).WithAnnotation(AddCheckedBlocks.UncheckedAnnotation);
case ILCode.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
+ case ILCode.PostIncrement:
+ case ILCode.PostIncrement_Ovf:
+ case ILCode.PostIncrement_Ovf_Un:
+ {
+ if (arg1 is DirectionExpression)
+ arg1 = ((DirectionExpression)arg1).Expression.Detach();
+ var uoe = new Ast.UnaryOperatorExpression(
+ (int)byteCode.Operand > 0 ? UnaryOperatorType.PostIncrement : UnaryOperatorType.PostDecrement, arg1);
+ uoe.AddAnnotation((byteCode.Code == ILCode.PostIncrement) ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation);
+ return uoe;
+ }
#endregion
#region Arrays
case ILCode.Newarr:
@@ -313,7 +324,8 @@ AstNode TransformByteCode(ILExpression byteCode)
case ILCode.Ldelem_Ref:
case ILCode.Ldelem_Any:
return arg1.Indexer(arg2);
- case ILCode.Ldelema: return MakeRef(arg1.Indexer(arg2));
+ case ILCode.Ldelema:
+ return MakeRef(arg1.Indexer(arg2));
case ILCode.Stelem_I:
case ILCode.Stelem_I1:
case ILCode.Stelem_I2:
@@ -324,6 +336,18 @@ AstNode TransformByteCode(ILExpression byteCode)
case ILCode.Stelem_Ref:
case ILCode.Stelem_Any:
return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
+ case ILCode.CompoundAssignment:
+ {
+ BinaryOperatorExpression boe = (BinaryOperatorExpression)arg1;
+ return new Ast.AssignmentExpression {
+ Left = boe.Left.Detach(),
+ Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator),
+ Right = boe.Right.Detach()
+ }.CopyAnnotationsFrom(boe);
+ // We do not mark the resulting assignment as RestoreOriginalAssignOperatorAnnotation, because
+ // the operator cannot be translated back to the expanded form (as the left-hand expression
+ // would be evaluated twice, and might have side-effects)
+ }
#endregion
#region Comparison
case ILCode.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
@@ -377,9 +401,10 @@ AstNode TransformByteCode(ILExpression byteCode)
}
return arg1;
}
- case ILCode.Conv_R4: return arg1.CastTo(typeof(float));
- case ILCode.Conv_R8: return arg1.CastTo(typeof(double));
- case ILCode.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO
+ case ILCode.Conv_R4:
+ case ILCode.Conv_R8:
+ case ILCode.Conv_R_Un: // TODO
+ return arg1;
case ILCode.Conv_Ovf_I1:
case ILCode.Conv_Ovf_I2:
case ILCode.Conv_Ovf_I4:
@@ -430,8 +455,14 @@ AstNode TransformByteCode(ILExpression byteCode)
#endregion
case ILCode.Arglist: return InlineAssembly(byteCode, args);
case ILCode.Break: return InlineAssembly(byteCode, args);
- case ILCode.Call: return TransformCall(false, operand, methodDef, args);
- case ILCode.Callvirt: return TransformCall(true, operand, methodDef, args);
+ case ILCode.Call:
+ case ILCode.CallGetter:
+ case ILCode.CallSetter:
+ return TransformCall(false, operand, args);
+ case ILCode.Callvirt:
+ case ILCode.CallvirtGetter:
+ case ILCode.CallvirtSetter:
+ return TransformCall(true, operand, args);
case ILCode.Ldftn: {
Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name);
@@ -487,7 +518,10 @@ AstNode TransformByteCode(ILExpression byteCode)
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand),
arg1);
- case ILCode.Ldflda: return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand));
+ case ILCode.Ldflda:
+ if (arg1 is DirectionExpression)
+ arg1 = ((DirectionExpression)arg1).Expression.Detach();
+ return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand));
case ILCode.Ldsflda:
return MakeRef(
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
@@ -664,7 +698,7 @@ Expression MakeDefaultValue(TypeReference type)
return new DefaultValueExpression { Type = AstBuilder.ConvertType(type) };
}
- static AstNode TransformCall(bool isVirtual, object operand, MethodDefinition methodDef, List<Ast.Expression> args)
+ AstNode TransformCall(bool isVirtual, object operand, List<Ast.Expression> args)
{
Cecil.MethodReference cecilMethod = ((MethodReference)operand);
Ast.Expression target;
@@ -684,7 +718,7 @@ static AstNode TransformCall(bool isVirtual, object operand, MethodDefinition me
}
if (target is ThisReferenceExpression && !isVirtual) {
// a non-virtual call on "this" might be a "base"-call.
- if ((cecilMethod.DeclaringType.IsGenericInstance ? cecilMethod.DeclaringType.GetElementType() : cecilMethod.DeclaringType) != methodDef.DeclaringType) {
+ if (cecilMethod.DeclaringType.GetElementType() != methodDef.DeclaringType) {
// If we're not calling a method in the current class; we must be calling one in the base class.
target = new BaseReferenceExpression();
}
@@ -702,6 +736,8 @@ static AstNode TransformCall(bool isVirtual, object operand, MethodDefinition me
if (cecilMethod.Name == "Get" && cecilMethod.DeclaringType is ArrayType && methodArgs.Count > 1) {
return target.Indexer(methodArgs);
+ } else if (cecilMethod.Name == "Address" && cecilMethod.DeclaringType is ArrayType && methodArgs.Count > 1) {
+ return MakeRef(target.Indexer(methodArgs));
} else if (cecilMethod.Name == "Set" && cecilMethod.DeclaringType is ArrayType && methodArgs.Count > 2) {
return new AssignmentExpression(target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)), methodArgs.Last());
}
@@ -865,7 +901,7 @@ static Ast.DirectionExpression MakeRef(Ast.Expression expr)
Ast.Expression Convert(Ast.Expression expr, Cecil.TypeReference actualType, Cecil.TypeReference reqType)
{
- if (reqType == null || actualType == reqType) {
+ if (actualType == null || reqType == null || TypeAnalysis.IsSameType(actualType, reqType)) {
return expr;
} else if (actualType is ByReferenceType && reqType is PointerType && expr is DirectionExpression) {
return Convert(
@@ -908,10 +944,12 @@ Ast.Expression Convert(Ast.Expression expr, Cecil.TypeReference actualType, Ceci
{
return expr.CastTo(AstBuilder.ConvertType(actualType));
}
-
- if (actualIsIntegerOrEnum && requiredIsIntegerOrEnum) {
- if (actualType.FullName == reqType.FullName)
- return expr;
+
+ bool actualIsPrimitiveType = actualIsIntegerOrEnum
+ || actualType.MetadataType == MetadataType.Single || actualType.MetadataType == MetadataType.Double;
+ bool requiredIsPrimitiveType = requiredIsIntegerOrEnum
+ || reqType.MetadataType == MetadataType.Single || reqType.MetadataType == MetadataType.Double;
+ if (actualIsPrimitiveType && requiredIsPrimitiveType) {
return expr.CastTo(AstBuilder.ConvertType(reqType));
}
return expr;
View
6 ICSharpCode.Decompiler/Ast/NameVariables.cs
@@ -159,6 +159,8 @@ static string GetNameFromExpression(ILExpression expr)
return CleanUpVariableName(((FieldReference)expr.Operand).Name);
case ILCode.Call:
case ILCode.Callvirt:
+ case ILCode.CallGetter:
+ case ILCode.CallvirtGetter:
MethodReference mr = (MethodReference)expr.Operand;
if (mr.Name.StartsWith("get_", StringComparison.OrdinalIgnoreCase) && mr.Parameters.Count == 0) {
// use name from properties, but not from indexers
@@ -184,6 +186,10 @@ static string GetNameForArgument(ILExpression parent, int i)
case ILCode.Call:
case ILCode.Callvirt:
case ILCode.Newobj:
+ case ILCode.CallGetter:
+ case ILCode.CallvirtGetter:
+ case ILCode.CallSetter:
+ case ILCode.CallvirtSetter:
MethodReference methodRef = (MethodReference)parent.Operand;
if (methodRef.Parameters.Count == 1 && i == parent.Arguments.Count - 1) {
// argument might be value of a setter
View
60 ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs
@@ -140,6 +140,28 @@ public override void Insert()
}
}
+ class ConvertCompoundAssignment : InsertedNode
+ {
+ readonly Expression expression;
+ readonly bool isChecked;
+
+ public ConvertCompoundAssignment(Expression expression, bool isChecked)
+ {
+ this.expression = expression;
+ this.isChecked = isChecked;
+ }
+
+ public override void Insert()
+ {
+ AssignmentExpression assign = expression.Annotation<ReplaceMethodCallsWithOperators.RestoreOriginalAssignOperatorAnnotation>().Restore(expression);
+ expression.ReplaceWith(assign);
+ if (isChecked)
+ assign.Right = new CheckedExpression { Expression = assign.Right.Detach() };
+ else
+ assign.Right = new UncheckedExpression { Expression = assign.Right.Detach() };
+ }
+ }
+
class InsertedBlock : InsertedNode
{
readonly Statement firstStatement; // inclusive
@@ -279,20 +301,38 @@ Result GetResult(AstNode node)
if (expr != null) {
CheckedUncheckedAnnotation annotation = expr.Annotation<CheckedUncheckedAnnotation>();
if (annotation != null) {
- // If the annotation requires this node to be in a specific context, set the cost of the other context to infinite.
+ // If the annotation requires this node to be in a specific context, add a huge cost to the other context
+ // That huge cost gives us the option to ignore a required checked/unchecked expression when there wouldn't be any
+ // solution otherwise. (e.g. "for (checked(M().x += 1); true; unchecked(M().x += 2)) {}")
if (annotation.IsChecked)
- result.CostInUncheckedContext = Cost.Infinite;
+ result.CostInUncheckedContext += new Cost(10000, 0);
else
- result.CostInCheckedContext = Cost.Infinite;
+ result.CostInCheckedContext += new Cost(10000, 0);
}
// Embed this node in an checked/unchecked expression:
- // We use '<' so that expressions are introduced on the deepest level possible (goal 3)
- if (result.CostInCheckedContext + new Cost(0, 1) < result.CostInUncheckedContext) {
- result.CostInUncheckedContext = result.CostInCheckedContext + new Cost(0, 1);
- result.NodesToInsertInUncheckedContext = result.NodesToInsertInCheckedContext + new InsertedExpression(expr, true);
- } else if (result.CostInUncheckedContext + new Cost(0, 1) < result.CostInCheckedContext) {
- result.CostInCheckedContext = result.CostInUncheckedContext + new Cost(0, 1);
- result.NodesToInsertInCheckedContext = result.NodesToInsertInUncheckedContext + new InsertedExpression(expr, false);
+ if (expr.Parent is ExpressionStatement) {
+ // We cannot use checked/unchecked for top-level-expressions.
+ // However, we could try converting a compound assignment (checked(a+=b);) or unary operator (checked(a++);)
+ // back to its old form.
+ if (expr.Annotation<ReplaceMethodCallsWithOperators.RestoreOriginalAssignOperatorAnnotation>() != null) {
+ // We use '<' so that expressions are introduced on the deepest level possible (goal 3)
+ if (result.CostInCheckedContext + new Cost(1, 1) < result.CostInUncheckedContext) {
+ result.CostInUncheckedContext = result.CostInCheckedContext + new Cost(1, 1);
+ result.NodesToInsertInUncheckedContext = result.NodesToInsertInCheckedContext + new ConvertCompoundAssignment(expr, true);
+ } else if (result.CostInUncheckedContext + new Cost(1, 1) < result.CostInCheckedContext) {
+ result.CostInCheckedContext = result.CostInUncheckedContext + new Cost(1, 1);
+ result.NodesToInsertInCheckedContext = result.NodesToInsertInUncheckedContext + new ConvertCompoundAssignment(expr, false);
+ }
+ }
+ } else {
+ // We use '<' so that expressions are introduced on the deepest level possible (goal 3)
+ if (result.CostInCheckedContext + new Cost(0, 1) < result.CostInUncheckedContext) {
+ result.CostInUncheckedContext = result.CostInCheckedContext + new Cost(0, 1);
+ result.NodesToInsertInUncheckedContext = result.NodesToInsertInCheckedContext + new InsertedExpression(expr, true);
+ } else if (result.CostInUncheckedContext + new Cost(0, 1) < result.CostInCheckedContext) {
+ result.CostInCheckedContext = result.CostInUncheckedContext + new Cost(0, 1);
+ result.NodesToInsertInCheckedContext = result.NodesToInsertInUncheckedContext + new InsertedExpression(expr, false);
+ }
}
}
return result;
View
2  ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
@@ -58,7 +58,7 @@ public override object VisitObjectCreateExpression(ObjectCreateExpression object
methodIdent.Remove();
if (!annotation.IsVirtual && obj is ThisReferenceExpression) {
// maybe it's getting the pointer of a base method?
- if (method.DeclaringType != context.CurrentType) {
+ if (method.DeclaringType.GetElementType() != context.CurrentType) {
obj = new BaseReferenceExpression();
}
}
View
3  ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
@@ -24,6 +24,9 @@ public IntroduceUsingDeclarations(DecompilerContext context)
public void Run(AstNode compilationUnit)
{
+ if (!context.Settings.UsingDeclarations)
+ return;
+
// First determine all the namespaces that need to be imported:
compilationUnit.AcceptVisitor(this, null);
View
10 ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
@@ -584,7 +584,7 @@ public SwitchStatement TransformSwitchOnString(IfElseStatement node)
Modifiers = Modifiers.Any,
Body = new BlockStatement {
new ReturnStatement {
- Expression = new NamedNode("fieldReference", new MemberReferenceExpression { Target = new ThisReferenceExpression() })
+ Expression = new AnyNode("fieldReference")
}
}
},
@@ -608,7 +608,7 @@ PropertyDeclaration TransformAutomaticProperties(PropertyDeclaration property)
Match m = automaticPropertyPattern.Match(property);
if (m != null) {
FieldDefinition field = m.Get("fieldReference").Single().Annotation<FieldReference>().ResolveWithinSameModule();
- if (field.IsCompilerGenerated()) {
+ if (field.IsCompilerGenerated() && field.DeclaringType == cecilProperty.DeclaringType) {
RemoveCompilerGeneratedAttribute(property.Getter.Attributes);
RemoveCompilerGeneratedAttribute(property.Setter.Attributes);
property.Getter.Body = null;
@@ -643,7 +643,11 @@ void RemoveCompilerGeneratedAttribute(AstNodeCollection<AttributeSection> attrib
new AssignmentExpression {
Left = new NamedNode("var1", new IdentifierExpression()),
Operator = AssignmentOperatorType.Assign,
- Right = new NamedNode("field", new MemberReferenceExpression { Target = new ThisReferenceExpression() })
+ Right = new NamedNode(
+ "field",
+ new MemberReferenceExpression {
+ Target = new Choice { new ThisReferenceExpression(), new TypeReferenceExpression { Type = new AnyNode() } }
+ })
},
new DoWhileStatement {
EmbeddedStatement = new BlockStatement {
View
117 ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
@@ -140,49 +140,49 @@ public override object VisitInvocationExpression(InvocationExpression invocation
}
}
+ /// <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)
+ /// </summary>
+ public class RestoreOriginalAssignOperatorAnnotation
+ {
+ readonly BinaryOperatorExpression binaryOperatorExpression;
+
+ public RestoreOriginalAssignOperatorAnnotation(BinaryOperatorExpression binaryOperatorExpression)
+ {
+ this.binaryOperatorExpression = binaryOperatorExpression;
+ }
+
+ public AssignmentExpression Restore(Expression expression)
+ {
+ expression.RemoveAnnotations<RestoreOriginalAssignOperatorAnnotation>();
+ AssignmentExpression assign = expression as AssignmentExpression;
+ if (assign == null) {
+ UnaryOperatorExpression uoe = (UnaryOperatorExpression)expression;
+ assign = new AssignmentExpression(uoe.Expression.Detach(), new PrimitiveExpression(1));
+ } else {
+ assign.Operator = AssignmentOperatorType.Assign;
+ }
+ binaryOperatorExpression.Right = assign.Right.Detach();
+ assign.Right = binaryOperatorExpression;
+ return assign;
+ }
+ }
+
public override object VisitAssignmentExpression(AssignmentExpression assignment, object data)
{
base.VisitAssignmentExpression(assignment, data);
// Combine "x = x op y" into "x op= y"
BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression;
if (binary != null && assignment.Operator == AssignmentOperatorType.Assign) {
- if (IsWithoutSideEffects(assignment.Left) && assignment.Left.Match(binary.Left) != null) {
- switch (binary.Operator) {
- case BinaryOperatorType.Add:
- assignment.Operator = AssignmentOperatorType.Add;
- break;
- case BinaryOperatorType.Subtract:
- assignment.Operator = AssignmentOperatorType.Subtract;
- break;
- case BinaryOperatorType.Multiply:
- assignment.Operator = AssignmentOperatorType.Multiply;
- break;
- case BinaryOperatorType.Divide:
- assignment.Operator = AssignmentOperatorType.Divide;
- break;
- case BinaryOperatorType.Modulus:
- assignment.Operator = AssignmentOperatorType.Modulus;
- break;
- case BinaryOperatorType.ShiftLeft:
- assignment.Operator = AssignmentOperatorType.ShiftLeft;
- break;
- case BinaryOperatorType.ShiftRight:
- assignment.Operator = AssignmentOperatorType.ShiftRight;
- break;
- case BinaryOperatorType.BitwiseAnd:
- assignment.Operator = AssignmentOperatorType.BitwiseAnd;
- break;
- case BinaryOperatorType.BitwiseOr:
- assignment.Operator = AssignmentOperatorType.BitwiseOr;
- break;
- case BinaryOperatorType.ExclusiveOr:
- assignment.Operator = AssignmentOperatorType.ExclusiveOr;
- break;
- }
+ if (CanConvertToCompoundAssignment(assignment.Left) && assignment.Left.Match(binary.Left) != null) {
+ assignment.Operator = GetAssignmentOperatorForBinaryOperator(binary.Operator);
if (assignment.Operator != AssignmentOperatorType.Assign) {
// If we found a shorter operator, get rid of the BinaryOperatorExpression:
assignment.CopyAnnotationsFrom(binary);
assignment.Right = binary.Right;
+ assignment.AddAnnotation(new RestoreOriginalAssignOperatorAnnotation(binary));
}
}
}
@@ -196,7 +196,7 @@ public override object VisitAssignmentExpression(AssignmentExpression assignment
// so we can pick post-increment which is more commonly used (for (int i = 0; i < x; i++))
if (assignment.Parent is ExpressionStatement)
type = (assignment.Operator == AssignmentOperatorType.Add) ? UnaryOperatorType.PostIncrement : UnaryOperatorType.PostDecrement;
- else
+ else
type = (assignment.Operator == AssignmentOperatorType.Add) ? UnaryOperatorType.Increment : UnaryOperatorType.Decrement;
assignment.ReplaceWith(new UnaryOperatorExpression(type, assignment.Left.Detach()).CopyAnnotationsFrom(assignment));
}
@@ -205,16 +205,51 @@ public override object VisitAssignmentExpression(AssignmentExpression assignment
return null;
}
- static bool IsWithoutSideEffects(Expression left)
+ public static AssignmentOperatorType GetAssignmentOperatorForBinaryOperator(BinaryOperatorType bop)
+ {
+ switch (bop) {
+ case BinaryOperatorType.Add:
+ return AssignmentOperatorType.Add;
+ case BinaryOperatorType.Subtract:
+ return AssignmentOperatorType.Subtract;
+ case BinaryOperatorType.Multiply:
+ return AssignmentOperatorType.Multiply;
+ case BinaryOperatorType.Divide:
+ return AssignmentOperatorType.Divide;
+ case BinaryOperatorType.Modulus:
+ return AssignmentOperatorType.Modulus;
+ case BinaryOperatorType.ShiftLeft:
+ return AssignmentOperatorType.ShiftLeft;
+ case BinaryOperatorType.ShiftRight:
+ return AssignmentOperatorType.ShiftRight;
+ case BinaryOperatorType.BitwiseAnd:
+ return AssignmentOperatorType.BitwiseAnd;
+ case BinaryOperatorType.BitwiseOr:
+ return AssignmentOperatorType.BitwiseOr;
+ case BinaryOperatorType.ExclusiveOr:
+ return AssignmentOperatorType.ExclusiveOr;
+ default:
+ return AssignmentOperatorType.Assign;
+ }
+ }
+
+ static bool CanConvertToCompoundAssignment(Expression left)
{
- if (left is ThisReferenceExpression)
- return true;
- if (left is IdentifierExpression)
- return true;
MemberReferenceExpression mre = left as MemberReferenceExpression;
if (mre != null)
- return mre.Annotation<FieldReference>() != null && IsWithoutSideEffects(mre.Target);
- return false;
+ return IsWithoutSideEffects(mre.Target);
+ IndexerExpression ie = left as IndexerExpression;
+ if (ie != null)
+ return IsWithoutSideEffects(ie.Target) && ie.Arguments.All(IsWithoutSideEffects);
+ UnaryOperatorExpression uoe = left as UnaryOperatorExpression;
+ if (uoe != null && uoe.Operator == UnaryOperatorType.Dereference)
+ return IsWithoutSideEffects(uoe.Expression);
+ return IsWithoutSideEffects(left);
+ }
+
+ static bool IsWithoutSideEffects(Expression left)
+ {
+ return left is ThisReferenceExpression || left is IdentifierExpression || left is TypeReferenceExpression;
}
void IAstTransform.Run(AstNode node)
View
12 ICSharpCode.Decompiler/DecompilerSettings.cs
@@ -128,6 +128,18 @@ public class DecompilerSettings : INotifyPropertyChanged
}
}
+ bool usingDeclarations = true;
+
+ public bool UsingDeclarations {
+ get { return usingDeclarations; }
+ set {
+ if (usingDeclarations != value) {
+ usingDeclarations = value;
+ OnPropertyChanged("UsingDeclarations");
+ }
+ }
+ }
+
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
View
8 ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
@@ -694,7 +694,13 @@ List<ILNode> ConvertToAst(List<ByteCode> body)
ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand);
expr.ILRanges.Add(ilRange);
- expr.Prefixes = byteCode.Prefixes;
+ if (byteCode.Prefixes != null && byteCode.Prefixes.Length > 0) {
+ ILExpressionPrefix[] prefixes = new ILExpressionPrefix[byteCode.Prefixes.Length];
+ for (int i = 0; i < prefixes.Length; i++) {
+ prefixes[i] = new ILExpressionPrefix((ILCode)byteCode.Prefixes[i].OpCode.Code, byteCode.Prefixes[i].Operand);
+ }
+ expr.Prefixes = prefixes;
+ }
// Label for this instruction
if (byteCode.Label != null) {
View
66 ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
@@ -16,6 +16,7 @@ public enum ILAstOptimizationStep
InlineVariables,
CopyPropagation,
YieldReturn,
+ PropertyAccessInstructions,
SplitToMovableBlocks,
TypeInference,
SimplifyShortCircuit,
@@ -27,6 +28,7 @@ public enum ILAstOptimizationStep
TransformArrayInitializers,
TransformCollectionInitializers,
MakeAssignmentExpression,
+ IntroducePostIncrement,
InlineVariables2,
FindLoops,
FindConditions,
@@ -79,6 +81,9 @@ public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizatio
if (abortBeforeStep == ILAstOptimizationStep.YieldReturn) return;
YieldReturnDecompiler.Run(context, method);
+ if (abortBeforeStep == ILAstOptimizationStep.PropertyAccessInstructions) return;
+ IntroducePropertyAccessInstructions(method);
+
if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
SplitToBasicBlocks(block);
@@ -120,6 +125,10 @@ public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizatio
if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression) return;
modified |= block.RunOptimization(MakeAssignmentExpression);
+ modified |= block.RunOptimization(MakeCompoundAssignments);
+
+ if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) return;
+ modified |= block.RunOptimization(IntroducePostIncrement);
if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) return;
modified |= new ILInlining(method).InlineAllInBlock(block);
@@ -282,6 +291,42 @@ void ReduceBranchInstructionSet(ILBlock block)
}
/// <summary>
+ /// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions.
+ ///
+ /// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)".
+ /// </summary>
+ void IntroducePropertyAccessInstructions(ILBlock method)
+ {
+ foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
+ if (expr.Code == ILCode.Call || expr.Code == ILCode.Callvirt) {
+ MethodReference cecilMethod = (MethodReference)expr.Operand;
+ if (cecilMethod.DeclaringType is ArrayType) {
+ switch (cecilMethod.Name) {
+ case "Get":
+ expr.Code = ILCode.CallGetter;
+ break;
+ case "Set":
+ expr.Code = ILCode.CallSetter;
+ break;
+ case "Address":
+ expr.Code = ILCode.CallGetter;
+ expr.AddPrefix(new ILExpressionPrefix(ILCode.PropertyAddress));
+ break;
+ }
+ } else {
+ MethodDefinition cecilMethodDef = cecilMethod.Resolve();
+ if (cecilMethodDef != null) {
+ if (cecilMethodDef.IsGetter)
+ expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallGetter : ILCode.CallvirtGetter;
+ else if (cecilMethodDef.IsSetter)
+ expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter;
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
/// Group input into a set of blocks that can be later arbitraliby schufled.
/// The method adds necessary branches to make control flow between blocks
/// explicit and thus order independent.
@@ -575,6 +620,27 @@ public static bool IsStoreToArray(this ILCode code)
}
}
+ public static bool IsLoadFromArray(this ILCode code)
+ {
+ switch (code) {
+ case ILCode.Ldelem_Any:
+ case ILCode.Ldelem_I:
+ case ILCode.Ldelem_I1:
+ case ILCode.Ldelem_I2:
+ case ILCode.Ldelem_I4:
+ case ILCode.Ldelem_I8:
+ case ILCode.Ldelem_U1:
+ case ILCode.Ldelem_U2:
+ case ILCode.Ldelem_U4:
+ case ILCode.Ldelem_R4:
+ case ILCode.Ldelem_R8:
+ case ILCode.Ldelem_Ref:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/// <summary>
/// Can the expression be used as a statement in C#?
/// </summary>
View
39 ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
@@ -247,12 +247,24 @@ public static IEnumerable<ILRange> Invert(IEnumerable<ILRange> input, int codeSi
}
}
+ public class ILExpressionPrefix
+ {
+ public readonly ILCode Code;
+ public readonly object Operand;
+
+ public ILExpressionPrefix(ILCode code, object operand = null)
+ {
+ this.Code = code;
+ this.Operand = operand;
+ }
+ }
+
public class ILExpression : ILNode
{
public ILCode Code { get; set; }
public object Operand { get; set; }
public List<ILExpression> Arguments { get; set; }
- public Instruction[] Prefixes { get; set; }
+ public ILExpressionPrefix[] Prefixes { get; set; }
// Mapping to the original instructions (useful for debugging)
public List<ILRange> ILRanges { get; set; }
@@ -283,13 +295,24 @@ public ILExpression(ILCode code, object operand, params ILExpression[] args)
this.ILRanges = new List<ILRange>(1);
}
- public Instruction GetPrefix(Code code)
+ public void AddPrefix(ILExpressionPrefix prefix)
+ {
+ ILExpressionPrefix[] arr = this.Prefixes;
+ if (arr == null)
+ arr = new ILExpressionPrefix[1];
+ else
+ Array.Resize(ref arr, arr.Length + 1);
+ arr[arr.Length - 1] = prefix;
+ this.Prefixes = arr;
+ }
+
+ public ILExpressionPrefix GetPrefix(ILCode code)
{
var prefixes = this.Prefixes;
if (prefixes != null) {
- foreach (Instruction i in prefixes) {
- if (i.OpCode.Code == code)
- return i;
+ foreach (ILExpressionPrefix p in prefixes) {
+ if (p.Code == code)
+ return p;
}
}
return null;
@@ -340,9 +363,9 @@ public override void WriteTo(ITextOutput output)
}
if (this.Prefixes != null) {
- foreach (Instruction prefix in this.Prefixes) {
- output.Write(prefix.OpCode.Name);
- output.Write(' ');
+ foreach (var prefix in this.Prefixes) {
+ output.Write(prefix.Code.GetName());
+ output.Write(". ");
}
}
View
62 ICSharpCode.Decompiler/ILAst/ILCodes.cs
@@ -1,27 +1,5 @@
-// Author:
-// Jb Evain (jbevain@gmail.com)
-//
-// Copyright (c) 2008 - 2010 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using Mono.Cecil;
@@ -268,9 +246,39 @@ public enum ILCode
Ldc_Decimal,
YieldBreak,
YieldReturn,
- DefaultValue, // default(T)
-
- Pattern // used for ILAst pattern nodes
+ /// <summary>
+ /// Represents the 'default(T)' instruction.
+ /// </summary>
+ /// <remarks>Introduced by SimplifyLdObjAndStObj step</remarks>
+ DefaultValue,
+ /// <summary>
+ /// ILExpression with a single child: binary operator.
+ /// This expression means that the binary operator will also assign the new value to its left-hand side.
+ /// 'CompoundAssignment' must not be used for local variables, as inlining (and other) optimizations don't know that it modifies the variable.
+ /// </summary>
+ /// <remarks>Introduced by MakeCompoundAssignments step</remarks>
+ CompoundAssignment,
+ /// <summary>
+ /// Represents the post-increment operator.
+ /// The first argument is the address of the variable to increment (ldloca instruction).
+ /// The second arugment is the amount the variable is incremented by (ldc.i4 instruction)
+ /// </summary>
+ /// <remarks>Introduced by IntroducePostIncrement step</remarks>
+ PostIncrement,
+ PostIncrement_Ovf, // checked variant of PostIncrement
+ PostIncrement_Ovf_Un, // checked variant of PostIncrement, for unsigned integers
+ /// <summary>Calls the getter of a static property (or indexer), or of an instance property on 'base'</summary>
+ CallGetter,
+ /// <summary>Calls the getter of an instance property (or indexer)</summary>
+ CallvirtGetter,
+ /// <summary>Calls the setter of a static property (or indexer), or of an instance property on 'base'</summary>
+ /// <remarks>This allows us to represent "while ((SomeProperty = val) != null) {}"</remarks>
+ CallSetter,
+ /// <summary>Calls the setter of a instance property (or indexer)</summary>
+ CallvirtSetter,
+ /// <summary>Simulates getting the address of a property. Used as prefix on CallGetter or CallvirtGetter.</summary>
+ /// <remarks>Used for postincrement for properties, and to represent the Address() method on multi-dimensional arrays</remarks>
+ PropertyAddress
}
public static class ILCodeUtil
View
10 ICSharpCode.Decompiler/ILAst/PatternMatching.cs
@@ -28,16 +28,6 @@ public static bool Match<T>(this ILNode node, ILCode code, out T operand)
return false;
}
- public static bool Match<T>(this ILNode node, ILCode code, T operand)
- {
- ILExpression expr = node as ILExpression;
- if (expr != null && expr.Prefixes == null && expr.Code == code) {
- Debug.Assert(expr.Arguments.Count == 0);
- return operand.Equals(expr.Operand);
- }
- return false;
- }
-
public static bool Match(this ILNode node, ILCode code, out List<ILExpression> args)
{
ILExpression expr = node as ILExpression;
View
359 ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
@@ -59,6 +59,18 @@ static bool TransformDecimalCtorToConstant(List<ILNode> body, ILExpression expr,
static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos)
{
bool modified = false;
+ expr = SimplifyLdObjAndStObj(expr, ref modified);
+ if (modified && body != null)
+ body[pos] = expr;
+ for (int i = 0; i < expr.Arguments.Count; i++) {
+ expr.Arguments[i] = SimplifyLdObjAndStObj(expr.Arguments[i], ref modified);
+ modified |= SimplifyLdObjAndStObj(null, expr.Arguments[i], -1);
+ }
+ return modified;
+ }
+
+ static ILExpression SimplifyLdObjAndStObj(ILExpression expr, ref bool modified)
+ {
if (expr.Code == ILCode.Initobj) {
expr.Code = ILCode.Stobj;
expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
@@ -84,13 +96,17 @@ static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos)
}
if (newCode != null) {
arg.Code = newCode.Value;
- if (expr.Code == ILCode.Stobj)
+ if (expr.Code == ILCode.Stobj) {
+ arg.InferredType = expr.InferredType;
+ arg.ExpectedType = expr.ExpectedType;
arg.Arguments.Add(arg2);
+ }
arg.ILRanges.AddRange(expr.ILRanges);
- body[pos] = arg;
modified = true;
+ return arg;
+ } else {
+ return expr;
}
- return modified;
}
#endregion
@@ -174,16 +190,14 @@ bool MakeAssignmentExpression(List<ILNode> body, ILExpression expr, int pos)
// stloc(v, exprVar)
// ->
// exprVar = stloc(v, ...))
- ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
ILVariable exprVar;
ILExpression initializer;
+ if (!(expr.Match(ILCode.Stloc, out exprVar, out initializer) && exprVar.IsGenerated))
+ return false;
+ ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
ILVariable v;
ILExpression stLocArg;
- if (expr.Match(ILCode.Stloc, out exprVar, out initializer) &&
- exprVar.IsGenerated &&
- nextExpr.Match(ILCode.Stloc, out v, out stLocArg) &&
- stLocArg.Match(ILCode.Ldloc, exprVar))
- {
+ if (nextExpr.Match(ILCode.Stloc, out v, out stLocArg) && stLocArg.MatchLdloc(exprVar)) {
ILExpression store2 = body.ElementAtOrDefault(pos + 2) as ILExpression;
if (StoreCanBeConvertedToAssignment(store2, exprVar)) {
// expr_44 = ...
@@ -208,17 +222,340 @@ bool MakeAssignmentExpression(List<ILNode> body, ILExpression expr, int pos)
nextExpr.Arguments[0] = initializer;
((ILExpression)body[pos]).Arguments[0] = nextExpr;
return true;
+ } else if ((nextExpr.Code == ILCode.Stsfld || nextExpr.Code == ILCode.CallSetter || nextExpr.Code == ILCode.CallvirtSetter) && nextExpr.Arguments.Count == 1) {
+ // exprVar = ...
+ // stsfld(fld, exprVar)
+ // ->
+ // exprVar = stsfld(fld, ...))
+ if (nextExpr.Arguments[0].MatchLdloc(exprVar)) {
+ body.RemoveAt(pos + 1); // remove stsfld
+ nextExpr.Arguments[0] = initializer;
+ ((ILExpression)body[pos]).Arguments[0] = nextExpr;
+ return true;
+ }
}
return false;
}
bool StoreCanBeConvertedToAssignment(ILExpression store, ILVariable exprVar)
{
- if (store != null && (store.Code == ILCode.Stloc || store.Code == ILCode.Stfld || store.Code == ILCode.Stsfld)) {
- return store.Arguments.Last().Code == ILCode.Ldloc && store.Arguments.Last().Operand == exprVar;
+ if (store == null)
+ return false;
+ switch (store.Code) {
+ case ILCode.Stloc:
+ case ILCode.Stfld:
+ case ILCode.Stsfld:
+ case ILCode.Stobj:
+ case ILCode.CallSetter:
+ case ILCode.CallvirtSetter:
+ break;
+ default:
+ if (!store.Code.IsStoreToArray())
+ return false;
+ break;
+ }
+ return store.Arguments.Last().Code == ILCode.Ldloc && store.Arguments.Last().Operand == exprVar;
+ }
+ #endregion
+
+ #region MakeCompoundAssignments
+ bool MakeCompoundAssignments(List<ILNode> body, ILExpression expr, int pos)
+ {
+ bool modified = false;
+ modified |= MakeCompoundAssignment(expr);
+ // Static fields and local variables are not handled here - those are expressions without side effects
+ // and get handled by ReplaceMethodCallsWithOperators
+ // (which does a reversible transform to the short operator form, as the introduction of checked/unchecked might have to revert to the long form).
+ foreach (ILExpression arg in expr.Arguments) {
+ modified |= MakeCompoundAssignments(null, arg, -1);
+ }
+ if (modified && body != null)
+ new ILInlining(method).InlineInto(body, pos, aggressive: false);
+ return modified;
+ }
+
+ bool MakeCompoundAssignment(ILExpression expr)
+ {
+ // stelem.any(T, ldloc(array), ldloc(pos), <OP>(ldelem.any(T, ldloc(array), ldloc(pos)), <RIGHT>))
+ // or
+ // stobj(T, ldloc(ptr), <OP>(ldobj(T, ldloc(ptr)), <RIGHT>))
+ ILCode expectedLdelemCode;
+ switch (expr.Code) {
+ case ILCode.Stelem_Any:
+ expectedLdelemCode = ILCode.Ldelem_Any;
+ break;
+ case ILCode.Stfld:
+ expectedLdelemCode = ILCode.Ldfld;
+ break;
+ case ILCode.Stobj:
+ expectedLdelemCode = ILCode.Ldobj;
+ break;
+ case ILCode.CallSetter:
+ expectedLdelemCode = ILCode.CallGetter;
+ break;
+ case ILCode.CallvirtSetter:
+ expectedLdelemCode = ILCode.CallvirtGetter;
+ break;
+ default:
+ return false;
+ }
+
+ // all arguments except the last (so either array+pos, or ptr):
+ bool hasGeneratedVar = false;
+ for (int i = 0; i < expr.Arguments.Count - 1; i++) {
+ ILVariable inputVar;
+ if (!expr.Arguments[i].Match(ILCode.Ldloc, out inputVar))
+ return false;
+ hasGeneratedVar |= inputVar.IsGenerated;
+ }
+ // At least one of the variables must be generated; otherwise we just keep the expanded form.
+ // We do this because we want compound assignments to be represented in ILAst only when strictly necessary;
+ // other compound assignments will be introduced by ReplaceMethodCallsWithOperator
+ // (which uses a reversible transformation, see ReplaceMethodCallsWithOperator.RestoreOriginalAssignOperatorAnnotation)
+ if (!hasGeneratedVar)
+ return false;
+
+ ILExpression op = expr.Arguments.Last();
+ if (!CanBeRepresentedAsCompoundAssignment(op.Code))
+ return false;
+ ILExpression ldelem = op.Arguments[0];
+ if (ldelem.Code != expectedLdelemCode)
+ return false;
+ Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1);
+ for (int i = 0; i < ldelem.Arguments.Count; i++) {
+ if (!ldelem.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand))
+ return false;
+ }
+ expr.Code = ILCode.CompoundAssignment;
+ expr.Operand = null;
+ expr.Arguments.RemoveRange(0, ldelem.Arguments.Count);
+ // result is "CompoundAssignment(<OP>(ldelem.any(...), <RIGHT>))"
+ return true;
+ }
+
+ static bool CanBeRepresentedAsCompoundAssignment(ILCode code)
+ {
+ switch (code) {
+ case ILCode.Add:
+ case ILCode.Add_Ovf:
+ case ILCode.Add_Ovf_Un:
+ case ILCode.Sub:
+ case ILCode.Sub_Ovf:
+ case ILCode.Sub_Ovf_Un:
+ case ILCode.Mul:
+ case ILCode.Mul_Ovf:
+ case ILCode.Mul_Ovf_Un:
+ case ILCode.Div:
+ case ILCode.Div_Un:
+ case ILCode.Rem:
+ case ILCode.Rem_Un:
+ case ILCode.And:
+ case ILCode.Or:
+ case ILCode.Xor:
+ case ILCode.Shl:
+ case ILCode.Shr:
+ case ILCode.Shr_Un:
+ return true;
+ default:
+ return false;
+ }
+ }
+ #endregion
+
+ #region IntroducePostIncrement
+ bool IntroducePostIncrement(List<ILNode> body, ILExpression expr, int pos)
+ {
+ bool modified = IntroducePostIncrementForVariables(body, expr, pos);
+ Debug.Assert(body[pos] == expr); // IntroducePostIncrementForVariables shouldn't change the expression reference
+ ILExpression newExpr = IntroducePostIncrementForInstanceFields(expr);
+ if (newExpr != null) {
+ modified = true;
+ body[pos] = newExpr;
+ new ILInlining(method).InlineIfPossible(body, ref pos);
+ }
+ return modified;
+ }
+
+ bool IntroducePostIncrementForVariables(List<ILNode> body, ILExpression expr, int pos)
+ {
+ // Works for variables and static fields/properties
+
+ // expr = ldloc(i)
+ // stloc(i, add(expr, ldc.i4(1)))
+ // ->
+ // expr = postincrement(1, ldloca(i))
+ ILVariable exprVar;
+ ILExpression exprInit;
+ if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated))
+ return false;
+ if (!(exprInit.Code == ILCode.Ldloc || exprInit.Code == ILCode.Ldsfld || (exprInit.Code == ILCode.CallGetter && exprInit.Arguments.Count == 0)))
+ return false;
+
+ ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
+ if (nextExpr == null)
+ return false;
+ if (exprInit.Code == ILCode.CallGetter) {
+ if (!(nextExpr.Code == ILCode.CallSetter && IsGetterSetterPair(exprInit.Operand, nextExpr.Operand)))
+ return false;
+ } else {
+ if (!(nextExpr.Code == (exprInit.Code == ILCode.Ldloc ? ILCode.Stloc : ILCode.Stsfld) && nextExpr.Operand == exprInit.Operand))
+ return false;
+ }
+ ILExpression addExpr = nextExpr.Arguments[0];
+
+ int incrementAmount;
+ ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount);
+ if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar)))
+ return false;
+
+ if (exprInit.Code == ILCode.Ldloc)
+ exprInit.Code = ILCode.Ldloca;
+ else if (exprInit.Code == ILCode.CallGetter)
+ exprInit.AddPrefix(new ILExpressionPrefix(ILCode.PropertyAddress));
+ else
+ exprInit.Code = ILCode.Ldsflda;
+ expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit);
+ body.RemoveAt(pos + 1); // TODO ILRanges
+ return true;
+ }
+
+ static bool IsGetterSetterPair(object getterOperand, object setterOperand)
+ {
+ MethodReference getter = getterOperand as MethodReference;
+ MethodReference setter = setterOperand as MethodReference;
+ if (getter == null || setter == null)
+ return false;
+ if (!TypeAnalysis.IsSameType(getter.DeclaringType, setter.DeclaringType))
+ return false;
+ MethodDefinition getterDef = getter.Resolve();
+ MethodDefinition setterDef = setter.Resolve();
+ if (getterDef == null || setterDef == null)
+ return false;
+ foreach (PropertyDefinition prop in getterDef.DeclaringType.Properties) {
+ if (prop.GetMethod == getterDef)
+ return prop.SetMethod == setterDef;
}
return false;
}
+
+ ILExpression IntroducePostIncrementForInstanceFields(ILExpression expr)
+ {
+ // stfld(field, ldloc(instance), add(stloc(helperVar, ldfld(field, ldloc(instance))), ldc.i4(1)))
+ // -> stloc(helperVar, postincrement(1, ldflda(field, ldloc(instance))))
+
+ // Also works for array elements and pointers:
+
+ // stelem.any(T, ldloc(instance), ldloc(pos), add(stloc(helperVar, ldelem.any(T, ldloc(instance), ldloc(pos))), ldc.i4(1)))
+ // -> stloc(helperVar, postincrement(1, ldelema(ldloc(instance), ldloc(pos))))
+
+ // stobj(T, ldloc(ptr), add(stloc(helperVar, ldobj(T, ldloc(ptr)), ldc.i4(1))))
+ // -> stloc(helperVar, postIncrement(1, ldloc(ptr)))
+
+ // callsetter(set_P, ldloc(instance), add(stloc(helperVar, callgetter(get_P, ldloc(instance))), ldc.i4(1)))
+ // -> stloc(helperVar, postIncrement(1, propertyaddress. callgetter(get_P, ldloc(instance))))
+
+ if (!(expr.Code == ILCode.Stfld || expr.Code.IsStoreToArray() || expr.Code == ILCode.Stobj || expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter))
+ return null;
+
+ // Test that all arguments except the last are ldloc (1 arg for fields and pointers, 2 args for arrays)
+ for (int i = 0; i < expr.Arguments.Count - 1; i++) {
+ if (expr.Arguments[i].Code != ILCode.Ldloc)
+ return null;
+ }
+
+ ILExpression addExpr = expr.Arguments[expr.Arguments.Count - 1];
+ int incrementAmount;
+ ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount);
+ ILVariable helperVar;
+ ILExpression initialValue;
+ if (!(incrementAmount != 0 && addExpr.Arguments[0].Match(ILCode.Stloc, out helperVar, out initialValue)))
+ return null;
+
+ if (expr.Code == ILCode.Stfld) {
+ if (initialValue.Code != ILCode.Ldfld)
+ return null;
+ // There might be two different FieldReference instances, so we compare the field's signatures:
+ FieldReference getField = (FieldReference)initialValue.Operand;
+ FieldReference setField = (FieldReference)expr.Operand;
+ if (!(TypeAnalysis.IsSameType(getField.DeclaringType, setField.DeclaringType)
+ && getField.Name == setField.Name && TypeAnalysis.IsSameType(getField.FieldType, setField.FieldType)))
+ {
+ return null;
+ }
+ } else if (expr.Code == ILCode.Stobj) {
+ if (!(initialValue.Code == ILCode.Ldobj && initialValue.Operand == expr.Operand))
+ return null;
+ } else if (expr.Code == ILCode.CallSetter) {
+ if (!(initialValue.Code == ILCode.CallGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand)))
+ return null;
+ } else if (expr.Code == ILCode.CallvirtSetter) {
+ if (!(initialValue.Code == ILCode.CallvirtGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand)))
+ return null;
+ } else {
+ if (!initialValue.Code.IsLoadFromArray())
+ return null;
+ }
+ Debug.Assert(expr.Arguments.Count - 1 == initialValue.Arguments.Count);
+ for (int i = 0; i < initialValue.Arguments.Count; i++) {
+ if (!initialValue.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand))
+ return null;
+ }
+
+ ILExpression stloc = addExpr.Arguments[0];
+ if (expr.Code == ILCode.Stobj) {
+ stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue.Arguments[0]);
+ } else if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) {
+ stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue);
+ initialValue.AddPrefix(new ILExpressionPrefix(ILCode.PropertyAddress));
+ } else {
+ stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue);
+ initialValue.Code = (expr.Code == ILCode.Stfld ? ILCode.Ldflda : ILCode.Ldelema);
+ }
+ // TODO: ILRanges?
+
+ return stloc;
+ }
+
+ ILCode GetIncrementCode(ILExpression addExpr, out int incrementAmount)
+ {
+ ILCode incrementCode;
+ bool decrement = false;
+ switch (addExpr.Code) {
+ case ILCode.Add:
+ incrementCode = ILCode.PostIncrement;
+ break;
+ case ILCode.Add_Ovf:
+ incrementCode = ILCode.PostIncrement_Ovf;
+ break;
+ case ILCode.Add_Ovf_Un:
+ incrementCode = ILCode.PostIncrement_Ovf_Un;
+ break;
+ case ILCode.Sub:
+ incrementCode = ILCode.PostIncrement;
+ decrement = true;
+ break;
+ case ILCode.Sub_Ovf:
+ incrementCode = ILCode.PostIncrement_Ovf;
+ decrement = true;
+ break;
+ case ILCode.Sub_Ovf_Un:
+ incrementCode = ILCode.PostIncrement_Ovf_Un;
+ decrement = true;
+ break;
+ default:
+ incrementAmount = 0;
+ return ILCode.Nop;
+ }
+ if (addExpr.Arguments[1].Match(ILCode.Ldc_I4, out incrementAmount)) {
+ if (incrementAmount == -1 || incrementAmount == 1) { // TODO pointer increment?
+ if (decrement)
+ incrementAmount = -incrementAmount;
+ return incrementCode;
+ }
+ }
+ incrementAmount = 0;
+ return ILCode.Nop;
+ }
#endregion
#region IntroduceFixedStatements
View
9 ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
@@ -63,6 +63,7 @@ public bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int po
bool isStloc = trueLocVar != null;
ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret;
TypeReference retType = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType;
+ bool retTypeIsBoolean = TypeAnalysis.IsBoolean(retType);
int leftBoolVal;
int rightBoolVal;
ILExpression newExpr;
@@ -72,7 +73,7 @@ public bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int po
// a ? b : true is equivalent to !a || b
// a ? b : false is equivalent to a && b
// a ? false : b is equivalent to !a && b
- if (retType == typeSystem.Boolean &&
+ if (retTypeIsBoolean &&
trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) &&
falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) &&
((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0))
@@ -84,14 +85,14 @@ public bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int po
} else {
newExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
}
- } else if (retType == typeSystem.Boolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal)) {
+ } else if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal)) {
// It can be expressed as logical expression
if (leftBoolVal != 0) {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr);
} else {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr);
}
- } else if (retType == typeSystem.Boolean && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal)) {
+ } else if (retTypeIsBoolean && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal)) {
// It can be expressed as logical expression
if (rightBoolVal != 0) {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
@@ -152,7 +153,7 @@ public bool SimplifyNullCoalescing(List<ILNode> body, ILBasicBlock head, int pos
head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
leftExpr.Match(ILCode.Ldloc, out leftVar) &&
head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
- leftExpr2.Match(ILCode.Ldloc, leftVar) &&
+ leftExpr2.MatchLdloc(leftVar) &&
labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) &&
rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) &&
v == v2 &&
View
84 ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
@@ -231,7 +231,7 @@ void RunInference(ILExpression expr)
/// <returns>The inferred type</returns>
TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
{
- if (expectedType != null && expr.ExpectedType != expectedType) {
+ if (expectedType != null && !IsSameType(expr.ExpectedType, expectedType)) {
expr.ExpectedType = expectedType;
if (expr.Code != ILCode.Stloc) // stloc is special case and never gets re-evaluated
forceInferChildren = true;
@@ -295,12 +295,16 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
#region Call / NewObj
case ILCode.Call:
case ILCode.Callvirt:
+ case ILCode.CallGetter:
+ case ILCode.CallvirtGetter:
+ case ILCode.CallSetter:
+ case ILCode.CallvirtSetter:
{
MethodReference method = (MethodReference)expr.Operand;
if (forceInferChildren) {
for (int i = 0; i < expr.Arguments.Count; i++) {
if (i == 0 && method.HasThis) {
- Instruction constraint = expr.GetPrefix(Code.Constrained);
+ ILExpressionPrefix constraint = expr.GetPrefix(ILCode.Constrained);
if (constraint != null)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType((TypeReference)constraint.Operand));
else if (method.DeclaringType.IsValueType)
@@ -312,7 +316,14 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
}
}
}
- return SubstituteTypeArgs(method.ReturnType, method);
+ if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) {
+ return SubstituteTypeArgs(method.Parameters.Last().ParameterType, method);
+ } else {
+ TypeReference type = SubstituteTypeArgs(method.ReturnType, method);
+ if (expr.GetPrefix(ILCode.PropertyAddress) != null && !(type is ByReferenceType))
+ type = new ByReferenceType(type);
+ return type;
+ }
}
case ILCode.Newobj:
{
@@ -411,7 +422,7 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
if (forceInferChildren) {
if (pointerType is PointerType)
InferTypeForExpression(expr.Arguments[0], new PointerType(operandType));
- else if (operandType != expr.Operand)
+ else if (!IsSameType(operandType, expr.Operand as TypeReference))
InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType));
InferTypeForExpression(expr.Arguments[1], operandType);
}
@@ -431,6 +442,17 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
return typeSystem.IntPtr;
case ILCode.Sizeof:
return typeSystem.Int32;
+ case ILCode.PostIncrement:
+ case ILCode.PostIncrement_Ovf:
+ case ILCode.PostIncrement_Ovf_Un:
+ {
+ TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
+ if (forceInferChildren && elementType != null) {
+ // Assign expected type to the child expression
+ InferTypeForExpression(expr.Arguments[0], new ByReferenceType(elementType));
+ }
+ return elementType;
+ }
#endregion
#region Arithmetic instructions
case ILCode.Not: // bitwise complement
@@ -470,6 +492,14 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
return InferTypeForExpression(expr.Arguments[0], typeSystem.UInt32);
+ case ILCode.CompoundAssignment:
+ {
+ TypeReference varType = InferTypeForExpression(expr.Arguments[0].Arguments[0], null);
+ if (forceInferChildren) {
+ InferTypeForExpression(expr.Arguments[0], varType);
+ }
+ return varType;
+ }
#endregion
#region Constant loading instructions
case ILCode.Ldnull:
@@ -553,14 +583,16 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
case ILCode.Stelem_R8:
case ILCode.Stelem_Ref:
case ILCode.Stelem_Any:
- if (forceInferChildren) {
+ {
ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
- InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
- if (arrayType != null) {
- InferTypeForExpression(expr.Arguments[2], arrayType.ElementType);
+ if (forceInferChildren) {
+ InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
+ if (arrayType != null) {
+ InferTypeForExpression(expr.Arguments[2], arrayType.ElementType);
+ }
}
+ return arrayType != null ? arrayType.ElementType : null;
}
- return null;
#endregion
#region Conversion instructions
case ILCode.Conv_I1:
@@ -604,8 +636,14 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
case ILCode.Conv_Ovf_U_Un:
return HandleConversion(NativeInt, false, expr.Arguments[0], expectedType, typeSystem.UIntPtr);
case ILCode.Conv_R4:
+ if (forceInferChildren) {
+ InferTypeForExpression(expr.Arguments[0], typeSystem.Single);
+ }
return typeSystem.Single;
case ILCode.Conv_R8:
+ if (forceInferChildren) {
+ InferTypeForExpression(expr.Arguments[0], typeSystem.Double);
+ }
return typeSystem.Double;
case ILCode.Conv_R_Un:
return (expectedType != null && expectedType.MetadataType == MetadataType.Single) ? typeSystem.Single : typeSystem.Double;
@@ -707,6 +745,7 @@ static TypeReference SubstituteTypeArgs(TypeReference type, MemberReference memb
TypeReference elementType = SubstituteTypeArgs(arrayType.ElementType, member);
if (elementType != arrayType.ElementType) {
ArrayType newArrayType = new ArrayType(elementType);
+ newArrayType.Dimensions.Clear(); // remove the single dimension that Cecil adds by default
foreach (ArrayDimension d in arrayType.Dimensions)
newArrayType.Dimensions.Add(d);
return newArrayType;
@@ -784,11 +823,11 @@ TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned,
ILExpression right = expr.Arguments[1];
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
- if (leftPreferred == rightPreferred) {
+ if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
- } else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
+ } else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
- } else if (leftPreferred == DoInferTypeForExpression(right, leftPreferred)) {
+ } else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
@@ -813,11 +852,11 @@ TypeReference InferArgumentsInAddition(ILExpression expr, bool? isSigned, TypeRe
InferTypeForExpression(left, typeSystem.IntPtr);
right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred;
- } else if (leftPreferred == rightPreferred) {
+ } else if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
- } else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
+ } else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
- } else if (leftPreferred == DoInferTypeForExpression(right, leftPreferred)) {
+ } else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
@@ -839,11 +878,11 @@ TypeReference InferArgumentsInSubtraction(ILExpression expr, bool? isSigned, Typ
return leftPreferred;
} else {
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
- if (leftPreferred == rightPreferred) {
+ if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
- } else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
+ } else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
- } else if (leftPreferred == DoInferTypeForExpression(right, leftPreferred)) {
+ } else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
@@ -1010,5 +1049,14 @@ public static void Reset(ILBlock method)
v.Type = null;
}
}
+
+ public static bool IsSameType(TypeReference type1, TypeReference type2)
+ {
+ if (type1 == type2)
+ return true;
+ if (type1 == null || type2 == null)
+ return false;
+ return type1.FullName == type2.FullName; // TODO: implement this more efficiently?
+ }
}
}
View
49 ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs
@@ -1,39 +1,46 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
-using System;
-
public class CheckedUnchecked
{
- public void Operators(int a, int b)
+ public int Operators(int a, int b)
{
- int c1 = checked(a + b);
- int u1 = unchecked(a + b);
- int c2 = checked(a - b);
- int u2 = unchecked(a - b);
- int c3 = checked(a * b);
- int u3 = unchecked(a * b);
- int c4 = checked(a / b);
- int u4 = unchecked(a / b);
- int c5 = checked(a % b);
- int u5 = unchecked(a % b);
+ int num = checked(a + b);
+ int num2 = a + b;
+ int num3 = checked(a - b);
+ int num4 = a - b;
+ int num5 = checked(a * b);
+ int num6 = a * b;
+ int num7 = a / b;
+ int num8 = a % b;
+ // The division operators / and % only exist in one form (checked vs. unchecked doesn't matter for them)
+ return num * num2 * num3 * num4 * num5 * num6 * num7 * num8;
}
- public void Cast(int a)
+ public int Cast(int a)
{
- short c1 = checked((short)a);
- short u1 = unchecked((short)a);
- byte c2 = checked((byte)a);
- byte u2 = unchecked((byte)a);
+ short num = checked((short)a);
+ short num2 = (short)a;
+ byte b = checked((byte)a);
+ byte b2 = (byte)a;
+ return num * num2 * b * b2;
}
public void ForWithCheckedIteratorAndUncheckedBody(int n)
{
checked {
for (int i = n + 1; i < n + 1; i++) {
- unchecked {
- n = i * i;
- }
+ n = unchecked(i * i);
+ }
+ }
+ }
+
+ public void ForWithCheckedInitializerAndUncheckedIterator(int n)
+ {
+ checked {
+ int i = n;
+ for (i -= 10; i < n; i = unchecked(i + 1)) {
+ n--;
}
}
}
View
17 ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
@@ -46,7 +46,11 @@ public static List<Action<int>> AnonymousMethodStoreWithinLoop()
for (int i = 0; i < 10; i++)
{
int counter;
- list.Add(x => counter = x);
+ list.Add(delegate(int x)
+ {
+ counter = x;
+ }
+ );
}
return list;
}
@@ -57,13 +61,20 @@ public static List<Action<int>> AnonymousMethodStoreOutsideLoop()
int counter;
for (int i = 0; i < 10; i++)
{
- list.Add(x => counter = x);
+ list.Add(delegate(int x)
+ {
+ counter = x;
+ }
+ );
}
return list;
}
public static Action StaticAnonymousMethodNoClosure()
{
- return delegate { Console.WriteLine(); };
+ return delegate
+ {
+ Console.WriteLine();
+ };
}
}
View
40 ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
@@ -7,42 +7,60 @@ public class ExceptionHandling
{
public void MethodEndingWithEndFinally()
{
- try {
+ try
+ {
throw null;
- } finally {
+ }
+ finally
+ {
Console.WriteLine();
}
}
public void MethodEndingWithRethrow()
{
- try {
+ try
+ {
throw null;
- } catch {
+ }
+ catch
+ {
throw;
}
}
public void TryCatchFinally()
{
- try {
+ try
+ {
Console.WriteLine("Try");
- } catch (Exception ex) {
+ }
+ catch (Exception ex)
+ {
Console.WriteLine(ex.Message);
- } finally {
+ }
+ finally
+ {
Console.WriteLine("Finally");
}
}
public void TryCatchMultipleHandlers()
{
- try {
+ try
+ {
Console.WriteLine("Try");
- } catch (InvalidOperationException ex) {
+ }
+ catch (InvalidOperationException ex)
+ {
Console.WriteLine(ex.Message);
- } catch (Exception ex) {
+ }
+ catch (Exception ex)
+ {
Console.WriteLine(ex.Message);
- } catch {
+ }
+ catch
+ {
Console.WriteLine("other");
}
}
View
4 ICSharpCode.Decompiler/Tests/Generics.cs
@@ -23,7 +23,7 @@ public MyArray(int capacity)
public void Size(int capacity)
{
- Array.Resize(ref this.arr, capacity);
+ Array.Resize<T>(ref this.arr, capacity);
}
public void Grow(int capacity)
@@ -43,7 +43,7 @@ public void Grow(int capacity)
{
}
- public static Dictionary<string, string>.KeyCollection.Enumerator GetEnumerator(Dictionary<string, string> d, MyArray<string>.NestedClass<int> nc)
+ public static Dictionary<string, string>.KeyCollection.Enumerator GetEnumerator(Dictionary<string, string> d, Generics.MyArray<string>.NestedClass<int> nc)
{
// Tests references to inner classes in generic classes
return d.Keys.GetEnumerator();
View
6 ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs
@@ -21,6 +21,12 @@ public override object VisitAttribute(NRefactory.CSharp.Attribute attribute, obj
if (section.Attributes.Count == 0)
section.Remove();
}
+ if (section.AttributeTarget == AttributeTarget.Module && type.Identifier == "UnverifiableCode")
+ {
+ attribute.Remove();
+ if (section.Attributes.Count == 0)
+ section.Remove();
+ }
return null;
}
View
6 ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -4,7 +4,7 @@
<ProjectGuid>{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
- <OutputType>Exe</OutputType>
+ <OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.Decompiler.Tests</RootNamespace>
<AssemblyName>ICSharpCode.Decompiler.Tests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
@@ -14,6 +14,7 @@
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<NoWarn>67,169</NoWarn>
+ <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget>
@@ -27,7 +28,6 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
- <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
@@ -35,7 +35,6 @@
<DebugSymbols>false</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
- <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
@@ -54,6 +53,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CheckedUnchecked.cs" />
+ <Compile Include="IncrementDecrement.cs" />
<Compile Include="Switch.cs" />
<Compile Include="UnsafeCode.cs" />
<Compile Include="YieldReturn.cs" />
View
217 ICSharpCode.Decompiler/Tests/IncrementDecrement.cs
@@ -0,0 +1,217 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+
+public class IncrementDecrement
+{
+ public class MutableClass
+ {
+ public int Field;
+
+ public int Property
+ {
+ get;
+ set;
+ }
+
+ public uint this[string name]
+ {
+ get
+ {
+ return 0u;
+ }
+ set
+ {
+ }
+ }
+ }
+
+ public static int StaticField;
+
+ public static int StaticProperty
+ {
+ get;
+ set;
+ }
+
+ private IncrementDecrement.MutableClass M()
+ {
+ return new IncrementDecrement.MutableClass();
+ }
+
+ private int[,] Array()
+ {
+ return null;
+ }
+
+ private unsafe int* GetPointer()
+ {
+ return null;
+ }
+
+ public int PreIncrementInAddition(int i, int j)
+ {
+ return i + ++j;
+ }
+
+ public int PreIncrementArrayElement(int[] array, int pos)
+ {
+ return --array[pos];
+ }
+
+ public int PreIncrementInstanceField()
+ {
+ return ++this.M().Field;
+ }
+
+ public int PreIncrementInstanceField2(IncrementDecrement.MutableClass m)
+ {
+ return ++m.Field;
+ }
+
+ public int PreIncrementInstanceProperty()
+ {
+ return ++this.M().Property;
+ }
+
+ public int PreIncrementStaticField()
+ {
+ return ++IncrementDecrement.StaticField;
+ }
+
+ public int PreIncrementStaticProperty()
+ {
+ return ++IncrementDecrement.StaticProperty;
+ }
+
+// public uint PreIncrementIndexer(string name)
+// {
+// return ++this.M()[name];
+// }
+
+ public int PreIncrementByRef(ref int i)
+ {
+ return ++i;
+ }
+
+ public unsafe int PreIncrementByPointer()
+ {
+ return ++(*this.GetPointer());
+ }
+
+ public int PreIncrement2DArray()
+ {
+ return ++this.Array()[1, 2];
+ }
+
+ public int CompoundAssignInstanceField()
+ {
+ return this.M().Field *= 10;
+ }
+
+ public int CompoundAssignInstanceProperty()