public override ControlFlowNode VisitSwitchStatement(SwitchStatement switchStatement, ControlFlowNode data) { // First, figure out which switch section will get called (if the expression is constant): ResolveResult constant = builder.EvaluateConstant(switchStatement.Expression); SwitchSection defaultSection = null; SwitchSection sectionMatchedByConstant = null; foreach (SwitchSection section in switchStatement.SwitchSections) { foreach (CaseLabel label in section.CaseLabels) { if (label.Expression.IsNull) { defaultSection = section; } else if (constant != null && constant.IsCompileTimeConstant) { ResolveResult labelConstant = builder.EvaluateConstant(label.Expression); if (builder.AreEqualConstants(constant, labelConstant)) { sectionMatchedByConstant = section; } } } } if (constant != null && constant.IsCompileTimeConstant && sectionMatchedByConstant == null) { sectionMatchedByConstant = defaultSection; } int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count; List <ControlFlowNode> sectionStartNodes = new List <ControlFlowNode>(); ControlFlowNode end = builder.CreateEndNode(switchStatement, addToNodeList: false); breakTargets.Push(end); foreach (SwitchSection section in switchStatement.SwitchSections) { int sectionStartNodeID = builder.nodes.Count; if (constant == null || !constant.IsCompileTimeConstant || section == sectionMatchedByConstant) { HandleStatementList(section.Statements, data); } else { // This section is unreachable: pass null to HandleStatementList. HandleStatementList(section.Statements, null); } // Don't bother connecting the ends of the sections: the 'break' statement takes care of that. // Store the section start node for 'goto case' statements. sectionStartNodes.Add(sectionStartNodeID < builder.nodes.Count ? builder.nodes[sectionStartNodeID] : null); } breakTargets.Pop(); if (defaultSection == null && sectionMatchedByConstant == null) { Connect(data, end); } if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) { // Resolve 'goto case' statements: for (int i = gotoCaseOrDefaultInOuterScope; i < gotoCaseOrDefault.Count; i++) { ControlFlowNode gotoCaseNode = gotoCaseOrDefault[i]; GotoCaseStatement gotoCaseStatement = gotoCaseNode.NextStatement as GotoCaseStatement; ResolveResult gotoCaseConstant = null; if (gotoCaseStatement != null) { gotoCaseConstant = builder.EvaluateConstant(gotoCaseStatement.LabelExpression); } int targetSectionIndex = -1; int currentSectionIndex = 0; foreach (SwitchSection section in switchStatement.SwitchSections) { foreach (CaseLabel label in section.CaseLabels) { if (gotoCaseStatement != null) { // goto case if (!label.Expression.IsNull) { ResolveResult labelConstant = builder.EvaluateConstant(label.Expression); if (builder.AreEqualConstants(gotoCaseConstant, labelConstant)) { targetSectionIndex = currentSectionIndex; } } } else { // goto default if (label.Expression.IsNull) { targetSectionIndex = currentSectionIndex; } } } currentSectionIndex++; } if (targetSectionIndex >= 0 && sectionStartNodes[targetSectionIndex] != null) { Connect(gotoCaseNode, sectionStartNodes[targetSectionIndex], ControlFlowEdgeType.Jump); } else { Connect(gotoCaseNode, end, ControlFlowEdgeType.Jump); } } gotoCaseOrDefault.RemoveRange(gotoCaseOrDefaultInOuterScope, gotoCaseOrDefault.Count - gotoCaseOrDefaultInOuterScope); } builder.nodes.Add(end); return(end); }
public override ControlFlowNode VisitSwitchStatement(SwitchStatement switchStatement, ControlFlowNode data) { // First, figure out which switch section will get called (if the expression is constant): ConstantResolveResult constant = builder.EvaluateConstant(switchStatement.Expression); SwitchSection defaultSection = null; SwitchSection sectionMatchedByConstant = null; foreach (SwitchSection section in switchStatement.SwitchSections) { foreach (CaseLabel label in section.CaseLabels) { if (label.Expression.IsNull) { defaultSection = section; } else if (constant != null) { ConstantResolveResult labelConstant = builder.EvaluateConstant(label.Expression); if (builder.AreEqualConstants(constant, labelConstant)) { sectionMatchedByConstant = section; } } } } if (constant != null && sectionMatchedByConstant == null) { sectionMatchedByConstant = defaultSection; } int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count; ControlFlowNode end = builder.CreateEndNode(switchStatement, addToNodeList: false); breakTargets.Push(end); foreach (SwitchSection section in switchStatement.SwitchSections) { if (constant == null || section == sectionMatchedByConstant) { HandleStatementList(section.Statements, data); } else { // This section is unreachable: pass null to HandleStatementList. HandleStatementList(section.Statements, null); } // Don't bother connecting the ends of the sections: the 'break' statement takes care of that. } breakTargets.Pop(); if (defaultSection == null && sectionMatchedByConstant == null) { Connect(data, end); } if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) { // Resolve 'goto case' statements: throw new NotImplementedException(); } builder.nodes.Add(end); return(end); }