From 66394b4e52832455854c89b2a43c2cfedd7c25e5 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 27 Aug 2017 16:10:26 +0200 Subject: [PATCH] Remove ILFunction.Read; Add AssignVariableNames --- .../CSharp/CSharpDecompiler.cs | 10 +- .../CSharp/ExpressionBuilder.cs | 6 +- .../CSharp/StatementBuilder.cs | 21 +- .../ICSharpCode.Decompiler.csproj | 1 + ICSharpCode.Decompiler/IL/DetectedLoop.cs | 17 +- .../IL/Instructions/ILFunction.cs | 13 - .../IL/Transforms/AssignVariableNames.cs | 348 ++++++++++++++++++ .../IL/Transforms/DelegateConstruction.cs | 8 +- .../ConnectMethodDecompiler.cs | 5 +- 9 files changed, 392 insertions(+), 37 deletions(-) create mode 100644 ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 814ff656c..73bdfe398 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -115,6 +115,7 @@ namespace ICSharpCode.Decompiler.CSharp } }, new DelegateConstruction(), + new AssignVariableNames() }; } @@ -127,11 +128,11 @@ namespace ICSharpCode.Decompiler.CSharp new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables new DecimalConstantTransform(), new IntroduceUsingDeclarations(), - new FixNameCollisions(), //new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations //new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods //new CombineQueryExpressions(context), //new FlattenSwitchBlocks(), + new FixNameCollisions(), }; public CancellationToken CancellationToken { get; set; } @@ -612,8 +613,11 @@ namespace ICSharpCode.Decompiler.CSharp void DecompileBody(MethodDefinition methodDefinition, IMethod method, EntityDeclaration entityDecl, ITypeResolveContext decompilationContext) { var specializingTypeSystem = typeSystem.GetSpecializingTypeSystem(decompilationContext); - ILFunction function = ILFunction.Read(specializingTypeSystem, methodDefinition, CancellationToken); - + var ilReader = new ILReader(specializingTypeSystem); + ilReader.UseDebugSymbols = settings.UseDebugSymbols; + var function = ilReader.ReadIL(methodDefinition.Body, CancellationToken); + function.CheckInvariant(ILPhase.Normal); + if (entityDecl != null) { int i = 0; var parameters = function.Variables.Where(v => v.Kind == VariableKind.Parameter).ToDictionary(v => v.Index); diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 5f2ed7bf4..e960aaac9 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1415,8 +1415,8 @@ namespace ICSharpCode.Decompiler.CSharp case BlockType.CollectionInitializer: case BlockType.ObjectInitializer: return TranslateObjectAndCollectionInitializer(block); - case BlockType.CompoundOperator: - return TranslateCompoundOperator(block); + case BlockType.PostfixOperator: + return TranslatePostfixOperator(block); default: return ErrorExpression("Unknown block type: " + block.Type); } @@ -1584,7 +1584,7 @@ namespace ICSharpCode.Decompiler.CSharp .WithRR(new ArrayCreateResolveResult(new ArrayType(compilation, type, dimensions), newArr.Indices.Select(i => Translate(i).ResolveResult).ToArray(), elementResolveResults)); } - TranslatedExpression TranslateCompoundOperator(Block block) + TranslatedExpression TranslatePostfixOperator(Block block) { var targetInst = (block.Instructions.ElementAtOrDefault(0) as StLoc)?.Value; var inst = (block.Instructions.ElementAtOrDefault(1) as StLoc)?.Value as BinaryNumericInstruction; diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 3d97733d3..a55b3e957 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -24,6 +24,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.Semantics; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; +using System; using System.Threading; namespace ICSharpCode.Decompiler.CSharp @@ -307,10 +308,10 @@ namespace ICSharpCode.Decompiler.CSharp continueStmt.Remove(); return new DoWhileStatement { EmbeddedStatement = blockStatement, - Condition = exprBuilder.TranslateCondition(loop.Condition) + Condition = exprBuilder.TranslateCondition(CombineConditions(loop.Conditions)) }; case LoopKind.For: - conditionExpr = exprBuilder.TranslateCondition(loop.Condition); + conditionExpr = exprBuilder.TranslateCondition(loop.Conditions[0]); blockStatement = ConvertAsBlock(loop.Body); var forBody = ConvertBlockContainer(blockStatement, container, loop.AdditionalBlocks, true); var forStmt = new ForStatement() { @@ -334,7 +335,7 @@ namespace ICSharpCode.Decompiler.CSharp if (!loop.Body.HasFlag(InstructionFlags.EndPointUnreachable)) blockStatement.Add(new BreakStatement()); } - if (loop.Condition == null) { + if (loop.Conditions == null) { conditionExpr = new PrimitiveExpression(true); Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount); Debug.Assert(blockStatement.Statements.First() is LabelStatement); @@ -343,7 +344,7 @@ namespace ICSharpCode.Decompiler.CSharp blockStatement.Statements.First().Remove(); } } else { - conditionExpr = exprBuilder.TranslateCondition(loop.Condition); + conditionExpr = exprBuilder.TranslateCondition(loop.Conditions[0]); blockStatement = ConvertBlockContainer(blockStatement, container, loop.AdditionalBlocks, true); } if (blockStatement.LastOrDefault() is ContinueStatement stmt) @@ -352,6 +353,18 @@ namespace ICSharpCode.Decompiler.CSharp } } + private ILInstruction CombineConditions(ILInstruction[] conditions) + { + ILInstruction condition = null; + foreach (var c in conditions) { + if (condition == null) + condition = new LogicNot(c); + else + condition = IfInstruction.LogicAnd(new LogicNot(c), condition); + } + return condition; + } + BlockStatement ConvertBlockContainer(BlockContainer container, bool isLoop) { return ConvertBlockContainer(new BlockStatement(), container, container.Blocks, isLoop); diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 923bb7f24..29a7a9858 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -288,6 +288,7 @@ + diff --git a/ICSharpCode.Decompiler/IL/DetectedLoop.cs b/ICSharpCode.Decompiler/IL/DetectedLoop.cs index 890dea2f0..c7bb97263 100644 --- a/ICSharpCode.Decompiler/IL/DetectedLoop.cs +++ b/ICSharpCode.Decompiler/IL/DetectedLoop.cs @@ -29,7 +29,7 @@ namespace ICSharpCode.Decompiler.IL { public BlockContainer Container { get; } public LoopKind Kind { get; private set; } - public ILInstruction Condition { get; private set; } + public ILInstruction[] Conditions { get; private set; } public Block IncrementBlock { get; private set; } public Block ContinueJumpTarget { get; private set; } // jumps to this block are "continue;" jumps public ILInstruction Body { get; private set; } // null in case of DoWhile @@ -64,19 +64,15 @@ namespace ICSharpCode.Decompiler.IL return new DetectedLoop(container).DetectLoopInternal(); } - private static Block FindDoWhileConditionBlock(BlockContainer container, out ILInstruction condition) + private static Block FindDoWhileConditionBlock(BlockContainer container, List conditions) { - condition = null; foreach (var b in container.Blocks) { if (b.Instructions.Last().MatchBranch(container.EntryPoint)) { // potentially the do-while-condition block int i = b.Instructions.Count - 2; while (i >= 0 && b.Instructions[i] is IfInstruction ifInst && ifInst.TrueInst.MatchLeave(container) && ifInst.FalseInst.MatchNop()) { - if (condition == null) - condition = new LogicNot(ifInst.Condition); - else - condition = IfInstruction.LogicAnd(new LogicNot(ifInst.Condition), condition); + conditions.Add(ifInst.Condition); i--; } if (i == -1) { @@ -105,7 +101,7 @@ namespace ICSharpCode.Decompiler.IL if (IncrementBlock != null) ContinueJumpTarget = IncrementBlock; } - Condition = conditionInst; + Conditions = new[] { conditionInst }; Body = trueInst; if (IncrementBlock != null) { // for-loop @@ -117,12 +113,13 @@ namespace ICSharpCode.Decompiler.IL } else { // do-while or while(true)-loop if (Container.EntryPoint.IncomingEdgeCount == 2) { - Block conditionBlock = FindDoWhileConditionBlock(Container, out var conditionInst2); + var conditions = new List(); + Block conditionBlock = FindDoWhileConditionBlock(Container, conditions); if (conditionBlock != null) { Kind = LoopKind.DoWhile; ContinueJumpTarget = conditionBlock; Body = null; - Condition = conditionInst2; + Conditions = conditions.ToArray(); AdditionalBlocks = Container.Blocks.Where(b => b != conditionBlock).ToArray(); } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs index 93b134239..f076d2e79 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs @@ -151,18 +151,5 @@ namespace ICSharpCode.Decompiler.IL Variables.Add(variable); return variable; } - - public static ILFunction Read(IDecompilerTypeSystem context, IMethod method, CancellationToken cancellationToken = default(CancellationToken)) - { - return Read(context, (MethodDefinition)context.GetCecil(method), cancellationToken); - } - - public static ILFunction Read(IDecompilerTypeSystem context, MethodDefinition methodDefinition, CancellationToken cancellationToken = default(CancellationToken)) - { - var ilReader = new ILReader(context); - var function = ilReader.ReadIL(methodDefinition.Body, cancellationToken); - function.CheckInvariant(ILPhase.Normal); - return function; - } } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs b/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs new file mode 100644 index 000000000..da549e2db --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs @@ -0,0 +1,348 @@ +// Copyright (c) 2017 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.Semantics; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Util; + +namespace ICSharpCode.Decompiler.IL.Transforms +{ + public class AssignVariableNames : IILTransform + { + static readonly Dictionary typeNameToVariableNameDict = new Dictionary { + { "System.Boolean", "flag" }, + { "System.Byte", "b" }, + { "System.SByte", "b" }, + { "System.Int16", "num" }, + { "System.Int32", "num" }, + { "System.Int64", "num" }, + { "System.UInt16", "num" }, + { "System.UInt32", "num" }, + { "System.UInt64", "num" }, + { "System.Single", "num" }, + { "System.Double", "num" }, + { "System.Decimal", "num" }, + { "System.String", "text" }, + { "System.Object", "obj" }, + { "System.Char", "c" } + }; + + ILTransformContext context; + string[] currentFieldNames; + Dictionary mapping; + Dictionary reservedVariableNames; + const char maxLoopVariableName = 'n'; + + public void Run(ILFunction function, ILTransformContext context) + { + this.context = context; + currentFieldNames = function.Method.DeclaringType.Fields.Select(f => f.Name).ToArray(); + reservedVariableNames = new Dictionary(); + foreach (ILFunction f in function.Descendants.OfType().Reverse()) { + PerformAssignment(f); + } + } + + void PerformAssignment(ILFunction function) + { + foreach (var p in function.Method.Parameters) + AddExistingName(p.Name); + foreach (var v in function.Variables) { + switch (v.Kind) { + case VariableKind.Parameter: + case VariableKind.StackSlot: // keep generated names + AddExistingName(v.Name); + break; + default: + string varName = v.Name; + if (context.Settings.UseDebugSymbols) { + if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || !IsValidName(varName)) { + // don't use the name from the debug symbols if it looks like a generated name + v.Name = null; + } else { + // use the name from the debug symbols + // (but ensure we don't use the same name for two variables) + v.Name = GetAlternativeName(varName); + } + } else { + v.Name = null; + } + break; + } + } + // Now generate names: + var mapping = new Dictionary(ILVariableEqualityComparer.Instance); + foreach (var inst in function.Descendants.OfType()) { + var v = inst.Variable; + if (!mapping.TryGetValue(v, out string name)) { + if (string.IsNullOrEmpty(v.Name)) + v.Name = GenerateNameForVariable(v, function.Body); + mapping.Add(v, v.Name); + } else { + v.Name = name; + } + } + } + + static bool IsValidName(string varName) + { + if (string.IsNullOrEmpty(varName)) + return false; + if (!(char.IsLetter(varName[0]) || varName[0] == '_')) + return false; + for (int i = 1; i < varName.Length; i++) { + if (!(char.IsLetterOrDigit(varName[i]) || varName[i] == '_')) + return false; + } + return true; + } + + public string GetAlternativeName(string oldVariableName) + { + if (oldVariableName.Length == 1 && oldVariableName[0] >= 'i' && oldVariableName[0] <= maxLoopVariableName) { + for (char c = 'i'; c <= maxLoopVariableName; c++) { + if (!reservedVariableNames.ContainsKey(c.ToString())) { + reservedVariableNames.Add(c.ToString(), 1); + return c.ToString(); + } + } + } + + int number; + string nameWithoutDigits = SplitName(oldVariableName, out number); + + if (!reservedVariableNames.ContainsKey(nameWithoutDigits)) { + reservedVariableNames.Add(nameWithoutDigits, number - 1); + } + int count = ++reservedVariableNames[nameWithoutDigits]; + if (count != 1) { + return nameWithoutDigits + count.ToString(); + } else { + return nameWithoutDigits; + } + } + + string GenerateNameForVariable(ILVariable variable, ILInstruction methodBody) + { + string proposedName = null; + if (variable.Type.IsKnownType(KnownTypeCode.Int32)) { + // test whether the variable might be a loop counter + bool isLoopCounter = false; + foreach (BlockContainer possibleLoop in methodBody.Descendants.OfType().Reverse()) { + if (possibleLoop.EntryPoint.IncomingEdgeCount == 1) continue; + var loop = DetectedLoop.DetectLoop(possibleLoop); + if (loop.Kind != LoopKind.For) continue; + var condition = loop.Conditions?[0]; + while (condition is LogicNot not) + condition = not.Argument; + if (condition is Comp comp) { + switch (comp.Kind) { + case ComparisonKind.GreaterThan: + case ComparisonKind.GreaterThanOrEqual: + case ComparisonKind.LessThan: + case ComparisonKind.LessThanOrEqual: + if (comp.Left.MatchLdLoc(variable)) { + isLoopCounter = true; + } + break; + } + } + } + if (isLoopCounter) { + // For loop variables, use i,j,k,l,m,n + for (char c = 'i'; c <= maxLoopVariableName; c++) { + if (!reservedVariableNames.ContainsKey(c.ToString())) { + proposedName = c.ToString(); + break; + } + } + } + } + if (string.IsNullOrEmpty(proposedName)) { + var proposedNameForStores = variable.StoreInstructions.OfType() + .Select(expr => GetNameFromInstruction(expr.Value)) + .Except(currentFieldNames).ToList(); + if (proposedNameForStores.Count == 1) { + proposedName = proposedNameForStores[0]; + } + } + if (string.IsNullOrEmpty(proposedName)) { + var proposedNameForLoads = variable.LoadInstructions + .Select(arg => GetNameForArgument(arg.Parent, arg.ChildIndex)) + .Except(currentFieldNames).ToList(); + if (proposedNameForLoads.Count == 1) { + proposedName = proposedNameForLoads[0]; + } + } + if (string.IsNullOrEmpty(proposedName)) { + proposedName = GetNameByType(variable.Type); + } + + // remove any numbers from the proposed name + int number; + proposedName = SplitName(proposedName, out number); + + if (!reservedVariableNames.ContainsKey(proposedName)) { + reservedVariableNames.Add(proposedName, 0); + } + int count = ++reservedVariableNames[proposedName]; + if (count > 1) { + return proposedName + count.ToString(); + } else { + return proposedName; + } + } + + static string GetNameFromInstruction(ILInstruction inst) + { + switch (inst) { + case LdObj ldobj: + IField field; + if (ldobj.Target is LdFlda ldflda) + field = ldflda.Field; + else if (ldobj.Target is LdsFlda ldsflda) + field = ldsflda.Field; + else + break; + return CleanUpVariableName(field.Name); + case CallInstruction call: + if (call is NewObj) break; + IMethod m = call.Method; + if (m.Name.StartsWith("get_", StringComparison.OrdinalIgnoreCase) && m.Parameters.Count == 0) { + // use name from properties, but not from indexers + return CleanUpVariableName(m.Name.Substring(4)); + } else if (m.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase) && m.Name.Length >= 4 && char.IsUpper(m.Name[3])) { + // use name from Get-methods + return CleanUpVariableName(m.Name.Substring(3)); + } + break; + } + return null; + } + + static string GetNameForArgument(ILInstruction parent, int i) + { + switch (parent) { + case StObj stobj: + IField field; + if (stobj.Target is LdFlda ldflda) + field = ldflda.Field; + else if (stobj.Target is LdsFlda ldsflda) + field = ldsflda.Field; + else + break; + return CleanUpVariableName(field.Name); + case CallInstruction call: + IMethod m = call.Method; + if (m.Parameters.Count == 1 && i == call.Arguments.Count - 1) { + // argument might be value of a setter + if (m.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase)) { + return CleanUpVariableName(m.Name.Substring(4)); + } else if (m.Name.StartsWith("Set", StringComparison.OrdinalIgnoreCase) && m.Name.Length >= 4 && char.IsUpper(m.Name[3])) { + return CleanUpVariableName(m.Name.Substring(3)); + } + } + var p = m.Parameters.ElementAtOrDefault((!(call is NewObj) && !m.IsStatic) ? i - 1 : i); + if (p != null && !string.IsNullOrEmpty(p.Name)) + return CleanUpVariableName(p.Name); + break; + case Return ret: + return "result"; + } + return null; + } + + string GetNameByType(IType type) + { + var git = type as ParameterizedType; + if (git != null && git.FullName == "System.Nullable`1" && git.TypeArguments.Count == 1) { + type = git.TypeArguments[0]; + } + + string name; + if (type is ArrayType) { + name = "array"; + } else if (type is PointerType) { + name = "ptr"; + } else if (type.IsAnonymousType()) { + name = "anon"; + } else if (type.Name.EndsWith("Exception", StringComparison.Ordinal)) { + name = "ex"; + } else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) { + name = type.Name; + // remove the 'I' for interfaces + if (name.Length >= 3 && name[0] == 'I' && char.IsUpper(name[1]) && char.IsLower(name[2])) + name = name.Substring(1); + name = CleanUpVariableName(name); + } + return name; + } + + void AddExistingName(string name) + { + if (string.IsNullOrEmpty(name)) + return; + string nameWithoutDigits = SplitName(name, out int number); + if (reservedVariableNames.TryGetValue(nameWithoutDigits, out int existingNumber)) { + reservedVariableNames[nameWithoutDigits] = Math.Max(number, existingNumber); + } else { + reservedVariableNames.Add(nameWithoutDigits, number); + } + } + + static string SplitName(string name, out int number) + { + // First, identify whether the name already ends with a number: + int pos = name.Length; + while (pos > 0 && name[pos - 1] >= '0' && name[pos - 1] <= '9') + pos--; + if (pos < name.Length) { + if (int.TryParse(name.Substring(pos), out number)) { + return name.Substring(0, pos); + } + } + number = 1; + return name; + } + + static string CleanUpVariableName(string name) + { + // remove the backtick (generics) + int pos = name.IndexOf('`'); + if (pos >= 0) + name = name.Substring(0, pos); + + // remove field prefix: + if (name.Length > 2 && name.StartsWith("m_", StringComparison.Ordinal)) + name = name.Substring(2); + else if (name.Length > 1 && name[0] == '_' && (char.IsLetter(name[1]) || name[1] == '_')) + name = name.Substring(1); + + if (name.Length == 0) + return "obj"; + else + return char.ToLower(name[0]) + name.Substring(1); + } + } +} diff --git a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs index 119707ebc..3d49bf927 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs @@ -139,9 +139,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms var targetMethod = ((IInstructionWithMethodOperand)value.Arguments[1]).Method; if (IsAnonymousMethod(decompilationContext.CurrentTypeDefinition, targetMethod)) { target = value.Arguments[0]; + var methodDefinition = (Mono.Cecil.MethodDefinition)context.TypeSystem.GetCecil(targetMethod); var localTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(new SimpleTypeResolveContext(targetMethod)); - var function = ILFunction.Read(localTypeSystem, targetMethod, context.CancellationToken); - + var ilReader = new ILReader(localTypeSystem); + ilReader.UseDebugSymbols = context.Settings.UseDebugSymbols; + var function = ilReader.ReadIL(methodDefinition.Body, context.CancellationToken); + function.CheckInvariant(ILPhase.Normal); + var contextPrefix = targetMethod.Name; foreach (ILVariable v in function.Variables.Where(v => v.Kind != VariableKind.Parameter)) { v.Name = contextPrefix + v.Name; diff --git a/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs index f4ddec62c..51accc294 100644 --- a/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs +++ b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs @@ -56,8 +56,9 @@ namespace ILSpy.BamlDecompiler // decompile method and optimize the switch var typeSystem = new DecompilerTypeSystem(method.Module); - ILFunction function = ILFunction.Read(typeSystem, method); - + var ilReader = new ILReader(typeSystem); + var function = ilReader.ReadIL(method.Body); + var context = new ILTransformContext { Settings = new DecompilerSettings(), TypeSystem = typeSystem }; function.RunTransforms(CSharpDecompiler.GetILTransforms(), context);