From d33c334f5a054494d8ba557cc872bdeaa0ddccae Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 14 Sep 2017 14:31:35 +0200 Subject: [PATCH] Fix #284 - Ability to disable decompilation of anonymous types to "var" --- .../CSharp/CSharpDecompiler.cs | 2 +- .../CSharp/ExpressionBuilder.cs | 15 +++++++-------- .../CSharp/Transforms/DeclareVariables.cs | 2 +- .../Transforms/PatternStatementTransform.cs | 6 +++--- ICSharpCode.Decompiler/DecompilerSettings.cs | 17 ++++++++++++++++- ILSpy/Options/DecompilerSettingsPanel.xaml | 1 + ILSpy/Options/DecompilerSettingsPanel.xaml.cs | 2 ++ 7 files changed, 31 insertions(+), 14 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 1947aff16..19be73a45 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -195,7 +195,7 @@ namespace ICSharpCode.Decompiler.CSharp } else if (type.IsCompilerGenerated()) { // if (type.Name.StartsWith("", StringComparison.Ordinal)) // return true; - if (type.IsAnonymousType()) + if (settings.AnonymousTypes && type.IsAnonymousType()) return true; } } diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 8c101d1f3..e1f4d4bad 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1011,7 +1011,7 @@ namespace ICSharpCode.Decompiler.CSharp simplifiedDelegateCreation.Arguments.Clear(); simplifiedDelegateCreation.Arguments.Add(replacement); replacement = simplifiedDelegateCreation; - } else if (!expectedType.ContainsAnonymousType()) { + } else if (!settings.AnonymousTypes || !expectedType.ContainsAnonymousType()) { replacement = new CastExpression(ConvertType(expectedType), replacement); } return replacement @@ -1025,7 +1025,7 @@ namespace ICSharpCode.Decompiler.CSharp int i = 0; foreach (var parameter in method.Parameters) { var pd = astBuilder.ConvertParameter(parameter); - if (parameter.Type.ContainsAnonymousType()) + if (settings.AnonymousTypes && parameter.Type.ContainsAnonymousType()) pd.Type = null; ILVariable v; if (variables.TryGetValue(i, out v)) @@ -1111,7 +1111,7 @@ namespace ICSharpCode.Decompiler.CSharp if (inst.OpCode == OpCode.NewObj) { var argumentExpressions = arguments.SelectArray(arg => arg.Expression); - if (method.DeclaringType.IsAnonymousType()) { + if (settings.AnonymousTypes && method.DeclaringType.IsAnonymousType()) { AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression(); var parameters = inst.Method.Parameters; if (CanInferAnonymousTypePropertyNamesFromArguments(argumentExpressions, parameters)) { @@ -1171,7 +1171,7 @@ namespace ICSharpCode.Decompiler.CSharp if (!argumentsCasted) { argumentsCasted = true; for (int i = 0; i < arguments.Length; i++) { - if (!method.Parameters[i].Type.ContainsAnonymousType()) + if (!settings.AnonymousTypes || !method.Parameters[i].Type.ContainsAnonymousType()) arguments[i] = arguments[i].ConvertTo(method.Parameters[i].Type, this); } } else if (!targetCasted) { @@ -1196,7 +1196,7 @@ namespace ICSharpCode.Decompiler.CSharp methodName = method.ImplementedInterfaceMembers[0].Name; } var mre = new MemberReferenceExpression(targetExpr, methodName); - if (requireTypeArguments && !method.TypeArguments.Any(a => a.ContainsAnonymousType())) + if (requireTypeArguments && (!settings.AnonymousTypes || !method.TypeArguments.Any(a => a.ContainsAnonymousType()))) mre.TypeArguments.AddRange(method.TypeArguments.Select(ConvertType)); var argumentExpressions = arguments.Select(arg => arg.Expression); expr = new InvocationExpression(mre, argumentExpressions); @@ -1621,8 +1621,7 @@ namespace ICSharpCode.Decompiler.CSharp } ArraySpecifier[] additionalSpecifiers; AstType typeExpression; - bool isAnonymouslyTyped = type.ContainsAnonymousType(); - if (isAnonymouslyTyped) { + if (settings.AnonymousTypes && type.ContainsAnonymousType()) { typeExpression = null; additionalSpecifiers = new[] { new ArraySpecifier() }; } else { @@ -1639,7 +1638,7 @@ namespace ICSharpCode.Decompiler.CSharp Initializer = root }; expr.AdditionalArraySpecifiers.AddRange(additionalSpecifiers); - if (!isAnonymouslyTyped) + if (!(bool)type.ContainsAnonymousType()) expr.Arguments.AddRange(newArr.Indices.Select(i => Translate(i).Expression)); return expr.WithILInstruction(block) .WithRR(new ArrayCreateResolveResult(new ArrayType(compilation, type, dimensions), newArr.Indices.Select(i => Translate(i).ResolveResult).ToArray(), elementResolveResults)); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs index ed9460248..4a27e8583 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs @@ -363,7 +363,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms } if (assignment != null && assignment.Operator == AssignmentOperatorType.Assign && assignment.Left.IsMatch(expectedExpr)) { AstType type; - if (v.Type.ContainsAnonymousType()) { + if (context.Settings.AnonymousTypes && v.Type.ContainsAnonymousType()) { type = new SimpleType("var"); } else { type = context.TypeSystemAstBuilder.ConvertType(v.Type); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs index 955cc93cb..9c718b350 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs @@ -280,7 +280,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms // variable is used, so we'll create a variable declaration variable.Kind = IL.VariableKind.UsingLocal; usingStatement.ResourceAcquisition = new VariableDeclarationStatement { - Type = variable.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(variable.Type), + Type = context.Settings.AnonymousTypes && variable.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(variable.Type), Variables = { new VariableInitializer { Name = variableName, @@ -401,7 +401,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms itemVar.Kind = IL.VariableKind.ForeachLocal; ForeachStatement foreachStatement = new ForeachStatement { - VariableType = itemVar.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(itemVar.Type), + VariableType = context.Settings.AnonymousTypes && itemVar.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(itemVar.Type), VariableName = itemVar.Name, InExpression = m.Get("collection").Single().Detach(), EmbeddedStatement = newBody @@ -533,7 +533,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms itemVar.Kind = IL.VariableKind.ForeachLocal; ForeachStatement foreachStatement = new ForeachStatement { - VariableType = itemVar.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(itemVar.Type), + VariableType = context.Settings.AnonymousTypes && itemVar.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(itemVar.Type), VariableName = itemVar.Name, }.WithILVariable(itemVar); BlockStatement body = new BlockStatement(); diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index 091026c7a..11663d098 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -41,7 +41,22 @@ namespace ICSharpCode.Decompiler } } } - + + bool anonymousTypes = true; + + /// + /// Decompile anonymous types. + /// + public bool AnonymousTypes { + get { return anonymousTypes; } + set { + if (anonymousTypes != value) { + anonymousTypes = value; + OnPropertyChanged("AnonymousTypes"); + } + } + } + bool expressionTrees = true; /// diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml b/ILSpy/Options/DecompilerSettingsPanel.xaml index 27584b43b..ecad2b28b 100644 --- a/ILSpy/Options/DecompilerSettingsPanel.xaml +++ b/ILSpy/Options/DecompilerSettingsPanel.xaml @@ -4,6 +4,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> Decompile anonymous methods/lambdas + Decompile anonymous types Decompile enumerators (yield return) Decompile async methods (async/await) Decompile query expressions diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs index 23d624cc5..b013aa708 100644 --- a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs +++ b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs @@ -51,6 +51,7 @@ namespace ICSharpCode.ILSpy.Options XElement e = settings["DecompilerSettings"]; DecompilerSettings s = new DecompilerSettings(); s.AnonymousMethods = (bool?)e.Attribute("anonymousMethods") ?? s.AnonymousMethods; + s.AnonymousTypes = (bool?)e.Attribute("anonymousTypes") ?? s.AnonymousTypes; s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn; s.AsyncAwait = (bool?)e.Attribute("asyncAwait") ?? s.AsyncAwait; s.AutomaticProperties = (bool?) e.Attribute("automaticProperties") ?? s.AutomaticProperties; @@ -67,6 +68,7 @@ namespace ICSharpCode.ILSpy.Options DecompilerSettings s = (DecompilerSettings)this.DataContext; XElement section = new XElement("DecompilerSettings"); section.SetAttributeValue("anonymousMethods", s.AnonymousMethods); + section.SetAttributeValue("anonymousTypes", s.AnonymousTypes); section.SetAttributeValue("yieldReturn", s.YieldReturn); section.SetAttributeValue("asyncAwait", s.AsyncAwait); section.SetAttributeValue("automaticProperties", s.AutomaticProperties);