From 6a98af56ada1732e3eed698d43c19b961195bc44 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 22 Apr 2011 22:26:28 +0200 Subject: [PATCH] Fixed decompilation when an object initializer is used on a collection type. --- .../ILAst/InitializerPeepholeTransforms.cs | 85 +++++++++---------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs index 059d4c93c..9853fed92 100644 --- a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs +++ b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs @@ -155,19 +155,12 @@ namespace ICSharpCode.Decompiler.ILAst if (!(expr.Match(ILCode.Stloc, out v, out newObjExpr) && newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))) return false; int originalPos = pos; - ILExpression initializer; - if (IsCollectionType(ctor.DeclaringType)) { - // Collection Initializer - initializer = ParseCollectionInitializer(body, ref pos, v, newObjExpr); - } else { - // Object Initializer - - // don't use object initializer syntax for closures - if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, ctor.DeclaringType.ResolveWithinSameModule())) - return false; - - initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr); - } + + // don't use object initializer syntax for closures + if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, ctor.DeclaringType.ResolveWithinSameModule())) + return false; + + ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(ctor.DeclaringType)); if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements return false; @@ -196,6 +189,9 @@ namespace ICSharpCode.Decompiler.ILAst // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject' ChangeFirstArgumentToInitializedObject(initializer); + inlining = new ILInlining(method); + inlining.InlineIfPossible(body, ref originalPos); + return true; } @@ -239,35 +235,6 @@ namespace ICSharpCode.Decompiler.ILAst return false; } - /// - /// Parses a collection initializer. - /// - /// ILAst block - /// - /// Input: position of the instruction assigning to 'v'. - /// Output: first position after the collection initializer - /// - /// The variable that holds the collection - /// The initial value of the collection (newobj instruction) - /// InitCollection instruction - ILExpression ParseCollectionInitializer(List body, ref int pos, ILVariable v, ILExpression newObjExpr) - { - Debug.Assert(((ILExpression)body[pos]).Code == ILCode.Stloc); - ILExpression collectionInitializer = new ILExpression(ILCode.InitCollection, null, newObjExpr); - // Take care not to modify any existing ILExpressions in here. - // We just construct new ones around the old ones, any modifications must wait until the whole - // object/collection initializer was analyzed. - while (++pos < body.Count) { - ILExpression nextExpr = body[pos] as ILExpression; - if (IsAddMethodCall(nextExpr) && nextExpr.Arguments[0].MatchLdloc(v)) { - collectionInitializer.Arguments.Add(nextExpr); - } else { - break; - } - } - return collectionInitializer; - } - /// /// Parses an object initializer. /// @@ -279,13 +246,13 @@ namespace ICSharpCode.Decompiler.ILAst /// The variable that holds the object being initialized /// The newobj instruction /// InitObject instruction - ILExpression ParseObjectInitializer(List body, ref int pos, ILVariable v, ILExpression newObjExpr) + ILExpression ParseObjectInitializer(List body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection) { Debug.Assert(((ILExpression)body[pos]).Code == ILCode.Stloc); // Take care not to modify any existing ILExpressions in here. // We just construct new ones around the old ones, any modifications must wait until the whole // object/collection initializer was analyzed. - ILExpression objectInitializer = new ILExpression(ILCode.InitObject, null, newObjExpr); + ILExpression objectInitializer = new ILExpression(isCollection ? ILCode.InitCollection : ILCode.InitObject, null, newObjExpr); List initializerStack = new List(); initializerStack.Add(objectInitializer); while (++pos < body.Count) { @@ -345,12 +312,36 @@ namespace ICSharpCode.Decompiler.ILAst ILExpression nestedInitializer = new ILExpression( IsCollectionType(returnType) ? ILCode.InitCollection : ILCode.InitObject, null, g); - // add new initializer to its parent, and push it on the stack: - initializerStack[initializerStack.Count - 1].Arguments.Add(nestedInitializer); + // add new initializer to its parent: + ILExpression parentInitializer = initializerStack[initializerStack.Count - 1]; + if (parentInitializer.Code == ILCode.InitCollection) { + // can't add children to collection initializer + if (parentInitializer.Arguments.Count == 1) { + // convert empty collection initializer to object initializer + parentInitializer.Code = ILCode.InitObject; + } else { + return false; + } + } + parentInitializer.Arguments.Add(nestedInitializer); initializerStack.Add(nestedInitializer); } ILExpression lastInitializer = initializerStack[initializerStack.Count - 1]; - return (lastInitializer.Code == ILCode.InitCollection) == isCollection; + if (isCollection) { + return lastInitializer.Code == ILCode.InitCollection; + } else { + if (lastInitializer.Code == ILCode.InitCollection) { + if (lastInitializer.Arguments.Count == 1) { + // convert empty collection initializer to object initializer + lastInitializer.Code = ILCode.InitObject; + return true; + } else { + return false; + } + } else { + return true; + } + } } static void ChangeFirstArgumentToInitializedObject(ILExpression initializer)