Browse Source

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

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
38b25a1a83
  1. 2
      Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs
  2. 28
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  3. 187
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  4. 7
      ICSharpCode.Decompiler/Ast/CommentStatement.cs
  5. 10
      ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
  6. 8
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  7. 122
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  8. 10
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  9. 48
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  10. BIN
      ICSharpCode.Decompiler/Tests/StackTests/StackTests.exe
  11. 132
      ICSharpCode.Decompiler/Tests/StackTests/StackTests.il
  12. 2
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  13. 2
      ILSpy/MainWindow.xaml.cs
  14. 55
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs
  15. 6
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs
  16. 10
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs
  17. 9
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs
  18. 4
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs
  19. 3
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs
  20. 9
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs
  21. 42
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs
  22. 13
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs
  23. 22
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs
  24. 9
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs
  25. 28
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs
  26. 20
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs
  27. 26
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs
  28. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs
  29. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs
  30. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs
  31. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs
  32. 6
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs
  33. 9
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs
  34. 38
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs
  35. 12
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs
  36. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs
  37. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs
  38. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs
  39. 6
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs
  40. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs
  41. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs
  42. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs
  43. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs
  44. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs
  45. 8
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs
  46. 90
      NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs
  47. 3
      NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

2
Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs

@ -304,7 +304,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -304,7 +304,7 @@ namespace ICSharpCode.NRefactory.Visitors
}
TypedValue right;
if (op == BinaryOperatorType.None) {
if (op == BinaryOperatorType.Any) {
right = Evaluate(assignmentExpression.Right);
} else {
BinaryOperatorExpression binOpExpr = new BinaryOperatorExpression();

28
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -31,9 +31,14 @@ namespace Decompiler @@ -31,9 +31,14 @@ namespace Decompiler
MethodDefinition method = member as MethodDefinition;
if (method != null && (method.IsGetter || method.IsSetter || method.IsAddOn || method.IsRemoveOn))
return true;
if (method != null && method.Name.StartsWith("<", StringComparison.Ordinal) && method.IsCompilerGenerated())
return true;
TypeDefinition type = member as TypeDefinition;
if (type != null && type.DeclaringType != null && type.Name.StartsWith("<>c__DisplayClass", StringComparison.Ordinal) && type.IsCompilerGenerated())
return true;
FieldDefinition field = member as FieldDefinition;
if (field != null && field.Name.StartsWith("CS$<>", StringComparison.Ordinal) && field.IsCompilerGenerated())
return true;
return false;
}
@ -411,6 +416,9 @@ namespace Decompiler @@ -411,6 +416,9 @@ namespace Decompiler
else
modifiers |= Modifiers.Override;
}
if (!methodDef.HasBody && !methodDef.IsAbstract)
modifiers |= Modifiers.Extern;
return modifiers;
}
#endregion
@ -419,6 +427,7 @@ namespace Decompiler @@ -419,6 +427,7 @@ namespace Decompiler
{
// Add fields
foreach(FieldDefinition fieldDef in typeDef.Fields) {
if (MemberIsHidden(fieldDef)) continue;
astType.AddChild(CreateField(fieldDef), TypeDeclaration.MemberRole);
}
@ -489,7 +498,8 @@ namespace Decompiler @@ -489,7 +498,8 @@ namespace Decompiler
ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.AddAnnotation(methodMapping);
if (methodMapping != null)
astMethod.AddAnnotation(methodMapping);
astMethod.Modifiers = ConvertModifiers(methodDef);
if (methodDef.IsStatic) {
// don't show visibility for static ctors
@ -515,7 +525,9 @@ namespace Decompiler @@ -515,7 +525,9 @@ namespace Decompiler
astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context)
}.WithAnnotation(propDef.GetMethod);
astProp.Getter.AddAnnotation(methodMapping);
if (methodMapping != null)
astProp.Getter.AddAnnotation(methodMapping);
}
if (propDef.SetMethod != null) {
// Create mapping - used in debugger
@ -524,7 +536,9 @@ namespace Decompiler @@ -524,7 +536,9 @@ namespace Decompiler
astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context)
}.WithAnnotation(propDef.SetMethod);
astProp.Setter.AddAnnotation(methodMapping);
if (methodMapping != null)
astProp.Setter.AddAnnotation(methodMapping);
}
return astProp;
}
@ -543,7 +557,9 @@ namespace Decompiler @@ -543,7 +557,9 @@ namespace Decompiler
astEvent.AddAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod, context)
}.WithAnnotation(eventDef.AddMethod);
astEvent.AddAccessor.AddAnnotation(methodMapping);
if (methodMapping != null)
astEvent.AddAccessor.AddAnnotation(methodMapping);
}
if (eventDef.RemoveMethod != null) {
// Create mapping - used in debugger
@ -552,7 +568,9 @@ namespace Decompiler @@ -552,7 +568,9 @@ namespace Decompiler
astEvent.RemoveAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod, context)
}.WithAnnotation(eventDef.RemoveMethod);
astEvent.RemoveAccessor.AddAnnotation(methodMapping);
if (methodMapping != null)
astEvent.RemoveAccessor.AddAnnotation(methodMapping);
}
return astEvent;
}

187
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -176,12 +176,6 @@ namespace Decompiler @@ -176,12 +176,6 @@ namespace Decompiler
return args;
}
AstNode TransformExpression(ILExpression expr)
{
List<Ast.Expression> args = TransformExpressionArguments(expr);
return TransformByteCode(expr, args);
}
Ast.Expression MakeBranchCondition(ILExpression expr)
{
switch(expr.Code) {
@ -204,22 +198,11 @@ namespace Decompiler @@ -204,22 +198,11 @@ namespace Decompiler
List<Ast.Expression> args = TransformExpressionArguments(expr);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
TypeReference arg1Type = args.Count >= 1 ? expr.Arguments[0].InferredType : null;
switch((Code)expr.Code) {
case Code.Brfalse:
if (arg1Type == typeSystem.Boolean)
return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
else if (TypeAnalysis.IsIntegerOrEnum(typeSystem, arg1Type))
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, new PrimitiveExpression(0));
else
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, new NullReferenceExpression());
return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case Code.Brtrue:
if (arg1Type == typeSystem.Boolean)
return arg1;
else if (TypeAnalysis.IsIntegerOrEnum(typeSystem, arg1Type))
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, new PrimitiveExpression(0));
else
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, new NullReferenceExpression());
return arg1;
case Code.Beq:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Bge:
@ -245,21 +228,6 @@ namespace Decompiler @@ -245,21 +228,6 @@ namespace Decompiler
}
}
AstNode TransformByteCode(ILExpression byteCode, List<Ast.Expression> args)
{
try {
AstNode ret = TransformByteCode_Internal(byteCode, args);
// ret.UserData["Type"] = byteCode.Type;
return ret;
} catch (NotImplementedException) {
// Output the operand of the unknown IL code as well
if (byteCode.Operand != null) {
args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
}
return new IdentifierExpression(byteCode.Code.GetName()).Invoke(args);
}
}
static string FormatByteCodeOperand(object operand)
{
if (operand == null) {
@ -285,7 +253,18 @@ namespace Decompiler @@ -285,7 +253,18 @@ namespace Decompiler
}
}
AstNode TransformByteCode_Internal(ILExpression byteCode, List<Ast.Expression> args)
AstNode TransformExpression(ILExpression expr)
{
List<Ast.Expression> args = TransformExpressionArguments(expr);
AstNode node = TransformByteCode(expr, args);
Expression astExpr = node as Expression;
if (astExpr != null)
return Convert(astExpr, expr.InferredType, expr.ExpectedType);
else
return node;
}
AstNode TransformByteCode(ILExpression byteCode, List<Ast.Expression> args)
{
ILCode opCode = byteCode.Code;
object operand = byteCode.Operand;
@ -381,48 +360,58 @@ namespace Decompiler @@ -381,48 +360,58 @@ namespace Decompiler
case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand);
#endregion
#region Comparison
case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2));
case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Cgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Cgt_Un:
// can also mean Inequality, when used with object references
{
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType)
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
else
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
}
case Code.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion
#region Conversions
case Code.Conv_I: return arg1.CastTo(typeof(int)); // TODO
case Code.Conv_I1: return arg1.CastTo(typeof(SByte));
case Code.Conv_I2: return arg1.CastTo(typeof(Int16));
case Code.Conv_I4: return arg1.CastTo(typeof(Int32));
case Code.Conv_I8: return arg1.CastTo(typeof(Int64));
case Code.Conv_U: return arg1.CastTo(typeof(uint)); // TODO
case Code.Conv_U1: return arg1.CastTo(typeof(Byte));
case Code.Conv_U2: return arg1.CastTo(typeof(UInt16));
case Code.Conv_U4: return arg1.CastTo(typeof(UInt32));
case Code.Conv_U8: return arg1.CastTo(typeof(UInt64));
case Code.Conv_I1:
case Code.Conv_I2:
case Code.Conv_I4:
case Code.Conv_I8:
case Code.Conv_U1:
case Code.Conv_U2:
case Code.Conv_U4:
case Code.Conv_U8:
return arg1; // conversion is handled by Convert() function using the info from type analysis
case Code.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case Code.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO
case Code.Conv_R4: return arg1.CastTo(typeof(float));
case Code.Conv_R8: return arg1.CastTo(typeof(double));
case Code.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO
case Code.Conv_Ovf_I: return arg1.CastTo(typeof(int));
case Code.Conv_Ovf_I1: return arg1.CastTo(typeof(SByte));
case Code.Conv_Ovf_I2: return arg1.CastTo(typeof(Int16));
case Code.Conv_Ovf_I4: return arg1.CastTo(typeof(Int32));
case Code.Conv_Ovf_I8: return arg1.CastTo(typeof(Int64));
case Code.Conv_Ovf_U: return arg1.CastTo(typeof(uint));
case Code.Conv_Ovf_U1: return arg1.CastTo(typeof(Byte));
case Code.Conv_Ovf_U2: return arg1.CastTo(typeof(UInt16));
case Code.Conv_Ovf_U4: return arg1.CastTo(typeof(UInt32));
case Code.Conv_Ovf_U8: return arg1.CastTo(typeof(UInt64));
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_I1_Un:
case Code.Conv_Ovf_I2_Un:
case Code.Conv_Ovf_I4_Un:
case Code.Conv_Ovf_I8_Un:
case Code.Conv_Ovf_U1_Un:
case Code.Conv_Ovf_U2_Un:
case Code.Conv_Ovf_U4_Un:
case Code.Conv_Ovf_U8_Un:
return arg1; // conversion was handled by Convert() function using the info from type analysis
case Code.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case Code.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr));
case Code.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr));
case Code.Conv_Ovf_U_Un: return arg1.CastTo(typeof(UIntPtr));
case Code.Conv_Ovf_I_Un: return arg1.CastTo(typeof(int));
case Code.Conv_Ovf_I1_Un: return arg1.CastTo(typeof(SByte));
case Code.Conv_Ovf_I2_Un: return arg1.CastTo(typeof(Int16));
case Code.Conv_Ovf_I4_Un: return arg1.CastTo(typeof(Int32));
case Code.Conv_Ovf_I8_Un: return arg1.CastTo(typeof(Int64));
case Code.Conv_Ovf_U_Un: return arg1.CastTo(typeof(uint));
case Code.Conv_Ovf_U1_Un: return arg1.CastTo(typeof(Byte));
case Code.Conv_Ovf_U2_Un: return arg1.CastTo(typeof(UInt16));
case Code.Conv_Ovf_U4_Un: return arg1.CastTo(typeof(UInt32));
case Code.Conv_Ovf_U8_Un: return arg1.CastTo(typeof(UInt64));
case Code.Castclass:
case Code.Unbox_Any:
return arg1.CastTo(operandAsTypeRef);
@ -504,20 +493,7 @@ namespace Decompiler @@ -504,20 +493,7 @@ namespace Decompiler
return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand));
}
case Code.Ldc_I4:
if (byteCode.InferredType == typeSystem.Boolean && (int)operand == 0)
return new Ast.PrimitiveExpression(false);
else if (byteCode.InferredType == typeSystem.Boolean && (int)operand == 1)
return new Ast.PrimitiveExpression(true);
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(CSharpPrimitiveCast.Cast(TypeCode.Int32, field.Constant, false), operand))
return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
}
}
}
return new Ast.PrimitiveExpression(operand);
return PrimitiveExpression((int)operand, byteCode.InferredType);
case Code.Ldc_I8:
case Code.Ldc_R4:
case Code.Ldc_R8:
@ -580,7 +556,6 @@ namespace Decompiler @@ -580,7 +556,6 @@ namespace Decompiler
case Code.Refanyval: return InlineAssembly(byteCode, args);
case Code.Ret: {
if (methodDef.ReturnType.FullName != "System.Void") {
arg1 = Convert(arg1, methodDef.ReturnType);
return new Ast.ReturnStatement { Expression = arg1 };
} else {
return new Ast.ReturnStatement();
@ -719,19 +694,57 @@ namespace Decompiler @@ -719,19 +694,57 @@ namespace Decompiler
return new DirectionExpression { Expression = expr, FieldDirection = FieldDirection.Ref };
}
static Ast.Expression Convert(Ast.Expression expr, Cecil.TypeReference reqType)
Ast.Expression Convert(Ast.Expression expr, Cecil.TypeReference actualType, Cecil.TypeReference reqType)
{
if (reqType == null) {
if (reqType == null || actualType == reqType) {
return expr;
} else {
bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(typeSystem, actualType);
bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(typeSystem, reqType);
if (reqType == typeSystem.Boolean) {
if (actualIsIntegerOrEnum) {
return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, PrimitiveExpression(0, actualType));
} else {
return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, new NullReferenceExpression());
}
}
if (actualType == typeSystem.Boolean && requiredIsIntegerOrEnum) {
return new ConditionalExpression {
Condition = expr,
TrueExpression = PrimitiveExpression(1, reqType),
FalseExpression = PrimitiveExpression(0, reqType)
};
}
if (actualIsIntegerOrEnum && requiredIsIntegerOrEnum) {
return expr.CastTo(AstBuilder.ConvertType(reqType));
}
return expr;
}
}
static Ast.Expression ConvertIntToBool(Ast.Expression astInt)
Expression PrimitiveExpression(long val, TypeReference type)
{
return astInt;
// return new Ast.ParenthesizedExpression(new Ast.BinaryOperatorExpression(astInt, BinaryOperatorType.InEquality, new Ast.PrimitiveExpression(0, "0")));
if (type == typeSystem.Boolean && val == 0)
return new Ast.PrimitiveExpression(false);
else if (type == typeSystem.Boolean && val == 1)
return new Ast.PrimitiveExpression(true);
if (type != null) { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs)
TypeDefinition enumDefinition = type.Resolve();
if (enumDefinition != null && enumDefinition.IsEnum) {
foreach (FieldDefinition field in enumDefinition.Fields) {
if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val))
return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
else if (!field.IsStatic && field.IsRuntimeSpecialName)
type = field.FieldType; // use primitive type of the enum
}
}
}
TypeCode code = TypeAnalysis.GetTypeCode(typeSystem, type);
if (code == TypeCode.Object)
return new Ast.PrimitiveExpression((int)val);
else
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
}
}
}

7
ICSharpCode.Decompiler/Ast/CommentStatement.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
using System;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
namespace Decompiler
{
@ -34,5 +35,11 @@ namespace Decompiler @@ -34,5 +35,11 @@ namespace Decompiler
cs.Remove();
}
}
protected override bool DoMatch(AstNode other, Match match)
{
CommentStatement o = other as CommentStatement;
return o != null && MatchString(comment, o.comment);
}
}
}

10
ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs

@ -26,17 +26,21 @@ namespace Decompiler @@ -26,17 +26,21 @@ namespace Decompiler
/// <param name="type">The type of the new variable</param>
/// <param name="name">The name of the new variable</param>
/// <param name="allowPassIntoLoops">Whether the variable is allowed to be placed inside a loop</param>
public static void DeclareVariable(AstNode node, AstType type, string name, bool allowPassIntoLoops = true)
public static VariableDeclarationStatement DeclareVariable(AstNode node, AstType type, string name, bool allowPassIntoLoops = true)
{
VariableDeclarationStatement result = null;
AstNode pos = FindInsertPos(node, name, allowPassIntoLoops);
if (pos != null) {
Match m = assignmentPattern.Match(pos);
if (m != null && m.Get<IdentifierExpression>("ident").Single().Identifier == name) {
pos.ReplaceWith(new VariableDeclarationStatement(type, name, m.Get<Expression>("init").Single().Detach()));
result = new VariableDeclarationStatement(type, name, m.Get<Expression>("init").Single().Detach());
pos.ReplaceWith(result);
} else {
pos.Parent.InsertChildBefore(pos, new VariableDeclarationStatement(type, name), BlockStatement.StatementRole);
result = new VariableDeclarationStatement(type, name);
pos.Parent.InsertChildBefore(pos, result, BlockStatement.StatementRole);
}
}
return result;
}
static AstNode FindInsertPos(AstNode node, string name, bool allowPassIntoLoops)

8
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -32,6 +32,10 @@ namespace Decompiler.Transforms @@ -32,6 +32,10 @@ namespace Decompiler.Transforms
}
}
internal sealed class CapturedVariableAnnotation
{
}
public DelegateConstruction(DecompilerContext context) : base(context)
{
}
@ -240,7 +244,9 @@ namespace Decompiler.Transforms @@ -240,7 +244,9 @@ namespace Decompiler.Transforms
}
// Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
foreach (var tuple in variablesToDeclare) {
DeclareVariableInSmallestScope.DeclareVariable(blockStatement, tuple.Item1, tuple.Item2, allowPassIntoLoops: false);
var newVarDecl = DeclareVariableInSmallestScope.DeclareVariable(blockStatement, tuple.Item1, tuple.Item2, allowPassIntoLoops: false);
if (newVarDecl != null)
newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
}
}
return null;

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

@ -19,26 +19,35 @@ namespace Decompiler.Transforms @@ -19,26 +19,35 @@ namespace Decompiler.Transforms
{
TransformUsings(compilationUnit);
TransformForeach(compilationUnit);
TransformFor(compilationUnit);
}
#region using
static readonly AstNode usingVarDeclPattern = new VariableDeclarationStatement {
/// <summary>
/// $type $variable = $initializer;
/// </summary>
static readonly AstNode variableDeclPattern = new VariableDeclarationStatement {
Type = new AnyNode("type").ToType(),
Variables = {
new NamedNode(
"variable",
new VariableInitializer {
Initializer = new AnyNode().ToExpression()
Initializer = new AnyNode("initializer").ToExpression()
}
).ToVariable()
}
};
/// <summary>
/// Variable declaration without initializer.
/// </summary>
static readonly AstNode simpleVariableDefinition = new VariableDeclarationStatement {
Type = new AnyNode().ToType(),
Variables = {
new VariableInitializer() // any name but no initializer
}
};
#region using
static readonly AstNode usingTryCatchPattern = new TryCatchStatement {
TryBlock = new AnyNode("body").ToBlock(),
FinallyBlock = new BlockStatement {
@ -65,7 +74,7 @@ namespace Decompiler.Transforms @@ -65,7 +74,7 @@ namespace Decompiler.Transforms
public void TransformUsings(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
Match m1 = usingVarDeclPattern.Match(node);
Match m1 = variableDeclPattern.Match(node);
if (m1 == null) continue;
AstNode tryCatch = node.NextSibling;
while (simpleVariableDefinition.Match(tryCatch) != null)
@ -103,25 +112,23 @@ namespace Decompiler.Transforms @@ -103,25 +112,23 @@ namespace Decompiler.Transforms
).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 {
EmbeddedStatement = new Choice {
// There are two forms of the foreach statement:
// one where the item variable is declared inside the loop,
// and one where it is declared outside of the loop.
// In the former case, we can apply the foreach pattern only if the variable wasn't captured.
{ "itemVariableInsideLoop",
new BlockStatement {
new WhileStatement {
Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"),
EmbeddedStatement = new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("itemType").ToType(),
Variables = {
new NamedNode(
"itemVariable",
new VariableInitializer {
Initializer = new Backreference("enumeratorIdent").ToExpression().Member("Current")
Initializer = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current")
}
).ToVariable()
}
@ -130,8 +137,29 @@ namespace Decompiler.Transforms @@ -130,8 +137,29 @@ namespace Decompiler.Transforms
}
}
}
},
{ "itemVariableOutsideLoop",
new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("itemType").ToType(),
Variables = {
new NamedNode("itemVariable", new VariableInitializer()).ToVariable()
}
},
new WhileStatement {
Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"),
EmbeddedStatement = new BlockStatement {
new AssignmentExpression {
Left = new IdentifierExpressionBackreference("itemVariable").ToExpression(),
Operator = AssignmentOperatorType.Assign,
Right = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current")
},
new Repeat(new AnyNode("statement")).ToStatement()
}
}
}
}
}
}.ToStatement()
};
public void TransformForeach(AstNode compilationUnit)
@ -141,21 +169,73 @@ namespace Decompiler.Transforms @@ -141,21 +169,73 @@ namespace Decompiler.Transforms
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();
if (m.Has("itemVariableInsideLoop") && itemVar.Annotation<DelegateConstruction.CapturedVariableAnnotation>() != null) {
// cannot move captured variables out of loops
continue;
}
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,
VariableName = itemVar.Name,
InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody
});
}
}
#endregion
#region for
WhileStatement forPattern = new WhileStatement {
Condition = new BinaryOperatorExpression {
Left = new NamedNode("ident", new IdentifierExpression()).ToExpression(),
Operator = BinaryOperatorType.Any,
Right = new AnyNode("endExpr").ToExpression()
},
EmbeddedStatement = new BlockStatement {
new Repeat(new AnyNode("statement")).ToStatement(),
new NamedNode(
"increment",
new ExpressionStatement(
new AssignmentExpression {
Left = new Backreference("ident").ToExpression(),
Operator = AssignmentOperatorType.Any,
Right = new AnyNode().ToExpression()
})).ToStatement(),
new ContinueStatement()
}
};
public void TransformFor(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
Match m1 = variableDeclPattern.Match(node);
if (m1 == null) continue;
AstNode next = node.NextSibling;
while (simpleVariableDefinition.Match(next) != null)
next = next.NextSibling;
Match m2 = forPattern.Match(next);
if (m2 == null) continue;
// ensure the variable in the for pattern is the same as in the declaration
if (m1.Get<VariableInitializer>("variable").Single().Name != m2.Get<IdentifierExpression>("ident").Single().Identifier)
continue;
WhileStatement loop = (WhileStatement)next;
node.Remove();
BlockStatement newBody = new BlockStatement();
foreach (Statement stmt in m2.Get<Statement>("statement"))
newBody.Add(stmt.Detach());
loop.ReplaceWith(
new ForStatement {
Initializers = { (VariableDeclarationStatement)node },
Condition = loop.Condition.Detach(),
Iterators = { m2.Get<Statement>("increment").Single().Detach() },
EmbeddedStatement = newBody
});
}
}
#endregion
}
}

10
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -203,6 +203,7 @@ namespace Decompiler @@ -203,6 +203,7 @@ namespace Decompiler
// Mapping to the original instructions (useful for debugging)
public List<ILRange> ILRanges { get; set; }
public TypeReference ExpectedType { get; set; }
public TypeReference InferredType { get; set; }
public ILExpression(ILCode code, object operand, params ILExpression[] args)
@ -296,6 +297,15 @@ namespace Decompiler @@ -296,6 +297,15 @@ namespace Decompiler
if (this.InferredType != null) {
output.Write(':');
this.InferredType.WriteTo(output, true, true);
if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) {
output.Write("[exp:");
this.ExpectedType.WriteTo(output, true, true);
output.Write(']');
}
} else if (this.ExpectedType != null) {
output.Write("[exp:");
this.ExpectedType.WriteTo(output, true, true);
output.Write(']');
}
output.Write('(');
bool first = true;

48
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -55,7 +55,7 @@ namespace Decompiler @@ -55,7 +55,7 @@ namespace Decompiler
}
bool anyArgumentIsMissingType = expr.Arguments.Any(a => a.InferredType == null);
if (expr.InferredType == null || anyArgumentIsMissingType)
expr.InferredType = InferTypeForExpression(expr, null, forceInferChildren: anyArgumentIsMissingType);
expr.InferredType = InferTypeForExpression(expr, expr.ExpectedType, forceInferChildren: anyArgumentIsMissingType);
}
foreach (ILNode child in node.GetChildren()) {
InferTypes(child);
@ -97,6 +97,7 @@ namespace Decompiler @@ -97,6 +97,7 @@ namespace Decompiler
/// <returns>The inferred type</returns>
TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
{
expr.ExpectedType = expectedType;
if (forceInferChildren || expr.InferredType == null)
expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren);
return expr.InferredType;
@ -552,13 +553,16 @@ namespace Decompiler @@ -552,13 +553,16 @@ namespace Decompiler
TypeReference leftPreferred = DoInferTypeForExpression(left, null);
TypeReference rightPreferred = DoInferTypeForExpression(right, null);
if (leftPreferred == rightPreferred) {
return left.InferredType = right.InferredType = leftPreferred;
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
return left.InferredType = right.InferredType = rightPreferred;
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
} else if (leftPreferred == DoInferTypeForExpression(right, leftPreferred)) {
return left.InferredType = right.InferredType = leftPreferred;
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
return left.InferredType = right.InferredType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
right.InferredType = DoInferTypeForExpression(left, right.ExpectedType);
return left.ExpectedType;
}
}
@ -637,5 +641,39 @@ namespace Decompiler @@ -637,5 +641,39 @@ namespace Decompiler
return true;
return null;
}
public static TypeCode GetTypeCode(TypeSystem typeSystem, TypeReference type)
{
if (type == typeSystem.Boolean)
return TypeCode.Boolean;
else if (type == typeSystem.Byte)
return TypeCode.Byte;
else if (type == typeSystem.Char)
return TypeCode.Char;
else if (type == typeSystem.Double)
return TypeCode.Double;
else if (type == typeSystem.Int16)
return TypeCode.Int16;
else if (type == typeSystem.Int32)
return TypeCode.Int32;
else if (type == typeSystem.Int64)
return TypeCode.Int64;
else if (type == typeSystem.Single)
return TypeCode.Single;
else if (type == typeSystem.Double)
return TypeCode.Double;
else if (type == typeSystem.SByte)
return TypeCode.SByte;
else if (type == typeSystem.UInt16)
return TypeCode.UInt16;
else if (type == typeSystem.UInt32)
return TypeCode.UInt32;
else if (type == typeSystem.UInt64)
return TypeCode.UInt64;
else if (type == typeSystem.String)
return TypeCode.String;
else
return TypeCode.Object;
}
}
}

BIN
ICSharpCode.Decompiler/Tests/StackTests/StackTests.exe

Binary file not shown.

132
ICSharpCode.Decompiler/Tests/StackTests/StackTests.il

@ -0,0 +1,132 @@ @@ -0,0 +1,132 @@
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 4:0:0:0
}
.assembly StackTests
{
.hash algorithm 0x00008004
.ver 1:0:4059:39717
}
.module StackTests.exe
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000003 // ILONLY 32BITREQUIRED
.class private auto ansi beforefieldinit StackTests.Program extends [mscorlib]System.Object
{
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
ldc.i4.0
call string StackTests.Program::Test1(bool cond)
call void [mscorlib]System.Console::WriteLine(string) // false
ldc.i4.1
call string StackTests.Program::Test1(bool cond)
call void [mscorlib]System.Console::WriteLine(string) // true
ldc.i4.0
ldc.i4.0
ldc.i4.0
call int32 StackTests.Program::Test2(int32 switch1, int32 br1, int32 br2)
call void [mscorlib]System.Console::WriteLine(int32) // 11
ldc.i4.0
ldc.i4.1
ldc.i4.0
call int32 StackTests.Program::Test2(int32 switch1, int32 br1, int32 br2)
call void [mscorlib]System.Console::WriteLine(int32) // 21
ldc.i4.1
ldc.i4.1
ldc.i4.1
call int32 StackTests.Program::Test2(int32 switch1, int32 br1, int32 br2)
call void [mscorlib]System.Console::WriteLine(int32) // 32
ldc.i4.2
ldc.i4.1
ldc.i4.0
call int32 StackTests.Program::Test2(int32 switch1, int32 br1, int32 br2)
call void [mscorlib]System.Console::WriteLine(int32) // 23
ret
}
.method public hidebysig static string Test1(bool cond) cil managed
{
ldarg.0
brtrue TRUE
FALSE:
ldstr "false"
br EXIT
TRUE:
ldstr "true"
EXIT:
ret
}
.method public hidebysig static int32 Test2(int32 switch1, int32 br1, int32 br2) cil managed
{
ldarg.0
switch (ENTRY1, ENTRY2, ENTRY3)
ldc.i4.0
ret
ENTRY1:
ldc.i4.1
br BRANCH1
ENTRY2:
ldc.i4.2
br BRANCH1
ENTRY3:
ldc.i4.3
br BRANCH2
BRANCH1:
ldarg.1
brtrue BRANCH2
EXIT1:
ldc.i4 10
add
ret
BRANCH2:
ldarg.2
brtrue.s EXIT3
EXIT2:
ldc.i4 20
add
ret
EXIT3:
ldc.i4 30
add
ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Program::.ctor
} // end of class StackTests.Program
// =============================================================

2
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -72,7 +72,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -72,7 +72,7 @@ namespace ICSharpCode.Decompiler.Tests
}
while ((line2 = r2.ReadLine()) != null) {
ok = false;
diff.WriteLine("+" + line1);
diff.WriteLine("+" + line2);
}
return ok;
}

2
ILSpy/MainWindow.xaml.cs

@ -26,6 +26,8 @@ using System.Threading.Tasks; @@ -26,6 +26,8 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.TreeView;
using ILSpy.Debugger.AvalonEdit;

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

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
@ -156,29 +157,45 @@ namespace ICSharpCode.NRefactory.CSharp @@ -156,29 +157,45 @@ namespace ICSharpCode.NRefactory.CSharp
internal bool DoMatch(AstNodeCollection<T> other, Match match)
{
AstNode cur1 = this.node.FirstChild;
AstNode cur2 = other.node.FirstChild;
while (true) {
while (cur1 != null && cur1.Role != role)
Stack<AstNode> patternStack = new Stack<AstNode>();
Stack<Pattern.PossibleMatch> stack = new Stack<Pattern.PossibleMatch>();
patternStack.Push(this.node.FirstChild);
stack.Push(new Pattern.PossibleMatch(other.node.FirstChild, match.CheckPoint()));
while (stack.Count > 0) {
AstNode cur1 = patternStack.Pop();
AstNode cur2 = stack.Peek().NextOther;
match.RestoreCheckPoint(stack.Pop().Checkpoint);
bool success = true;
while (cur1 != null && success) {
while (cur1 != null && cur1.Role != role)
cur1 = cur1.NextSibling;
while (cur2 != null && cur2.Role != role)
cur2 = cur2.NextSibling;
if (cur1 == null)
break;
Pattern pattern = cur1 as Pattern;
if (pattern == null && cur1.NodeType == NodeType.Placeholder)
pattern = cur1.GetChildByRole(TypePlaceholder.ChildRole) as Pattern;
if (pattern != null) {
Debug.Assert(stack.Count == patternStack.Count);
success = pattern.DoMatchCollection(role, cur2, match, stack);
Debug.Assert(stack.Count >= patternStack.Count);
while (stack.Count > patternStack.Count)
patternStack.Push(cur1.NextSibling);
} else {
success = cur1.DoMatch(cur2, match);
}
cur1 = cur1.NextSibling;
if (cur2 != null)
cur2 = cur2.NextSibling;
}
while (cur2 != null && cur2.Role != role)
cur2 = cur2.NextSibling;
if (cur1 == null || cur2 == null)
break;
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;
if (success && cur2 == null)
return true;
}
return cur1 == null && cur2 == null;
return false;
}
}
}

6
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs

@ -75,7 +75,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -75,7 +75,8 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
AssignmentExpression o = other as AssignmentExpression;
return o != null && this.Left.DoMatch(o.Left, match) && this.Operator == o.Operator && this.Right.DoMatch(o.Right, match);
return o != null && (this.Operator == AssignmentOperatorType.Any || this.Operator == o.Operator)
&& this.Left.DoMatch(o.Left, match) && this.Right.DoMatch(o.Right, match);
}
public static string GetOperatorSymbol(AssignmentOperatorType op)
@ -136,5 +137,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -136,5 +137,8 @@ namespace ICSharpCode.NRefactory.CSharp
BitwiseOr,
/// <summary>left ^= right</summary>
ExclusiveOr,
/// <summary>Any operator (for pattern matching)</summary>
Any
}
}

10
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//
// BinaryOperatorExpression.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -75,7 +75,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -75,7 +75,8 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
BinaryOperatorExpression o = other as BinaryOperatorExpression;
return o != null && this.Left.DoMatch(o.Left, match) && this.Operator == o.Operator && this.Right.DoMatch(o.Right, match);
return o != null && (this.Operator == BinaryOperatorType.Any || this.Operator == o.Operator)
&& this.Left.DoMatch(o.Left, match) && this.Right.DoMatch(o.Right, match);
}
public static string GetOperatorSymbol(BinaryOperatorType op)
@ -175,6 +176,9 @@ namespace ICSharpCode.NRefactory.CSharp @@ -175,6 +176,9 @@ namespace ICSharpCode.NRefactory.CSharp
/// <summary>left ?? right</summary>
NullCoalescing,
None
/// <summary>
/// Any binary operator (used in pattern matching)
/// </summary>
Any
}
}

9
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp
@ -50,6 +51,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -50,6 +51,14 @@ namespace ICSharpCode.NRefactory.CSharp
return (Expression)base.Clone();
}
// Make debugging easier by giving Expressions a ToString() implementation
public override string ToString()
{
StringWriter w = new StringWriter();
AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null);
return w.ToString();
}
public Expression ReplaceWith(Func<Expression, Expression> replaceFunction)
{
if (replaceFunction == null)

4
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs

@ -31,6 +31,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -31,6 +31,8 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary>
public class PrimitiveExpression : Expression
{
public static readonly object AnyValue = new object();
AstLocation startLocation;
public override AstLocation StartLocation {
get {
@ -70,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -70,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
PrimitiveExpression o = other as PrimitiveExpression;
return o != null && object.Equals(this.Value, o.Value);
return o != null && (this.Value == AnyValue || object.Equals(this.Value, o.Value));
}
}
}

3
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs

@ -44,7 +44,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -44,7 +44,8 @@ namespace ICSharpCode.NRefactory.CSharp
Expression,
Token,
QueryClause,
Pattern
Pattern,
Placeholder
}
}

9
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs

@ -12,6 +12,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -12,6 +12,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
readonly string groupName;
public string GroupName {
get { return groupName; }
}
public AnyNode(string groupName = null)
{
this.groupName = groupName;
@ -22,5 +26,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -22,5 +26,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
match.Add(this.groupName, other);
return other != null && !other.IsNull;
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return ((IPatternAstVisitor<T, S>)visitor).VisitAnyNode(this, data);
}
}
}

42
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs

@ -13,6 +13,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -13,6 +13,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
readonly string referencedGroupName;
public string ReferencedGroupName {
get { return referencedGroupName; }
}
public Backreference(string referencedGroupName)
{
if (referencedGroupName == null)
@ -24,5 +28,43 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -24,5 +28,43 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
return match.Get(referencedGroupName).Last().Match(other) != null;
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return ((IPatternAstVisitor<T, S>)visitor).VisitBackreference(this, data);
}
}
/// <summary>
/// Matches identifier expressions that have the same identifier as the referenced variable/type definition/method definition.
/// </summary>
public class IdentifierExpressionBackreference : Pattern
{
readonly string referencedGroupName;
public string ReferencedGroupName {
get { return referencedGroupName; }
}
public IdentifierExpressionBackreference(string referencedGroupName)
{
if (referencedGroupName == null)
throw new ArgumentNullException("referencedGroupName");
this.referencedGroupName = referencedGroupName;
}
protected internal override bool DoMatch(AstNode other, Match match)
{
IdentifierExpression ident = other as IdentifierExpression;
if (ident == null || ident.TypeArguments.Any())
return false;
AstNode referenced = match.Get(referencedGroupName).Last();
return ident.Identifier == referenced.GetChildByRole(AstNode.Roles.Identifier).Name;
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return ((IPatternAstVisitor<T, S>)visitor).VisitIdentifierExpressionBackreference(this, data);
}
}
}

13
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs

@ -3,13 +3,14 @@ @@ -3,13 +3,14 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
/// <summary>
/// Matches one of several alternatives.
/// </summary>
public class Choice : Pattern, IEnumerable
public class Choice : Pattern, IEnumerable<AstNode>
{
public static readonly Role<AstNode> AlternativeRole = new Role<AstNode>("Alternative", AstNode.Null);
@ -35,9 +36,19 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -35,9 +36,19 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
return false;
}
IEnumerator<AstNode> IEnumerable<AstNode>.GetEnumerator()
{
return GetChildrenByRole(AlternativeRole).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetChildrenByRole(AlternativeRole).GetEnumerator();
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return ((IPatternAstVisitor<T, S>)visitor).VisitChoice(this, data);
}
}
}

22
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
// 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;
namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
/// <summary>
/// Extended AST visitor that works for patterns.
/// </summary>
public interface IPatternAstVisitor<in T, out S> : IAstVisitor<T, S>
{
S VisitPlaceholder(AstNode placeholder, AstNode child, T data);
S VisitAnyNode(AnyNode anyNode, T data);
S VisitBackreference(Backreference backreference, T data);
S VisitChoice(Choice choice, T data);
S VisitNamedNode(NamedNode namedNode, T data);
S VisitRepeat(Repeat repeat, T data);
S VisitIdentifierExpressionBackreference(IdentifierExpressionBackreference identifierExpressionBackreference, T data);
}
}

9
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedGroup.cs → NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs

@ -14,6 +14,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -14,6 +14,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
readonly string groupName;
public string GroupName {
get { return groupName; }
}
public NamedNode(string groupName, AstNode childNode)
{
this.groupName = groupName;
@ -25,5 +29,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -25,5 +29,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
match.Add(this.groupName, other);
return GetChildByRole(ElementRole).DoMatch(other, match);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return ((IPatternAstVisitor<T, S>)visitor).VisitNamedNode(this, data);
}
}
}

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

@ -2,6 +2,9 @@ @@ -2,6 +2,9 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
@ -14,16 +17,21 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -14,16 +17,21 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
get { return NodeType.Pattern; }
}
protected internal virtual bool DoMatchCollection(Role role, ref AstNode other, Match match)
internal struct PossibleMatch
{
bool result = DoMatch(other, match);
other = other.NextSibling;
return result;
public readonly AstNode NextOther; // next node after the last matched node
public readonly int Checkpoint; // checkpoint
public PossibleMatch(AstNode nextOther, int checkpoint)
{
this.NextOther = nextOther;
this.Checkpoint = checkpoint;
}
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
internal virtual bool DoMatchCollection(Role role, AstNode pos, Match match, Stack<PossibleMatch> backtrackingStack)
{
return default(S);
return DoMatch(pos, match);
}
public AstType ToType()
@ -50,5 +58,13 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -50,5 +58,13 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
return new VariablePlaceholder(this);
}
// Make debugging easier by giving Patterns a ToString() implementation
public override string ToString()
{
StringWriter w = new StringWriter();
AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null);
return w.ToString();
}
}
}

20
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs

@ -15,12 +15,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -15,12 +15,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
}
public override NodeType NodeType {
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
get { return NodeType.Placeholder; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data);
}
protected internal override bool DoMatch(AstNode other, Match match)
@ -37,12 +37,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -37,12 +37,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
}
public override NodeType NodeType {
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
get { return NodeType.Placeholder; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data);
}
protected internal override bool DoMatch(AstNode other, Match match)
@ -59,12 +59,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -59,12 +59,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
}
public override NodeType NodeType {
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
get { return NodeType.Placeholder; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data);
}
protected internal override bool DoMatch(AstNode other, Match match)
@ -81,12 +81,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -81,12 +81,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
}
public override NodeType NodeType {
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
get { return NodeType.Placeholder; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data);
}
protected internal override bool DoMatch(AstNode other, Match match)
@ -103,12 +103,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -103,12 +103,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
}
public override NodeType NodeType {
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
get { return NodeType.Placeholder; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
return ((IPatternAstVisitor<T, S>)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data);
}
protected internal override bool DoMatch(AstNode other, Match match)

26
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.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;
using System.Diagnostics;
namespace ICSharpCode.NRefactory.CSharp.PatternMatching
@ -20,24 +21,22 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -20,24 +21,22 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
AddChild(childNode, ElementRole);
}
protected internal override bool DoMatchCollection(Role role, ref AstNode other, Match match)
internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack<Pattern.PossibleMatch> backtrackingStack)
{
Debug.Assert(other != null && other.Role == role);
Debug.Assert(pos == null || pos.Role == role);
int matchCount = 0;
var lastValidCheckpoint = match.CheckPoint();
if (this.MinCount <= 0)
backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint()));
AstNode element = GetChildByRole(ElementRole);
AstNode pos = other;
while (pos != null && element.DoMatch(pos, match)) {
while (matchCount < this.MaxCount && 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;
if (matchCount >= this.MinCount)
backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint()));
}
match.RestoreCheckPoint(lastValidCheckpoint); // restote old checkpoint after failed match
return matchCount >= MinCount && matchCount <= MaxCount;
return false; // never do a normal (single-element) match; always make the caller look at the results on the back-tracking stack.
}
protected internal override bool DoMatch(AstNode other, Match match)
@ -45,7 +44,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -45,7 +44,12 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
if (other == null || other.IsNull)
return this.MinCount <= 0;
else
return GetChildByRole(ElementRole).DoMatch(other, match);
return this.MaxCount >= 1 && GetChildByRole(ElementRole).DoMatch(other, match);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return ((IPatternAstVisitor<T, S>)visitor).VisitRepeat(this, data);
}
}
}

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

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

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

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

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

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// DoWhileStatement.cs
//
// Author:
@ -68,6 +68,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -68,6 +68,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitDoWhileStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
DoWhileStatement o = other as DoWhileStatement;
return o != null && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match) && this.Condition.DoMatch(o.Condition, match);
}
}
}

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

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

6
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs

@ -63,5 +63,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -63,5 +63,11 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitFixedStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
FixedStatement o = other as FixedStatement;
return o != null && this.Variables.DoMatch(o.Variables, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match);
}
}
}

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

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// ForeachStatement.cs
//
// Author:
@ -75,5 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -75,5 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitForeachStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
ForeachStatement o = other as ForeachStatement;
return o != null && this.VariableType.DoMatch(o.VariableType, match) && MatchString(this.VariableName, o.VariableName)
&& this.InExpression.DoMatch(o.InExpression, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match);
}
}
}

38
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs

@ -56,14 +56,6 @@ namespace ICSharpCode.NRefactory.CSharp @@ -56,14 +56,6 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
/// <summary>
/// Used for "goto case LabelExpression;"
/// </summary>
public Expression LabelExpression {
get { return GetChildByRole (Roles.Expression); }
set { SetChildByRole (Roles.Expression, value); }
}
public CSharpTokenNode SemicolonToken {
get { return GetChildByRole (Roles.Semicolon); }
}
@ -72,6 +64,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -72,6 +64,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitGotoStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
GotoStatement o = other as GotoStatement;
return o != null && MatchString(this.Label, o.Label);
}
}
/// <summary>
@ -89,18 +87,6 @@ namespace ICSharpCode.NRefactory.CSharp @@ -89,18 +87,6 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (CaseKeywordRole); }
}
public string Label {
get {
return GetChildByRole (Roles.Identifier).Name;
}
set {
if (string.IsNullOrEmpty(value))
SetChildByRole(Roles.Identifier, null);
else
SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
}
}
/// <summary>
/// Used for "goto case LabelExpression;"
/// </summary>
@ -117,6 +103,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -117,6 +103,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitGotoCaseStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
GotoCaseStatement o = other as GotoCaseStatement;
return o != null && this.LabelExpression.DoMatch(o.LabelExpression, match);
}
}
/// <summary>
@ -142,5 +134,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -142,5 +134,11 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitGotoDefaultStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
GotoDefaultStatement o = other as GotoDefaultStatement;
return o != null;
}
}
}

12
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// LabelStatement.cs
//
// Author:
@ -40,9 +40,19 @@ namespace ICSharpCode.NRefactory.CSharp @@ -40,9 +40,19 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
public CSharpTokenNode Colon {
get { return GetChildByRole (Roles.Colon); }
}
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitLabelStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
LabelStatement o = other as LabelStatement;
return o != null && MatchString(this.Label, o.Label);
}
}
}

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

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

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

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

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs

@ -52,10 +52,5 @@ namespace ICSharpCode.NRefactory.CSharp @@ -52,10 +52,5 @@ namespace ICSharpCode.NRefactory.CSharp
public override NodeType NodeType {
get { return NodeType.Statement; }
}
protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.CSharp.PatternMatching.Match match)
{
throw new NotImplementedException();
}
}
}

6
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs

@ -69,6 +69,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -69,6 +69,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
return visitor.VisitSwitchStatement (this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
SwitchStatement o = other as SwitchStatement;
return o != null && this.Expression.DoMatch(o.Expression, match) && this.SwitchSections.DoMatch(o.SwitchSections, match);
}
}
public class SwitchSection : AstNode

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

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

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

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

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

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

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

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

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

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

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

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

90
NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

@ -8,6 +8,8 @@ using System.Globalization; @@ -8,6 +8,8 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
@ -15,7 +17,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -15,7 +17,7 @@ namespace ICSharpCode.NRefactory.CSharp
/// <summary>
/// Outputs the AST.
/// </summary>
public class OutputVisitor : IAstVisitor<object, object>
public class OutputVisitor : IPatternAstVisitor<object, object>
{
readonly IOutputFormatter formatter;
readonly CSharpFormattingPolicy policy;
@ -1989,5 +1991,91 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1989,5 +1991,91 @@ namespace ICSharpCode.NRefactory.CSharp
return EndNode(identifier);
}
#endregion
#region Pattern Nodes
object IPatternAstVisitor<object, object>.VisitPlaceholder(AstNode placeholder, AstNode child, object data)
{
StartNode(placeholder);
child.AcceptVisitor(this, data);
return EndNode(placeholder);
}
object IPatternAstVisitor<object, object>.VisitAnyNode(AnyNode anyNode, object data)
{
StartNode(anyNode);
if (!string.IsNullOrEmpty(anyNode.GroupName)) {
WriteIdentifier(anyNode.GroupName);
WriteToken(":", AstNode.Roles.Colon);
}
WriteKeyword("anyNode");
return EndNode(anyNode);
}
object IPatternAstVisitor<object, object>.VisitBackreference(Backreference backreference, object data)
{
StartNode(backreference);
WriteKeyword("backreference");
LPar();
WriteIdentifier(backreference.ReferencedGroupName);
RPar();
return EndNode(backreference);
}
object IPatternAstVisitor<object, object>.VisitIdentifierExpressionBackreference(IdentifierExpressionBackreference identifierExpressionBackreference, object data)
{
StartNode(identifierExpressionBackreference);
WriteKeyword("identifierBackreference");
LPar();
WriteIdentifier(identifierExpressionBackreference.ReferencedGroupName);
RPar();
return EndNode(identifierExpressionBackreference);
}
object IPatternAstVisitor<object, object>.VisitChoice(Choice choice, object data)
{
StartNode(choice);
WriteKeyword("choice");
Space();
LPar();
NewLine();
formatter.Indent();
foreach (AstNode alternative in choice) {
alternative.AcceptVisitor(this, data);
if (alternative != choice.LastChild)
WriteToken(",", AstNode.Roles.Comma);
NewLine();
}
formatter.Unindent();
RPar();
return EndNode(choice);
}
object IPatternAstVisitor<object, object>.VisitNamedNode(NamedNode namedNode, object data)
{
StartNode(namedNode);
if (!string.IsNullOrEmpty(namedNode.GroupName)) {
WriteIdentifier(namedNode.GroupName);
WriteToken(":", AstNode.Roles.Colon);
}
namedNode.GetChildByRole(NamedNode.ElementRole).AcceptVisitor(this, data);
return EndNode(namedNode);
}
object IPatternAstVisitor<object, object>.VisitRepeat(Repeat repeat, object data)
{
StartNode(repeat);
WriteKeyword("repeat");
LPar();
if (repeat.MinCount != 0 || repeat.MaxCount != int.MaxValue) {
WriteIdentifier(repeat.MinCount.ToString());
WriteToken(",", AstNode.Roles.Comma);
WriteIdentifier(repeat.MaxCount.ToString());
WriteToken(",", AstNode.Roles.Comma);
}
repeat.GetChildByRole(Repeat.ElementRole).AcceptVisitor(this, data);
RPar();
return EndNode(repeat);
}
#endregion
}
}

3
NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -98,8 +98,9 @@ @@ -98,8 +98,9 @@
<Compile Include="CSharp\Ast\PatternMatching\Choice.cs" />
<Compile Include="CSharp\Ast\PatternMatching\AnyNode.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Backreference.cs" />
<Compile Include="CSharp\Ast\PatternMatching\IPatternAstVisitor.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Match.cs" />
<Compile Include="CSharp\Ast\PatternMatching\NamedGroup.cs" />
<Compile Include="CSharp\Ast\PatternMatching\NamedNode.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Repeat.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Pattern.cs" />
<Compile Include="CSharp\Ast\PatternMatching\Placeholder.cs" />

Loading…
Cancel
Save