diff options
author | Matt Ward <matt.ward@xamarin.com> | 2015-11-19 12:43:19 +0300 |
---|---|---|
committer | Matt Ward <matt.ward@xamarin.com> | 2015-11-19 12:43:19 +0300 |
commit | 3464fad275c48d7c4ffb3602dfcc66afa467b76a (patch) | |
tree | 10db040d0a2cf55165ac8d43dd24b60ca297a887 /main/contrib/ICSharpCode.Decompiler/Ast/Transforms | |
parent | d94562154c646871e5af85aeb9eca1ece86776f9 (diff) | |
parent | 203ed0aabb6a60c7bb18f3b7b490588ab09cf38e (diff) |
Merge branch 'master' into aspnet-project-wizard
Conflicts:
main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
main/tests/UnitTests/UnitTests.csproj
Diffstat (limited to 'main/contrib/ICSharpCode.Decompiler/Ast/Transforms')
6 files changed, 141 insertions, 27 deletions
diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs index 3b38762651..ed1155ba15 100644 --- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs +++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs @@ -144,6 +144,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName)) continue; } + IfElseStatement ies = stmt as IfElseStatement; + if (ies != null) { + foreach (var child in IfElseChainChildren(ies)) { + BlockStatement subBlock = child as BlockStatement; + if (subBlock != null) + DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops); + } + continue; + } foreach (AstNode child in stmt.Children) { BlockStatement subBlock = child as BlockStatement; if (subBlock != null) { @@ -268,6 +277,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } } } + + IfElseStatement ies = stmt as IfElseStatement; + if (ies != null) { + foreach (var child in IfElseChainChildren(ies)) { + if (!(child is BlockStatement) && UsesVariable(child, variableName)) + return false; + } + return true; + } // We can move the variable into a sub-block only if the variable is used in only that sub-block (and not in expressions such as the loop condition) for (AstNode child = stmt.FirstChild; child != null; child = child.NextSibling) { @@ -285,6 +303,19 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } return true; } + + static IEnumerable<AstNode> IfElseChainChildren(IfElseStatement ies) + { + IfElseStatement prev; + do { + yield return ies.Condition; + yield return ies.TrueStatement; + prev = ies; + ies = ies.FalseStatement as IfElseStatement; + } while (ies != null); + if (!prev.FalseStatement.IsNull) + yield return prev.FalseStatement; + } static bool HasNestedBlocks(AstNode node) { diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index 9c5aa97f6e..0741466f95 100644 --- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -180,8 +180,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms foreach (AstNode node in body.Descendants) { if (node is ThisReferenceExpression) node.ReplaceWith(target.Clone()); - } + Expression replacement; if (isLambda) { LambdaExpression lambda = new LambdaExpression(); lambda.CopyAnnotationsFrom(ame); @@ -189,11 +189,19 @@ namespace ICSharpCode.Decompiler.Ast.Transforms Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression; returnExpr.Remove(); lambda.Body = returnExpr; - objectCreateExpression.ReplaceWith(lambda); + replacement = lambda; } else { ame.Body = body; - objectCreateExpression.ReplaceWith(ame); + replacement = ame; + } + var expectedType = objectCreateExpression.Annotation<TypeInformation>().ExpectedType.Resolve(); + if (expectedType != null && !expectedType.IsDelegate()) { + var simplifiedDelegateCreation = (ObjectCreateExpression)objectCreateExpression.Clone(); + simplifiedDelegateCreation.Arguments.Clear(); + simplifiedDelegateCreation.Arguments.Add(replacement); + replacement = simplifiedDelegateCreation; } + objectCreateExpression.ReplaceWith(replacement); return true; } diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs index 32f7cb0dbe..ffd6f5ac76 100644 --- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs +++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs @@ -804,7 +804,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms return new IndexerExpression(targetConverted, indexConverted); } IList<Expression> indexesConverted = ConvertExpressionsArray(index); - if (indexConverted != null) { + if (indexesConverted != null) { return new IndexerExpression(targetConverted, indexesConverted); } return null; diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs index 43548e38d4..a9e72564f3 100644 --- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs +++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs @@ -35,7 +35,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms protected override bool VisitChildren(AstNode node, object data) { bool result = false; - for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { + AstNode next; + for (AstNode child = node.FirstChild; child != null; child = next) { + // Store next to allow the loop to continue + // if the visitor removes/replaces child. + next = child.NextSibling; result |= child.AcceptVisitor(this, data); } if (result && node is EntityDeclaration && !(node is Accessor)) { diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs index 5c3784fa4c..4182eec8f2 100644 --- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs +++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs @@ -38,24 +38,23 @@ namespace ICSharpCode.Decompiler.Ast.Transforms public void Run(AstNode compilationUnit) { - if (!context.Settings.UsingDeclarations) - return; - // First determine all the namespaces that need to be imported: compilationUnit.AcceptVisitor(new FindRequiredImports(this), null); importedNamespaces.Add("System"); // always import System, even when not necessary - // Now add using declarations for those namespaces: - foreach (string ns in importedNamespaces.OrderByDescending(n => n)) { - // we go backwards (OrderByDescending) through the list of namespaces because we insert them backwards - // (always inserting at the start of the list) - string[] parts = ns.Split('.'); - AstType nsType = new SimpleType(parts[0]); - for (int i = 1; i < parts.Length; i++) { - nsType = new MemberType { Target = nsType, MemberName = parts[i] }; + if (context.Settings.UsingDeclarations) { + // Now add using declarations for those namespaces: + foreach (string ns in importedNamespaces.OrderByDescending(n => n)) { + // we go backwards (OrderByDescending) through the list of namespaces because we insert them backwards + // (always inserting at the start of the list) + string[] parts = ns.Split('.'); + AstType nsType = new SimpleType(parts[0]); + for (int i = 1; i < parts.Length; i++) { + nsType = new MemberType { Target = nsType, MemberName = parts[i] }; + } + compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, SyntaxTree.MemberRole); } - compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, SyntaxTree.MemberRole); } if (!context.Settings.FullyQualifyAmbiguousTypeNames) diff --git a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs index 22d1afe627..bff2cc6b95 100644 --- a/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs +++ b/main/contrib/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs @@ -99,6 +99,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms if (result != null) return result; } + AstNode simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement); + if (simplifiedIfElse != null) + return simplifiedIfElse; return base.VisitIfElseStatement(ifElseStatement, data); } @@ -614,6 +617,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms static readonly AstNode lockTryCatchPattern = new TryCatchStatement { TryBlock = new BlockStatement { + new OptionalNode(new VariableDeclarationStatement()).ToStatement(), new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke( "Enter", new AnyNode("enter"), new DirectionExpression { @@ -626,21 +630,57 @@ namespace ICSharpCode.Decompiler.Ast.Transforms new IfElseStatement { Condition = new Backreference("flag"), TrueStatement = new BlockStatement { - new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new NamedNode("exit", new IdentifierExpression(Pattern.AnyString))) + new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new AnyNode("exit")) } } }}; + + static readonly AstNode oldMonitorCallPattern = new ExpressionStatement( + new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Enter", new AnyNode("enter")) + ); + + static readonly AstNode oldLockTryCatchPattern = new TryCatchStatement + { + TryBlock = new BlockStatement { + new Repeat(new AnyNode()).ToStatement() + }, + FinallyBlock = new BlockStatement { + new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new AnyNode("exit")) + } + }; + + bool AnalyzeLockV2(ExpressionStatement node, out Expression enter, out Expression exit) + { + enter = null; + exit = null; + Match m1 = oldMonitorCallPattern.Match(node); + if (!m1.Success) return false; + Match m2 = oldLockTryCatchPattern.Match(node.NextSibling); + if (!m2.Success) return false; + enter = m1.Get<Expression>("enter").Single(); + exit = m2.Get<Expression>("exit").Single(); + return true; + } + + bool AnalyzeLockV4(ExpressionStatement node, out Expression enter, out Expression exit) + { + enter = null; + exit = null; + Match m1 = lockFlagInitPattern.Match(node); + if (!m1.Success) return false; + Match m2 = lockTryCatchPattern.Match(node.NextSibling); + if (!m2.Success) return false; + enter = m2.Get<Expression>("enter").Single(); + exit = m2.Get<Expression>("exit").Single(); + return m1.Get<IdentifierExpression>("variable").Single().Identifier == m2.Get<IdentifierExpression>("flag").Single().Identifier; + } public LockStatement TransformLock(ExpressionStatement node) { - Match m1 = lockFlagInitPattern.Match(node); - if (!m1.Success) return null; - AstNode tryCatch = node.NextSibling; - Match m2 = lockTryCatchPattern.Match(tryCatch); - if (!m2.Success) return null; - if (m1.Get<IdentifierExpression>("variable").Single().Identifier == m2.Get<IdentifierExpression>("flag").Single().Identifier) { - Expression enter = m2.Get<Expression>("enter").Single(); - IdentifierExpression exit = m2.Get<IdentifierExpression>("exit").Single(); + Expression enter, exit; + bool isV2 = AnalyzeLockV2(node, out enter, out exit); + if (isV2 || AnalyzeLockV4(node, out enter, out exit)) { + AstNode tryCatch = node.NextSibling; if (!exit.IsMatch(enter)) { // If exit and enter are not the same, then enter must be "exit = ..." AssignmentExpression assign = enter as AssignmentExpression; @@ -656,7 +696,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms LockStatement l = new LockStatement(); l.Expression = enter.Detach(); l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.Detach(); - ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove(); // Remove 'Enter()' call + if (!isV2) // Remove 'Enter()' call + ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove(); tryCatch.ReplaceWith(l); node.Remove(); // remove flag variable return l; @@ -1047,5 +1088,36 @@ namespace ICSharpCode.Decompiler.Ast.Transforms return null; } #endregion + + #region Simplify cascading if-else-if statements + static readonly IfElseStatement cascadingIfElsePattern = new IfElseStatement + { + Condition = new AnyNode(), + TrueStatement = new AnyNode(), + FalseStatement = new BlockStatement { + Statements = { + new NamedNode( + "nestedIfStatement", + new IfElseStatement { + Condition = new AnyNode(), + TrueStatement = new AnyNode(), + FalseStatement = new OptionalNode(new AnyNode()) + } + ) + } + } + }; + + AstNode SimplifyCascadingIfElseStatements(IfElseStatement node) + { + Match m = cascadingIfElsePattern.Match(node); + if (m.Success) { + IfElseStatement elseIf = m.Get<IfElseStatement>("nestedIfStatement").Single(); + node.FalseStatement = elseIf.Detach(); + } + + return null; + } + #endregion } } |