public function serialize(ControlFlowGraph $graph) { $dot = "digraph G {\n"; $this->ids = new \SplObjectStorage(); $this->idCount = 0; $dot .= " " . $this->getId($graph->getImplicitReturn()) . " [shape=box,label=\"implicit return\",style=filled]\n"; $entryPoint = $graph->getEntryPoint(); $nodes = $graph->getNodes(); foreach ($nodes as $astNode) { $node = $nodes[$astNode]; $id = $this->getId($node); $dot .= sprintf(' %s [shape=box,label="%s"', $id, str_replace('"', '\\"', NodeUtil::getStringRepr($astNode))); if ($node === $entryPoint) { $dot .= ",style=filled"; } $dot .= "]\n"; foreach ($node->getOutEdges() as $edge) { $dot .= sprintf(" %s -> %s", $id, $this->getId($edge->getDest())); switch ($edge->getType()) { case GraphEdge::TYPE_ON_FALSE: $dot .= ' [label="false"]'; break; case GraphEdge::TYPE_ON_TRUE: $dot .= ' [label="true"]'; break; case GraphEdge::TYPE_ON_EX: $dot .= ' [label="exception"]'; break; } $dot .= "\n"; } } $dot .= "}"; return $dot; }
private function tryRemoveDeadAssignments(NodeTraversal $t, ControlFlowGraph $cfg) { $nodes = $cfg->getDirectedGraphNodes(); foreach ($nodes as $cfgNode) { $inState = $cfgNode->getAttribute(DataFlowAnalysis::ATTR_FLOW_STATE_IN); $outState = $cfgNode->getAttribute(DataFlowAnalysis::ATTR_FLOW_STATE_OUT); $n = $cfgNode->getAstNode(); if (null === $n) { continue; } switch (true) { case $n instanceof \PHPParser_Node_Stmt_If: case $n instanceof \PHPParser_Node_Stmt_ElseIf: case $n instanceof \PHPParser_Node_Stmt_While: case $n instanceof \PHPParser_Node_Stmt_Do: case $n instanceof \PHPParser_Node_Stmt_For: case $n instanceof \PHPParser_Node_Stmt_Switch: case $n instanceof \PHPParser_Node_Stmt_Case: if (null !== ($condition = NodeUtil::getConditionExpression($n))) { $this->tryRemoveAssignment($t, $condition, null, $inState, $outState); } continue 2; case $n instanceof \PHPParser_Node_Stmt_Return: if (null !== $n->expr) { $this->tryRemoveAssignment($t, $n->expr, null, $inState, $outState); } continue 2; } $this->tryRemoveAssignment($t, $n, null, $inState, $outState); } }
private function connectToPossibleExceptionHandler(\PHPParser_Node $cfgNode, \PHPParser_Node $target) { if (!self::mayThrowException($target)) { return; } if ($this->exceptionHandlers->isEmpty()) { return; } foreach ($this->exceptionHandlers as $handler) { assert($handler instanceof \PHPParser_Node_Stmt_TryCatch); $catches = $handler->catches; $this->graph->connectIfNotConnected($cfgNode, GraphEdge::TYPE_ON_EX, $catches[0]); break; } }
public function testComputeFixedPoint() { $graph = new ControlFlowGraph($entry = $this->getAstNode()); $node1 = $this->getAstNode(); $graph->connect($entry, null, $node1); $node2 = $this->getAstNode(); $graph->connect($node1, null, $node2); $node3 = $this->getAstNode(); $graph->connect($node3, null, $node2); $node4 = $this->getAstNode(); $graph->connect($node2, null, $node4); $callback = $this->getMock('Scrutinizer\\PhpAnalyzer\\ControlFlow\\EdgeCallbackInterface'); $t = new FixedPointGraphTraversal($callback); $callback->expects($this->at(0))->method('traverseEdge')->with($entry, null, $node1)->will($this->returnValue(true)); $callback->expects($this->at(1))->method('traverseEdge')->with($node1, null, $node2)->will($this->returnValue(false)); $t->computeFixedPointWithEntry($graph, $entry); }
public function testBranchedSimpleIf() { // if (a) { a = 0; } else { b = 0; } c = b; $a = new Variable('a'); $b = new Variable('b'); $c = new Variable('c'); $inst1 = new BranchInstruction($a); $inst2 = ArithmeticInstruction::newAssignNumberToVariableInstruction($a, 0); $inst3 = ArithmeticInstruction::newAssignNumberToVariableInstruction($b, 0); $inst4 = ArithmeticInstruction::newAssignVariableToVariableInstruction($c, $b); $cfg = new ControlFlowGraph($inst1); $cfg->connectIfNotConnected($inst1, GraphEdge::TYPE_ON_TRUE, $inst2); $cfg->connectIfNotConnected($inst1, GraphEdge::TYPE_ON_FALSE, $inst3); $cfg->connectIfNotConnected($inst2, GraphEdge::TYPE_UNCOND, $inst4); $cfg->connectIfNotConnected($inst3, GraphEdge::TYPE_UNCOND, $inst4); $n1 = $cfg->getNode($inst1); $n2 = $cfg->getNode($inst2); $n3 = $cfg->getNode($inst3); $n4 = $cfg->getNode($inst4); $constProp = new BranchedDummyConstPropagation($cfg); $constProp->analyze(); // We cannot conclude anything from if(a). $this->verifyInHas($n1, $a, null); $this->verifyInHas($n1, $b, null); $this->verifyInHas($n1, $c, null); // Nothing is known on the true branch. $this->verifyInHas($n2, $a, null); $this->verifyInHas($n2, $b, null); $this->verifyInHas($n2, $c, null); // Verify that we have a = 0 on the false branch. $this->verifyInHas($n3, $a, 0); $this->verifyInHas($n3, $b, null); $this->verifyInHas($n3, $c, null); // After the merge we should still have a = 0. $this->verifyInHas($n4, $a, 0); }