Browse Source

Add support for switch over strings.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
55e51394b9
  1. 2
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 124
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  3. 12
      ICSharpCode.Decompiler/DecompilerSettings.cs
  4. 25
      ICSharpCode.Decompiler/Tests/Switch.cs

2
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -645,7 +645,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -645,7 +645,7 @@ namespace ICSharpCode.Decompiler.Ast
}
}
// Default invocation
AdjustArgumentsForMethodCall(cecilMethod, methodArgs);
AdjustArgumentsForMethodCall(cecilMethodDef ?? cecilMethod, methodArgs);
return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod);
}

124
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.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.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
@ -33,6 +34,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -33,6 +34,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
TransformDoWhile(compilationUnit);
if (context.Settings.LockStatement)
TransformLock(compilationUnit);
if (context.Settings.SwitchStatementOnString)
TransformSwitchOnString(compilationUnit);
if (context.Settings.AutomaticProperties)
TransformAutomaticProperties(compilationUnit);
if (context.Settings.AutomaticEvents)
@ -90,7 +93,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -90,7 +93,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public void TransformUsings(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
foreach (AstNode node in compilationUnit.Descendants.OfType<VariableDeclarationStatement>().ToArray()) {
Match m1 = variableDeclPattern.Match(node);
if (m1 == null) continue;
AstNode tryCatch = node.NextSibling;
@ -181,7 +184,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -181,7 +184,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public void TransformForeach(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
foreach (AstNode node in compilationUnit.Descendants.OfType<UsingStatement>().ToArray()) {
Match m = foreachPattern.Match(node);
if (m == null)
continue;
@ -228,7 +231,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -228,7 +231,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public void TransformFor(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
foreach (AstNode node in compilationUnit.Descendants.OfType<VariableDeclarationStatement>().ToArray()) {
Match m1 = variableDeclPattern.Match(node);
if (m1 == null) continue;
AstNode next = node.NextSibling;
@ -335,7 +338,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -335,7 +338,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public void TransformLock(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
foreach (AstNode node in compilationUnit.Descendants.OfType<VariableDeclarationStatement>().ToArray()) {
Match m1 = lockFlagInitPattern.Match(node);
if (m1 == null) continue;
AstNode tryCatch = node.NextSibling;
@ -379,6 +382,117 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -379,6 +382,117 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
#endregion
#region switch on strings
static readonly IfElseStatement switchOnStringPattern = new IfElseStatement {
Condition = new BinaryOperatorExpression {
Left = new NamedNode("switchVar", new IdentifierExpression()),
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 VariableDeclarationStatement {
Type = new PrimitiveType("int"),
Variables = { new NamedNode("intVar", new VariableInitializer()) }
},
new IfElseStatement {
Condition = new Backreference("cachedDict").ToExpression().Invoke(
"TryGetValue",
new Backreference("switchVar"),
new DirectionExpression {
FieldDirection = FieldDirection.Out,
Expression = new IdentifierExpressionBackreference("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 void TransformSwitchOnString(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.OfType<IfElseStatement>().ToArray()) {
Match m = switchOnStringPattern.Match(node);
if (m == null)
continue;
if (m.Has("nonNullDefaultStmt") && !m.Has("nullStmt"))
continue;
FieldReference cachedDictField = m.Get("cachedDict").Single().Annotation<FieldReference>();
if (cachedDictField == null || !cachedDictField.DeclaringType.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
continue;
List<Statement> dictCreation = m.Get<BlockStatement>("dictCreation").Single().Statements.ToList();
List<KeyValuePair<string, int>> dict = BuildDictionary(dictCreation);
SwitchStatement sw = m.Get<SwitchStatement>("switch").Single();
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);
if (m.Has("nonNullDefaultStmt")) {
section = new SwitchSection();
section.CaseLabels.Add(new CaseLabel());
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);
}
}
List<KeyValuePair<string, int>> BuildDictionary(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;
PrimitiveExpression arg1 = ie.Arguments.ElementAtOrDefault(0) as PrimitiveExpression;
PrimitiveExpression arg2 = ie.Arguments.ElementAtOrDefault(1) as PrimitiveExpression;
if (arg1 != null && arg2 != null && arg1.Value is string && arg2.Value is int)
dict.Add(new KeyValuePair<string, int>((string)arg1.Value, (int)arg2.Value));
}
return dict;
}
#endregion
#region Automatic Properties
static readonly PropertyDeclaration automaticPropertyPattern = new PropertyDeclaration {
Attributes = { new Repeat(new AnyNode()) },
@ -440,7 +554,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -440,7 +554,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
#endregion
#region Automatic Events
Accessor automaticEventPatternV4 = new Accessor {
static readonly Accessor automaticEventPatternV4 = new Accessor {
Body = new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("type"),

12
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -116,6 +116,18 @@ namespace ICSharpCode.Decompiler @@ -116,6 +116,18 @@ namespace ICSharpCode.Decompiler
}
}
bool switchStatementOnString = true;
public bool SwitchStatementOnString {
get { return switchStatementOnString; }
set {
if (switchStatementOnString != value) {
switchStatementOnString = value;
OnPropertyChanged("SwitchStatementOnString");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)

25
ICSharpCode.Decompiler/Tests/Switch.cs

@ -15,9 +15,32 @@ public static class Switch @@ -15,9 +15,32 @@ public static class Switch
}
}
public static string SwitchOverString(string text)
public static string SwitchOverString1(string text)
{
switch (text) {
case "First case":
return "Text1";
case "Second case":
case "2nd case":
return "Text2";
case "Third case":
return "Text3";
case "Fourth case":
return "Text4";
case "Fifth case":
return "Text5";
case "Sixth case":
return "Text6";
case null:
return null;
default:
return "Default";
}
}
public static string SwitchOverString2()
{
switch (Environment.UserName) {
case "First case":
return "Text1";
case "Second case":

Loading…
Cancel
Save