void FindMultipleEnumeration(VariableReferenceNode startNode) { var vrg = GetAssignmentUsageGraph(startNode); visitedNodes = new HashSet <VariableReferenceNode> (); collectedNodes = new HashSet <VariableReferenceNode> (); // degree of a node is the number of references that can be reached by the node nodeDegree = new Dictionary <VariableReferenceNode, int> (); foreach (var node in vrg) { if (node.References.Count == 0 || !visitedNodes.Add(node)) { continue; } ProcessNode(node); if (nodeDegree [node] > 1) { collectedNodes.Add(node); } } foreach (var node in collectedNodes) { AddIssues(node.References); } }
ExpressionNodeCreationVisitor(ISet <AstNode> references, CSharpAstResolver resolver, VariableReferenceNode startNode) { this.references = references; this.resolver = resolver; this.startNode = this.endNode = startNode ?? new VariableReferenceNode(); }
/// <summary> /// convert a variable reference graph starting from the specified node to an assignment usage graph, /// in which nodes are connect if and only if they contains references using the same assigned value /// </summary> /// <param name="startNode">starting node of the variable reference graph</param> /// <returns> /// list of VariableReferenceNode, each of which is a starting node of a sub-graph in which references all /// use the same assigned value /// </returns> static IEnumerable <VariableReferenceNode> GetAssignmentUsageGraph(VariableReferenceNode startNode) { var graph = new List <VariableReferenceNode> (); var visited = new HashSet <VariableReferenceNode> (); var stack = new Stack <VariableReferenceNode> (); stack.Push(startNode); while (stack.Count > 0) { var node = stack.Pop(); if (!visited.Add(node)) { continue; } var nodes = SplitNode(node); graph.AddRange(nodes); foreach (var addedNode in nodes) { visited.Add(addedNode); } foreach (var nextNode in nodes.Last().NextNodes) { stack.Push(nextNode); } } return(graph); }
public override void VisitConditionalExpression(ConditionalExpression conditionalExpression) { conditionalExpression.Condition.AcceptVisitor(this); var resolveResult = resolver.Resolve(conditionalExpression.Condition); if (resolveResult.ConstantValue is bool) { if ((bool)resolveResult.ConstantValue) { conditionalExpression.TrueExpression.AcceptVisitor(this); } else { conditionalExpression.FalseExpression.AcceptVisitor(this); } return; } var nextEndNode = new VariableReferenceNode(); var trueNode = CreateNode(references, resolver, conditionalExpression.TrueExpression, null, nextEndNode); var falseNode = CreateNode(references, resolver, conditionalExpression.FalseExpression, null, nextEndNode); endNode.AddNextNode(trueNode); endNode.AddNextNode(falseNode); endNode = nextEndNode; }
VariableReferenceNode GetStatementEndNode(VariableReferenceNode currentNode, Statement statement) { var expressions = statement.AcceptVisitor(getExpr); VariableReferenceNode endNode; ExpressionNodeCreationVisitor.CreateNode(references, resolver, expressions, currentNode, out endNode); return(endNode); }
/// <summary> /// split references in the specified node into sub nodes according to the value they uses /// </summary> /// <param name="node">node to split</param> /// <returns>list of sub nodes</returns> static IList <VariableReferenceNode> SplitNode(VariableReferenceNode node) { var subNodes = new List <VariableReferenceNode> (); // find indices of all assignments in node and use them to split references var assignmentIndices = new List <int> { -1 }; for (int i = 0; i < node.References.Count; i++) { if (IsAssignment(node.References [i])) { assignmentIndices.Add(i); } } assignmentIndices.Add(node.References.Count); for (int i = 0; i < assignmentIndices.Count - 1; i++) { var index1 = assignmentIndices [i]; var index2 = assignmentIndices [i + 1]; if (index1 + 1 >= index2) { continue; } var subNode = new VariableReferenceNode(); for (int refIndex = index1 + 1; refIndex < index2; refIndex++) { subNode.References.Add(node.References [refIndex]); } subNodes.Add(subNode); } if (subNodes.Count == 0) { subNodes.Add(new VariableReferenceNode()); } var firstNode = subNodes [0]; foreach (var prevNode in node.PreviousNodes) { prevNode.NextNodes.Remove(node); // connect two nodes if the first ref is not an assignment if (firstNode.References.FirstOrDefault() == node.References.FirstOrDefault()) { prevNode.NextNodes.Add(firstNode); } } var lastNode = subNodes [subNodes.Count - 1]; foreach (var nextNode in node.NextNodes) { nextNode.PreviousNodes.Remove(node); lastNode.AddNextNode(nextNode); } return(subNodes); }
void ProcessNode(VariableReferenceNode node, bool addIssue, IDictionary <VariableReferenceNode, NodeState> nodeStates) { if (nodeStates [node] == NodeState.None) { nodeStates [node] = NodeState.Processing; } bool?reachable = false; foreach (var nextNode in node.NextNodes) { if (nodeStates [nextNode] == NodeState.None) { ProcessNode(nextNode, false, nodeStates); } if (nodeStates [nextNode] == NodeState.UsageReachable) { reachable = true; break; } // downstream nodes are not fully processed (e.g. due to loop), there is no enough info to // determine the node state if (nodeStates [nextNode] != NodeState.UsageUnreachable) { reachable = null; } } // add issue if it is not possible to reach any usage via NextNodes if (addIssue && reachable == false) { AddIssue(node.References [node.References.Count - 1]); } if (nodeStates [node] != NodeState.Processing) { return; } switch (reachable) { case null: nodeStates [node] = NodeState.None; break; case true: nodeStates [node] = NodeState.UsageReachable; break; case false: nodeStates [node] = NodeState.UsageUnreachable; break; } }
static ExpressionNodeCreationVisitor CreateVisitor(ISet <AstNode> references, CSharpAstResolver resolver, Expression rootExpr, VariableReferenceNode startNode = null, VariableReferenceNode nextNode = null) { var visitor = new ExpressionNodeCreationVisitor(references, resolver, startNode); rootExpr.AcceptVisitor(visitor); if (nextNode != null) { visitor.endNode.AddNextNode(nextNode); } return(visitor); }
public static VariableReferenceNode CreateNode(ISet <AstNode> references, CSharpAstResolver resolver, IEnumerable <Expression> expressions, VariableReferenceNode startNode, out VariableReferenceNode endNode) { startNode = startNode ?? new VariableReferenceNode(); endNode = startNode; foreach (var expr in expressions) { var visitor = CreateVisitor(references, resolver, expr, endNode); endNode = visitor.endNode; } return(startNode); }
VariableReferenceNode AddNode(ControlFlowNode startNode) { var node = new VariableReferenceNode(); var cfNode = startNode; while (true) { if (variableReferenceGraphBuilder.ctx.CancellationToken.IsCancellationRequested) { return(null); } if (nodeDict.ContainsKey(cfNode)) { node.AddNextNode(nodeDict [cfNode]); break; } // create a new node for fork point if (cfNode.Incoming.Count > 1 || cfNode.Outgoing.Count > 1) { nodeDict [cfNode] = node; var forkNode = new VariableReferenceNode(); node.AddNextNode(forkNode); node = forkNode; } nodeDict [cfNode] = node; if (IsValidControlFlowNode(cfNode) && refStatements.Contains(cfNode.NextStatement)) { node = GetStatementEndNode(node, cfNode.NextStatement); } if (cfNode.Outgoing.Count == 1) { cfNode = cfNode.Outgoing [0].To; } else { foreach (var e in cfNode.Outgoing) { node.AddNextNode(AddNode(e.To)); } break; } } VariableReferenceNode result; if (!nodeDict.TryGetValue(startNode, out result)) { return(new VariableReferenceNode()); } return(result); }
void ProcessNode(VariableReferenceNode node) { var degree = nodeDegree [node] = 0; foreach (var nextNode in node.NextNodes) { collectedNodes.Add(nextNode); if (visitedNodes.Add(nextNode)) { ProcessNode(nextNode); } degree = Math.Max(degree, nodeDegree [nextNode]); } nodeDegree [node] = degree + node.References.Count; }
void ProcessNodes(VariableReferenceNode startNode) { // node state of a node indicates whether it is possible for an upstream node to reach any usage via // the node var nodeStates = new Dictionary <VariableReferenceNode, NodeState>(); var assignments = new List <VariableReferenceNode>(); // dfs to preprocess all nodes and find nodes which end with assignment var stack = new Stack <VariableReferenceNode>(); stack.Push(startNode); while (stack.Count > 0) { var node = stack.Pop(); if (node.References.Count > 0) { nodeStates [node] = IsAssignment(node.References [0]) ? NodeState.UsageUnreachable : NodeState.UsageReachable; } else { nodeStates [node] = NodeState.None; } // find indices of all assignments in node.References var assignmentIndices = new List <int>(); for (int i = 0; i < node.References.Count; i++) { if (IsAssignment(node.References [i])) { assignmentIndices.Add(i); } } // for two consecutive assignments, the first one is redundant for (int i = 0; i < assignmentIndices.Count - 1; i++) { var index1 = assignmentIndices [i]; var index2 = assignmentIndices [i + 1]; if (index1 + 1 == index2) { AddIssue(node.References [index1]); } } // if the node ends with an assignment, add it to assignments so as to check if it is redundant // later if (assignmentIndices.Count > 0 && assignmentIndices [assignmentIndices.Count - 1] == node.References.Count - 1) { assignments.Add(node); } foreach (var nextNode in node.NextNodes) { if (!nodeStates.ContainsKey(nextNode)) { stack.Push(nextNode); } } } foreach (var node in assignments) { // we do not analyze an assignment inside a try block as it can jump to any catch block or finally block if (IsInsideTryBlock(node.References [0])) { continue; } ProcessNode(node, true, nodeStates); } }
public void AddNextNode(VariableReferenceNode node) { NextNodes.Add(node); node.PreviousNodes.Add(this); }
static VariableReferenceNode CreateNode(ISet <AstNode> references, CSharpAstResolver resolver, Expression rootExpr, VariableReferenceNode startNode = null, VariableReferenceNode nextNode = null) { return(CreateVisitor(references, resolver, rootExpr, startNode, nextNode).startNode); }