Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Krüger <mkrueger@xamarin.com>2015-08-14 08:19:35 +0300
committerMike Krüger <mkrueger@xamarin.com>2015-08-14 08:19:35 +0300
commit6e89be0c1970091167e888c1f3565e62c215fd75 (patch)
treea9be66b48b4a510b41006b2d30ba4160f79b5903 /main/contrib
parent6e0f0a9547094cfa6d9b5fc6a151691b667c4d3c (diff)
Fixed 'Bug 33024 - Decompiler fails on most classes'
Diffstat (limited to 'main/contrib')
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/Annotations.cs4
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/AstBuilder.cs30
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs104
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs28
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs31
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs14
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs2
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs6
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs23
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs92
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs40
-rw-r--r--main/contrib/ICSharpCode.Decompiler/CecilExtensions.cs47
-rw-r--r--main/contrib/ICSharpCode.Decompiler/DecompilerException.cs2
-rw-r--r--main/contrib/ICSharpCode.Decompiler/DecompilerSettings.cs16
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs8
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs4
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs22
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj12
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs99
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs8
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs222
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs3
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/ILInlining.cs20
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/PatternMatching.cs6
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/StateRange.cs14
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs15
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs15
-rw-r--r--main/contrib/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs30
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs3
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs32
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs16
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj7
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Tests/TestRunner.cs63
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs2
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Tests/UnsafeCode.cs42
-rw-r--r--main/contrib/ICSharpCode.Decompiler/Tests/ValueTypes.cs17
36 files changed, 815 insertions, 284 deletions
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Annotations.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Annotations.cs
index 7b22dd0136..1c957292ec 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/Annotations.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/Annotations.cs
@@ -10,10 +10,12 @@ namespace ICSharpCode.Decompiler.Ast
public class TypeInformation
{
public readonly TypeReference InferredType;
+ public readonly TypeReference ExpectedType;
- public TypeInformation(TypeReference inferredType)
+ public TypeInformation(TypeReference inferredType, TypeReference expectedType)
{
this.InferredType = inferredType;
+ this.ExpectedType = expectedType;
}
}
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/main/contrib/ICSharpCode.Decompiler/Ast/AstBuilder.cs
index b488cf4840..82d6a71554 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/AstBuilder.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/AstBuilder.cs
@@ -176,14 +176,19 @@ namespace ICSharpCode.Decompiler.Ast
RunTransformations();
syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
- var outputFormatter = new TextTokenWriter(output) { FoldBraces = context.Settings.FoldBraces };
+ var outputFormatter = new TextTokenWriter(output, context) { FoldBraces = context.Settings.FoldBraces };
var formattingPolicy = context.Settings.CSharpFormattingOptions;
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy));
}
public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false)
{
- if (assemblyDefinition.Name.Version != null) {
+ AddAssembly(assemblyDefinition.MainModule, onlyAssemblyLevel);
+ }
+
+ public void AddAssembly(ModuleDefinition moduleDefinition, bool onlyAssemblyLevel = false)
+ {
+ if (moduleDefinition.Assembly != null && moduleDefinition.Assembly.Name.Version != null) {
syntaxTree.AddChild(
new AttributeSection {
AttributeTarget = "assembly",
@@ -192,22 +197,24 @@ namespace ICSharpCode.Decompiler.Ast
Type = new SimpleType("AssemblyVersion")
.WithAnnotation(new TypeReference(
"System.Reflection", "AssemblyVersionAttribute",
- assemblyDefinition.MainModule, assemblyDefinition.MainModule.TypeSystem.Corlib)),
+ moduleDefinition, moduleDefinition.TypeSystem.Corlib)),
Arguments = {
- new PrimitiveExpression(assemblyDefinition.Name.Version.ToString())
+ new PrimitiveExpression(moduleDefinition.Assembly.Name.Version.ToString())
}
}
}
}, EntityDeclaration.AttributeRole);
}
- ConvertCustomAttributes(syntaxTree, assemblyDefinition, "assembly");
- ConvertSecurityAttributes(syntaxTree, assemblyDefinition, "assembly");
- ConvertCustomAttributes(syntaxTree, assemblyDefinition.MainModule, "module");
- AddTypeForwarderAttributes(syntaxTree, assemblyDefinition.MainModule, "assembly");
+ if (moduleDefinition.Assembly != null) {
+ ConvertCustomAttributes(syntaxTree, moduleDefinition.Assembly, "assembly");
+ ConvertSecurityAttributes(syntaxTree, moduleDefinition.Assembly, "assembly");
+ }
+ ConvertCustomAttributes(syntaxTree, moduleDefinition, "module");
+ AddTypeForwarderAttributes(syntaxTree, moduleDefinition, "assembly");
if (!onlyAssemblyLevel) {
- foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) {
+ foreach (TypeDefinition typeDef in moduleDefinition.Types) {
// Skip the <Module> class
if (typeDef.Name == "<Module>") continue;
// Skip any hidden types
@@ -330,19 +337,22 @@ namespace ICSharpCode.Decompiler.Ast
if (typeDef.IsEnum) {
long expectedEnumMemberValue = 0;
bool forcePrintingInitializers = IsFlagsEnum(typeDef);
+ TypeCode baseType = TypeCode.Int32;
foreach (FieldDefinition field in typeDef.Fields) {
if (!field.IsStatic) {
// the value__ field
if (field.FieldType != typeDef.Module.TypeSystem.Int32) {
astType.AddChild(ConvertType(field.FieldType), Roles.BaseType);
+ baseType = TypeAnalysis.GetTypeCode(field.FieldType);
}
} else {
EnumMemberDeclaration enumMember = new EnumMemberDeclaration();
+ ConvertCustomAttributes(enumMember, field);
enumMember.AddAnnotation(field);
enumMember.Name = CleanName(field.Name);
long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false);
if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) {
- enumMember.AddChild(new PrimitiveExpression(field.Constant), EnumMemberDeclaration.InitializerRole);
+ enumMember.AddChild(new PrimitiveExpression(CSharpPrimitiveCast.Cast(baseType, field.Constant, false)), EnumMemberDeclaration.InitializerRole);
}
expectedEnumMemberValue = memberValue + 1;
astType.AddChild(enumMember, Roles.TypeMemberRole);
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/main/contrib/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
index fae41f6860..e98e8dbc71 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
@@ -52,8 +52,8 @@ namespace ICSharpCode.Decompiler.Ast
/// These are used to update the parameter names when the decompiler generates names for the parameters.</param>
/// <returns>Block for the method body</returns>
public static BlockStatement CreateMethodBody(MethodDefinition methodDef,
- DecompilerContext context,
- IEnumerable<ParameterDeclaration> parameters = null)
+ DecompilerContext context,
+ IEnumerable<ParameterDeclaration> parameters = null)
{
MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
@@ -103,8 +103,8 @@ namespace ICSharpCode.Decompiler.Ast
if (parameters != null) {
foreach (var pair in (from p in parameters
- join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter
- select new { p, v.Name }))
+ join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter
+ select new { p, v.Name }))
{
pair.p.Name = pair.Name;
}
@@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.Ast
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) {
if (catchClause.ExceptionVariable == null
- && (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object))
+ && (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object))
{
tryCatchStmt.CatchClauses.Add(new Ast.CatchClause { Body = TransformBlock(catchClause) });
} else {
@@ -262,7 +262,7 @@ namespace ICSharpCode.Decompiler.Ast
result = node;
if (result != null)
- result = result.WithAnnotation(new TypeInformation(expr.InferredType));
+ result = result.WithAnnotation(new TypeInformation(expr.InferredType, expr.ExpectedType));
if (result != null)
return result.WithAnnotation(ilRanges);
@@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
- if (byteCode.Arguments[0].ExpectedType is PointerType) {
- arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
- boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
- } else if (byteCode.Arguments[1].ExpectedType is PointerType) {
- arg1 = DivideBySize(arg1, ((PointerType)byteCode.InferredType).ElementType);
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
+ boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
+ if (byteCode.Arguments[0].ExpectedType is PointerType ||
+ byteCode.Arguments[1].ExpectedType is PointerType) {
boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
- } else {
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@@ -314,12 +308,9 @@ namespace ICSharpCode.Decompiler.Ast
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
+ boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
if (byteCode.Arguments[0].ExpectedType is PointerType) {
- arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
- } else {
- boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
@@ -460,12 +451,30 @@ namespace ICSharpCode.Decompiler.Ast
// can also mean Inequality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne;
+
+ // when comparing signed integral values using Cgt_Un with 0
+ // the Ast should actually contain InEquality since "(uint)a > 0u" is identical to "a != 0"
+ if (arg1Type.IsSignedIntegralType())
+ {
+ var p = arg2 as Ast.PrimitiveExpression;
+ if (p != null && p.Value.IsZero()) goto case ILCode.Cne;
+ }
+
goto case ILCode.Cgt;
}
case ILCode.Cle_Un: {
// can also mean Equality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq;
+
+ // when comparing signed integral values using Cle_Un with 0
+ // the Ast should actually contain Equality since "(uint)a <= 0u" is identical to "a == 0"
+ if (arg1Type.IsSignedIntegralType())
+ {
+ var p = arg2 as Ast.PrimitiveExpression;
+ if (p != null && p.Value.IsZero()) goto case ILCode.Ceq;
+ }
+
goto case ILCode.Cle;
}
case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
@@ -706,7 +715,7 @@ namespace ICSharpCode.Decompiler.Ast
}
return new StackAllocExpression {
Type = AstBuilder.ConvertType(type),
- CountExpression = DivideBySize(arg1, type)
+ CountExpression = arg1
};
}
case ILCode.Mkrefany:
@@ -849,7 +858,7 @@ namespace ICSharpCode.Decompiler.Ast
args[args.Count - 1].AddAnnotation(new ParameterDeclarationAnnotation(byteCode));
return args[args.Count - 1];
case ILCode.Await:
- return new UnaryOperatorExpression(UnaryOperatorType.Await, arg1);
+ return new UnaryOperatorExpression(UnaryOperatorType.Await, UnpackDirectionExpression(arg1));
case ILCode.NullableOf:
case ILCode.ValueOf:
return arg1;
@@ -902,45 +911,6 @@ namespace ICSharpCode.Decompiler.Ast
}
}
- /// <summary>
- /// Divides expr by the size of 'type'.
- /// </summary>
- Expression DivideBySize(Expression expr, TypeReference type)
- {
- CastExpression cast = expr as CastExpression;
- if (cast != null && cast.Type is PrimitiveType && ((PrimitiveType)cast.Type).Keyword == "int")
- expr = cast.Expression.Detach();
-
- Expression sizeOfExpression;
- switch (TypeAnalysis.GetInformationAmount(type)) {
- case 1:
- case 8:
- sizeOfExpression = new PrimitiveExpression(1);
- break;
- case 16:
- sizeOfExpression = new PrimitiveExpression(2);
- break;
- case 32:
- sizeOfExpression = new PrimitiveExpression(4);
- break;
- case 64:
- sizeOfExpression = new PrimitiveExpression(8);
- break;
- default:
- sizeOfExpression = new SizeOfExpression { Type = AstBuilder.ConvertType(type) };
- break;
- }
-
- BinaryOperatorExpression boe = expr as BinaryOperatorExpression;
- if (boe != null && boe.Operator == BinaryOperatorType.Multiply && sizeOfExpression.IsMatch(boe.Right))
- return boe.Left.Detach();
-
- if (sizeOfExpression.IsMatch(expr))
- return new PrimitiveExpression(1);
-
- return new BinaryOperatorExpression(expr, BinaryOperatorType.Divide, sizeOfExpression);
- }
-
Expression MakeDefaultValue(TypeReference type)
{
TypeDefinition typeDef = type.Resolve();
@@ -975,10 +945,7 @@ namespace ICSharpCode.Decompiler.Ast
// Unpack any DirectionExpression that is used as target for the call
// (calling methods on value types implicitly passes the first argument by reference)
- if (target is DirectionExpression) {
- target = ((DirectionExpression)target).Expression;
- target.Remove(); // detach from DirectionExpression
- }
+ target = UnpackDirectionExpression(target);
if (cecilMethodDef != null) {
// convert null.ToLower() to ((string)null).ToLower()
@@ -1078,6 +1045,15 @@ namespace ICSharpCode.Decompiler.Ast
return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod);
}
+ static Expression UnpackDirectionExpression(Expression target)
+ {
+ if (target is DirectionExpression) {
+ return ((DirectionExpression)target).Expression.Detach();
+ } else {
+ return target;
+ }
+ }
+
static void AdjustArgumentsForMethodCall(MethodReference cecilMethod, List<Expression> methodArgs)
{
// Convert 'ref' into 'out' where necessary
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs b/main/contrib/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs
index b77284cb24..4f52b89d0d 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs
@@ -30,6 +30,7 @@ namespace ICSharpCode.Decompiler.Ast
public class TextTokenWriter : TokenWriter
{
readonly ITextOutput output;
+ readonly DecompilerContext context;
readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
int braceLevelWithinType = -1;
bool inDocumentationComment = false;
@@ -40,15 +41,22 @@ namespace ICSharpCode.Decompiler.Ast
public bool FoldBraces = false;
- public TextTokenWriter(ITextOutput output)
+ public TextTokenWriter(ITextOutput output, DecompilerContext context)
{
if (output == null)
throw new ArgumentNullException("output");
+ if (context == null)
+ throw new ArgumentNullException("context");
this.output = output;
+ this.context = context;
}
public override void WriteIdentifier(Identifier identifier)
{
+ if (identifier.IsVerbatim || CSharpOutputVisitor.IsKeyword(identifier.Name, identifier)) {
+ output.Write('@');
+ }
+
var definition = GetCurrentDefinition();
if (definition != null) {
output.WriteDefinition(identifier.Name, definition, false);
@@ -89,6 +97,24 @@ namespace ICSharpCode.Decompiler.Ast
if (memberRef == null && node.Role == Roles.TargetExpression && (node.Parent is InvocationExpression || node.Parent is ObjectCreateExpression)) {
memberRef = node.Parent.Annotation<MemberReference>();
}
+ if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && memberRef != null) {
+ var declaringType = memberRef.DeclaringType.Resolve();
+ if (declaringType != null && declaringType.IsDelegate())
+ return null;
+ }
+ return FilterMemberReference(memberRef);
+ }
+
+ MemberReference FilterMemberReference(MemberReference memberRef)
+ {
+ if (memberRef == null)
+ return null;
+
+ if (context.Settings.AutomaticEvents && memberRef is FieldDefinition) {
+ var field = (FieldDefinition)memberRef;
+ return field.DeclaringType.Events.FirstOrDefault(ev => ev.Name == field.Name) ?? memberRef;
+ }
+
return memberRef;
}
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs
index 3b38762651..ed1155ba15 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs
@@ -144,6 +144,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName))
continue;
}
+ IfElseStatement ies = stmt as IfElseStatement;
+ if (ies != null) {
+ foreach (var child in IfElseChainChildren(ies)) {
+ BlockStatement subBlock = child as BlockStatement;
+ if (subBlock != null)
+ DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops);
+ }
+ continue;
+ }
foreach (AstNode child in stmt.Children) {
BlockStatement subBlock = child as BlockStatement;
if (subBlock != null) {
@@ -268,6 +277,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
}
}
+
+ IfElseStatement ies = stmt as IfElseStatement;
+ if (ies != null) {
+ foreach (var child in IfElseChainChildren(ies)) {
+ if (!(child is BlockStatement) && UsesVariable(child, variableName))
+ return false;
+ }
+ return true;
+ }
// We can move the variable into a sub-block only if the variable is used in only that sub-block (and not in expressions such as the loop condition)
for (AstNode child = stmt.FirstChild; child != null; child = child.NextSibling) {
@@ -285,6 +303,19 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
return true;
}
+
+ static IEnumerable<AstNode> IfElseChainChildren(IfElseStatement ies)
+ {
+ IfElseStatement prev;
+ do {
+ yield return ies.Condition;
+ yield return ies.TrueStatement;
+ prev = ies;
+ ies = ies.FalseStatement as IfElseStatement;
+ } while (ies != null);
+ if (!prev.FalseStatement.IsNull)
+ yield return prev.FalseStatement;
+ }
static bool HasNestedBlocks(AstNode node)
{
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
index 9c5aa97f6e..0741466f95 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
@@ -180,8 +180,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (AstNode node in body.Descendants) {
if (node is ThisReferenceExpression)
node.ReplaceWith(target.Clone());
-
}
+ Expression replacement;
if (isLambda) {
LambdaExpression lambda = new LambdaExpression();
lambda.CopyAnnotationsFrom(ame);
@@ -189,11 +189,19 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression;
returnExpr.Remove();
lambda.Body = returnExpr;
- objectCreateExpression.ReplaceWith(lambda);
+ replacement = lambda;
} else {
ame.Body = body;
- objectCreateExpression.ReplaceWith(ame);
+ replacement = ame;
+ }
+ var expectedType = objectCreateExpression.Annotation<TypeInformation>().ExpectedType.Resolve();
+ if (expectedType != null && !expectedType.IsDelegate()) {
+ var simplifiedDelegateCreation = (ObjectCreateExpression)objectCreateExpression.Clone();
+ simplifiedDelegateCreation.Arguments.Clear();
+ simplifiedDelegateCreation.Arguments.Add(replacement);
+ replacement = simplifiedDelegateCreation;
}
+ objectCreateExpression.ReplaceWith(replacement);
return true;
}
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs
index 32f7cb0dbe..ffd6f5ac76 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs
@@ -804,7 +804,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return new IndexerExpression(targetConverted, indexConverted);
}
IList<Expression> indexesConverted = ConvertExpressionsArray(index);
- if (indexConverted != null) {
+ if (indexesConverted != null) {
return new IndexerExpression(targetConverted, indexesConverted);
}
return null;
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs
index 43548e38d4..a9e72564f3 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs
@@ -35,7 +35,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
protected override bool VisitChildren(AstNode node, object data)
{
bool result = false;
- for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
+ AstNode next;
+ for (AstNode child = node.FirstChild; child != null; child = next) {
+ // Store next to allow the loop to continue
+ // if the visitor removes/replaces child.
+ next = child.NextSibling;
result |= child.AcceptVisitor(this, data);
}
if (result && node is EntityDeclaration && !(node is Accessor)) {
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
index 5c3784fa4c..4182eec8f2 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
@@ -38,24 +38,23 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public void Run(AstNode compilationUnit)
{
- if (!context.Settings.UsingDeclarations)
- return;
-
// First determine all the namespaces that need to be imported:
compilationUnit.AcceptVisitor(new FindRequiredImports(this), null);
importedNamespaces.Add("System"); // always import System, even when not necessary
- // Now add using declarations for those namespaces:
- foreach (string ns in importedNamespaces.OrderByDescending(n => n)) {
- // we go backwards (OrderByDescending) through the list of namespaces because we insert them backwards
- // (always inserting at the start of the list)
- string[] parts = ns.Split('.');
- AstType nsType = new SimpleType(parts[0]);
- for (int i = 1; i < parts.Length; i++) {
- nsType = new MemberType { Target = nsType, MemberName = parts[i] };
+ if (context.Settings.UsingDeclarations) {
+ // Now add using declarations for those namespaces:
+ foreach (string ns in importedNamespaces.OrderByDescending(n => n)) {
+ // we go backwards (OrderByDescending) through the list of namespaces because we insert them backwards
+ // (always inserting at the start of the list)
+ string[] parts = ns.Split('.');
+ AstType nsType = new SimpleType(parts[0]);
+ for (int i = 1; i < parts.Length; i++) {
+ nsType = new MemberType { Target = nsType, MemberName = parts[i] };
+ }
+ compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, SyntaxTree.MemberRole);
}
- compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, SyntaxTree.MemberRole);
}
if (!context.Settings.FullyQualifyAmbiguousTypeNames)
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
index 22d1afe627..bff2cc6b95 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
@@ -99,6 +99,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (result != null)
return result;
}
+ AstNode simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement);
+ if (simplifiedIfElse != null)
+ return simplifiedIfElse;
return base.VisitIfElseStatement(ifElseStatement, data);
}
@@ -614,6 +617,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
static readonly AstNode lockTryCatchPattern = new TryCatchStatement {
TryBlock = new BlockStatement {
+ new OptionalNode(new VariableDeclarationStatement()).ToStatement(),
new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke(
"Enter", new AnyNode("enter"),
new DirectionExpression {
@@ -626,21 +630,57 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new IfElseStatement {
Condition = new Backreference("flag"),
TrueStatement = new BlockStatement {
- new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new NamedNode("exit", new IdentifierExpression(Pattern.AnyString)))
+ new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new AnyNode("exit"))
}
}
}};
+
+ static readonly AstNode oldMonitorCallPattern = new ExpressionStatement(
+ new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Enter", new AnyNode("enter"))
+ );
+
+ static readonly AstNode oldLockTryCatchPattern = new TryCatchStatement
+ {
+ TryBlock = new BlockStatement {
+ new Repeat(new AnyNode()).ToStatement()
+ },
+ FinallyBlock = new BlockStatement {
+ new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new AnyNode("exit"))
+ }
+ };
+
+ bool AnalyzeLockV2(ExpressionStatement node, out Expression enter, out Expression exit)
+ {
+ enter = null;
+ exit = null;
+ Match m1 = oldMonitorCallPattern.Match(node);
+ if (!m1.Success) return false;
+ Match m2 = oldLockTryCatchPattern.Match(node.NextSibling);
+ if (!m2.Success) return false;
+ enter = m1.Get<Expression>("enter").Single();
+ exit = m2.Get<Expression>("exit").Single();
+ return true;
+ }
+
+ bool AnalyzeLockV4(ExpressionStatement node, out Expression enter, out Expression exit)
+ {
+ enter = null;
+ exit = null;
+ Match m1 = lockFlagInitPattern.Match(node);
+ if (!m1.Success) return false;
+ Match m2 = lockTryCatchPattern.Match(node.NextSibling);
+ if (!m2.Success) return false;
+ enter = m2.Get<Expression>("enter").Single();
+ exit = m2.Get<Expression>("exit").Single();
+ return m1.Get<IdentifierExpression>("variable").Single().Identifier == m2.Get<IdentifierExpression>("flag").Single().Identifier;
+ }
public LockStatement TransformLock(ExpressionStatement node)
{
- Match m1 = lockFlagInitPattern.Match(node);
- if (!m1.Success) return null;
- AstNode tryCatch = node.NextSibling;
- Match m2 = lockTryCatchPattern.Match(tryCatch);
- if (!m2.Success) return null;
- if (m1.Get<IdentifierExpression>("variable").Single().Identifier == m2.Get<IdentifierExpression>("flag").Single().Identifier) {
- Expression enter = m2.Get<Expression>("enter").Single();
- IdentifierExpression exit = m2.Get<IdentifierExpression>("exit").Single();
+ Expression enter, exit;
+ bool isV2 = AnalyzeLockV2(node, out enter, out exit);
+ if (isV2 || AnalyzeLockV4(node, out enter, out exit)) {
+ AstNode tryCatch = node.NextSibling;
if (!exit.IsMatch(enter)) {
// If exit and enter are not the same, then enter must be "exit = ..."
AssignmentExpression assign = enter as AssignmentExpression;
@@ -656,7 +696,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
LockStatement l = new LockStatement();
l.Expression = enter.Detach();
l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.Detach();
- ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove(); // Remove 'Enter()' call
+ if (!isV2) // Remove 'Enter()' call
+ ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove();
tryCatch.ReplaceWith(l);
node.Remove(); // remove flag variable
return l;
@@ -1047,5 +1088,36 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null;
}
#endregion
+
+ #region Simplify cascading if-else-if statements
+ static readonly IfElseStatement cascadingIfElsePattern = new IfElseStatement
+ {
+ Condition = new AnyNode(),
+ TrueStatement = new AnyNode(),
+ FalseStatement = new BlockStatement {
+ Statements = {
+ new NamedNode(
+ "nestedIfStatement",
+ new IfElseStatement {
+ Condition = new AnyNode(),
+ TrueStatement = new AnyNode(),
+ FalseStatement = new OptionalNode(new AnyNode())
+ }
+ )
+ }
+ }
+ };
+
+ AstNode SimplifyCascadingIfElseStatements(IfElseStatement node)
+ {
+ Match m = cascadingIfElsePattern.Match(node);
+ if (m.Success) {
+ IfElseStatement elseIf = m.Get<IfElseStatement>("nestedIfStatement").Single();
+ node.FalseStatement = elseIf.Detach();
+ }
+
+ return null;
+ }
+ #endregion
}
}
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs b/main/contrib/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs
index 8de45cca56..f0f5ece532 100644
--- a/main/contrib/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs
@@ -32,9 +32,11 @@ namespace ICSharpCode.Decompiler.Ast
if (resolveTypeArguments)
return BaseTypes(derivedType).Any(t => t.Item == baseType);
else {
- var comparableBaseType = baseType.ResolveOrThrow();
+ var comparableBaseType = baseType.Resolve();
+ if (comparableBaseType == null)
+ return false;
while (derivedType.BaseType != null) {
- var resolvedBaseType = derivedType.BaseType.ResolveOrThrow();
+ var resolvedBaseType = derivedType.BaseType.Resolve();
if (resolvedBaseType == null)
return false;
if (comparableBaseType == resolvedBaseType)
@@ -185,24 +187,32 @@ namespace ICSharpCode.Decompiler.Ast
if (derivedType == null)
throw new ArgumentNullException("derivedType");
- var visibility = IsVisibleFromDerived(baseMember);
- if (visibility.HasValue)
- return visibility.Value;
+ MethodAttributes attrs = GetAccessAttributes(baseMember) & MethodAttributes.MemberAccessMask;
+ if (attrs == MethodAttributes.Private)
+ return false;
if (baseMember.DeclaringType.Module == derivedType.Module)
return true;
- // TODO: Check also InternalsVisibleToAttribute.
- return false;
- }
- private static bool? IsVisibleFromDerived(IMemberDefinition member)
- {
- MethodAttributes attrs = GetAccessAttributes(member) & MethodAttributes.MemberAccessMask;
- if (attrs == MethodAttributes.Private)
+ if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem) {
+ var derivedTypeAsm = derivedType.Module.Assembly;
+ var asm = baseMember.DeclaringType.Module.Assembly;
+
+ if (asm.HasCustomAttributes) {
+ var attributes = asm.CustomAttributes
+ .Where(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.InternalsVisibleToAttribute");
+ foreach (var attribute in attributes) {
+ string assemblyName = attribute.ConstructorArguments[0].Value as string;
+ assemblyName = assemblyName.Split(',')[0]; // strip off any public key info
+ if (assemblyName == derivedTypeAsm.Name.Name)
+ return true;
+ }
+ }
+
return false;
- if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem)
- return null;
- return true;
+ }
+
+ return true;
}
private static MethodAttributes GetAccessAttributes(IMemberDefinition member)
diff --git a/main/contrib/ICSharpCode.Decompiler/CecilExtensions.cs b/main/contrib/ICSharpCode.Decompiler/CecilExtensions.cs
index cc047e09cd..0c7cb1e409 100644
--- a/main/contrib/ICSharpCode.Decompiler/CecilExtensions.cs
+++ b/main/contrib/ICSharpCode.Decompiler/CecilExtensions.cs
@@ -126,6 +126,41 @@ namespace ICSharpCode.Decompiler
return false;
return type.IsValueType || type.IsVoid();
}
+
+ /// <summary>
+ /// checks if the given TypeReference is one of the following types:
+ /// [sbyte, short, int, long, IntPtr]
+ /// </summary>
+ public static bool IsSignedIntegralType(this TypeReference type)
+ {
+ return type.MetadataType == MetadataType.SByte ||
+ type.MetadataType == MetadataType.Int16 ||
+ type.MetadataType == MetadataType.Int32 ||
+ type.MetadataType == MetadataType.Int64 ||
+ type.MetadataType == MetadataType.IntPtr;
+ }
+
+ /// <summary>
+ /// checks if the given value is a numeric zero-value.
+ /// NOTE that this only works for types: [sbyte, short, int, long, IntPtr, byte, ushort, uint, ulong, float, double and decimal]
+ /// </summary>
+ public static bool IsZero(this object value)
+ {
+ return value.Equals((sbyte)0) ||
+ value.Equals((short)0) ||
+ value.Equals(0) ||
+ value.Equals(0L) ||
+ value.Equals(IntPtr.Zero) ||
+ value.Equals((byte)0) ||
+ value.Equals((ushort)0) ||
+ value.Equals(0u) ||
+ value.Equals(0UL) ||
+ value.Equals(0.0f) ||
+ value.Equals(0.0) ||
+ value.Equals((decimal)0);
+
+ }
+
#endregion
/// <summary>
@@ -190,6 +225,7 @@ namespace ICSharpCode.Decompiler
return null;
}
+ [Obsolete("throwing exceptions is considered a bug")]
public static TypeDefinition ResolveOrThrow(this TypeReference typeReference)
{
var resolved = typeReference.Resolve();
@@ -323,5 +359,16 @@ namespace ICSharpCode.Decompiler
}
return false;
}
+
+ public static bool IsDelegate(this TypeDefinition type)
+ {
+ if (type.BaseType != null && type.BaseType.Namespace == "System") {
+ if (type.BaseType.Name == "MulticastDelegate")
+ return true;
+ if (type.BaseType.Name == "Delegate" && type.Name != "MulticastDelegate")
+ return true;
+ }
+ return false;
+ }
}
}
diff --git a/main/contrib/ICSharpCode.Decompiler/DecompilerException.cs b/main/contrib/ICSharpCode.Decompiler/DecompilerException.cs
index d62b516da4..5f5f022fc5 100644
--- a/main/contrib/ICSharpCode.Decompiler/DecompilerException.cs
+++ b/main/contrib/ICSharpCode.Decompiler/DecompilerException.cs
@@ -23,7 +23,7 @@ using Mono.Cecil;
namespace ICSharpCode.Decompiler
{
/// <summary>
- /// Desctiption of DecompilerException.
+ /// Description of DecompilerException.
/// </summary>
public class DecompilerException : Exception, ISerializable
{
diff --git a/main/contrib/ICSharpCode.Decompiler/DecompilerSettings.cs b/main/contrib/ICSharpCode.Decompiler/DecompilerSettings.cs
index c3790203da..a354291ed2 100644
--- a/main/contrib/ICSharpCode.Decompiler/DecompilerSettings.cs
+++ b/main/contrib/ICSharpCode.Decompiler/DecompilerSettings.cs
@@ -295,6 +295,21 @@ namespace ICSharpCode.Decompiler
}
}
+ bool makeAssignmentExpressions = true;
+
+ /// <summary>
+ /// Gets/Sets whether to use assignment expressions such as in while ((count = Do()) != 0) ;
+ /// </summary>
+ public bool MakeAssignmentExpressions {
+ get { return makeAssignmentExpressions; }
+ set {
+ if (makeAssignmentExpressions != value) {
+ makeAssignmentExpressions = value;
+ OnPropertyChanged("MakeAssignmentExpressions");
+ }
+ }
+ }
+
bool alwaysGenerateExceptionVariableForCatchBlocks = false;
/// <summary>
@@ -318,6 +333,7 @@ namespace ICSharpCode.Decompiler
if (csharpFormattingOptions == null) {
csharpFormattingOptions = FormattingOptionsFactory.CreateAllman();
csharpFormattingOptions.IndentSwitchBody = false;
+ csharpFormattingOptions.ArrayInitializerWrapping = Wrapping.WrapAlways;
}
return csharpFormattingOptions;
}
diff --git a/main/contrib/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs b/main/contrib/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
index 4c2080045e..ea6e54dbea 100644
--- a/main/contrib/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
@@ -359,6 +359,10 @@ namespace ICSharpCode.Decompiler.Disassembler
} else if (operand is float) {
float val = (float)operand;
if (val == 0) {
+ if (1 / val == float.NegativeInfinity) {
+ // negative zero is a special case
+ writer.Write('-');
+ }
writer.Write("0.0");
} else if (float.IsInfinity(val) || float.IsNaN(val)) {
byte[] data = BitConverter.GetBytes(val);
@@ -375,6 +379,10 @@ namespace ICSharpCode.Decompiler.Disassembler
} else if (operand is double) {
double val = (double)operand;
if (val == 0) {
+ if (1 / val == double.NegativeInfinity) {
+ // negative zero is a special case
+ writer.Write('-');
+ }
writer.Write("0.0");
} else if (double.IsInfinity(val) || double.IsNaN(val)) {
byte[] data = BitConverter.GetBytes(val);
diff --git a/main/contrib/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/main/contrib/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
index a45a718207..ef6d32e69d 100644
--- a/main/contrib/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
@@ -54,8 +54,8 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA);
output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize);
output.WriteLine(".maxstack {0}", body.MaxStackSize);
- if (method.DeclaringType.Module.Assembly.EntryPoint == method)
- output.WriteLine (".entrypoint");
+ if (method.DeclaringType.Module.Assembly != null && method.DeclaringType.Module.Assembly.EntryPoint == method)
+ output.WriteLine (".entrypoint");
if (method.Body.HasVariables) {
output.Write(".locals ");
diff --git a/main/contrib/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/main/contrib/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
index 1a7d1a4f71..fcdb2b926e 100644
--- a/main/contrib/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
@@ -33,7 +33,7 @@ namespace ICSharpCode.Decompiler.Disassembler
/// </summary>
public sealed class ReflectionDisassembler
{
- ITextOutput output;
+ readonly ITextOutput output;
CancellationToken cancellationToken;
bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings)
MethodBodyDisassembler methodBodyDisassembler;
@@ -213,8 +213,9 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine();
}
}
+ WriteParameterAttributes(0, method.MethodReturnType, method.MethodReturnType);
foreach (var p in method.Parameters) {
- WriteParameterAttributes(p);
+ WriteParameterAttributes(p.Index + 1, p, p);
}
WriteSecurityDeclarations(method);
@@ -613,22 +614,17 @@ namespace ICSharpCode.Decompiler.Disassembler
}
}
- bool HasParameterAttributes(ParameterDefinition p)
+ void WriteParameterAttributes(int index, IConstantProvider cp, ICustomAttributeProvider cap)
{
- return p.HasConstant || p.HasCustomAttributes;
- }
-
- void WriteParameterAttributes(ParameterDefinition p)
- {
- if (!HasParameterAttributes(p))
+ if (!cp.HasConstant && !cap.HasCustomAttributes)
return;
- output.Write(".param [{0}]", p.Index + 1);
- if (p.HasConstant) {
+ output.Write(".param [{0}]", index);
+ if (cp.HasConstant) {
output.Write(" = ");
- WriteConstant(p.Constant);
+ WriteConstant(cp.Constant);
}
output.WriteLine();
- WriteAttributes(p.CustomAttributes);
+ WriteAttributes(cap.CustomAttributes);
}
void WriteConstant(object constant)
diff --git a/main/contrib/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/main/contrib/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index b46b95935f..08ad03daf0 100644
--- a/main/contrib/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/main/contrib/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -56,6 +56,7 @@
<Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NameVariables.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" />
+ <Compile Include="Ast\TextTokenWriter.cs" />
<Compile Include="Ast\Transforms\AddCheckedBlocks.cs" />
<Compile Include="Ast\Transforms\CombineQueryExpressions.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
@@ -97,6 +98,8 @@
<Compile Include="FlowAnalysis\SsaOptimization.cs" />
<Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
+ <Compile Include="ILAst\AsyncDecompiler.cs" />
+ <Compile Include="ILAst\LiftedOperators.cs" />
<Compile Include="ILAst\InitializerPeepholeTransforms.cs" />
<Compile Include="ILAst\DefaultDictionary.cs" />
<Compile Include="ILAst\GotoRemoval.cs" />
@@ -109,6 +112,8 @@
<Compile Include="ILAst\PatternMatching.cs" />
<Compile Include="ILAst\PeepholeTransform.cs" />
<Compile Include="ILAst\SimpleControlFlow.cs" />
+ <Compile Include="ILAst\StateRange.cs" />
+ <Compile Include="ILAst\SymbolicExecution.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ILAst\YieldReturnDecompiler.cs" />
<Compile Include="ITextOutput.cs" />
@@ -116,11 +121,6 @@
<Compile Include="ReferenceResolvingException.cs" />
<Compile Include="TextOutputWriter.cs" />
<None Include="Properties\AssemblyInfo.template.cs" />
- <Compile Include="ILAst\LiftedOperators.cs" />
- <Compile Include="ILAst\StateRange.cs" />
- <Compile Include="ILAst\SymbolicExecution.cs" />
- <Compile Include="ILAst\AsyncDecompiler.cs" />
- <Compile Include="Ast\TextTokenWriter.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\external\cecil\Mono.Cecil.csproj">
@@ -147,4 +147,4 @@
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
-</Project>
+</Project> \ No newline at end of file
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs
index 4535c0f82a..c8a7f9b76a 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs
@@ -58,6 +58,7 @@ namespace ICSharpCode.Decompiler.ILAst
FieldDefinition builderField;
FieldDefinition stateField;
Dictionary<FieldDefinition, ILVariable> fieldToParameterMap = new Dictionary<FieldDefinition, ILVariable>();
+ ILVariable cachedStateVar;
// These fields are set by AnalyzeMoveNext()
int finalState = -2;
@@ -155,7 +156,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression loadStateMachineForBuilderExpr;
if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr))
return false;
- if (!loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar))
+ if (!(loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar) || loadStateMachineForBuilderExpr.MatchLdloc(stateMachineVar)))
return false;
builderField = builderFieldRef.ResolveWithinSameModule();
if (builderField == null)
@@ -235,36 +236,50 @@ namespace ICSharpCode.Decompiler.ILAst
{
ILBlock ilMethod = CreateILAst(moveNextMethod);
- if (ilMethod.Body.Count != 6)
+ int startIndex;
+ if (ilMethod.Body.Count == 6) {
+ startIndex = 0;
+ } else if (ilMethod.Body.Count == 7) {
+ // stloc(cachedState, ldfld(valuetype StateMachineStruct::<>1__state, ldloc(this)))
+ ILExpression cachedStateInit;
+ if (!ilMethod.Body[0].Match(ILCode.Stloc, out cachedStateVar, out cachedStateInit))
+ throw new SymbolicAnalysisFailedException();
+ ILExpression instanceExpr;
+ FieldReference loadedField;
+ if (!cachedStateInit.Match(ILCode.Ldfld, out loadedField, out instanceExpr) || loadedField.ResolveWithinSameModule() != stateField || !instanceExpr.MatchThis())
+ throw new SymbolicAnalysisFailedException();
+ startIndex = 1;
+ } else {
throw new SymbolicAnalysisFailedException();
+ }
- mainTryCatch = ilMethod.Body[0] as ILTryCatchBlock;
+ mainTryCatch = ilMethod.Body[startIndex + 0] as ILTryCatchBlock;
if (mainTryCatch == null || mainTryCatch.CatchBlocks.Count != 1)
throw new SymbolicAnalysisFailedException();
if (mainTryCatch.FaultBlock != null || mainTryCatch.FinallyBlock != null)
throw new SymbolicAnalysisFailedException();
- setResultAndExitLabel = ilMethod.Body[1] as ILLabel;
+ setResultAndExitLabel = ilMethod.Body[startIndex + 1] as ILLabel;
if (setResultAndExitLabel == null)
throw new SymbolicAnalysisFailedException();
- if (!MatchStateAssignment(ilMethod.Body[2], out finalState))
+ if (!MatchStateAssignment(ilMethod.Body[startIndex + 2], out finalState))
throw new SymbolicAnalysisFailedException();
// call(AsyncTaskMethodBuilder`1::SetResult, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloc(<>t__result))
MethodReference setResultMethod;
ILExpression builderExpr;
if (methodType == AsyncMethodType.TaskOfT) {
- if (!ilMethod.Body[3].Match(ILCode.Call, out setResultMethod, out builderExpr, out resultExpr))
+ if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr, out resultExpr))
throw new SymbolicAnalysisFailedException();
} else {
- if (!ilMethod.Body[3].Match(ILCode.Call, out setResultMethod, out builderExpr))
+ if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr))
throw new SymbolicAnalysisFailedException();
}
if (!(setResultMethod.Name == "SetResult" && IsBuilderFieldOnThis(builderExpr)))
throw new SymbolicAnalysisFailedException();
- exitLabel = ilMethod.Body[4] as ILLabel;
+ exitLabel = ilMethod.Body[startIndex + 4] as ILLabel;
if (exitLabel == null)
throw new SymbolicAnalysisFailedException();
}
@@ -318,7 +333,7 @@ namespace ICSharpCode.Decompiler.ILAst
bool MatchStateAssignment(ILNode stfld, out int stateID)
{
- // stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(-2))
+ // stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(stateId))
stateID = 0;
FieldReference fieldRef;
ILExpression target, val;
@@ -329,6 +344,31 @@ namespace ICSharpCode.Decompiler.ILAst
}
return false;
}
+
+ bool MatchRoslynStateAssignment(List<ILNode> block, int index, out int stateID)
+ {
+ // v = ldc.i4(stateId)
+ // stloc(cachedState, v)
+ // stfld(StateMachine::<>1__state, ldloc(this), v)
+ stateID = 0;
+ if (index < 0)
+ return false;
+ ILVariable v;
+ ILExpression val;
+ if (!block[index].Match(ILCode.Stloc, out v, out val) || !val.Match(ILCode.Ldc_I4, out stateID))
+ return false;
+ ILExpression loadV;
+ if (!block[index + 1].MatchStloc(cachedStateVar, out loadV) || !loadV.MatchLdloc(v))
+ return false;
+ ILExpression target;
+ FieldReference fieldRef;
+ if (block[index + 2].Match(ILCode.Stfld, out fieldRef, out target, out loadV)) {
+ return fieldRef.ResolveWithinSameModule() == stateField
+ && target.MatchThis()
+ && loadV.MatchLdloc(v);
+ }
+ return false;
+ }
#endregion
#region AnalyzeStateMachine
@@ -345,7 +385,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (body.Count == 0)
throw new SymbolicAnalysisFailedException();
}
- StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.AsyncMoveNext, stateField);
+ StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.AsyncMoveNext, stateField, cachedStateVar);
int bodyLength = block.Body.Count;
int pos = rangeAnalysis.AssignStateRanges(body, bodyLength);
rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);
@@ -405,7 +445,7 @@ namespace ICSharpCode.Decompiler.ILAst
var tryBody = tryCatchBlock.TryBlock.Body;
if (tryBody.Count == 0)
throw new SymbolicAnalysisFailedException();
- StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(tryBody[0], StateRangeAnalysisMode.AsyncMoveNext, stateField);
+ StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(tryBody[0], StateRangeAnalysisMode.AsyncMoveNext, stateField, cachedStateVar);
int tryBodyLength = tryBody.Count;
int posInTryBody = rangeAnalysis.AssignStateRanges(tryBody, tryBodyLength);
rangeAnalysis.EnsureLabelAtPos(tryBody, ref posInTryBody, ref tryBodyLength);
@@ -435,18 +475,16 @@ namespace ICSharpCode.Decompiler.ILAst
List<ILNode> ConvertFinally(List<ILNode> body)
{
List<ILNode> newBody = new List<ILNode>(body);
+ if (newBody.Count == 0)
+ return newBody;
ILLabel endFinallyLabel;
ILExpression ceqExpr;
- if (newBody.Count > 0 && newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) {
- ILExpression loadDoFinallyBodies, loadZero;
- object unused;
- if (ceqExpr.Match(ILCode.Ceq, out unused, out loadDoFinallyBodies, out loadZero)) {
- int num;
- if (loadDoFinallyBodies.MatchLdloc(doFinallyBodies) && loadZero.Match(ILCode.Ldc_I4, out num) && num == 0) {
+ if (newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) {
+ ILExpression condition;
+ if (MatchLogicNot(ceqExpr, out condition)) {
+ if (condition.MatchLdloc(doFinallyBodies)) {
newBody.RemoveAt(0);
- }
- } else if (ceqExpr.Match(ILCode.LogicNot, out loadDoFinallyBodies)) {
- if (loadDoFinallyBodies.MatchLdloc(doFinallyBodies)) {
+ } else if (condition.Code == ILCode.Clt && condition.Arguments[0].MatchLdloc(cachedStateVar) && condition.Arguments[1].MatchLdcI4(0)) {
newBody.RemoveAt(0);
}
}
@@ -454,6 +492,17 @@ namespace ICSharpCode.Decompiler.ILAst
return newBody;
}
+ bool MatchLogicNot(ILExpression expr, out ILExpression arg)
+ {
+ ILExpression loadZero;
+ object unused;
+ if (expr.Match(ILCode.Ceq, out unused, out arg, out loadZero)) {
+ int num;
+ return loadZero.Match(ILCode.Ldc_I4, out num) && num == 0;
+ }
+ return expr.Match(ILCode.LogicNot, out arg);
+ }
+
void HandleAwait(List<ILNode> newBody, out ILVariable awaiterVar, out FieldDefinition awaiterField, out int targetStateID)
{
// Handle the instructions prior to the exit out of the method to detect what is being awaited.
@@ -475,7 +524,8 @@ namespace ICSharpCode.Decompiler.ILAst
newBody.RemoveAt(newBody.Count - 1); // remove AwaitUnsafeOnCompleted call
if (callAwaitUnsafeOnCompleted == null || callAwaitUnsafeOnCompleted.Code != ILCode.Call)
throw new SymbolicAnalysisFailedException();
- if (((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name != "AwaitUnsafeOnCompleted")
+ string methodName = ((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name;
+ if (methodName != "AwaitUnsafeOnCompleted" && methodName != "AwaitOnCompleted")
throw new SymbolicAnalysisFailedException();
if (callAwaitUnsafeOnCompleted.Arguments.Count != 3)
throw new SymbolicAnalysisFailedException();
@@ -493,9 +543,10 @@ namespace ICSharpCode.Decompiler.ILAst
throw new SymbolicAnalysisFailedException();
// stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(0))
- if (!MatchStateAssignment(newBody.LastOrDefault(), out targetStateID))
- throw new SymbolicAnalysisFailedException();
- newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment
+ if (MatchStateAssignment(newBody.LastOrDefault(), out targetStateID))
+ newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment
+ else if (MatchRoslynStateAssignment(newBody, newBody.Count - 3, out targetStateID))
+ newBody.RemoveRange(newBody.Count - 3, 3); // remove awaiter field assignment
}
#endregion
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
index da8c6c6beb..e30398e042 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
@@ -413,11 +413,11 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
- // Occasionally the compilers or obfuscators generate unreachable code (which might be intentonally invalid)
- // I belive it is safe to just remove it
+ // Occasionally the compilers or obfuscators generate unreachable code (which might be intentionally invalid)
+ // I believe it is safe to just remove it
body.RemoveAll(b => b.StackBefore == null);
- // Genertate temporary variables to replace stack
+ // Generate temporary variables to replace stack
foreach(ByteCode byteCode in body) {
int argIdx = 0;
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length;
@@ -652,7 +652,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Find the first and widest scope
int tryStart = ehs.Min(eh => eh.TryStart.Offset);
int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset);
- var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).OrderBy(eh => eh.TryStart.Offset).ToList();
+ var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).ToList();
// Remember that any part of the body migt have been removed due to unreachability
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
index 5de51b9b1a..ce62816d7a 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
@@ -20,9 +20,11 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
using Mono.Cecil.Cil;
+using Mono.CSharp;
namespace ICSharpCode.Decompiler.ILAst
{
@@ -37,6 +39,7 @@ namespace ICSharpCode.Decompiler.ILAst
PropertyAccessInstructions,
SplitToMovableBlocks,
TypeInference,
+ HandlePointerArithmetic,
SimplifyShortCircuit,
SimplifyTernaryOperator,
SimplifyNullCoalescing,
@@ -123,6 +126,9 @@ namespace ICSharpCode.Decompiler.ILAst
// Types are needed for the ternary operator optimization
TypeAnalysis.Run(context, method);
+ if (abortBeforeStep == ILAstOptimizationStep.HandlePointerArithmetic) return;
+ HandlePointerArithmetic(method);
+
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
bool modified;
do {
@@ -168,11 +174,15 @@ namespace ICSharpCode.Decompiler.ILAst
modified |= block.RunOptimization(TransformObjectInitializers);
if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression) return;
- modified |= block.RunOptimization(MakeAssignmentExpression);
+ if (context.Settings.MakeAssignmentExpressions) {
+ modified |= block.RunOptimization(MakeAssignmentExpression);
+ }
modified |= block.RunOptimization(MakeCompoundAssignments);
if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) return;
- modified |= block.RunOptimization(IntroducePostIncrement);
+ if (context.Settings.IntroduceIncrementAndDecrement) {
+ modified |= block.RunOptimization(IntroducePostIncrement);
+ }
if (abortBeforeStep == ILAstOptimizationStep.InlineExpressionTreeParameterDeclarations) return;
if (context.Settings.ExpressionTrees) {
@@ -223,11 +233,13 @@ namespace ICSharpCode.Decompiler.ILAst
new ILInlining(method).InlineAllVariables();
if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) return;
- foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
- for (int i = 0; i < block.Body.Count; i++) {
- // TODO: Move before loops
- CachedDelegateInitializationWithField(block, ref i);
- CachedDelegateInitializationWithLocal(block, ref i);
+ if (context.Settings.AnonymousMethods) {
+ foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
+ for (int i = 0; i < block.Body.Count; i++) {
+ // TODO: Move before loops
+ CachedDelegateInitializationWithField(block, ref i);
+ CachedDelegateInitializationWithLocal(block, ref i);
+ }
}
}
@@ -337,15 +349,15 @@ namespace ICSharpCode.Decompiler.ILAst
expr.ILRanges.Clear();
continue;
case ILCode.__Brfalse: op = ILCode.LogicNot; break;
- case ILCode.__Beq: op = ILCode.Ceq; break;
+ case ILCode.__Beq: op = ILCode.Ceq; break;
case ILCode.__Bne_Un: op = ILCode.Cne; break;
- case ILCode.__Bgt: op = ILCode.Cgt; break;
+ case ILCode.__Bgt: op = ILCode.Cgt; break;
case ILCode.__Bgt_Un: op = ILCode.Cgt_Un; break;
- case ILCode.__Ble: op = ILCode.Cle; break;
+ case ILCode.__Ble: op = ILCode.Cle; break;
case ILCode.__Ble_Un: op = ILCode.Cle_Un; break;
- case ILCode.__Blt: op = ILCode.Clt; break;
+ case ILCode.__Blt: op = ILCode.Clt; break;
case ILCode.__Blt_Un: op = ILCode.Clt_Un; break;
- case ILCode.__Bge: op = ILCode.Cge; break;
+ case ILCode.__Bge: op = ILCode.Cge; break;
case ILCode.__Bge_Un: op = ILCode.Cge_Un; break;
default:
continue;
@@ -424,9 +436,9 @@ namespace ICSharpCode.Decompiler.ILAst
// Might be 'newobj(SomeDelegate, target, ldvirtftn(F, target))'.
ILVariable target;
if (expr.Arguments[0].Match(ILCode.Ldloc, out target)
- && expr.Arguments[1].Code == ILCode.Ldvirtftn
- && expr.Arguments[1].Arguments.Count == 1
- && expr.Arguments[1].Arguments[0].MatchLdloc(target))
+ && expr.Arguments[1].Code == ILCode.Ldvirtftn
+ && expr.Arguments[1].Arguments.Count == 1
+ && expr.Arguments[1].Arguments[0].MatchLdloc(target))
{
// Remove the 'target' argument from the ldvirtftn instruction.
// It's not needed in the translation to C#, and needs to be eliminated so that the target expression
@@ -461,9 +473,9 @@ namespace ICSharpCode.Decompiler.ILAst
// Start a new basic block if necessary
if (currNode is ILLabel ||
- currNode is ILTryCatchBlock || // Counts as label
- lastNode.IsConditionalControlFlow() ||
- lastNode.IsUnconditionalControlFlow())
+ currNode is ILTryCatchBlock || // Counts as label
+ lastNode.IsConditionalControlFlow() ||
+ lastNode.IsUnconditionalControlFlow())
{
// Try to reuse the label
ILLabel label = currNode as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++).ToString() };
@@ -656,6 +668,180 @@ namespace ICSharpCode.Decompiler.ILAst
return combinedVariable;
});
}
+
+ void HandlePointerArithmetic(ILNode method)
+ {
+ foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
+ List<ILExpression> args = expr.Arguments;
+ switch (expr.Code) {
+ case ILCode.Localloc:
+ {
+ PointerType type = expr.InferredType as PointerType;
+ if (type != null) {
+ ILExpression arg0 = args[0];
+ ILExpression expr2 = expr;
+ DivideOrMultiplyBySize(ref expr2, ref arg0, type.ElementType, true);
+ // expr shouldn't change
+ if (expr2 != expr)
+ throw new InvalidOperationException();
+ args[0] = arg0;
+ }
+ break;
+ }
+ case ILCode.Add:
+ case ILCode.Add_Ovf:
+ case ILCode.Add_Ovf_Un:
+ {
+ ILExpression arg0 = args[0];
+ ILExpression arg1 = args[1];
+ if (expr.InferredType is PointerType) {
+ if (arg0.ExpectedType is PointerType) {
+ DivideOrMultiplyBySize(ref arg0, ref arg1, ((PointerType)expr.InferredType).ElementType, true);
+ } else if (arg1.ExpectedType is PointerType)
+ DivideOrMultiplyBySize(ref arg1, ref arg0, ((PointerType)expr.InferredType).ElementType, true);
+ }
+ args[0] = arg0;
+ args[1] = arg1;
+ break;
+ }
+ case ILCode.Sub:
+ case ILCode.Sub_Ovf:
+ case ILCode.Sub_Ovf_Un:
+ {
+ ILExpression arg0 = args[0];
+ ILExpression arg1 = args[1];
+ if (expr.InferredType is PointerType) {
+ if (arg0.ExpectedType is PointerType && !(arg1.InferredType is PointerType))
+ DivideOrMultiplyBySize(ref arg0, ref arg1, ((PointerType)expr.InferredType).ElementType, true);
+ }
+ args[0] = arg0;
+ args[1] = arg1;
+ break;
+ }
+ case ILCode.Conv_I8:
+ {
+ ILExpression arg0 = args[0];
+ // conv.i8(div:intptr(p0 - p1))
+ if (arg0.Code == ILCode.Div && arg0.InferredType.FullName == "System.IntPtr")
+ {
+ ILExpression dividend = arg0.Arguments[0];
+ if (dividend.InferredType.FullName == "System.IntPtr" &&
+ (dividend.Code == ILCode.Sub || dividend.Code == ILCode.Sub_Ovf || dividend.Code == ILCode.Sub_Ovf_Un))
+ {
+ PointerType pointerType0 = dividend.Arguments[0].InferredType as PointerType;
+ PointerType pointerType1 = dividend.Arguments[1].InferredType as PointerType;
+
+ if (pointerType0 != null && pointerType1 != null) {
+ if (pointerType0.ElementType.FullName == "System.Void" ||
+ pointerType0.ElementType.FullName != pointerType1.ElementType.FullName) {
+ pointerType0 = pointerType1 = new PointerType(typeSystem.Byte);
+ dividend.Arguments[0] = Cast(dividend.Arguments[0], pointerType0);
+ dividend.Arguments[1] = Cast(dividend.Arguments[1], pointerType1);
+ }
+
+ DivideOrMultiplyBySize(ref dividend, ref arg0, pointerType0.ElementType, false);
+ // dividend shouldn't change
+ if (args[0].Arguments[0] != dividend)
+ throw new InvalidOperationException();
+ }
+ }
+ }
+ args[0] = arg0;
+ break;
+ }
+ }
+ }
+ }
+
+ static ILExpression UnwrapIntPtrCast(ILExpression expr)
+ {
+ if (expr.Code != ILCode.Conv_I && expr.Code != ILCode.Conv_U)
+ return expr;
+
+ ILExpression arg = expr.Arguments[0];
+ switch (arg.InferredType.MetadataType) {
+ case MetadataType.Byte:
+ case MetadataType.SByte:
+ case MetadataType.UInt16:
+ case MetadataType.Int16:
+ case MetadataType.UInt32:
+ case MetadataType.Int32:
+ case MetadataType.UInt64:
+ case MetadataType.Int64:
+ return arg;
+ }
+
+ return expr;
+ }
+
+ static ILExpression Cast(ILExpression expr, TypeReference type)
+ {
+ return new ILExpression(ILCode.Castclass, type, expr)
+ {
+ InferredType = type,
+ ExpectedType = type
+ };
+ }
+
+ void DivideOrMultiplyBySize(ref ILExpression pointerExpr, ref ILExpression adjustmentExpr, TypeReference elementType, bool divide)
+ {
+ adjustmentExpr = UnwrapIntPtrCast(adjustmentExpr);
+
+ ILExpression sizeOfExpression;
+ switch (TypeAnalysis.GetInformationAmount(elementType)) {
+ case 0: // System.Void
+ pointerExpr = Cast(pointerExpr, new PointerType(typeSystem.Byte));
+ goto case 1;
+ case 1:
+ case 8:
+ sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 1);
+ break;
+ case 16:
+ sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 2);
+ break;
+ case 32:
+ sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 4);
+ break;
+ case 64:
+ sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 8);
+ break;
+ default:
+ sizeOfExpression = new ILExpression(ILCode.Sizeof, elementType);
+ break;
+ }
+
+ if (divide && (adjustmentExpr.Code == ILCode.Mul || adjustmentExpr.Code == ILCode.Mul_Ovf || adjustmentExpr.Code == ILCode.Mul_Ovf_Un) ||
+ !divide && (adjustmentExpr.Code == ILCode.Div || adjustmentExpr.Code == ILCode.Div_Un)) {
+ ILExpression mulArg = adjustmentExpr.Arguments[1];
+ if (mulArg.Code == sizeOfExpression.Code && sizeOfExpression.Operand.Equals(mulArg.Operand)) {
+ adjustmentExpr = UnwrapIntPtrCast(adjustmentExpr.Arguments[0]);
+ return;
+ }
+ }
+
+ if (adjustmentExpr.Code == sizeOfExpression.Code) {
+ if (sizeOfExpression.Operand.Equals(adjustmentExpr.Operand)) {
+ adjustmentExpr = new ILExpression(ILCode.Ldc_I4, 1);
+ return;
+ }
+
+ if (adjustmentExpr.Code == ILCode.Ldc_I4) {
+ int offsetInBytes = (int)adjustmentExpr.Operand;
+ int elementSize = (int)sizeOfExpression.Operand;
+
+ if (offsetInBytes % elementSize != 0) {
+ pointerExpr = Cast(pointerExpr, new PointerType(typeSystem.Byte));
+ return;
+ }
+
+ adjustmentExpr.Operand = offsetInBytes / elementSize;
+ return;
+ }
+ }
+
+ if (!(sizeOfExpression.Code == ILCode.Ldc_I4 && (int)sizeOfExpression.Operand == 1))
+ adjustmentExpr = new ILExpression(divide ? ILCode.Div_Un : ILCode.Mul, null, adjustmentExpr, sizeOfExpression);
+ }
public static void ReplaceVariables(ILNode node, Func<ILVariable, ILVariable> variableMapping)
{
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
index 7fd74a60e8..9cd42a14fc 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
@@ -21,10 +21,13 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Text;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
+using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
using Mono.Cecil.Cil;
+using Mono.CSharp;
using Cecil = Mono.Cecil;
namespace ICSharpCode.Decompiler.ILAst
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/ILInlining.cs
index 880592b103..11140ef083 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/ILInlining.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/ILInlining.cs
@@ -50,32 +50,36 @@ namespace ICSharpCode.Decompiler.ILAst
AnalyzeNode(method);
}
- void AnalyzeNode(ILNode node)
+ /// <summary>
+ /// For each variable reference, adds <paramref name="direction"/> to the num* dicts.
+ /// Direction will be 1 for analysis, and -1 when removing a node from analysis.
+ /// </summary>
+ void AnalyzeNode(ILNode node, int direction = 1)
{
ILExpression expr = node as ILExpression;
if (expr != null) {
ILVariable locVar = expr.Operand as ILVariable;
if (locVar != null) {
if (expr.Code == ILCode.Stloc) {
- numStloc[locVar] = numStloc.GetOrDefault(locVar) + 1;
+ numStloc[locVar] = numStloc.GetOrDefault(locVar) + direction;
} else if (expr.Code == ILCode.Ldloc) {
- numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + 1;
+ numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + direction;
} else if (expr.Code == ILCode.Ldloca) {
- numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + 1;
+ numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + direction;
} else {
throw new NotSupportedException(expr.Code.ToString());
}
}
foreach (ILExpression child in expr.Arguments)
- AnalyzeNode(child);
+ AnalyzeNode(child, direction);
} else {
var catchBlock = node as ILTryCatchBlock.CatchBlock;
if (catchBlock != null && catchBlock.ExceptionVariable != null) {
- numStloc[catchBlock.ExceptionVariable] = numStloc.GetOrDefault(catchBlock.ExceptionVariable) + 1;
+ numStloc[catchBlock.ExceptionVariable] = numStloc.GetOrDefault(catchBlock.ExceptionVariable) + direction;
}
foreach (ILNode child in node.GetChildren())
- AnalyzeNode(child);
+ AnalyzeNode(child, direction);
}
}
@@ -194,6 +198,7 @@ namespace ICSharpCode.Decompiler.ILAst
// The variable is never loaded
if (inlinedExpression.HasNoSideEffects()) {
// Remove completely
+ AnalyzeNode(body[pos], -1);
body.RemoveAt(pos);
return true;
} else if (inlinedExpression.CanBeExpressionStatement() && v.IsGenerated) {
@@ -334,6 +339,7 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Stfld:
case ILCode.Ldfld:
case ILCode.Ldflda:
+ case ILCode.Await:
return true;
}
}
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/PatternMatching.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/PatternMatching.cs
index 31fcf62b15..441088b903 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/PatternMatching.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/PatternMatching.cs
@@ -167,5 +167,11 @@ namespace ICSharpCode.Decompiler.ILAst
ILVariable v;
return node.Match(ILCode.Stloc, out v, out expr) && v == expectedVar;
}
+
+ public static bool MatchLdcI4(this ILNode node, int expectedValue)
+ {
+ int v;
+ return node.Match(ILCode.Ldc_I4, out v) && v == expectedValue;
+ }
}
}
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/StateRange.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/StateRange.cs
index 4a55e1d0b6..3a3dfc2f34 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/StateRange.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/StateRange.cs
@@ -137,23 +137,25 @@ namespace ICSharpCode.Decompiler.ILAst
internal DefaultDictionary<ILNode, StateRange> ranges;
SymbolicEvaluationContext evalContext;
- internal Dictionary<MethodDefinition, Interval> finallyMethodToStateInterval; // used only for IteratorDispose
+ internal Dictionary<MethodDefinition, StateRange> finallyMethodToStateRange; // used only for IteratorDispose
/// <summary>
/// Initializes the state range logic:
/// Clears 'ranges' and sets 'ranges[entryPoint]' to the full range (int.MinValue to int.MaxValue)
/// </summary>
- public StateRangeAnalysis(ILNode entryPoint, StateRangeAnalysisMode mode, FieldDefinition stateField)
+ public StateRangeAnalysis(ILNode entryPoint, StateRangeAnalysisMode mode, FieldDefinition stateField, ILVariable cachedStateVar = null)
{
this.mode = mode;
this.stateField = stateField;
if (mode == StateRangeAnalysisMode.IteratorDispose) {
- finallyMethodToStateInterval = new Dictionary<MethodDefinition, Interval>();
+ finallyMethodToStateRange = new Dictionary<MethodDefinition, StateRange>();
}
ranges = new DefaultDictionary<ILNode, StateRange>(n => new StateRange());
ranges[entryPoint] = new StateRange(int.MinValue, int.MaxValue);
evalContext = new SymbolicEvaluationContext(stateField);
+ if (cachedStateVar != null)
+ evalContext.AddStateVariable(cachedStateVar);
}
public int AssignStateRanges(List<ILNode> body, int bodyLength)
@@ -213,7 +215,7 @@ namespace ICSharpCode.Decompiler.ILAst
break;
case ILCode.Brtrue:
{
- SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
+ SymbolicValue val = evalContext.Eval(expr.Arguments[0]).AsBool();
if (val.Type == SymbolicValueType.StateEquals) {
ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant);
StateRange nextRange = ranges[body[i + 1]];
@@ -249,9 +251,9 @@ namespace ICSharpCode.Decompiler.ILAst
// in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks
if (mode == StateRangeAnalysisMode.IteratorDispose) {
MethodDefinition mdef = (expr.Operand as MethodReference).ResolveWithinSameModule();
- if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
+ if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef))
throw new SymbolicAnalysisFailedException();
- finallyMethodToStateInterval.Add(mdef, nodeRange.ToEnclosingInterval());
+ finallyMethodToStateRange.Add(mdef, nodeRange);
break;
} else {
goto default;
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs
index 98255f2f2d..5fb40acf92 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs
@@ -67,7 +67,16 @@ namespace ICSharpCode.Decompiler.ILAst
this.Type = type;
this.Constant = constant;
}
-
+
+ public SymbolicValue AsBool()
+ {
+ if (Type == SymbolicValueType.State) {
+ // convert state integer to bool:
+ // if (state + c) = if (state + c != 0) = if (state != -c)
+ return new SymbolicValue(SymbolicValueType.StateInEquals, unchecked(-Constant));
+ }
+ return this;
+ }
public override string ToString()
{
return string.Format("[SymbolicValue {0}: {1}]", this.Type, this.Constant);
@@ -133,7 +142,7 @@ namespace ICSharpCode.Decompiler.ILAst
// bool: (state == right.Constant - left.Constant)
return new SymbolicValue(expr.Code == ILCode.Ceq ? SymbolicValueType.StateEquals : SymbolicValueType.StateInEquals, unchecked(right.Constant - left.Constant));
case ILCode.LogicNot:
- SymbolicValue val = Eval(expr.Arguments[0]);
+ SymbolicValue val = Eval(expr.Arguments[0]).AsBool();
if (val.Type == SymbolicValueType.StateEquals)
return new SymbolicValue(SymbolicValueType.StateInEquals, val.Constant);
else if (val.Type == SymbolicValueType.StateInEquals)
@@ -141,7 +150,7 @@ namespace ICSharpCode.Decompiler.ILAst
else
return Failed();
default:
- return Failed();
+ return Failed();
}
}
}
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
index b050353ab4..6ed1f4dc05 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
@@ -450,7 +450,7 @@ namespace ICSharpCode.Decompiler.ILAst
return (TypeReference)expr.Operand;
case ILCode.Localloc:
if (forceInferChildren) {
- InferTypeForExpression(expr.Arguments[0], typeSystem.Int32);
+ InferTypeForExpression(expr.Arguments[0], null);
}
if (expectedType is PointerType)
return expectedType;
@@ -539,6 +539,8 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
TypeReference type = NumericPromotion(InferTypeForExpression(expr.Arguments[0], null));
+ if (type == null)
+ return null;
TypeReference expectedInputType = null;
switch (type.MetadataType) {
case MetadataType.Int32:
@@ -827,7 +829,7 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Await:
{
TypeReference taskType = InferTypeForExpression(expr.Arguments[0], null);
- if (taskType.Name == "Task`1" && taskType.IsGenericInstance && taskType.Namespace == "System.Threading.Tasks") {
+ if (taskType != null && taskType.Name == "Task`1" && taskType.IsGenericInstance && taskType.Namespace == "System.Threading.Tasks") {
return ((GenericInstanceType)taskType).GenericArguments[0];
}
return null;
@@ -1011,7 +1013,7 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred;
- InferTypeForExpression(right, typeSystem.IntPtr);
+ InferTypeForExpression(right, null);
return leftPreferred;
}
if (IsEnum(leftPreferred)) {
@@ -1022,7 +1024,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (rightPreferred is PointerType) {
- InferTypeForExpression(left, typeSystem.IntPtr);
+ InferTypeForExpression(left, null);
right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred;
}
@@ -1042,7 +1044,10 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred;
- InferTypeForExpression(right, typeSystem.IntPtr);
+ TypeReference rightPreferred = InferTypeForExpression(right, null);
+ // subtracting two pointers is not a pointer
+ if (rightPreferred is PointerType)
+ return typeSystem.IntPtr;
return leftPreferred;
}
if (IsEnum(leftPreferred)) {
diff --git a/main/contrib/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs b/main/contrib/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
index b4b6183bf8..2da165f610 100644
--- a/main/contrib/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
+++ b/main/contrib/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
@@ -312,7 +312,7 @@ namespace ICSharpCode.Decompiler.ILAst
// This is (int.MinValue, int.MaxValue) for the first instruction.
// These ranges are propagated depending on the conditional jumps performed by the code.
- Dictionary<MethodDefinition, Interval> finallyMethodToStateInterval;
+ Dictionary<MethodDefinition, StateRange> finallyMethodToStateRange;
void ConstructExceptionTable()
{
@@ -321,11 +321,11 @@ namespace ICSharpCode.Decompiler.ILAst
var rangeAnalysis = new StateRangeAnalysis(ilMethod.Body[0], StateRangeAnalysisMode.IteratorDispose, stateField);
rangeAnalysis.AssignStateRanges(ilMethod.Body, ilMethod.Body.Count);
- finallyMethodToStateInterval = rangeAnalysis.finallyMethodToStateInterval;
+ finallyMethodToStateRange = rangeAnalysis.finallyMethodToStateRange;
// Now look at the finally blocks:
foreach (var tryFinally in ilMethod.GetSelfAndChildrenRecursive<ILTryCatchBlock>()) {
- Interval interval = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]].ToEnclosingInterval();
+ var range = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]];
var finallyBody = tryFinally.FinallyBlock.Body;
if (finallyBody.Count != 2)
throw new SymbolicAnalysisFailedException();
@@ -338,9 +338,9 @@ namespace ICSharpCode.Decompiler.ILAst
throw new SymbolicAnalysisFailedException();
MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference);
- if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
+ if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef))
throw new SymbolicAnalysisFailedException();
- finallyMethodToStateInterval.Add(mdef, interval);
+ finallyMethodToStateRange.Add(mdef, range);
}
rangeAnalysis = null;
}
@@ -430,10 +430,9 @@ namespace ICSharpCode.Decompiler.ILAst
bodyLength--; // don't conside the stloc instruction to be part of the body
}
- // verify that the last element in the body is a label pointing to the 'ret(false)'
+ // The last element in the body usually is a label pointing to the 'ret(false)'
returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
- if (returnFalseLabel == null)
- throw new SymbolicAnalysisFailedException();
+ // Note: in Roslyn-compiled code, returnFalseLabel may be null.
var rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.IteratorMoveNext, stateField);
int pos = rangeAnalysis.AssignStateRanges(body, bodyLength);
@@ -485,7 +484,7 @@ namespace ICSharpCode.Decompiler.ILAst
throw new SymbolicAnalysisFailedException();
int val = (int)expr.Arguments[0].Operand;
if (val == 0) {
- newBody.Add(MakeGoTo(returnFalseLabel));
+ newBody.Add(new ILExpression(ILCode.YieldBreak, null));
} else if (val == 1) {
newBody.Add(MakeGoTo(labels, currentState));
} else {
@@ -497,7 +496,7 @@ namespace ICSharpCode.Decompiler.ILAst
// handle direct return (e.g. in release builds)
int val = (int)expr.Arguments[0].Operand;
if (val == 0) {
- newBody.Add(MakeGoTo(returnFalseLabel));
+ newBody.Add(new ILExpression(ILCode.YieldBreak, null));
} else if (val == 1) {
newBody.Add(MakeGoTo(labels, currentState));
} else {
@@ -507,21 +506,21 @@ namespace ICSharpCode.Decompiler.ILAst
MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference);
if (method == null)
throw new SymbolicAnalysisFailedException();
- Interval interval;
+ StateRange stateRange;
if (method == disposeMethod) {
// Explicit call to dispose is used for "yield break;" within the method.
ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnFalseLabel)
throw new SymbolicAnalysisFailedException();
- newBody.Add(MakeGoTo(returnFalseLabel));
- } else if (finallyMethodToStateInterval.TryGetValue(method, out interval)) {
+ newBody.Add(new ILExpression(ILCode.YieldBreak, null));
+ } else if (finallyMethodToStateRange.TryGetValue(method, out stateRange)) {
// Call to Finally-method
- int index = stateChanges.FindIndex(ss => ss.NewState >= interval.Start && ss.NewState <= interval.End);
+ int index = stateChanges.FindIndex(ss => stateRange.Contains(ss.NewState));
if (index < 0)
throw new SymbolicAnalysisFailedException();
ILLabel label = new ILLabel();
- label.Name = "JumpOutOfTryFinally" + interval.Start + "_" + interval.End;
+ label.Name = "JumpOutOfTryFinally" + stateChanges[index].NewState;
newBody.Add(new ILExpression(ILCode.Leave, label));
SetState stateChange = stateChanges[index];
@@ -544,6 +543,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression MakeGoTo(ILLabel targetLabel)
{
+ Debug.Assert(targetLabel != null);
if (targetLabel == returnFalseLabel)
return new ILExpression(ILCode.YieldBreak, null);
else
diff --git a/main/contrib/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs b/main/contrib/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs
index 552d092ee5..5cb49aad73 100644
--- a/main/contrib/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs
@@ -87,7 +87,8 @@ namespace ICSharpCode.Decompiler.Tests
{
if(String.IsNullOrWhiteSpace(s))
return true;
- return s.Trim().StartsWith("//");
+ s = s.Trim();
+ return s.StartsWith("//") || s.StartsWith("#"); // Also ignore #pragmas for warning suppression
}
public static string ConcatLines(IEnumerable<string> lines)
diff --git a/main/contrib/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs b/main/contrib/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
index 8205042a97..659bb2be68 100644
--- a/main/contrib/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
@@ -35,10 +35,8 @@ namespace ICSharpCode.Decompiler.Tests
{
protected static void ValidateFileRoundtrip(string samplesFileName)
{
- var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName));
- var testCode = RemoveIgnorableLines(lines);
- var decompiledTestCode = RoundtripCode(testCode);
- CodeAssert.AreEqual(testCode, decompiledTestCode);
+ var fullPath = Path.Combine(@"..\..\Tests", samplesFileName);
+ AssertRoundtripCode(fullPath);
}
static string RemoveIgnorableLines(IEnumerable<string> lines)
@@ -46,29 +44,27 @@ namespace ICSharpCode.Decompiler.Tests
return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l)));
}
- /// <summary>
- /// Compiles and decompiles a source code.
- /// </summary>
- /// <param name="code">The source code to copile.</param>
- /// <returns>The decompilation result of compiled source code.</returns>
- static string RoundtripCode(string code)
+ protected static void AssertRoundtripCode(string fileName, bool optimize = false, bool useDebug = false, int compilerVersion = 4)
{
- DecompilerSettings settings = new DecompilerSettings();
- settings.FullyQualifyAmbiguousTypeNames = false;
- AssemblyDefinition assembly = Compile(code);
- AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule) { Settings = settings });
+ var code = RemoveIgnorableLines(File.ReadLines(fileName));
+ AssemblyDefinition assembly = CompileLegacy(code, optimize, useDebug, compilerVersion);
+
+ AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree);
+
StringWriter output = new StringWriter();
decompiler.GenerateCode(new PlainTextOutput(output));
- return output.ToString();
+ CodeAssert.AreEqual(code, output.ToString());
}
- static AssemblyDefinition Compile(string code)
+ protected static AssemblyDefinition CompileLegacy(string code, bool optimize, bool useDebug, int compilerVersion)
{
- CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
+ CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v" + new Version(compilerVersion, 0) } });
CompilerParameters options = new CompilerParameters();
- options.ReferencedAssemblies.Add("System.Core.dll");
+ options.CompilerOptions = "/unsafe /o" + (optimize ? "+" : "-") + (useDebug ? " /debug" : "");
+ if (compilerVersion >= 4)
+ options.ReferencedAssemblies.Add("System.Core.dll");
CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try
{
diff --git a/main/contrib/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs b/main/contrib/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
index 5d5071f676..70c00fc655 100644
--- a/main/contrib/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
@@ -62,6 +62,22 @@ public static class DelegateConstruction
}
return null;
}
+
+ public void LambdaInForLoop()
+ {
+ for (int i = 0; i < 100000; i++) {
+ Bar(() => Foo());
+ }
+ }
+
+ public int Foo()
+ {
+ return 0;
+ }
+
+ public void Bar(Func<int> f)
+ {
+ }
}
public static void Test(this string a)
diff --git a/main/contrib/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/main/contrib/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
index 69598ac73f..8bb4934e78 100644
--- a/main/contrib/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/main/contrib/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -67,6 +67,7 @@
<Compile Include="CallOverloadedMethod.cs" />
<Compile Include="CheckedUnchecked.cs" />
<Compile Include="ControlFlow.cs" />
+ <Compile Include="DoubleConstants.cs" />
<Compile Include="ExpressionTrees.cs" />
<None Include="IL\SequenceOfNestedIfs.Output.cs" />
<Compile Include="IL\ILTests.cs" />
@@ -74,6 +75,7 @@
<Compile Include="CustomShortCircuitOperators.cs" />
<Compile Include="Helpers\CodeAssert.cs" />
<Compile Include="IncrementDecrement.cs" />
+ <Compile Include="Lock.cs" />
<Compile Include="PInvoke.cs" />
<Compile Include="QueryExpressions.cs" />
<Compile Include="Switch.cs" />
@@ -126,11 +128,12 @@
<Name>ICSharpCode.Decompiler</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup />
<ItemGroup>
- <Folder Include="IL" />
+ <None Include="BooleanConsumedAsInteger.il" />
</ItemGroup>
<ItemGroup>
- <None Include="BooleanConsumedAsInteger.il" />
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project> \ No newline at end of file
diff --git a/main/contrib/ICSharpCode.Decompiler/Tests/TestRunner.cs b/main/contrib/ICSharpCode.Decompiler/Tests/TestRunner.cs
index 009a3c6c17..215725b0a6 100644
--- a/main/contrib/ICSharpCode.Decompiler/Tests/TestRunner.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Tests/TestRunner.cs
@@ -32,7 +32,7 @@ using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests
{
[TestFixture]
- public class TestRunner
+ public class TestRunner : DecompilerTestBase
{
[Test]
public void Async()
@@ -67,7 +67,8 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void ExceptionHandling()
{
- TestFile(@"..\..\Tests\ExceptionHandling.cs", optimize: false);
+ AssertRoundtripCode(@"..\..\Tests\ExceptionHandling.cs", optimize: false);
+ AssertRoundtripCode(@"..\..\Tests\ExceptionHandling.cs", optimize: false);
}
[Test]
@@ -85,7 +86,14 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void ControlFlowWithDebug()
{
- TestFile(@"..\..\Tests\ControlFlow.cs", optimize: false, useDebug: true);
+ AssertRoundtripCode(@"..\..\Tests\ControlFlow.cs", optimize: false, useDebug: true);
+ AssertRoundtripCode(@"..\..\Tests\ControlFlow.cs", optimize: false, useDebug: true);
+ }
+
+ [Test]
+ public void DoubleConstants()
+ {
+ TestFile(@"..\..\Tests\DoubleConstants.cs");
}
[Test]
@@ -107,6 +115,13 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
+ public void Lock()
+ {
+ //TestFile(@"..\..\Tests\Lock.cs", compilerVersion: 2);
+ TestFile(@"..\..\Tests\Lock.cs", compilerVersion: 4);
+ }
+
+ [Test]
public void Loops()
{
TestFile(@"..\..\Tests\Loops.cs");
@@ -172,44 +187,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\TypeAnalysisTests.cs");
}
- static void TestFile(string fileName, bool useDebug = false)
- {
- TestFile(fileName, false, useDebug);
- TestFile(fileName, true, useDebug);
- }
-
- static void TestFile(string fileName, bool optimize, bool useDebug = false)
+ static void TestFile(string fileName, bool useDebug = false, int compilerVersion = 4)
{
- string code = File.ReadAllText(fileName);
- AssemblyDefinition assembly = Compile(code, optimize, useDebug);
- AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
- decompiler.AddAssembly(assembly);
- new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree);
- StringWriter output = new StringWriter();
- decompiler.GenerateCode(new PlainTextOutput(output));
- CodeAssert.AreEqual(code, output.ToString());
- }
-
- static AssemblyDefinition Compile(string code, bool optimize, bool useDebug)
- {
- CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
- CompilerParameters options = new CompilerParameters();
- options.CompilerOptions = "/unsafe /o" + (optimize ? "+" : "-") + (useDebug ? " /debug": "");
- options.ReferencedAssemblies.Add("System.Core.dll");
- CompilerResults results = provider.CompileAssemblyFromSource(options, code);
- try {
- if (results.Errors.Count > 0) {
- StringBuilder b = new StringBuilder("Compiler error:");
- foreach (var error in results.Errors) {
- b.AppendLine(error.ToString());
- }
- throw new Exception(b.ToString());
- }
- return AssemblyDefinition.ReadAssembly(results.PathToAssembly);
- } finally {
- File.Delete(results.PathToAssembly);
- results.TempFiles.Delete();
- }
+ AssertRoundtripCode(fileName, optimize: false, useDebug: useDebug, compilerVersion: compilerVersion);
+ AssertRoundtripCode(fileName, optimize: true, useDebug: useDebug, compilerVersion: compilerVersion);
+ AssertRoundtripCode(fileName, optimize: false, useDebug: useDebug, compilerVersion: compilerVersion);
+ AssertRoundtripCode(fileName, optimize: true, useDebug: useDebug, compilerVersion: compilerVersion);
}
}
}
diff --git a/main/contrib/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs b/main/contrib/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
index 72db7aa465..4a85b9f88a 100644
--- a/main/contrib/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs
@@ -679,7 +679,9 @@ namespace HideMembers3
}
public class J2 : J
{
+#pragma warning disable 0108 // Deliberate bad code for test case
public int get_P;
+#pragma warning restore 0108
}
}
//$$ HideMembers4
diff --git a/main/contrib/ICSharpCode.Decompiler/Tests/UnsafeCode.cs b/main/contrib/ICSharpCode.Decompiler/Tests/UnsafeCode.cs
index 66fb29529b..cce6d525c7 100644
--- a/main/contrib/ICSharpCode.Decompiler/Tests/UnsafeCode.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Tests/UnsafeCode.cs
@@ -122,7 +122,47 @@ public class UnsafeCode
}
return this.PointerReferenceExpression((double*)ptr);
}
-
+
+ public unsafe int* PointerArithmetic(int* p)
+ {
+ return p + 2;
+ }
+
+ public unsafe byte* PointerArithmetic2(long* p, int y, int x)
+ {
+ return (byte*)((short*)p + (y * x));
+ }
+
+ public unsafe long* PointerArithmetic3(long* p)
+ {
+ return (long*)((byte*)p + 3);
+ }
+
+ public unsafe long* PointerArithmetic4(void* p)
+ {
+ return (long*)((byte*)p + 3);
+ }
+
+ public unsafe int PointerArithmetic5(void* p, byte* q, int i)
+ {
+ return (int)(q[i] + *(byte*)p);
+ }
+
+ public unsafe int PointerSubtraction(long* p, long* q)
+ {
+ return (int)((long)(p - q));
+ }
+
+ public unsafe int PointerSubtraction2(long* p, short* q)
+ {
+ return (int)((long)((byte*)p - (byte*)q));
+ }
+
+ public unsafe int PointerSubtraction3(void* p, void* q)
+ {
+ return (int)((long)((byte*)p - (byte*)q));
+ }
+
unsafe ~UnsafeCode()
{
this.PassPointerAsRefParameter(this.NullPointer);
diff --git a/main/contrib/ICSharpCode.Decompiler/Tests/ValueTypes.cs b/main/contrib/ICSharpCode.Decompiler/Tests/ValueTypes.cs
index b3aa644786..1493cff4c9 100644
--- a/main/contrib/ICSharpCode.Decompiler/Tests/ValueTypes.cs
+++ b/main/contrib/ICSharpCode.Decompiler/Tests/ValueTypes.cs
@@ -168,4 +168,21 @@ public static class ValueTypes
Console.WriteLine("true");
}
}
+
+ public static void CompareNotEqual0IsReallyNotEqual(IComparable<int> a)
+ {
+ if (a.CompareTo(0) != 0)
+ {
+ Console.WriteLine("true");
+ }
+ }
+
+ public static void CompareEqual0IsReallyEqual(IComparable<int> a)
+ {
+ if (a.CompareTo(0) == 0)
+ {
+ Console.WriteLine("true");
+ }
+ }
+
}