|
|
@ -96,11 +96,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms |
|
|
|
|
|
|
|
|
|
|
|
public override AstNode VisitIfElseStatement(IfElseStatement ifElseStatement) |
|
|
|
public override AstNode VisitIfElseStatement(IfElseStatement ifElseStatement) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (context.Settings.SwitchStatementOnString) { |
|
|
|
|
|
|
|
AstNode result = TransformSwitchOnString(ifElseStatement); |
|
|
|
|
|
|
|
if (result != null) |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
AstNode simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement); |
|
|
|
AstNode simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement); |
|
|
|
if (simplifiedIfElse != null) |
|
|
|
if (simplifiedIfElse != null) |
|
|
|
return simplifiedIfElse; |
|
|
|
return simplifiedIfElse; |
|
|
@ -256,174 +251,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region switch on strings
|
|
|
|
|
|
|
|
static readonly IfElseStatement switchOnStringPattern = new IfElseStatement { |
|
|
|
|
|
|
|
Condition = new BinaryOperatorExpression { |
|
|
|
|
|
|
|
Left = new AnyNode("switchExpr"), |
|
|
|
|
|
|
|
Operator = BinaryOperatorType.InEquality, |
|
|
|
|
|
|
|
Right = new NullReferenceExpression() |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
TrueStatement = new BlockStatement { |
|
|
|
|
|
|
|
new IfElseStatement { |
|
|
|
|
|
|
|
Condition = new BinaryOperatorExpression { |
|
|
|
|
|
|
|
Left = new AnyNode("cachedDict"), |
|
|
|
|
|
|
|
Operator = BinaryOperatorType.Equality, |
|
|
|
|
|
|
|
Right = new NullReferenceExpression() |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
TrueStatement = new AnyNode("dictCreation") |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
new IfElseStatement { |
|
|
|
|
|
|
|
Condition = new InvocationExpression(new MemberReferenceExpression(new Backreference("cachedDict").ToExpression(), "TryGetValue"), |
|
|
|
|
|
|
|
new NamedNode("switchVar", new IdentifierExpression(Pattern.AnyString)), |
|
|
|
|
|
|
|
new DirectionExpression { |
|
|
|
|
|
|
|
FieldDirection = FieldDirection.Out, |
|
|
|
|
|
|
|
Expression = new IdentifierExpression(Pattern.AnyString).WithName("intVar") |
|
|
|
|
|
|
|
}), |
|
|
|
|
|
|
|
TrueStatement = new BlockStatement { |
|
|
|
|
|
|
|
Statements = { |
|
|
|
|
|
|
|
new NamedNode( |
|
|
|
|
|
|
|
"switch", new SwitchStatement { |
|
|
|
|
|
|
|
Expression = new IdentifierExpressionBackreference("intVar"), |
|
|
|
|
|
|
|
SwitchSections = { new Repeat(new AnyNode()) } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
new Repeat(new AnyNode("nonNullDefaultStmt")).ToStatement() |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
FalseStatement = new OptionalNode("nullStmt", new BlockStatement { Statements = { new Repeat(new AnyNode()) } }) |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public SwitchStatement TransformSwitchOnString(IfElseStatement node) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Match m = switchOnStringPattern.Match(node); |
|
|
|
|
|
|
|
if (!m.Success) |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
// switchVar must be the same as switchExpr; or switchExpr must be an assignment and switchVar the left side of that assignment
|
|
|
|
|
|
|
|
if (!m.Get("switchVar").Single().IsMatch(m.Get("switchExpr").Single())) { |
|
|
|
|
|
|
|
AssignmentExpression assign = m.Get("switchExpr").Single() as AssignmentExpression; |
|
|
|
|
|
|
|
if (!(assign != null && m.Get("switchVar").Single().IsMatch(assign.Left))) |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
FieldReference cachedDictField = m.Get<AstNode>("cachedDict").Single().Annotation<FieldReference>(); |
|
|
|
|
|
|
|
if (cachedDictField == null) |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
List<Statement> dictCreation = m.Get<BlockStatement>("dictCreation").Single().Statements.ToList(); |
|
|
|
|
|
|
|
List<KeyValuePair<string, int>> dict = BuildDictionary(dictCreation); |
|
|
|
|
|
|
|
SwitchStatement sw = m.Get<SwitchStatement>("switch").Single(); |
|
|
|
|
|
|
|
sw.Expression = m.Get<Expression>("switchExpr").Single().Detach(); |
|
|
|
|
|
|
|
foreach (SwitchSection section in sw.SwitchSections) { |
|
|
|
|
|
|
|
List<CaseLabel> labels = section.CaseLabels.ToList(); |
|
|
|
|
|
|
|
section.CaseLabels.Clear(); |
|
|
|
|
|
|
|
foreach (CaseLabel label in labels) { |
|
|
|
|
|
|
|
PrimitiveExpression expr = label.Expression as PrimitiveExpression; |
|
|
|
|
|
|
|
if (expr == null || !(expr.Value is int)) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
int val = (int)expr.Value; |
|
|
|
|
|
|
|
foreach (var pair in dict) { |
|
|
|
|
|
|
|
if (pair.Value == val) |
|
|
|
|
|
|
|
section.CaseLabels.Add(new CaseLabel { Expression = new PrimitiveExpression(pair.Key) }); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (m.Has("nullStmt")) { |
|
|
|
|
|
|
|
SwitchSection section = new SwitchSection(); |
|
|
|
|
|
|
|
section.CaseLabels.Add(new CaseLabel { Expression = new NullReferenceExpression() }); |
|
|
|
|
|
|
|
BlockStatement block = m.Get<BlockStatement>("nullStmt").Single(); |
|
|
|
|
|
|
|
block.Statements.Add(new BreakStatement()); |
|
|
|
|
|
|
|
section.Statements.Add(block.Detach()); |
|
|
|
|
|
|
|
sw.SwitchSections.Add(section); |
|
|
|
|
|
|
|
} else if (m.Has("nonNullDefaultStmt")) { |
|
|
|
|
|
|
|
sw.SwitchSections.Add( |
|
|
|
|
|
|
|
new SwitchSection { |
|
|
|
|
|
|
|
CaseLabels = { new CaseLabel { Expression = new NullReferenceExpression() } }, |
|
|
|
|
|
|
|
Statements = { new BlockStatement { new BreakStatement() } } |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (m.Has("nonNullDefaultStmt")) { |
|
|
|
|
|
|
|
SwitchSection section = new SwitchSection(); |
|
|
|
|
|
|
|
section.CaseLabels.Add(new CaseLabel()); |
|
|
|
|
|
|
|
BlockStatement block = new BlockStatement(); |
|
|
|
|
|
|
|
block.Statements.AddRange(m.Get<Statement>("nonNullDefaultStmt").Select(s => s.Detach())); |
|
|
|
|
|
|
|
block.Add(new BreakStatement()); |
|
|
|
|
|
|
|
section.Statements.Add(block); |
|
|
|
|
|
|
|
sw.SwitchSections.Add(section); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
node.ReplaceWith(sw); |
|
|
|
|
|
|
|
return sw; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<KeyValuePair<string, int>> BuildDictionary(List<Statement> dictCreation) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (context.Settings.ObjectOrCollectionInitializers && dictCreation.Count == 1) |
|
|
|
|
|
|
|
return BuildDictionaryFromInitializer(dictCreation[0]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return BuildDictionaryFromAddMethodCalls(dictCreation); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static readonly Statement assignInitializedDictionary = new ExpressionStatement { |
|
|
|
|
|
|
|
Expression = new AssignmentExpression { |
|
|
|
|
|
|
|
Left = new AnyNode().ToExpression(), |
|
|
|
|
|
|
|
Right = new ObjectCreateExpression { |
|
|
|
|
|
|
|
Type = new AnyNode(), |
|
|
|
|
|
|
|
Arguments = { new Repeat(new AnyNode()) }, |
|
|
|
|
|
|
|
Initializer = new ArrayInitializerExpression { |
|
|
|
|
|
|
|
Elements = { new Repeat(new AnyNode("dictJumpTable")) } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<KeyValuePair<string, int>> BuildDictionaryFromInitializer(Statement statement) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
List<KeyValuePair<string, int>> dict = new List<KeyValuePair<string, int>>(); |
|
|
|
|
|
|
|
Match m = assignInitializedDictionary.Match(statement); |
|
|
|
|
|
|
|
if (!m.Success) |
|
|
|
|
|
|
|
return dict; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (ArrayInitializerExpression initializer in m.Get<ArrayInitializerExpression>("dictJumpTable")) { |
|
|
|
|
|
|
|
KeyValuePair<string, int> pair; |
|
|
|
|
|
|
|
if (TryGetPairFrom(initializer.Elements, out pair)) |
|
|
|
|
|
|
|
dict.Add(pair); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return dict; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static List<KeyValuePair<string, int>> BuildDictionaryFromAddMethodCalls(List<Statement> dictCreation) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
List<KeyValuePair<string, int>> dict = new List<KeyValuePair<string, int>>(); |
|
|
|
|
|
|
|
for (int i = 0; i < dictCreation.Count; i++) { |
|
|
|
|
|
|
|
ExpressionStatement es = dictCreation[i] as ExpressionStatement; |
|
|
|
|
|
|
|
if (es == null) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
InvocationExpression ie = es.Expression as InvocationExpression; |
|
|
|
|
|
|
|
if (ie == null) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KeyValuePair<string, int> pair; |
|
|
|
|
|
|
|
if (TryGetPairFrom(ie.Arguments, out pair)) |
|
|
|
|
|
|
|
dict.Add(pair); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return dict; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static bool TryGetPairFrom(AstNodeCollection<Expression> expressions, out KeyValuePair<string, int> pair) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
PrimitiveExpression arg1 = expressions.ElementAtOrDefault(0) as PrimitiveExpression; |
|
|
|
|
|
|
|
PrimitiveExpression arg2 = expressions.ElementAtOrDefault(1) as PrimitiveExpression; |
|
|
|
|
|
|
|
if (arg1 != null && arg2 != null && arg1.Value is string && arg2.Value is int) { |
|
|
|
|
|
|
|
pair = new KeyValuePair<string, int>((string)arg1.Value, (int)arg2.Value); |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pair = default(KeyValuePair<string, int>); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region Automatic Properties
|
|
|
|
#region Automatic Properties
|
|
|
|
static readonly PropertyDeclaration automaticPropertyPattern = new PropertyDeclaration { |
|
|
|
static readonly PropertyDeclaration automaticPropertyPattern = new PropertyDeclaration { |
|
|
|
Attributes = { new Repeat(new AnyNode()) }, |
|
|
|
Attributes = { new Repeat(new AnyNode()) }, |
|
|
|