Browse Source

Extract foreach transform to method and improve readability.

pull/870/merge
Siegfried Pammer 8 years ago
parent
commit
3aba0fe57a
  1. 83
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

83
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -262,49 +262,58 @@ namespace ICSharpCode.Decompiler.CSharp @@ -262,49 +262,58 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override Statement VisitUsingInstruction(UsingInstruction inst)
{
var resource = exprBuilder.Translate(inst.ResourceExpression);
var m = getEnumeratorPattern.Match(resource.Expression);
if (inst.Body is BlockContainer container && m.Success) {
var enumeratorVar = m.Get<IdentifierExpression>("enumerator").Single().GetILVariable();
var loop = DetectedLoop.DetectLoop(container);
if (loop.Kind == LoopKind.While && loop.Body is Block body) {
var condition = exprBuilder.TranslateCondition(loop.Conditions.Single());
var m2 = moveNextConditionPattern.Match(condition.Expression);
if (m2.Success) {
var enumeratorVar2 = m2.Get<IdentifierExpression>("enumerator").Single().GetILVariable();
if (enumeratorVar2 == enumeratorVar && BodyHasSingleGetCurrent(body, enumeratorVar, condition.ILInstructions.Single(),
out var singleGetter, out var needsUninlining, out var itemVariable)) {
var collectionExpr = m.Get<Expression>("collection").Single().Detach();
if (needsUninlining) {
itemVariable = currentFunction.RegisterVariable(
VariableKind.ForeachLocal, singleGetter.Method.ReturnType,
AssignVariableNames.GenerateVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), "item")
);
singleGetter.ReplaceWith(new LdLoc(itemVariable));
body.Instructions.Insert(0, new StLoc(itemVariable, singleGetter));
} else {
itemVariable.Kind = VariableKind.ForeachLocal;
itemVariable.Name = AssignVariableNames.GenerateVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), "item", itemVariable);
}
var whileLoop = (WhileStatement)ConvertAsBlock(inst.Body).Single();
BlockStatement foreachBody = (BlockStatement)whileLoop.EmbeddedStatement.Detach();
foreachBody.Statements.First().Detach();
return new ForeachStatement {
VariableType = exprBuilder.ConvertType(itemVariable.Type),
VariableName = itemVariable.Name,
InExpression = collectionExpr,
EmbeddedStatement = foreachBody
};
}
}
}
}
var transformed = TransformToForeach(inst, out var resource);
if (transformed != null)
return transformed;
return new UsingStatement {
ResourceAcquisition = resource,
EmbeddedStatement = ConvertAsBlock(inst.Body)
};
}
ForeachStatement TransformToForeach(UsingInstruction inst, out TranslatedExpression resource)
{
resource = exprBuilder.Translate(inst.ResourceExpression);
var m = getEnumeratorPattern.Match(resource.Expression);
if (!(inst.Body is BlockContainer container) || !m.Success)
return null;
var enumeratorVar = m.Get<IdentifierExpression>("enumerator").Single().GetILVariable();
var loop = DetectedLoop.DetectLoop(container);
if (loop.Kind != LoopKind.While || !(loop.Body is Block body))
return null;
var condition = exprBuilder.TranslateCondition(loop.Conditions.Single());
var m2 = moveNextConditionPattern.Match(condition.Expression);
if (!m2.Success)
return null;
var enumeratorVar2 = m2.Get<IdentifierExpression>("enumerator").Single().GetILVariable();
if (enumeratorVar2 != enumeratorVar || !BodyHasSingleGetCurrent(body, enumeratorVar, condition.ILInstructions.Single(),
out var singleGetter, out var needsUninlining, out var itemVariable))
return null;
var collectionExpr = m.Get<Expression>("collection").Single();
if (needsUninlining) {
itemVariable = currentFunction.RegisterVariable(
VariableKind.ForeachLocal, singleGetter.Method.ReturnType,
AssignVariableNames.GenerateVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), "item")
);
singleGetter.ReplaceWith(new LdLoc(itemVariable));
body.Instructions.Insert(0, new StLoc(itemVariable, singleGetter));
} else {
if (!itemVariable.IsSingleDefinition)
return null;
itemVariable.Kind = VariableKind.ForeachLocal;
itemVariable.Name = AssignVariableNames.GenerateVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), "item", itemVariable);
}
var whileLoop = (WhileStatement)ConvertAsBlock(inst.Body).Single();
BlockStatement foreachBody = (BlockStatement)whileLoop.EmbeddedStatement.Detach();
foreachBody.Statements.First().Detach();
return new ForeachStatement {
VariableType = exprBuilder.ConvertType(itemVariable.Type),
VariableName = itemVariable.Name,
InExpression = collectionExpr.Detach(),
EmbeddedStatement = foreachBody
};
}
bool BodyHasSingleGetCurrent(Block body, ILVariable enumerator, ILInstruction moveNextUsage, out CallInstruction singleGetter, out bool needsUninlining, out ILVariable existingVariable)
{
singleGetter = null;

Loading…
Cancel
Save