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]