public ControlFlowEdge(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type) { if (from == null) throw new ArgumentNullException("from"); if (to == null) throw new ArgumentNullException("to"); this.From = from; this.To = to; this.Type = type; }
public override void VisitYieldStatement(YieldStatementSyntax node) { if (node.IsKind(SyntaxKind.YieldBreakStatement)) { // end not connected with data curNode = builder.CreateEndNode(node); } else { CreateConnectedEndNode(node); } }
public override void VisitTryStatement(TryStatementSyntax node) { ControlFlowNode end = builder.CreateEndNode(node, addToNodeList: false); HandleEmbeddedStatement(node.Block, curNode); var edge = Connect(curNode, end); if (node.Finally?.Block != null) edge.AddJumpOutOfTryFinally(node); var tryEndPoint = curNode; foreach (var cc in node.Catches) { HandleEmbeddedStatement(cc.Block, tryEndPoint); edge = Connect(tryEndPoint, end); if (node.Finally?.Block != null) edge.AddJumpOutOfTryFinally(node); } if (node.Finally?.Block != null) { // Don't connect the end of the try-finally block to anything. // Consumers of the CFG will have to special-case try-finally. HandleEmbeddedStatement(node.Finally.Block, curNode); } builder.nodes.Add(end); curNode = end; }
public override void VisitThrowStatement(ThrowStatementSyntax node) { // end not connected with data curNode = builder.CreateEndNode(node); }
public override void VisitGotoStatement(GotoStatementSyntax node) { if (node.IsKind(SyntaxKind.GotoDefaultStatement) || node.IsKind(SyntaxKind.GotoCaseStatement)) { gotoCaseOrDefault.Add(curNode); } else { builder.gotoStatements.Add(node); } curNode = builder.CreateEndNode(node); }
internal ControlFlowEdge Connect(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type = ControlFlowEdgeType.Normal) { if (from == null || to == null) return null; ControlFlowEdge edge = builder.CreateEdge(from, to, type); from.Outgoing.Add(edge); to.Incoming.Add(edge); return edge; }
public override void VisitSwitchStatement(SwitchStatementSyntax node) { // First, figure out which switch section will get called (if the expression is constant): var constant = builder.EvaluateConstant(node.Expression); SwitchSectionSyntax defaultSection = null; SwitchSectionSyntax sectionMatchedByConstant = null; foreach (var section in node.Sections) { foreach (var label in section.Labels) { if (label.IsKind(SyntaxKind.DefaultSwitchLabel)) { defaultSection = section; } else if (constant.HasValue /*&& constant.IsCompileTimeConstant*/) { var scl = label as CaseSwitchLabelSyntax; var labelConstant = builder.EvaluateConstant(scl.Value); if (builder.AreEqualConstants(constant, labelConstant)) { sectionMatchedByConstant = section; } } } } if (constant.HasValue && sectionMatchedByConstant == null) { sectionMatchedByConstant = defaultSection; } int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count; List <ControlFlowNode> sectionStartNodes = new List <ControlFlowNode>(); ControlFlowNode end = builder.CreateEndNode(node, addToNodeList: false); breakTargets.Push(end); var myEntryPoint = curNode; foreach (var section in node.Sections) { int sectionStartNodeID = builder.nodes.Count; if (!constant.HasValue || section == sectionMatchedByConstant) { curNode = myEntryPoint; HandleStatementList(section.Statements, myEntryPoint); } else { // This section is unreachable: pass null to HandleStatementList. curNode = null; 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(myEntryPoint, end); } if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) { // Resolve 'goto case' statements: for (int i = gotoCaseOrDefaultInOuterScope; i < gotoCaseOrDefault.Count; i++) { ControlFlowNode gotoCaseNode = gotoCaseOrDefault[i]; var gotoCaseStatement = gotoCaseNode.NextStatement as GotoStatementSyntax; Optional <object> gotoCaseConstant = null; if (gotoCaseStatement != null) { gotoCaseConstant = builder.EvaluateConstant(gotoCaseStatement.Expression); } int targetSectionIndex = -1; int currentSectionIndex = 0; foreach (var section in node.Sections) { foreach (var label in section.Labels) { if (label is CaseSwitchLabelSyntax) { var scl = label as CaseSwitchLabelSyntax; // goto case if (scl.Value != null) { var labelConstant = builder.EvaluateConstant(scl.Value); if (builder.AreEqualConstants(gotoCaseConstant, labelConstant)) { targetSectionIndex = currentSectionIndex; } } } else { // goto default if (label.IsKind(SyntaxKind.DefaultSwitchLabel)) { 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); curNode = end; }
public override void VisitBlock(BlockSyntax node) { // C# 4.0 spec: §8.2 Blocks curNode = HandleStatementList(node.Statements, curNode); CreateConnectedEndNode(node); }
public override void VisitForStatement(ForStatementSyntax forStatement) { // Initializers/Iterators ? -> difference between NR5/Roslyn -> they're not statements anymore. // HandleStatementList(forStatement.Initializers, curNode); // for (initializers <data>; <condition>cond; <iteratorStart>iterators<iteratorEnd>) { <bodyStart> embeddedStmt; <bodyEnd> } <end> ControlFlowNode end = builder.CreateEndNode(forStatement, addToNodeList: false); ControlFlowNode conditionNode = builder.CreateSpecialNode(forStatement, ControlFlowNodeType.LoopCondition); Connect(curNode, conditionNode); int iteratorStartNodeID = builder.nodes.Count; ControlFlowNode iteratorEnd = null; // HandleStatementList(forStatement.Incrementors, null); ControlFlowNode iteratorStart; if (iteratorEnd != null) { iteratorStart = builder.nodes[iteratorStartNodeID]; Connect(iteratorEnd, conditionNode); } else { iteratorStart = conditionNode; } breakTargets.Push(end); continueTargets.Push(iteratorStart); ControlFlowNode bodyStart = builder.CreateStartNode(forStatement.Statement); Visit (forStatement.Statement); Connect(curNode, iteratorStart); breakTargets.Pop(); continueTargets.Pop(); bool? cond = forStatement.Condition == null ? true : builder.EvaluateCondition(forStatement.Condition); if (cond != false) Connect(conditionNode, bodyStart, ControlFlowEdgeType.ConditionTrue); if (cond != true) Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse); builder.nodes.Add(end); curNode = end; }
public override void VisitDoStatement(DoStatementSyntax node) { // <data> do { <bodyStart> embeddedStmt; <bodyEnd>} <condition> while(cond); <end> ControlFlowNode end = builder.CreateEndNode(node, addToNodeList: false); ControlFlowNode conditionNode = builder.CreateSpecialNode(node, ControlFlowNodeType.LoopCondition, addToNodeList: false); breakTargets.Push(end); continueTargets.Push(conditionNode); ControlFlowNode bodyStart = builder.CreateStartNode(node.Statement); Connect(curNode, bodyStart); Visit(node.Statement); Connect(curNode, conditionNode); bool? cond = builder.EvaluateCondition(node.Condition); if (cond != false) Connect(conditionNode, bodyStart, ControlFlowEdgeType.ConditionTrue); if (cond != true) Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse); breakTargets.Pop(); continueTargets.Pop(); builder.nodes.Add(conditionNode); builder.nodes.Add(end); curNode = end; }
public override void VisitSwitchStatement(SwitchStatementSyntax node) { // First, figure out which switch section will get called (if the expression is constant): var constant = builder.EvaluateConstant(node.Expression); SwitchSectionSyntax defaultSection = null; SwitchSectionSyntax sectionMatchedByConstant = null; foreach (var section in node.Sections) { foreach (var label in section.Labels) { if (label.IsKind(SyntaxKind.DefaultSwitchLabel)) { defaultSection = section; } else if (constant.HasValue /*&& constant.IsCompileTimeConstant*/) { var scl = label as CaseSwitchLabelSyntax; var labelConstant = builder.EvaluateConstant(scl.Value); if (builder.AreEqualConstants(constant, labelConstant)) sectionMatchedByConstant = section; } } } if (constant.HasValue && sectionMatchedByConstant == null) sectionMatchedByConstant = defaultSection; int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count; List<ControlFlowNode> sectionStartNodes = new List<ControlFlowNode>(); ControlFlowNode end = builder.CreateEndNode(node, addToNodeList: false); breakTargets.Push(end); var myEntryPoint = curNode; foreach (var section in node.Sections) { int sectionStartNodeID = builder.nodes.Count; if (!constant.HasValue || section == sectionMatchedByConstant) { curNode = myEntryPoint; HandleStatementList(section.Statements, myEntryPoint); } else { // This section is unreachable: pass null to HandleStatementList. curNode = null; 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(myEntryPoint, end); } if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) { // Resolve 'goto case' statements: for (int i = gotoCaseOrDefaultInOuterScope; i < gotoCaseOrDefault.Count; i++) { ControlFlowNode gotoCaseNode = gotoCaseOrDefault[i]; var gotoCaseStatement = gotoCaseNode.NextStatement as GotoStatementSyntax; Optional<object> gotoCaseConstant = null; if (gotoCaseStatement != null) { gotoCaseConstant = builder.EvaluateConstant(gotoCaseStatement.Expression); } int targetSectionIndex = -1; int currentSectionIndex = 0; foreach (var section in node.Sections) { foreach (var label in section.Labels) { if (label is CaseSwitchLabelSyntax) { var scl = label as CaseSwitchLabelSyntax; // goto case if (scl.Value != null) { var labelConstant = builder.EvaluateConstant(scl.Value); if (builder.AreEqualConstants(gotoCaseConstant, labelConstant)) targetSectionIndex = currentSectionIndex; } } else { // goto default if (label.IsKind(SyntaxKind.DefaultSwitchLabel)) 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); curNode = end; }
public override void VisitIfStatement(IfStatementSyntax node) { bool? cond = builder.EvaluateCondition(node.Condition); var startNode = curNode; ControlFlowNode trueBegin = builder.CreateStartNode(node.Statement); if (cond != false) Connect(startNode, trueBegin, ControlFlowEdgeType.ConditionTrue); curNode = trueBegin; Visit(node.Statement); ControlFlowNode trueEnd = curNode; ControlFlowNode falseEnd = null; if (node.Else?.Statement != null) { ControlFlowNode falseBegin = builder.CreateStartNode(node.Else?.Statement); if (cond != true) Connect(startNode, falseBegin, ControlFlowEdgeType.ConditionFalse); curNode = trueBegin; Visit(node.Else?.Statement); falseEnd = curNode; } // (if no else statement exists, both falseBegin and falseEnd will be null) ControlFlowNode end = builder.CreateEndNode(node); Connect(trueEnd, end); if (falseEnd != null) { Connect(falseEnd, end); } else if (cond != true) { Connect(startNode, end, ControlFlowEdgeType.ConditionFalse); } curNode = end; }
ControlFlowNode HandleStatementList(IEnumerable<StatementSyntax> statements, ControlFlowNode source) { var oldCurNode = curNode; ControlFlowNode childNode = null; foreach (var stmt in statements) { if (childNode == null) { curNode = childNode = builder.CreateStartNode(stmt); if (source != null) Connect(source, childNode); } // Debug.Assert(childNode.NextStatement == stmt); Visit(stmt); childNode = curNode; // Debug.Assert(childNode.PreviousStatement == stmt); } curNode = oldCurNode; return childNode ?? source; }
public override void VisitBlock(BlockSyntax node) { // C# 4.0 spec: §8.2 Blocks curNode = HandleStatementList(node.Statements, curNode); CreateConnectedEndNode(node); }
/// <summary> /// Creates an end node for <c>stmt</c> and connects <c>from</c> with the new node. /// </summary> void CreateConnectedEndNode(StatementSyntax stmt) { ControlFlowNode newNode = builder.CreateEndNode(stmt); Connect(curNode, newNode); curNode = newNode; }
void HandleEmbeddedStatement(StatementSyntax embeddedStatement, ControlFlowNode source) { if (embeddedStatement == null) { curNode = source; } ControlFlowNode bodyStart = builder.CreateStartNode(embeddedStatement); if (source != null) Connect(source, bodyStart); Visit(embeddedStatement); }
protected virtual ControlFlowEdge CreateEdge(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type) { cancellationToken.ThrowIfCancellationRequested(); return(new ControlFlowEdge(from, to, type)); }
public override void VisitForEachStatement(ForEachStatementSyntax node) { // <data> foreach (<condition>...) { <bodyStart>embeddedStmt<bodyEnd> } <end> ControlFlowNode end = builder.CreateEndNode(node, addToNodeList: false); ControlFlowNode conditionNode = builder.CreateSpecialNode(node, ControlFlowNodeType.LoopCondition); Connect(curNode, conditionNode); breakTargets.Push(end); continueTargets.Push(conditionNode); HandleEmbeddedStatement(node.Statement, conditionNode); Connect(curNode, conditionNode); breakTargets.Pop(); continueTargets.Pop(); Connect(conditionNode, end); builder.nodes.Add(end); curNode = end; }
ControlFlowNode HandleStatementList(IEnumerable <StatementSyntax> statements, ControlFlowNode source) { var oldCurNode = curNode; ControlFlowNode childNode = null; foreach (var stmt in statements) { if (childNode == null) { curNode = childNode = builder.CreateStartNode(stmt); if (source != null) { Connect(source, childNode); } } // Debug.Assert(childNode.NextStatement == stmt); Visit(stmt); childNode = curNode; // Debug.Assert(childNode.PreviousStatement == stmt); } curNode = oldCurNode; return(childNode ?? source); }
public override void VisitContinueStatement(ContinueStatementSyntax node) { if (continueTargets.Count > 0) { var target = continueTargets.Peek(); Connect(curNode, target, ControlFlowEdgeType.Jump); curNode = target; } curNode = builder.CreateEndNode(node); }
public override void VisitThrowStatement(ThrowStatementSyntax node) { // end not connected with data curNode = builder.CreateEndNode(node); }
protected virtual ControlFlowEdge CreateEdge(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type) { cancellationToken.ThrowIfCancellationRequested(); return new ControlFlowEdge(from, to, type); }