Browse Source

Add support for the using statement. Closes #7.

pull/37/head
Daniel Grunwald 14 years ago
parent
commit
221781f8f1
  1. 5
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 7
      ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs
  3. 7
      ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  4. 6
      ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs
  5. 9
      ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
  6. 18
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  7. 68
      ICSharpCode.Decompiler/Ast/Transforms/UsingStatementTransform.cs
  8. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  9. 2
      ILSpy/CSharpLanguage.cs
  10. 4
      ILSpy/TreeNodes/ThreadedTreeNode.cs

5
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -3,6 +3,7 @@ using System.Collections.Generic; @@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Decompiler.Transforms;
using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
@ -40,9 +41,9 @@ namespace Decompiler @@ -40,9 +41,9 @@ namespace Decompiler
GenerateCode(output, null);
}
public void GenerateCode(ITextOutput output, Predicate<IAstVisitor<object, object>> transformAbortCondition)
public void GenerateCode(ITextOutput output, Predicate<IAstTransform> transformAbortCondition)
{
Transforms.TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition, context);
TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition, context);
astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null);
var outputFormatter = new TextOutputFormatter(output);

7
ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs

@ -11,7 +11,7 @@ namespace Decompiler.Transforms @@ -11,7 +11,7 @@ namespace Decompiler.Transforms
/// <summary>
/// Base class for AST visitors that need the current type/method context info.
/// </summary>
public abstract class ContextTrackingVisitor : DepthFirstAstVisitor<object, object>
public abstract class ContextTrackingVisitor : DepthFirstAstVisitor<object, object>, IAstTransform
{
protected readonly DecompilerContext context;
@ -65,5 +65,10 @@ namespace Decompiler.Transforms @@ -65,5 +65,10 @@ namespace Decompiler.Transforms
context.CurrentMethod = null;
}
}
void IAstTransform.Run(AstNode node)
{
node.AcceptVisitor(this, null);
}
}
}

7
ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -8,7 +8,7 @@ using Mono.Cecil; @@ -8,7 +8,7 @@ using Mono.Cecil;
namespace Decompiler.Transforms
{
public class ConvertConstructorCallIntoInitializer : DepthFirstAstVisitor<object, object>
public class ConvertConstructorCallIntoInitializer : DepthFirstAstVisitor<object, object>, IAstTransform
{
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
{
@ -51,5 +51,10 @@ namespace Decompiler.Transforms @@ -51,5 +51,10 @@ namespace Decompiler.Transforms
}
return null;
}
void IAstTransform.Run(AstNode node)
{
node.AcceptVisitor(this, null);
}
}
}

6
ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs

@ -5,7 +5,7 @@ using ICSharpCode.NRefactory.CSharp; @@ -5,7 +5,7 @@ using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms
{
public class PushNegation: DepthFirstAstVisitor<object, object>
public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform
{
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data)
{
@ -97,5 +97,9 @@ namespace Decompiler.Transforms @@ -97,5 +97,9 @@ namespace Decompiler.Transforms
return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data);
}
}
void IAstTransform.Run(AstNode node)
{
node.AcceptVisitor(this, null);
}
}
}

9
ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs

@ -11,7 +11,7 @@ namespace Decompiler.Transforms @@ -11,7 +11,7 @@ namespace Decompiler.Transforms
/// Replaces method calls with the appropriate operator expressions.
/// Also simplifies "x = x op y" into "x op= y" where possible.
/// </summary>
public class ReplaceMethodCallsWithOperators : DepthFirstAstVisitor<object, object>
public class ReplaceMethodCallsWithOperators : DepthFirstAstVisitor<object, object>, IAstTransform
{
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
@ -145,7 +145,7 @@ namespace Decompiler.Transforms @@ -145,7 +145,7 @@ namespace Decompiler.Transforms
// First, combine "x = x op y" into "x op= y"
BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression;
if (binary != null && assignment.Operator == AssignmentOperatorType.Assign) {
if (IsWithoutSideEffects(assignment.Left) && AstComparer.AreEqual(assignment.Left, binary.Left) == true) {
if (IsWithoutSideEffects(assignment.Left) && assignment.Left.Match(binary.Left) != null) {
switch (binary.Operator) {
case BinaryOperatorType.Add:
assignment.Operator = AssignmentOperatorType.Add;
@ -191,5 +191,10 @@ namespace Decompiler.Transforms @@ -191,5 +191,10 @@ namespace Decompiler.Transforms
{
return left is IdentifierExpression; // TODO
}
void IAstTransform.Run(AstNode node)
{
node.AcceptVisitor(this, null);
}
}
}

18
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -7,19 +7,25 @@ using ICSharpCode.NRefactory.CSharp; @@ -7,19 +7,25 @@ using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms
{
public interface IAstTransform
{
void Run(AstNode node);
}
public static class TransformationPipeline
{
public static IAstVisitor<object, object>[] CreatePipeline(DecompilerContext context)
public static IAstTransform[] CreatePipeline(DecompilerContext context)
{
return new IAstVisitor<object, object>[] {
return new IAstTransform[] {
new PushNegation(),
new DelegateConstruction(context),
new UsingStatementTransform(),
new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(),
};
}
public static void RunTransformationsUntil(AstNode node, Predicate<IAstVisitor<object, object>> abortCondition, DecompilerContext context)
public static void RunTransformationsUntil(AstNode node, Predicate<IAstTransform> abortCondition, DecompilerContext context)
{
if (node == null)
return;
@ -37,11 +43,11 @@ namespace Decompiler.Transforms @@ -37,11 +43,11 @@ namespace Decompiler.Transforms
}
}
foreach (var visitor in CreatePipeline(context)) {
foreach (var transform in CreatePipeline(context)) {
context.CancellationToken.ThrowIfCancellationRequested();
if (abortCondition != null && abortCondition(visitor))
if (abortCondition != null && abortCondition(transform))
return;
node.AcceptVisitor(visitor, null);
transform.Run(node);
}
}
}

68
ICSharpCode.Decompiler/Ast/Transforms/UsingStatementTransform.cs

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Linq;
using Decompiler.Transforms;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
namespace Decompiler.Transforms
{
/// <summary>
/// Description of UsingStatementTransform.
/// </summary>
public class UsingStatementTransform : IAstTransform
{
static readonly AstNode usingVarDeclPattern = new VariableDeclarationStatement {
Type = new AnyNode("type").ToType(),
Variables = {
new NamedNode(
"variable",
new VariableInitializer {
Initializer = new AnyNode().ToExpression()
}
).ToVariable()
}
};
static readonly AstNode usingTryCatchPattern = new TryCatchStatement {
TryBlock = new AnyNode("body").ToBlock(),
FinallyBlock = new BlockStatement {
Statements = {
new IfElseStatement {
Condition = new BinaryOperatorExpression(
new NamedNode("ident", new IdentifierExpression()).ToExpression(),
BinaryOperatorType.InEquality,
new NullReferenceExpression()
),
TrueStatement = new BlockStatement {
Statements = {
new ExpressionStatement(new Backreference("ident").ToExpression().Invoke("Dispose"))
}
}
}
}
}
};
public void Run(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
Match m1 = usingVarDeclPattern.Match(node);
if (m1 == null) continue;
Match m2 = usingTryCatchPattern.Match(node.NextSibling);
if (m2 == null) continue;
if (((VariableInitializer)m1["variable"].Single()).Name == ((IdentifierExpression)m2["ident"].Single()).Identifier) {
BlockStatement body = (BlockStatement)m2["body"].Single();
body.Remove();
node.NextSibling.Remove();
node.ReplaceWith(
varDecl => new UsingStatement {
ResourceAcquisition = varDecl,
EmbeddedStatement = body
});
}
}
}
}
}

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -66,6 +66,7 @@ @@ -66,6 +66,7 @@
<Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" />
<Compile Include="Ast\Transforms\TransformationPipeline.cs" />
<Compile Include="Ast\Transforms\UsingStatementTransform.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="DecompilerException.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />
@ -113,6 +114,7 @@ @@ -113,6 +114,7 @@
<Folder Include="Ast\Transforms" />
<Folder Include="Disassembler" />
<Folder Include="ILAst" />
<Folder Include="Mono.Cecil.Rocks" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild">

2
ILSpy/CSharpLanguage.cs

@ -36,7 +36,7 @@ namespace ICSharpCode.ILSpy @@ -36,7 +36,7 @@ namespace ICSharpCode.ILSpy
{
string name = "C#";
bool showAllMembers;
Predicate<IAstVisitor<object, object>> transformAbortCondition = null;
Predicate<IAstTransform> transformAbortCondition = null;
public CSharpLanguage()
{

4
ILSpy/TreeNodes/ThreadedTreeNode.cs

@ -50,8 +50,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -50,8 +50,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
result.Add(child);
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action<ILSpyTreeNode>(
delegate (ILSpyTreeNode newChild) {
// don't access "child" here the background thread might already be running
// the next loop iteration
// don't access "child" here the
// background thread might already be running the next loop iteration
if (loadChildrenTask == thisTask) {
this.Children.Insert(this.Children.Count - 1, newChild);
}

Loading…
Cancel
Save