Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
cd9a56090e
  1. 25
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 24
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 10
      ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
  4. 161
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  5. 48
      ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs
  6. 2
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  7. 82
      ICSharpCode.Decompiler/Ast/Transforms/UsingStatementTransform.cs
  8. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  9. 46
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  10. 61
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  11. 54
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  12. 111
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  13. 21
      ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
  14. 8
      ICSharpCode.Decompiler/Tests/Loops.cs
  15. 14
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs
  16. 7
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs
  17. 51
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs
  18. 22
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs
  19. 9
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs
  20. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs
  21. 2
      NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs
  22. 1
      NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

25
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -9,6 +9,7 @@ using ICSharpCode.NRefactory.CSharp; @@ -9,6 +9,7 @@ using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
using Mono.Cecil.Cil;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier;
namespace Decompiler
{
@ -149,6 +150,9 @@ namespace Decompiler @@ -149,6 +150,9 @@ namespace Decompiler
astType.ClassType = ClassType.Class;
}
astType.TypeParameters.AddRange(MakeTypeParameters(typeDef.GenericParameters));
astType.Constraints.AddRange(MakeConstraints(typeDef.GenericParameters));
// Nested types
foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
if (MemberIsHidden(nestedTypeDef))
@ -451,16 +455,33 @@ namespace Decompiler @@ -451,16 +455,33 @@ namespace Decompiler
MethodDeclaration astMethod = new MethodDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.AddAnnotation(methodMapping);
astMethod.Name = methodDef.Name;
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Name = methodDef.Name;
astMethod.TypeParameters.AddRange(MakeTypeParameters(methodDef.GenericParameters));
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters));
if (!methodDef.DeclaringType.IsInterface) {
astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
}
return astMethod;
}
IEnumerable<TypeParameterDeclaration> MakeTypeParameters(IEnumerable<GenericParameter> genericParameters)
{
return genericParameters.Select(
gp => new TypeParameterDeclaration {
Name = gp.Name,
Variance = gp.IsContravariant ? VarianceModifier.Contravariant : gp.IsCovariant ? VarianceModifier.Covariant : VarianceModifier.Invariant
});
}
IEnumerable<Constraint> MakeConstraints(IEnumerable<GenericParameter> genericParameters)
{
// TODO
return Enumerable.Empty<Constraint>();
}
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{
// Create mapping - used in debugger

24
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -4,6 +4,7 @@ using System.Collections.Generic; @@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.Utils;
using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil;
@ -77,9 +78,9 @@ namespace Decompiler @@ -77,9 +78,9 @@ namespace Decompiler
Ast.BlockStatement astBlock = new BlockStatement();
if (block != null) {
if (block.EntryGoto != null)
astBlock.AddStatement((Statement)TransformExpression(block.EntryGoto));
astBlock.Add((Statement)TransformExpression(block.EntryGoto));
foreach(ILNode node in block.Body) {
astBlock.AddStatements(TransformNode(node));
astBlock.AddRange(TransformNode(node));
}
}
return astBlock;
@ -102,10 +103,17 @@ namespace Decompiler @@ -102,10 +103,17 @@ namespace Decompiler
throw new Exception();
}
}
} else if (node is ILLoop) {
yield return new Ast.ForStatement {
EmbeddedStatement = TransformBlock(((ILLoop)node).ContentBlock)
} else if (node is ILWhileLoop) {
ILWhileLoop ilLoop = (ILWhileLoop)node;
if (ilLoop.PreLoopLabel != null)
yield return TransformNode(ilLoop.PreLoopLabel).Single();
WhileStatement whileStmt = new WhileStatement() {
Condition = ilLoop.Condition != null ? MakeBranchCondition(ilLoop.Condition) : new PrimitiveExpression(true),
EmbeddedStatement = TransformBlock(ilLoop.BodyBlock)
};
yield return whileStmt;
if (ilLoop.PostLoopGoto != null)
yield return (Statement)TransformExpression(ilLoop.PostLoopGoto);
} else if (node is ILCondition) {
ILCondition conditionalNode = (ILCondition)node;
if (conditionalNode.FalseBlock.Body.Any()) {
@ -290,7 +298,7 @@ namespace Decompiler @@ -290,7 +298,7 @@ namespace Decompiler
BlockStatement branchCommand = null;
if (byteCode.Operand is ILLabel) {
branchCommand = new BlockStatement();
branchCommand.AddStatement(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
branchCommand.Add(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
}
switch((Code)opCode) {
@ -500,11 +508,11 @@ namespace Decompiler @@ -500,11 +508,11 @@ namespace Decompiler
return new Ast.PrimitiveExpression(false);
else if (byteCode.InferredType == typeSystem.Boolean && (int)operand == 1)
return new Ast.PrimitiveExpression(true);
if (byteCode.InferredType != null && byteCode.InferredType.IsValueType) {
if (byteCode.InferredType != null) { // cannot rely on IsValueType, it's not set for typerefs (but is set for typespecs)
TypeDefinition enumDefinition = byteCode.InferredType.Resolve();
if (enumDefinition != null && enumDefinition.IsEnum) {
foreach (FieldDefinition field in enumDefinition.Fields) {
if (field.IsStatic && object.Equals(field.Constant, operand))
if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int32, field.Constant, false), operand))
return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
}
}

10
ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs

@ -59,15 +59,19 @@ namespace Decompiler @@ -59,15 +59,19 @@ namespace Decompiler
}
node = node.NextSibling;
}
if (withinPos != null && withinPos.Role == BlockStatement.StatementRole && (allowPassIntoLoops || !IsLoop(pos)))
if (withinPos != null && withinPos.Role == BlockStatement.StatementRole && AllowPassInto(pos, allowPassIntoLoops))
return withinPos;
else
return pos;
}
static bool IsLoop(AstNode node)
static bool AllowPassInto(AstNode node, bool allowPassIntoLoops)
{
return node is ForStatement || node is ForeachStatement || node is DoWhileStatement || node is WhileStatement;
if (node is AnonymousMethodExpression || node is LambdaExpression)
return false;
if (node is ForStatement || node is ForeachStatement || node is DoWhileStatement || node is WhileStatement)
return allowPassIntoLoops;
return true;
}
}
}

161
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
// 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;
using Mono.Cecil;
namespace Decompiler.Transforms
{
/// <summary>
/// Finds the expanded form of using statements using pattern matching and replaces it with a UsingStatement.
/// </summary>
public class PatternStatementTransform : IAstTransform
{
public void Run(AstNode compilationUnit)
{
TransformUsings(compilationUnit);
TransformForeach(compilationUnit);
}
#region using
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 simpleVariableDefinition = new VariableDeclarationStatement {
Type = new AnyNode().ToType(),
Variables = {
new VariableInitializer() // any name but no initializer
}
};
static readonly AstNode usingTryCatchPattern = new TryCatchStatement {
TryBlock = new AnyNode("body").ToBlock(),
FinallyBlock = new BlockStatement {
new Choice {
{ "valueType",
new ExpressionStatement(new NamedNode("ident", new IdentifierExpression()).ToExpression().Invoke("Dispose"))
},
{ "referenceType",
new IfElseStatement {
Condition = new BinaryOperatorExpression(
new NamedNode("ident", new IdentifierExpression()).ToExpression(),
BinaryOperatorType.InEquality,
new NullReferenceExpression()
),
TrueStatement = new BlockStatement {
new ExpressionStatement(new Backreference("ident").ToExpression().Invoke("Dispose"))
}
}
}
}.ToStatement()
}
};
public void TransformUsings(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
Match m1 = usingVarDeclPattern.Match(node);
if (m1 == null) continue;
AstNode tryCatch = node.NextSibling;
while (simpleVariableDefinition.Match(tryCatch) != null)
tryCatch = tryCatch.NextSibling;
Match m2 = usingTryCatchPattern.Match(tryCatch);
if (m2 == null) continue;
if (m1.Get<VariableInitializer>("variable").Single().Name == m2.Get<IdentifierExpression>("ident").Single().Identifier) {
if (m2.Has("valueType")) {
// if there's no if(x!=null), then it must be a value type
TypeReference tr = m1.Get<AstType>("type").Single().Annotation<TypeReference>();
if (tr == null || !tr.IsValueType)
continue;
}
BlockStatement body = m2.Get<BlockStatement>("body").Single();
tryCatch.ReplaceWith(
new UsingStatement {
ResourceAcquisition = node.Detach(),
EmbeddedStatement = body.Detach()
});
}
}
}
#endregion
#region foreach
UsingStatement foreachPattern = new UsingStatement {
ResourceAcquisition = new VariableDeclarationStatement {
Type = new AnyNode("enumeratorType").ToType(),
Variables = {
new NamedNode(
"enumeratorVariable",
new VariableInitializer {
Initializer = new AnyNode("collection").ToExpression().Invoke("GetEnumerator")
}
).ToVariable()
}
},
EmbeddedStatement = new BlockStatement {
new ForStatement {
EmbeddedStatement = new BlockStatement {
new IfElseStatement {
Condition = new UnaryOperatorExpression(
UnaryOperatorType.Not,
new NamedNode("enumeratorIdent", new IdentifierExpression()).ToExpression().Invoke("MoveNext")
),
TrueStatement = new BlockStatement {
new BreakStatement()
},
FalseStatement = new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("itemType").ToType(),
Variables = {
new NamedNode(
"itemVariable",
new VariableInitializer {
Initializer = new Backreference("enumeratorIdent").ToExpression().Member("Current")
}
).ToVariable()
}
},
new Repeat(new AnyNode("statement")).ToStatement()
}
}
}
}
}
};
public void TransformForeach(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
Match m = foreachPattern.Match(node);
if (m == null)
continue;
VariableInitializer enumeratorVar = m.Get<VariableInitializer>("enumeratorVariable").Single();
if (enumeratorVar.Name != m.Get<IdentifierExpression>("enumeratorIdent").Single().Identifier)
continue;
VariableInitializer itemVar = m.Get<VariableInitializer>("itemVariable").Single();
BlockStatement newBody = new BlockStatement();
foreach (Statement stmt in m.Get<Statement>("statement"))
newBody.Add(stmt.Detach());
node.ReplaceWith(
new ForeachStatement {
VariableType = m.Get<AstType>("itemType").Single().Detach(),
VariableName = enumeratorVar.Name,
InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody
});
}
}
#endregion
}
}

48
ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs

@ -7,9 +7,9 @@ namespace Decompiler.Transforms.Ast @@ -7,9 +7,9 @@ namespace Decompiler.Transforms.Ast
{
public class RemoveGotos: DepthFirstAstVisitor<object, object>
{
Stack<ForStatement> enteredLoops = new Stack<ForStatement>();
Stack<Statement> enteredLoops = new Stack<Statement>();
ForStatement CurrentLoop {
Statement CurrentLoop {
get {
if (enteredLoops.Count > 0) {
return enteredLoops.Peek();
@ -19,6 +19,20 @@ namespace Decompiler.Transforms.Ast @@ -19,6 +19,20 @@ namespace Decompiler.Transforms.Ast
}
}
Statement CurrentLoopBody {
get {
if (this.CurrentLoop == null) {
return null;
} else if (this.CurrentLoop is ForStatement) {
return ((ForStatement)this.CurrentLoop).EmbeddedStatement;
} else if (this.CurrentLoop is WhileStatement) {
return ((WhileStatement)this.CurrentLoop).EmbeddedStatement;
} else {
return null;
}
}
}
public override object VisitForStatement(ForStatement forStatement, object data)
{
enteredLoops.Push(forStatement);
@ -27,13 +41,13 @@ namespace Decompiler.Transforms.Ast @@ -27,13 +41,13 @@ namespace Decompiler.Transforms.Ast
return null;
}
// public override object VisitWhileStatement(WhileStatement whileStatement, object data)
// {
// enteredLoops.Push(whileStatement);
// base.VisitWhileStatement(whileStatement, data);
// enteredLoops.Pop();
// return null;
// }
public override object VisitWhileStatement(WhileStatement whileStatement, object data)
{
enteredLoops.Push(whileStatement);
base.VisitWhileStatement(whileStatement, data);
enteredLoops.Pop();
return null;
}
public override object VisitBlockStatement(BlockStatement blockStatement, object data)
{
@ -159,9 +173,19 @@ namespace Decompiler.Transforms.Ast @@ -159,9 +173,19 @@ namespace Decompiler.Transforms.Ast
// Replace goto with 'continue'
// Continue statement which moves at the very end of loop
if (CurrentLoop != null &&
(CurrentLoop.EmbeddedStatement is BlockStatement) &&
((CurrentLoop.EmbeddedStatement as BlockStatement).LastChild as LabelStatement) != null &&
((CurrentLoop.EmbeddedStatement as BlockStatement).LastChild as LabelStatement).Label == gotoStatement.Label) {
(CurrentLoopBody is BlockStatement) &&
((CurrentLoopBody as BlockStatement).LastChild as LabelStatement) != null &&
((CurrentLoopBody as BlockStatement).LastChild as LabelStatement).Label == gotoStatement.Label) {
gotoStatement.ReplaceWith(new ContinueStatement());
return null;
}
// Replace goto with 'continue'
// Jump before while
if (CurrentLoop is WhileStatement &&
CurrentLoop.PrevSibling != null &&
CurrentLoop.PrevSibling is LabelStatement &&
(CurrentLoop.PrevSibling as LabelStatement).Label == gotoStatement.Label) {
gotoStatement.ReplaceWith(new ContinueStatement());
return null;
}

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

@ -19,7 +19,7 @@ namespace Decompiler.Transforms @@ -19,7 +19,7 @@ namespace Decompiler.Transforms
return new IAstTransform[] {
new PushNegation(),
new DelegateConstruction(context),
new UsingStatementTransform(),
new PatternStatementTransform(),
new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(),
};

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

@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
// 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;
using Mono.Cecil;
namespace Decompiler.Transforms
{
/// <summary>
/// Finds the expanded form of using statements using pattern matching and replaces it with a UsingStatement.
/// </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 Choice {
{ "valueType",
new ExpressionStatement(new NamedNode("ident", new IdentifierExpression()).ToExpression().Invoke("Dispose"))
},
{ "referenceType",
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"))
}
}
}
}
}.ToStatement()
}
}
};
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 (m1.Get<VariableInitializer>("variable").Single().Name == m2.Get<IdentifierExpression>("ident").Single().Identifier) {
if (m2.Has("valueType")) {
// if there's no if(x!=null), then it must be a value type
TypeReference tr = m1.Get<AstType>("type").Single().Annotation<TypeReference>();
if (tr == null || !tr.IsValueType)
continue;
}
BlockStatement body = m2.Get<BlockStatement>("body").Single();
body.Remove();
node.NextSibling.Remove();
node.ReplaceWith(
varDecl => new UsingStatement {
ResourceAcquisition = varDecl,
EmbeddedStatement = body
});
}
}
}
}
}

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -68,7 +68,7 @@ @@ -68,7 +68,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="Ast\Transforms\PatternStatementTransform.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="CodeMappings.cs" />
<Compile Include="DecompilerException.cs" />

46
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -37,6 +37,7 @@ namespace Decompiler @@ -37,6 +37,7 @@ namespace Decompiler
public int PushCount;
public string Name { get { return "IL_" + this.Offset.ToString("X2"); } }
public ByteCode Next;
public Instruction[] Prefixes; // Non-null only if needed
public List<StackSlot> StackBefore;
public List<ILVariable> StoreTo;
@ -57,7 +58,14 @@ namespace Decompiler @@ -57,7 +58,14 @@ namespace Decompiler
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}:{1} {2} ", this.Name, this.Label != null ? " *" : "", this.Code.GetName());
sb.AppendFormat("{0}:{1} ", this.Name, this.Label != null ? " *" : "");
if (this.Prefixes != null) {
foreach (var prefix in this.Prefixes) {
sb.Append(prefix.OpCode.Name);
sb.Append(' ');
}
}
sb.Append(this.Code.GetName());
if (this.Operand is ILLabel) {
sb.Append(((ILLabel)this.Operand).Name);
} else if (this.Operand is ILLabel[]) {
@ -126,7 +134,14 @@ namespace Decompiler @@ -126,7 +134,14 @@ namespace Decompiler
{
// Create temporary structure for the stack analysis
List<ByteCode> body = new List<ByteCode>(methodDef.Body.Instructions.Count);
List<Instruction> prefixes = null;
foreach(Instruction inst in methodDef.Body.Instructions) {
if (inst.OpCode.OpCodeType == OpCodeType.Prefix) {
if (prefixes == null)
prefixes = new List<Instruction>(1);
prefixes.Add(inst);
continue;
}
ILCode code = (ILCode)inst.OpCode.Code;
object operand = inst.Operand;
ILCodeUtil.ExpandMacro(ref code, ref operand, methodDef.Body);
@ -138,6 +153,11 @@ namespace Decompiler @@ -138,6 +153,11 @@ namespace Decompiler
PopCount = inst.GetPopCount(),
PushCount = inst.GetPushCount()
};
if (prefixes != null) {
byteCode.Offset = prefixes[0].Offset;
byteCode.Prefixes = prefixes.ToArray();
prefixes = null;
}
instrToByteCode[inst] = byteCode;
body.Add(byteCode);
}
@ -420,6 +440,7 @@ namespace Decompiler @@ -420,6 +440,7 @@ namespace Decompiler
ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand);
expr.ILRanges.Add(ilRange);
expr.Prefixes = byteCode.Prefixes;
// Label for this instruction
if (byteCode.Label != null) {
@ -468,16 +489,25 @@ namespace Decompiler @@ -468,16 +489,25 @@ namespace Decompiler
// We are moving the expression evaluation past the other aguments.
// It is ok to pass ldloc because the expression can not contain stloc and thus the ldcoc will still return the same value
if (arg.Code == ILCode.Ldloc) {
bool canInline;
allowInline.TryGetValue((ILVariable)arg.Operand, out canInline);
if (arg.Operand == currExpr.Operand && canInline) {
if (arg.Operand == currExpr.Operand) {
bool canInline;
allowInline.TryGetValue((ILVariable)arg.Operand, out canInline);
// Assigne the ranges for optimized away instrustions somewhere
currExpr.Arguments[0].ILRanges.AddRange(currExpr.ILRanges);
currExpr.Arguments[0].ILRanges.AddRange(nextExpr.Arguments[j].ILRanges);
ast.RemoveAt(i);
nextExpr.Arguments[j] = currExpr.Arguments[0]; // Inline the stloc body
i -= 2; // Try the same index again
break; // Found
if (canInline) {
ast.RemoveAt(i);
nextExpr.Arguments[j] = currExpr.Arguments[0]; // Inline the stloc body
i -= 2; // Try the same index again
break; // Found
} else {
ast.RemoveAt(i);
nextExpr.Arguments[j] = currExpr; // Inline the whole stloc
i -= 2; // Try the same index again
break; // Found
}
}
} else {
break; // Side-effects

61
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -32,12 +32,13 @@ namespace Decompiler.ControlFlow @@ -32,12 +32,13 @@ namespace Decompiler.ControlFlow
}
if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return;
UpdateLabelRefCounts(method);
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
ControlFlowGraph graph;
graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand);
graph.ComputeDominance();
graph.ComputeDominanceFrontier();
block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, true);
block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, false);
}
if (abortBeforeStep == ILAstOptimizationStep.FindConditions) return;
@ -45,6 +46,9 @@ namespace Decompiler.ControlFlow @@ -45,6 +46,9 @@ namespace Decompiler.ControlFlow
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
ControlFlowGraph graph;
graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand);
// TODO: Fix
if (graph == null)
continue;
graph.ComputeDominance();
graph.ComputeDominanceFrontier();
block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint);
@ -94,11 +98,11 @@ namespace Decompiler.ControlFlow @@ -94,11 +98,11 @@ namespace Decompiler.ControlFlow
bool added = false;
// Insert split
if ((currNode is ILLabel && !(lastNode is ILLabel)) ||
if (currNode is ILLabel ||
lastNode is ILTryCatchBlock ||
currNode is ILTryCatchBlock ||
(lastNode is ILExpression) && ((ILExpression)lastNode).IsBranch() ||
(currNode is ILExpression) && ((ILExpression)currNode).IsBranch())
(currNode is ILExpression) && (((ILExpression)currNode).IsBranch() && basicBlock.Body.Count > 0))
{
ILBasicBlock lastBlock = basicBlock;
basicBlock = new ILBasicBlock();
@ -140,7 +144,7 @@ namespace Decompiler.ControlFlow @@ -140,7 +144,7 @@ namespace Decompiler.ControlFlow
// Create graph nodes
labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
Dictionary<ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
Dictionary<ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
foreach(ILNode node in nodes) {
ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal);
cfNodes.Add(cfNode);
@ -153,6 +157,9 @@ namespace Decompiler.ControlFlow @@ -153,6 +157,9 @@ namespace Decompiler.ControlFlow
}
}
if (!labelToCfNode.ContainsKey(entryLabel))
return null;
// Entry endge
ControlFlowNode entryNode = labelToCfNode[entryLabel];
ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);
@ -196,18 +203,32 @@ namespace Decompiler.ControlFlow @@ -196,18 +203,32 @@ namespace Decompiler.ControlFlow
&& node.DominanceFrontier.Contains(node)
&& (node != entryPoint || !excludeEntryPoint))
{
HashSet<ControlFlowNode> loopContents = new HashSet<ControlFlowNode>();
FindLoopContents(scope, loopContents, node, node);
HashSet<ControlFlowNode> loopContents = FindDominatedNodes(scope, node);
ILWhileLoop loop = new ILWhileLoop();
ILCondition cond;
HashSet<ControlFlowNode> condNodes;
ILLabel condLabel;
if (TryMatchCondition(loopContents, new ControlFlowNode[]{}, node, out cond, out condNodes, out condLabel)) {
loopContents.ExceptWith(condNodes);
scope.ExceptWith(condNodes);
// Use loop to implement condition
loop.Condition = cond.Condition;
loop.PreLoopLabel = condLabel;
loop.PostLoopGoto = cond.FalseBlock.EntryGoto;
loop.BodyBlock = new ILBlock() { EntryGoto = cond.TrueBlock.EntryGoto };
} else {
// Give the block some explicit entry point
ILLabel entryLabel = new ILLabel() { Name = "Loop_" + (nextBlockIndex++) };
loop.BodyBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, entryLabel) };
((ILBasicBlock)node.UserData).Body.Insert(0, entryLabel);
}
loop.BodyBlock.Body = FindLoops(loopContents, node, true);
// Move the content into loop block
scope.ExceptWith(loopContents);
ILLabel entryLabel = new ILLabel() { Name = "Loop_" + (nextBlockIndex++) };
((ILBasicBlock)node.UserData).Body.Insert(0, entryLabel);
result.Add(new ILLoop() {
ContentBlock = new ILBlock(FindLoops(loopContents, node, true)) {
EntryGoto = new ILExpression(ILCode.Br, entryLabel)
}
});
result.Add(loop);
}
// Using the dominator tree should ensure we find the the widest loop first
@ -224,22 +245,12 @@ namespace Decompiler.ControlFlow @@ -224,22 +245,12 @@ namespace Decompiler.ControlFlow
return result;
}
static void FindLoopContents(HashSet<ControlFlowNode> scope, HashSet<ControlFlowNode> loopContents, ControlFlowNode loopHead, ControlFlowNode addNode)
{
if (scope.Contains(addNode) && loopHead.Dominates(addNode) && loopContents.Add(addNode)) {
foreach (var edge in addNode.Incoming) {
FindLoopContents(scope, loopContents, loopHead, edge.Source);
}
}
}
void UpdateLabelRefCounts(ILBlock method)
{
labelRefCount = new Dictionary<ILLabel, int>();
foreach(ILLabel label in method.GetSelfAndChildrenRecursive<ILLabel>()) {
labelRefCount[label] = 0;
}
foreach(ILLabel target in method.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.GetBranchTargets())) {
if (!labelRefCount.ContainsKey(target))
labelRefCount[target] = 0;
labelRefCount[target]++;
}
}

54
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -199,6 +199,7 @@ namespace Decompiler @@ -199,6 +199,7 @@ namespace Decompiler
public ILCode Code { get; set; }
public object Operand { get; set; }
public List<ILExpression> Arguments { get; set; }
public Instruction[] Prefixes { get; set; }
// Mapping to the original instructions (useful for debugging)
public List<ILRange> ILRanges { get; set; }
@ -212,6 +213,18 @@ namespace Decompiler @@ -212,6 +213,18 @@ namespace Decompiler
this.ILRanges = new List<ILRange>(1);
}
public Instruction GetPrefix(Code code)
{
var prefixes = this.Prefixes;
if (prefixes != null) {
foreach (Instruction i in prefixes) {
if (i.OpCode.Code == code)
return i;
}
}
return null;
}
public override IEnumerable<ILNode> GetChildren()
{
return Arguments;
@ -272,6 +285,13 @@ namespace Decompiler @@ -272,6 +285,13 @@ namespace Decompiler
}
}
if (this.Prefixes != null) {
foreach (Instruction prefix in this.Prefixes) {
output.Write(prefix.OpCode.Name);
output.Write(' ');
}
}
output.Write(Code.GetName());
if (this.InferredType != null) {
output.Write(':');
@ -287,6 +307,11 @@ namespace Decompiler @@ -287,6 +307,11 @@ namespace Decompiler
method.DeclaringType.WriteTo(output, true, true);
output.Write("::");
output.WriteReference(method.Name, method);
} else if (Operand is FieldReference) {
FieldReference field = (FieldReference)Operand;
field.DeclaringType.WriteTo(output, true, true);
output.Write("::");
output.WriteReference(field.Name, field);
} else {
DisassemblerHelpers.WriteOperand(output, Operand);
}
@ -301,23 +326,40 @@ namespace Decompiler @@ -301,23 +326,40 @@ namespace Decompiler
}
}
public class ILLoop : ILNode
public class ILWhileLoop : ILNode
{
public ILBlock ContentBlock;
public ILLabel PreLoopLabel; // Label allowing to jump to condition
public ILExpression Condition;
public ILBlock BodyBlock; // BodyBlock.EntryGoto performs the goto for a met condition
public ILExpression PostLoopGoto; // Performs the goto for a failed condition
public override IEnumerable<ILNode> GetChildren()
{
if (this.ContentBlock != null)
yield return ContentBlock;
if (this.PreLoopLabel != null)
yield return this.PreLoopLabel;
if (this.Condition != null)
yield return this.Condition;
if (this.BodyBlock != null)
yield return this.BodyBlock;
if (this.PostLoopGoto != null)
yield return this.PostLoopGoto;
}
public override void WriteTo(ITextOutput output)
{
output.WriteLine("loop {");
if (this.PreLoopLabel != null)
this.PreLoopLabel.WriteTo(output);
output.WriteLine("");
output.Write("loop (");
if (this.Condition != null)
this.Condition.WriteTo(output);
output.WriteLine(") {");
output.Indent();
ContentBlock.WriteTo(output);
this.BodyBlock.WriteTo(output);
output.Unindent();
output.WriteLine("}");
if (this.PostLoopGoto != null)
this.PostLoopGoto.WriteTo(output);
}
}

111
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -128,8 +128,8 @@ namespace Decompiler @@ -128,8 +128,8 @@ namespace Decompiler
if (v.Type == null)
v.Type = t;
}
return v.Type;
}
return null;
case Code.Ldloc:
{
ILVariable v = (ILVariable)expr.Operand;
@ -160,20 +160,25 @@ namespace Decompiler @@ -160,20 +160,25 @@ namespace Decompiler
MethodReference method = (MethodReference)expr.Operand;
if (forceInferChildren) {
for (int i = 0; i < expr.Arguments.Count; i++) {
if (i == 0 && method.HasThis)
InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
else
InferTypeForExpression(expr.Arguments[i], method.Parameters[method.HasThis ? i - 1: i].ParameterType);
if (i == 0 && method.HasThis) {
Instruction constraint = expr.GetPrefix(Code.Constrained);
if (constraint != null)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType((TypeReference)constraint.Operand));
else
InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
} else {
InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1: i].ParameterType, method));
}
}
}
return method.ReturnType;
return SubstituteTypeArgs(method.ReturnType, method);
}
case Code.Newobj:
{
MethodReference ctor = (MethodReference)expr.Operand;
if (forceInferChildren) {
for (int i = 0; i < ctor.Parameters.Count; i++) {
InferTypeForExpression(expr.Arguments[i], ctor.Parameters[i].ParameterType);
InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(ctor.Parameters[i].ParameterType, ctor));
}
}
return ctor.DeclaringType;
@ -181,19 +186,23 @@ namespace Decompiler @@ -181,19 +186,23 @@ namespace Decompiler
#endregion
#region Load/Store Fields
case Code.Ldfld:
return UnpackModifiers(((FieldReference)expr.Operand).FieldType);
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType);
return GetFieldType((FieldReference)expr.Operand);
case Code.Ldsfld:
return UnpackModifiers(((FieldReference)expr.Operand).FieldType);
return GetFieldType((FieldReference)expr.Operand);
case Code.Ldflda:
case Code.Ldsflda:
return new ByReferenceType(UnpackModifiers(((FieldReference)expr.Operand).FieldType));
return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
case Code.Stfld:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], ((FieldReference)expr.Operand).FieldType);
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType);
InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand));
}
return null;
case Code.Stsfld:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).FieldType);
InferTypeForExpression(expr.Arguments[0], GetFieldType((FieldReference)expr.Operand));
return null;
#endregion
#region Reference/Pointer instructions
@ -456,7 +465,69 @@ namespace Decompiler @@ -456,7 +465,69 @@ namespace Decompiler
}
}
TypeReference UnpackPointer(TypeReference pointerOrManagedReference)
static TypeReference GetFieldType(FieldReference fieldReference)
{
return SubstituteTypeArgs(UnpackModifiers(fieldReference.FieldType), fieldReference);
}
static TypeReference SubstituteTypeArgs(TypeReference type, MemberReference member)
{
if (type is TypeSpecification) {
ArrayType arrayType = type as ArrayType;
if (arrayType != null) {
TypeReference elementType = SubstituteTypeArgs(arrayType.ElementType, member);
if (elementType != arrayType.ElementType) {
ArrayType newArrayType = new ArrayType(elementType);
foreach (ArrayDimension d in arrayType.Dimensions)
newArrayType.Dimensions.Add(d);
return newArrayType;
} else {
return type;
}
}
ByReferenceType refType = type as ByReferenceType;
if (refType != null) {
TypeReference elementType = SubstituteTypeArgs(refType.ElementType, member);
return elementType != refType.ElementType ? new ByReferenceType(elementType) : type;
}
GenericInstanceType giType = type as GenericInstanceType;
if (giType != null) {
GenericInstanceType newType = new GenericInstanceType(giType.ElementType);
bool isChanged = false;
for (int i = 0; i < giType.GenericArguments.Count; i++) {
newType.GenericArguments.Add(SubstituteTypeArgs(giType.GenericArguments[i], member));
isChanged |= newType.GenericArguments[i] != giType.GenericArguments[i];
}
return isChanged ? newType : type;
}
OptionalModifierType optmodType = type as OptionalModifierType;
if (optmodType != null) {
TypeReference elementType = SubstituteTypeArgs(optmodType.ElementType, member);
return elementType != optmodType.ElementType ? new OptionalModifierType(optmodType.ModifierType, elementType) : type;
}
RequiredModifierType reqmodType = type as RequiredModifierType;
if (reqmodType != null) {
TypeReference elementType = SubstituteTypeArgs(reqmodType.ElementType, member);
return elementType != reqmodType.ElementType ? new RequiredModifierType(reqmodType.ModifierType, elementType) : type;
}
PointerType ptrType = type as PointerType;
if (ptrType != null) {
TypeReference elementType = SubstituteTypeArgs(ptrType.ElementType, member);
return elementType != ptrType.ElementType ? new PointerType(elementType) : type;
}
}
GenericParameter gp = type as GenericParameter;
if (gp != null) {
if (gp.Owner.GenericParameterType == GenericParameterType.Method) {
return ((GenericInstanceMethod)member).GenericArguments[gp.Position];
} else {
return ((GenericInstanceType)member.DeclaringType).GenericArguments[gp.Position];
}
}
return type;
}
static TypeReference UnpackPointer(TypeReference pointerOrManagedReference)
{
ByReferenceType refType = pointerOrManagedReference as ByReferenceType;
if (refType != null)
@ -554,13 +625,11 @@ namespace Decompiler @@ -554,13 +625,11 @@ namespace Decompiler
{
if (type == null)
return null;
if (type.IsValueType) {
// value type might be an enum
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
return IsSigned(typeDef.Module.TypeSystem, underlyingType);
}
// unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec)
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
return IsSigned(typeDef.Module.TypeSystem, underlyingType);
}
if (type == typeSystem.Byte || type == typeSystem.UInt16 || type == typeSystem.UInt32 || type == typeSystem.UInt64 || type == typeSystem.UIntPtr)
return false;

21
ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
public static class DelegateConstruction
{
@ -38,4 +39,24 @@ public static class DelegateConstruction @@ -38,4 +39,24 @@ public static class DelegateConstruction
{
return new Func<string>(((string)null).ToUpper);
}
public static List<Action<int>> AnonymousMethodStoreWithinLoop()
{
List<Action<int>> list = new List<Action<int>>();
for (int i = 0; i < 10; i++) {
int counter;
list.Add(x => counter = x);
}
return list;
}
public static List<Action<int>> AnonymousMethodStoreOutsideLoop()
{
List<Action<int>> list = new List<Action<int>>();
int counter;
for (int i = 0; i < 10; i++) {
list.Add(x => counter = x);
}
return list;
}
}

8
ICSharpCode.Decompiler/Tests/Loops.cs

@ -13,6 +13,14 @@ public class Loops @@ -13,6 +13,14 @@ public class Loops
}
}
public void ForEachOverList(List<string> list)
{
// List has a struct as enumerator, so produces quite different IL than foreach over the IEnumerable interface
foreach (string text in list) {
text.ToLower();
}
}
public void ForEachOverArray(string[] array)
{
foreach (string text in array) {

14
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs

@ -165,10 +165,18 @@ namespace ICSharpCode.NRefactory.CSharp @@ -165,10 +165,18 @@ namespace ICSharpCode.NRefactory.CSharp
cur2 = cur2.NextSibling;
if (cur1 == null || cur2 == null)
break;
if (!cur1.DoMatch(cur2, match))
return false;
Pattern pattern = cur1 as Pattern;
if (pattern == null && cur1.NodeType == NodeType.Pattern)
pattern = cur1.GetChildByRole(TypePlaceholder.ChildRole) as Pattern;
if (pattern != null) {
if (!pattern.DoMatchCollection(role, ref cur2, match))
return false;
} else {
if (!cur1.DoMatch(cur2, match))
return false;
cur2 = cur2.NextSibling;
}
cur1 = cur1.NextSibling;
cur2 = cur2.NextSibling;
}
return cur1 == null && cur2 == null;
}

7
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs

@ -14,6 +14,13 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -14,6 +14,13 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
get { return NodeType.Pattern; }
}
protected internal virtual bool DoMatchCollection(Role role, ref AstNode other, Match match)
{
bool result = DoMatch(other, match);
other = other.NextSibling;
return result;
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return default(S);

51
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// 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.Diagnostics;
namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
/// <summary>
/// Represents an optional node.
/// </summary>
public class Repeat : Pattern
{
public static readonly Role<AstNode> ElementRole = new Role<AstNode>("Element", AstNode.Null);
public int MinCount;
public int MaxCount = int.MaxValue;
public Repeat(AstNode childNode)
{
AddChild(childNode, ElementRole);
}
protected internal override bool DoMatchCollection(Role role, ref AstNode other, Match match)
{
Debug.Assert(other != null && other.Role == role);
int matchCount = 0;
var lastValidCheckpoint = match.CheckPoint();
AstNode element = GetChildByRole(ElementRole);
AstNode pos = other;
while (pos != null && element.DoMatch(pos, match)) {
matchCount++;
lastValidCheckpoint = match.CheckPoint();
do {
pos = pos.NextSibling;
} while (pos != null && pos.Role != role);
// set 'other' (=pointer in collection) to the next node after the valid match
other = pos;
}
match.RestoreCheckPoint(lastValidCheckpoint); // restote old checkpoint after failed match
return matchCount >= MinCount && matchCount <= MaxCount;
}
protected internal override bool DoMatch(AstNode other, Match match)
{
if (other == null || other.IsNull)
return this.MinCount <= 0;
else
return GetChildByRole(ElementRole).DoMatch(other, match);
}
}
}

22
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp
/// <summary>
/// { Statements }
/// </summary>
public class BlockStatement : Statement
public class BlockStatement : Statement, IEnumerable<Statement>
{
public static readonly Role<Statement> StatementRole = new Role<Statement>("Statement", Statement.Null);
@ -81,17 +81,17 @@ namespace ICSharpCode.NRefactory.CSharp @@ -81,17 +81,17 @@ namespace ICSharpCode.NRefactory.CSharp
}
#region Builder methods
public void AddStatement(Statement statement)
public void Add(Statement statement)
{
AddChild(statement, StatementRole);
}
public void AddStatement(Expression expression)
public void Add(Expression expression)
{
AddChild(new ExpressionStatement { Expression = expression }, StatementRole);
}
public void AddStatements(IEnumerable<Statement> statements)
public void AddRange(IEnumerable<Statement> statements)
{
foreach (Statement st in statements)
AddChild(st, StatementRole);
@ -99,13 +99,23 @@ namespace ICSharpCode.NRefactory.CSharp @@ -99,13 +99,23 @@ namespace ICSharpCode.NRefactory.CSharp
public void AddAssignment(Expression left, Expression right)
{
AddStatement(new AssignmentExpression { Left = left, Operator = AssignmentOperatorType.Assign, Right = right });
Add(new AssignmentExpression { Left = left, Operator = AssignmentOperatorType.Assign, Right = right });
}
public void AddReturnStatement(Expression expression)
{
AddStatement(new ReturnStatement { Expression = expression });
Add(new ReturnStatement { Expression = expression });
}
#endregion
IEnumerator<Statement> IEnumerable<Statement>.GetEnumerator()
{
return this.Statements.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.Statements.GetEnumerator();
}
}
}

9
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//
// ForStatement.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -75,5 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -75,5 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitForStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
ForStatement o = other as ForStatement;
return o != null && this.Initializers.DoMatch(o.Initializers, match) && this.Condition.DoMatch(o.Condition, match)
&& this.Iterators.DoMatch(o.Iterators, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match);
}
}
}

8
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// UsingStatement.cs
//
// Author:
@ -62,5 +62,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -62,5 +62,11 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitUsingStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
UsingStatement o = other as UsingStatement;
return o != null && this.ResourceAcquisition.DoMatch(o.ResourceAcquisition, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match);
}
}
}

2
NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

@ -382,6 +382,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -382,6 +382,8 @@ namespace ICSharpCode.NRefactory.CSharp
void WriteEmbeddedStatement(Statement embeddedStatement)
{
if (embeddedStatement.IsNull)
return;
BlockStatement block = embeddedStatement as BlockStatement;
if (block != null)
VisitBlockStatement(block, null);

1
NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -100,6 +100,7 @@ @@ -100,6 +100,7 @@
<Compile Include="CSharp\Ast\PatternMatching\Backreference.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Match.cs" />
<Compile Include="CSharp\Ast\PatternMatching\NamedGroup.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Repeat.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Pattern.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Placeholder.cs" />
<Compile Include="CSharp\Ast\NotImplementedAstVisitor.cs" />

Loading…
Cancel
Save