private static IList <CSharpSwitchCase> ReduceGotos(IList <CSharpSwitchCase> cases) { var testValueToCaseMap = new Dictionary <object, CSharpSwitchCase>(); var analyzer = new SwitchCaseGotoAnalyzer(); var defaultCase = default(CSharpSwitchCase); foreach (var @case in cases) { foreach (var testValue in @case.TestValues) { if (testValue == SwitchCaseDefaultValue) { defaultCase = @case; } testValueToCaseMap.Add(testValue.OrNullSentinel(), @case); } analyzer.Analyze(@case); } var caseHasJumpInto = new HashSet <CSharpSwitchCase>(); foreach (var info in analyzer.SwitchCaseInfos.Values) { if (info.HasGotoDefault) { if (defaultCase == null) { throw Error.InvalidGotoDefault(); } caseHasJumpInto.Add(defaultCase); } foreach (var gotoCase in info.GotoCases) { if (!testValueToCaseMap.TryGetValue(gotoCase.OrNullSentinel(), out CSharpSwitchCase @case)) { throw Error.InvalidGotoCase(gotoCase.ToDebugString()); } caseHasJumpInto.Add(@case); } } if (caseHasJumpInto.Count > 0) { var caseJumpTargets = new Dictionary <CSharpSwitchCase, LabelTarget>(); var defaultJumpTarget = default(LabelTarget); foreach (var @case in caseHasJumpInto) { var label = default(LabelTarget); if (@case == defaultCase) { label = defaultJumpTarget = Expression.Label("__default"); } else { label = Expression.Label(FormattableString.Invariant($"__case<{@case.TestValues[0].ToDebugString()}>")); } caseJumpTargets.Add(@case, label); } var rewriter = new SwitchCaseRewriter(testValue => caseJumpTargets[testValueToCaseMap[testValue.OrNullSentinel()]], defaultJumpTarget); var newCases = new CSharpSwitchCase[cases.Count]; var i = 0; foreach (var @case in cases) { var newBody = rewriter.Visit(@case.Statements); if (caseJumpTargets.TryGetValue(@case, out LabelTarget jumpTarget)) { newBody = newBody.AddFirst(Expression.Label(jumpTarget)).ToReadOnly(); } newCases[i++] = @case.Update(newBody); } return(newCases); } else { return(cases); } }
private static IList<CSharpSwitchCase> ReduceGotos(IList<CSharpSwitchCase> cases) { var testValueToCaseMap = new Dictionary<object, CSharpSwitchCase>(); var analyzer = new SwitchCaseGotoAnalyzer(); var defaultCase = default(CSharpSwitchCase); foreach (var @case in cases) { foreach (var testValue in @case.TestValues) { if (testValue == SwitchCaseDefaultValue) { defaultCase = @case; } testValueToCaseMap.Add(testValue.OrNullSentinel(), @case); } analyzer.Analyze(@case); } var caseHasJumpInto = new HashSet<CSharpSwitchCase>(); foreach (var info in analyzer.SwitchCaseInfos.Values) { if (info.HasGotoDefault) { if (defaultCase == null) { throw Error.InvalidGotoDefault(); } caseHasJumpInto.Add(defaultCase); } foreach (var gotoCase in info.GotoCases) { var @case = default(CSharpSwitchCase); if (!testValueToCaseMap.TryGetValue(gotoCase.OrNullSentinel(), out @case)) { throw Error.InvalidGotoCase(gotoCase.ToDebugString()); } caseHasJumpInto.Add(@case); } } if (caseHasJumpInto.Count > 0) { var caseJumpTargets = new Dictionary<CSharpSwitchCase, LabelTarget>(); var defaultJumpTarget = default(LabelTarget); foreach (var @case in caseHasJumpInto) { var label = default(LabelTarget); if (@case == defaultCase) { label = defaultJumpTarget = Expression.Label("__default"); } else { label = Expression.Label(FormattableString.Invariant($"__case<{@case.TestValues[0].ToDebugString()}>")); } caseJumpTargets.Add(@case, label); } var rewriter = new SwitchCaseRewriter(testValue => caseJumpTargets[testValueToCaseMap[testValue.OrNullSentinel()]], defaultJumpTarget); var newCases = new CSharpSwitchCase[cases.Count]; var i = 0; foreach (var @case in cases) { var newBody = rewriter.Visit(@case.Statements); var jumpTarget = default(LabelTarget); if (caseJumpTargets.TryGetValue(@case, out jumpTarget)) { newBody = newBody.AddFirst(Expression.Label(jumpTarget)).ToReadOnly(); } newCases[i++] = @case.Update(newBody); } return newCases; } else { return cases; } }