diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs
index 474c1e952..9b1d35af4 100644
--- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs
+++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs
@@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.Ast
public void AddType(TypeDefinition typeDef)
{
- TypeDeclaration astType = CreateType(typeDef);
+ var astType = CreateType(typeDef);
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
if (astNS != null) {
astNS.AddChild(astType, NamespaceDeclaration.MemberRole);
@@ -153,7 +153,12 @@ namespace ICSharpCode.Decompiler.Ast
astCompileUnit.AddChild(CreateEvent(ev), CompilationUnit.MemberRole);
}
- public TypeDeclaration CreateType(TypeDefinition typeDef)
+ ///
+ /// Creates the AST for a type definition.
+ ///
+ ///
+ /// TypeDeclaration or DelegateDeclaration.
+ public AttributedNode CreateType(TypeDefinition typeDef)
{
// create CSharp code mappings - used for debugger
if (!CSharpCodeMapping.SourceCodeMappings.ContainsKey(typeDef.FullName)) {
@@ -191,13 +196,13 @@ namespace ICSharpCode.Decompiler.Ast
astType.Constraints.AddRange(MakeConstraints(genericParameters));
// Nested types
- foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
+ foreach (TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
if (MemberIsHidden(nestedTypeDef, context.Settings))
continue;
astType.AddChild(CreateType(nestedTypeDef), TypeDeclaration.MemberRole);
}
-
+ AttributedNode result = astType;
if (typeDef.IsEnum) {
long expectedEnumMemberValue = 0;
bool forcePrintingInitializers = IsFlagsEnum(typeDef);
@@ -218,6 +223,21 @@ namespace ICSharpCode.Decompiler.Ast
astType.AddChild(enumMember, TypeDeclaration.MemberRole);
}
}
+ } else if (typeDef.BaseType != null && typeDef.BaseType.FullName == "System.MulticastDelegate") {
+ DelegateDeclaration dd = new DelegateDeclaration();
+ dd.Modifiers = astType.Modifiers & ~Modifiers.Sealed;
+ dd.Name = astType.Name;
+ dd.AddAnnotation(typeDef);
+ astType.Attributes.MoveTo(dd.Attributes);
+ astType.TypeParameters.MoveTo(dd.TypeParameters);
+ astType.Constraints.MoveTo(dd.Constraints);
+ foreach (var m in typeDef.Methods) {
+ if (m.Name == "Invoke") {
+ dd.ReturnType = ConvertType(m.ReturnType, m.MethodReturnType);
+ dd.Parameters.AddRange(MakeParameters(m.Parameters));
+ }
+ }
+ result = dd;
} else {
// Base type
if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != "System.Object") {
@@ -231,7 +251,7 @@ namespace ICSharpCode.Decompiler.Ast
}
context.CurrentType = oldCurrentType;
- return astType;
+ return result;
}
public void Transform(IAstTransform transform)
@@ -736,6 +756,7 @@ namespace ICSharpCode.Decompiler.Ast
CustomEventDeclaration CreateEvent(EventDefinition eventDef)
{
CustomEventDeclaration astEvent = new CustomEventDeclaration();
+ ConvertCustomAttributes(astEvent, eventDef);
astEvent.AddAnnotation(eventDef);
astEvent.Name = CleanName(eventDef.Name);
astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
@@ -1148,7 +1169,7 @@ namespace ICSharpCode.Decompiler.Ast
}
}
TypeCode code = TypeAnalysis.GetTypeCode(type);
- if (code == TypeCode.Object)
+ if (code == TypeCode.Object || code == TypeCode.Empty)
return new Ast.PrimitiveExpression((int)val);
else
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
index 6da566fcb..8b732fc9b 100644
--- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
+++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
@@ -22,6 +22,7 @@ namespace ICSharpCode.Decompiler.Ast
TypeSystem typeSystem;
DecompilerContext context;
HashSet localVariablesToDefine = new HashSet(); // local variables that are missing a definition
+ HashSet implicitlyDefinedVariables = new HashSet(); // local variables that are implicitly defined (e.g. catch handler)
public static BlockStatement CreateMethodBody(MethodDefinition methodDef, DecompilerContext context)
{
@@ -69,7 +70,7 @@ namespace ICSharpCode.Decompiler.Ast
context.CancellationToken.ThrowIfCancellationRequested();
Ast.BlockStatement astBlock = TransformBlock(ilMethod);
CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
- foreach (ILVariable v in localVariablesToDefine) {
+ foreach (ILVariable v in localVariablesToDefine.Except(implicitlyDefinedVariables)) {
DeclareVariableInSmallestScope.DeclareVariable(astBlock, AstBuilder.ConvertType(v.Type), v.Name);
}
@@ -143,6 +144,8 @@ namespace ICSharpCode.Decompiler.Ast
var tryCatchStmt = new Ast.TryCatchStatement();
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) {
+ if (catchClause.ExceptionVariable != null)
+ implicitlyDefinedVariables.Add(catchClause.ExceptionVariable);
tryCatchStmt.CatchClauses.Add(
new Ast.CatchClause {
Type = AstBuilder.ConvertType(catchClause.ExceptionType),
@@ -610,7 +613,7 @@ namespace ICSharpCode.Decompiler.Ast
};
}
}
- } else if (cecilMethodDef.Name == "Invoke" && cecilMethodDef.DeclaringType.BaseType.FullName == "System.MulticastDelegate") {
+ } else if (cecilMethodDef.Name == "Invoke" && cecilMethodDef.DeclaringType.BaseType != null && cecilMethodDef.DeclaringType.BaseType.FullName == "System.MulticastDelegate") {
AdjustArgumentsForMethodCall(cecilMethod, methodArgs);
return target.Invoke(methodArgs);
}
@@ -754,6 +757,8 @@ namespace ICSharpCode.Decompiler.Ast
}
if (actualIsIntegerOrEnum && requiredIsIntegerOrEnum) {
+ if (actualType.FullName == reqType.FullName)
+ return expr;
return expr.CastTo(AstBuilder.ConvertType(reqType));
}
return expr;
diff --git a/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs b/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
index 1bc37a624..36d319fa8 100644
--- a/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
+++ b/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
@@ -47,13 +47,13 @@ namespace ICSharpCode.Decompiler.Ast
static AstNode FindInsertPos(AstNode node, string name, bool allowPassIntoLoops)
{
- IdentifierExpression ident = node as IdentifierExpression;
- if (ident != null && ident.Identifier == name && ident.TypeArguments.Count == 0)
- return node;
-
AstNode pos = null;
AstNode withinPos = null;
while (node != null) {
+ IdentifierExpression ident = node as IdentifierExpression;
+ if (ident != null && ident.Identifier == name && ident.TypeArguments.Count == 0)
+ return node;
+
AstNode withinCurrent = FindInsertPos(node.FirstChild, name, allowPassIntoLoops);
if (withinCurrent != null) {
if (pos == null) {
diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
index 977867036..daf9d868e 100644
--- a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
+++ b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
@@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (m == null)
break;
- FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation();
+ FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation().ResolveWithinSameModule();
if (fieldDef == null)
break;
AttributedNode fieldOrEventDecl = typeDeclaration.Members.FirstOrDefault(f => f.Annotation() == fieldDef);
@@ -106,7 +106,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
AssignmentExpression assignment = es.Expression as AssignmentExpression;
if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign)
break;
- FieldDefinition fieldDef = assignment.Left.Annotation();
+ FieldDefinition fieldDef = assignment.Left.Annotation().ResolveWithinSameModule();
if (fieldDef == null || !fieldDef.IsStatic)
break;
FieldDeclaration fieldDecl = typeDeclaration.Members.OfType().FirstOrDefault(f => f.Annotation() == fieldDef);
diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
index 4dd384831..9e2dc5042 100644
--- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
+++ b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
@@ -334,7 +334,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
continue;
Match m = automaticPropertyPattern.Match(property);
if (m != null) {
- FieldDefinition field = m.Get("fieldReference").Single().Annotation();
+ FieldDefinition field = m.Get("fieldReference").Single().Annotation().ResolveWithinSameModule();
if (field.IsCompilerGenerated()) {
RemoveCompilerGeneratedAttribute(property.Getter.Attributes);
RemoveCompilerGeneratedAttribute(property.Setter.Attributes);
diff --git a/ICSharpCode.Decompiler/CecilExtensions.cs b/ICSharpCode.Decompiler/CecilExtensions.cs
index 1ef980d1f..2280eba14 100644
--- a/ICSharpCode.Decompiler/CecilExtensions.cs
+++ b/ICSharpCode.Decompiler/CecilExtensions.cs
@@ -159,9 +159,25 @@ namespace ICSharpCode.Decompiler
return accessorMethods;
}
+ public static FieldDefinition ResolveWithinSameModule(this FieldReference field)
+ {
+ if (field != null && field.DeclaringType.GetElementType().Module == field.Module)
+ return field.Resolve();
+ else
+ return null;
+ }
+
+ public static MethodDefinition ResolveWithinSameModule(this MethodReference method)
+ {
+ if (method != null && method.DeclaringType.GetElementType().Module == method.Module)
+ return method.Resolve();
+ else
+ return null;
+ }
+
public static bool IsCompilerGenerated(this ICustomAttributeProvider provider)
{
- if (provider.HasCustomAttributes) {
+ if (provider != null && provider.HasCustomAttributes) {
foreach (CustomAttribute a in provider.CustomAttributes) {
if (a.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")
return true;
diff --git a/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs b/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
index 08c2aaca9..961a58aa2 100644
--- a/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
+++ b/ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
@@ -33,7 +33,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) {
if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) {
if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) {
- i -= ILInlining.InlineInto(block, i + 1, method) - 1;
+ i -= new ILInlining(method).InlineInto(block, i + 1) - 1;
}
return;
}
@@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.ILAst
((ILExpression)block.Body[i]).Arguments[0] = new ILExpression(
ILCode.InitArray, newArrInst.Operand, operands.ToArray());
block.Body.RemoveRange(i + 1, arrayLength);
- i -= ILInlining.InlineInto(block, i + 1, method) - 1;
+ i -= new ILInlining(method).InlineInto(block, i + 1) - 1;
}
};
}
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
index 708dbd123..a58f7b1aa 100644
--- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
@@ -23,8 +23,8 @@ namespace ICSharpCode.Decompiler.ILAst
GotoRemoval,
DuplicateReturns,
FlattenIfStatements,
- PeepholeTransforms,
InlineVariables2,
+ PeepholeTransforms,
TypeInference,
None
}
@@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.InlineVariables) return;
// Works better after simple goto removal because of the following debug pattern: stloc X; br Next; Next:; ldloc X
- InlineVariables(method);
+ ILInlining.InlineAllVariables(method);
if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) {
@@ -97,12 +97,12 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.FlattenIfStatements) return;
FlattenIfStatements(method);
+ if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) return;
+ ILInlining.InlineAllVariables(method);
+
if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return;
PeepholeTransforms.Run(context, method);
- if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) return;
- InlineVariables(method);
-
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
TypeAnalysis.Run(context, method);
@@ -135,88 +135,6 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
- void InlineVariables(ILBlock method)
- {
- // Analyse the whole method
- Dictionary numStloc = new Dictionary();
- Dictionary numLdloc = new Dictionary();
- Dictionary numLdloca = new Dictionary();
-
- foreach(ILExpression expr in method.GetSelfAndChildrenRecursive()) {
- ILVariable locVar = expr.Operand as ILVariable;
- if (locVar != null) {
- if (expr.Code == ILCode.Stloc) {
- numStloc[locVar] = numStloc.GetOrDefault(locVar) + 1;
- } else if (expr.Code == ILCode.Ldloc) {
- numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + 1;
- } else if (expr.Code == ILCode.Ldloca) {
- numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + 1;
- } else {
- throw new NotSupportedException(expr.Code.ToString());
- }
- }
- }
-
- // Inline all blocks
- foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) {
- List body = block.Body;
- for(int i = 0; i < body.Count - 1;) {
- ILExpression nextExpr = body[i + 1] as ILExpression;
- ILVariable locVar;
- ILExpression expr;
- ILExpression ldParent;
- int ldPos;
- if (body[i].Match(ILCode.Stloc, out locVar, out expr) &&
- numStloc.GetOrDefault(locVar) == 1 &&
- numLdloc.GetOrDefault(locVar) == 1 &&
- numLdloca.GetOrDefault(locVar) == 0 &&
- nextExpr != null &&
- FindLdloc(nextExpr, locVar, out ldParent, out ldPos) == true &&
- ldParent != null)
- {
- // Assign the ranges of the optimized instrustions
- expr.ILRanges.AddRange(((ILExpression)body[i]).ILRanges);
- expr.ILRanges.AddRange(ldParent.Arguments[ldPos].ILRanges);
-
- // We are moving the expression evaluation past the other aguments.
- // It is ok to pass ldloc because the expression can not contain stloc and thus the ldloc will still return the same value
- body.RemoveAt(i);
- ldParent.Arguments[ldPos] = expr; // Inline the stloc body
- i = Math.Max(0, i - 1); // Go back one step
- } else {
- i++;
- }
- }
- }
- }
-
- ///
- /// Finds the position to inline to.
- ///
- /// true = found; false = cannot continue search; null = not found
- static bool? FindLdloc(ILExpression expr, ILVariable v, out ILExpression parent, out int pos)
- {
- parent = null;
- pos = 0;
- for (int i = 0; i < expr.Arguments.Count; i++) {
- // Stop when seeing an opcode that does not guarantee that its operands will be evaluated
- // Inlining in that case migth result in the inlined expresion not being evaluted
- if (i == 1 && (expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr || expr.Code == ILCode.TernaryOp))
- return false;
-
- ILExpression arg = expr.Arguments[i];
- if (arg.Code == ILCode.Ldloc && arg.Operand == v) {
- parent = expr;
- pos = i;
- return true;
- }
- bool? r = FindLdloc(arg, v, out parent, out pos);
- if (r != null)
- return r;
- }
- return expr.Code == ILCode.Ldloc ? (bool?)null : false;
- }
-
///
/// Reduces the branch codes to just br and brtrue.
/// Moves ILRanges to the branch argument
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
index 89ad2b781..332690245 100644
--- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
@@ -465,9 +465,12 @@ namespace ICSharpCode.Decompiler.ILAst
public override void WriteTo(ITextOutput output)
{
- Debug.Assert(Values.Count > 0);
- foreach (int i in this.Values) {
- output.WriteLine("case {0}:", i);
+ if (this.Values != null) {
+ foreach (int i in this.Values) {
+ output.WriteLine("case {0}:", i);
+ }
+ } else {
+ output.WriteLine("default:");
}
output.Indent();
base.WriteTo(output);
diff --git a/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/ICSharpCode.Decompiler/ILAst/ILInlining.cs
index 7ec19e7a2..073c01087 100644
--- a/ICSharpCode.Decompiler/ILAst/ILInlining.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILInlining.cs
@@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -12,18 +13,70 @@ namespace ICSharpCode.Decompiler.ILAst
///
public class ILInlining
{
+ public static void InlineAllVariables(ILBlock method)
+ {
+ ILInlining i = new ILInlining(method);
+ foreach (ILBlock block in method.GetSelfAndChildrenRecursive())
+ i.InlineAllInBlock(block);
+ }
+
+ Dictionary numStloc = new Dictionary();
+ Dictionary numLdloc = new Dictionary();
+ Dictionary numLdloca = new Dictionary();
+
+ public ILInlining(ILBlock method)
+ {
+ // Analyse the whole method
+ foreach(ILExpression expr in method.GetSelfAndChildrenRecursive()) {
+ ILVariable locVar = expr.Operand as ILVariable;
+ if (locVar != null) {
+ if (expr.Code == ILCode.Stloc) {
+ numStloc[locVar] = numStloc.GetOrDefault(locVar) + 1;
+ } else if (expr.Code == ILCode.Ldloc) {
+ numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + 1;
+ } else if (expr.Code == ILCode.Ldloca) {
+ numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + 1;
+ } else {
+ throw new NotSupportedException(expr.Code.ToString());
+ }
+ }
+ }
+ }
+
+ public void InlineAllInBlock(ILBlock block)
+ {
+ List body = block.Body;
+ for(int i = 0; i < body.Count - 1;) {
+ ILExpression nextExpr = body[i + 1] as ILExpression;
+ ILVariable locVar;
+ ILExpression expr;
+ ILExpression ldParent;
+ int ldPos;
+ if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineIfPossible(block, i)) {
+
+
+ // We are moving the expression evaluation past the other aguments.
+ // It is ok to pass ldloc because the expression can not contain stloc and thus the ldloc will still return the same value
+
+ i = Math.Max(0, i - 1); // Go back one step
+ } else {
+ i++;
+ }
+ }
+ }
+
///
/// Inlines instructions before pos into block.Body[pos].
///
/// The number of instructions that were inlined.
- public static int InlineInto(ILBlock block, int pos, ILBlock method)
+ public int InlineInto(ILBlock block, int pos)
{
int count = 0;
while (--pos >= 0) {
ILExpression expr = block.Body[pos] as ILExpression;
if (expr == null || expr.Code != ILCode.Stloc)
break;
- if (InlineIfPossible(block, pos, method))
+ if (InlineIfPossible(block, pos))
count++;
else
break;
@@ -34,9 +87,16 @@ namespace ICSharpCode.Decompiler.ILAst
///
/// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible.
///
- public static bool InlineIfPossible(ILBlock block, int pos, ILBlock method)
+ public bool InlineIfPossible(ILBlock block, int pos)
{
- if (InlineIfPossible((ILExpression)block.Body[pos], block.Body.ElementAtOrDefault(pos+1), method)) {
+ ILVariable v;
+ ILExpression inlinedExpression;
+ if (block.Body[pos].Match(ILCode.Stloc, out v, out inlinedExpression)
+ && InlineIfPossible(v, inlinedExpression, block.Body.ElementAtOrDefault(pos+1)))
+ {
+ // Assign the ranges of the stloc instruction:
+ inlinedExpression.ILRanges.AddRange(((ILExpression)block.Body[pos]).ILRanges);
+ // Remove the stloc instruction:
block.Body.RemoveAt(pos);
return true;
}
@@ -46,17 +106,24 @@ namespace ICSharpCode.Decompiler.ILAst
///
/// Inlines 'expr' into 'next', if possible.
///
- public static bool InlineIfPossible(ILExpression expr, ILNode next, ILBlock method)
+ bool InlineIfPossible(ILVariable v, ILExpression inlinedExpression, ILNode next)
{
- if (expr.Code != ILCode.Stloc)
- throw new ArgumentException("expr must be stloc");
// ensure the variable is accessed only a single time
- if (method.GetSelfAndChildrenRecursive().Count(e => e != expr && e.Operand == expr.Operand) != 1)
+ if (!(numStloc.GetOrDefault(v) == 1 && numLdloc.GetOrDefault(v) == 1 && numLdloca.GetOrDefault(v) == 0))
return false;
+ HashSet forbiddenVariables = new HashSet();
+ foreach (ILExpression potentialStore in inlinedExpression.GetSelfAndChildrenRecursive()) {
+ if (potentialStore.Code == ILCode.Stloc)
+ forbiddenVariables.Add((ILVariable)potentialStore.Operand);
+ }
ILExpression parent;
int pos;
- if (FindLoadInNext(next as ILExpression, (ILVariable)expr.Operand, out parent, out pos) == true) {
- parent.Arguments[pos] = expr.Arguments[0];
+ if (FindLoadInNext(next as ILExpression, v, forbiddenVariables, out parent, out pos) == true) {
+ // Assign the ranges of the ldloc instruction:
+ inlinedExpression.ILRanges.AddRange(parent.Arguments[pos].ILRanges);
+
+ parent.Arguments[pos] = inlinedExpression;
+
return true;
}
return false;
@@ -66,29 +133,39 @@ namespace ICSharpCode.Decompiler.ILAst
/// Finds the position to inline to.
///
/// true = found; false = cannot continue search; null = not found
- static bool? FindLoadInNext(ILExpression expr, ILVariable v, out ILExpression parent, out int pos)
+ bool? FindLoadInNext(ILExpression expr, ILVariable v, HashSet forbiddenVariables, out ILExpression parent, out int pos)
{
parent = null;
pos = 0;
if (expr == null)
return false;
for (int i = 0; i < expr.Arguments.Count; i++) {
+ // Stop when seeing an opcode that does not guarantee that its operands will be evaluated.
+ // Inlining in that case might result in the inlined expresion not being evaluted.
+ if (i == 1 && (expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr || expr.Code == ILCode.TernaryOp))
+ return false;
+
ILExpression arg = expr.Arguments[i];
+
if (arg.Code == ILCode.Ldloc && arg.Operand == v) {
parent = expr;
pos = i;
return true;
}
- bool? r = FindLoadInNext(arg, v, out parent, out pos);
+ bool? r = FindLoadInNext(arg, v, forbiddenVariables, out parent, out pos);
if (r != null)
return r;
}
- return IsWithoutSideEffects(expr.Code) ? (bool?)null : false;
- }
-
- static bool IsWithoutSideEffects(ILCode code)
- {
- return code == ILCode.Ldloc;
+ if (expr.Code == ILCode.Ldloc) {
+ ILVariable loadedVar = (ILVariable)expr.Operand;
+ if (!forbiddenVariables.Contains(loadedVar) && numLdloca.GetOrDefault(loadedVar) == 0) {
+ // the expression is loading a non-forbidden variable:
+ // we're allowed to continue searching
+ return null;
+ }
+ }
+ // otherwise: abort, inlining is not possible
+ return false;
}
}
}
diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
index 31e1f1afb..bf5dd5d4d 100644
--- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
+++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
@@ -163,7 +163,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (parent.Arguments[j].Code == ILCode.Ldsfld && parent.Arguments[j].Operand == field) {
parent.Arguments[j] = newObj;
block.Body.RemoveAt(i);
- i -= ILInlining.InlineInto(block, i, method);
+ i -= new ILInlining(method).InlineInto(block, i);
return;
}
}
diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
index e09d14e33..9c211f83d 100644
--- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
+++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
@@ -28,6 +28,10 @@ namespace ICSharpCode.Decompiler.ILAst
ta.method = method;
ta.InferTypes(method);
ta.InferRemainingStores();
+ // Now that stores were inferred, we can infer the remaining instructions that depended on those stored
+ // (but which didn't provide an expected type for the store)
+ // For example, this is necessary to make a switch() over a generated variable work correctly.
+ ta.InferTypes(method);
}
DecompilerContext context;
@@ -257,7 +261,15 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Initobj:
return null;
case ILCode.Localloc:
- return typeSystem.IntPtr;
+ if (forceInferChildren) {
+ InferTypeForExpression(expr.Arguments[0], typeSystem.Int32);
+ }
+ if (expectedType is PointerType)
+ return expectedType;
+ else
+ return typeSystem.IntPtr;
+ case ILCode.Sizeof:
+ return typeSystem.Int32;
#endregion
#region Arithmetic instructions
case ILCode.Not: // bitwise complement
@@ -348,7 +360,6 @@ namespace ICSharpCode.Decompiler.ILAst
{
ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
if (forceInferChildren) {
- InferTypeForExpression(expr.Arguments[0], new ArrayType(typeSystem.Byte));
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
}
return arrayType != null ? arrayType.ElementType : null;
@@ -386,33 +397,43 @@ namespace ICSharpCode.Decompiler.ILAst
#region Conversion instructions
case ILCode.Conv_I1:
case ILCode.Conv_Ovf_I1:
+ case ILCode.Conv_Ovf_I1_Un:
return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == true) ? expectedType : typeSystem.SByte;
case ILCode.Conv_I2:
case ILCode.Conv_Ovf_I2:
+ case ILCode.Conv_Ovf_I2_Un:
return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int16;
case ILCode.Conv_I4:
case ILCode.Conv_Ovf_I4:
+ case ILCode.Conv_Ovf_I4_Un:
return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int32;
case ILCode.Conv_I8:
case ILCode.Conv_Ovf_I8:
+ case ILCode.Conv_Ovf_I8_Un:
return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int64;
case ILCode.Conv_U1:
case ILCode.Conv_Ovf_U1:
+ case ILCode.Conv_Ovf_U1_Un:
return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == false) ? expectedType : typeSystem.Byte;
case ILCode.Conv_U2:
case ILCode.Conv_Ovf_U2:
+ case ILCode.Conv_Ovf_U2_Un:
return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt16;
case ILCode.Conv_U4:
case ILCode.Conv_Ovf_U4:
+ case ILCode.Conv_Ovf_U4_Un:
return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt32;
case ILCode.Conv_U8:
case ILCode.Conv_Ovf_U8:
+ case ILCode.Conv_Ovf_U8_Un:
return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt64;
case ILCode.Conv_I:
case ILCode.Conv_Ovf_I:
+ case ILCode.Conv_Ovf_I_Un:
return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == true) ? expectedType : typeSystem.IntPtr;
case ILCode.Conv_U:
case ILCode.Conv_Ovf_U:
+ case ILCode.Conv_Ovf_U_Un:
return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == false) ? expectedType : typeSystem.UIntPtr;
case ILCode.Conv_R4:
return typeSystem.Single;
diff --git a/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs b/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
index d7b83381c..b7e3f6d29 100644
--- a/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
+++ b/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
@@ -130,18 +130,12 @@ namespace ICSharpCode.Decompiler.ILAst
static FieldDefinition GetFieldDefinition(FieldReference field)
{
- if (field != null && field.DeclaringType.IsGenericInstance)
- return field.Resolve();
- else
- return field as FieldDefinition;
+ return CecilExtensions.ResolveWithinSameModule(field);
}
static MethodDefinition GetMethodDefinition(MethodReference method)
{
- if (method != null && method.DeclaringType.IsGenericInstance)
- return method.Resolve();
- else
- return method as MethodDefinition;
+ return CecilExtensions.ResolveWithinSameModule(method);
}
bool MatchEnumeratorCreationNewObj(ILExpression expr, out MethodDefinition ctor)
diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs
index 1a05566b4..f744e9563 100644
--- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs
+++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs
@@ -46,7 +46,7 @@ namespace AttributeWithTypeArgument
[AttributeUsage(AttributeTargets.All)]
public class MyTypeAttribute : Attribute
{
- public MyTypeAttribute(Type t) : base()
+ public MyTypeAttribute(Type t)
{
}
}
diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs
index dbd064eb4..bfaf57c8a 100644
--- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs
+++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs
@@ -20,7 +20,7 @@ namespace aa
[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : Attribute
{
- public MyAttribute(CustomAtributes.EnumWithFlag en) : base()
+ public MyAttribute(CustomAtributes.EnumWithFlag en)
{
}
}
diff --git a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs
index 398144b2e..3bb80ed84 100644
--- a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs
+++ b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs
@@ -6,6 +6,7 @@ using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests.Types
{
+ [TestFixture]
public class TypeTests : DecompilerTestBase
{
[Test]