/**
  * @dataProvider getTests
  */
 public function testIntegration($sourceFile)
 {
     $parser = new \PHPParser_Parser();
     $ast = $parser->parse(new \PHPParser_Lexer(file_get_contents($sourceFile)));
     $traverser = new \PHPParser_NodeTraverser();
     $traverser->addVisitor(new \PHPParser_NodeVisitor_NameResolver());
     $traverser->addVisitor(new NormalizingNodeVisitor());
     $ast = $traverser->traverse($ast);
     if (count($ast) > 1) {
         $ast = array(new BlockNode($ast));
     }
     $traverser = new \PHPParser_NodeTraverser();
     $traverser->addVisitor(new \PHPParser_NodeVisitor_NodeConnector());
     $traverser->traverse($ast);
     // do _NOT_ assign the ast here as it clones the nodes on traversal and leads to problems
     $cfa = new ControlFlowAnalysis();
     $cfa->process($ast[0]);
     $cfg = $cfa->getGraph();
     $serializer = new GraphvizSerializer();
     $dot = $serializer->serialize($cfg);
     $dotFile = substr($sourceFile, 0, -4) . '.dot';
     if (!is_file($dotFile)) {
         file_put_contents($dotFile . '.tmp', $dot);
         $this->fail(sprintf('Dotfile "%s" does not exist, wrote current output to "%s".', $dotFile, basename($dotFile . '.tmp')));
     }
     $this->assertSame($dot, file_get_contents($dotFile));
 }
 private function getCfg(\PHPParser_Node $ast)
 {
     $traverser = new \PHPParser_NodeTraverser();
     $traverser->addVisitor(new \PHPParser_NodeVisitor_NodeConnector());
     $traverser->traverse(array($ast));
     $cfa = new ControlFlowAnalysis();
     $cfa->process($ast);
     return $this->graph = $cfa->getGraph();
 }
 /**
  * @return ControlFlowGraph
  */
 public function getControlFlowGraph()
 {
     if ($cfg = $this->cfgs->top()) {
         return $cfg;
     }
     $cfa = new ControlFlowAnalysis();
     $cfa->process($this->getScopeRoot());
     $this->cfgs->pop();
     $this->cfgs->push($cfg = $cfa->getGraph());
     return $cfg;
 }
 /**
  * @group foo
  */
 public function testCfgDoesNotTraverseExpressionTrees()
 {
     $expr = new \PHPParser_Node_Expr_Assign(new \PHPParser_Node_Expr_Variable('foo'), new \PHPParser_Node_Scalar_String('foo'));
     $this->normalizeAst(array($expr));
     $this->cfa->process($expr);
     $graph = $this->cfa->getGraph();
     $this->assertSame($expr, $graph->getEntryPoint()->getAstNode());
     $this->assertSame(1, count($out = $graph->getOutEdges($expr)));
     $this->assertSame($out[0]->getDest(), $graph->getImplicitReturn());
     $this->assertSame(1, count($graph->getNodes()));
 }
 private function handleCase(\PHPParser_Node_Stmt_Case $node)
 {
     if (!$this->getSetting('non_commented_switch_fallthrough')) {
         return;
     }
     if (0 === count($node->stmts)) {
         return;
     }
     // Check if the next statement is a CASE statement.
     $nextCase = $node->getAttribute('next');
     if (!$nextCase instanceof \PHPParser_Node_Stmt_Case) {
         return;
     }
     // If the last statement of the CASE node is a BREAK/CONTINUE/RETURN
     // THROW/GOTO statement, then we can always rule out a FALL-THROUGH. The
     // opposite, i.e. when there is none, is not true though.
     foreach ($node->stmts as $lastStmt) {
     }
     if ($lastStmt instanceof \PHPParser_Node_Stmt_Break || $lastStmt instanceof \PHPParser_Node_Stmt_Continue || $lastStmt instanceof \PHPParser_Node_Stmt_Return || $lastStmt instanceof \PHPParser_Node_Stmt_Throw || $lastStmt instanceof \PHPParser_Node_Stmt_Goto) {
         return;
     }
     $cfa = new ControlFlowAnalysis();
     $cfa->process($node);
     $graph = $cfa->getGraph();
     //         $serializer = new GraphvizSerializer();
     //         echo $serializer->serialize($graph);
     // In case of a fallthrough, the control flow falls through to the statements block
     // of the next CASE statement. If that node is not part of the control flow graph,
     // then the control flow cannot reach from this starting node.
     if (!$graph->hasNode($nextCase->stmts)) {
         return;
     }
     foreach ($node->stmts as $lastChild) {
     }
     $previousLineEnd = $lastChild->getLine();
     if ($previousLineEnd === $nextCase->getLine()) {
         $this->phpFile->addComment($previousLineEnd, Comment::warning('coding_style.unreadable_case', 'Consider moving this CASE statement to a new line.'));
         return;
     }
     $code = explode("\n", $this->phpFile->getContent());
     $foundComment = false;
     for ($i = $previousLineEnd, $c = $nextCase->getLine(); $i < $c; $i++) {
         if (empty($code[$i])) {
             continue;
         }
         $lineTokens = token_get_all('<?php ' . $code[$i]);
         foreach ($lineTokens as $token) {
             if (!is_array($token)) {
                 continue;
             }
             if (T_CASE === $token[0] || T_DEFAULT === $token[0]) {
                 break 2;
             }
             if (T_COMMENT === $token[0] || T_DOC_COMMENT === $token[0]) {
                 $foundComment = true;
                 break 2;
             }
         }
     }
     // TODO: Improve where the comment is being applied. If there is only one fall-through
     //       it would be nice to add the comment directly where the fall-through is
     //       happening. If there are multiple fall-throughs, then we can apply the
     //       comment at the end of the entire block as is the current behavior.
     if (!$foundComment) {
         $this->phpFile->addComment($previousLineEnd, Comment::warning('suspicious_code.non_empty_switch_fallthrough', 'Consider adding a comment if this fall-through is intended.'));
     }
 }
 private function computeDefUse($code)
 {
     $code = sprintf('<?php function foo($param1, $param2) { %s }', $code);
     $ast = ParseUtils::parse($code);
     $scope = (new SyntacticScopeCreator())->createScope($ast);
     $cfa = new ControlFlowAnalysis();
     $cfa->process($ast);
     $cfg = $cfa->getGraph();
     $this->analysis = new MustBeReachingDefAnalysis($cfg, $scope);
     $this->analysis->analyze();
     $this->def = $this->use = null;
     NodeTraversal::traverseWithCallback($ast, new PreOrderCallback(function (NodeTraversal $t, \PHPParser_Node $node) {
         if (!$node instanceof \PHPParser_Node_Stmt_Label) {
             return;
         }
         if ('D' === $node->name) {
             $this->def = $node->getAttribute('next');
         } else {
             if ('U' === $node->name) {
                 $this->use = $node->getAttribute('next');
             } else {
                 if (0 === strpos($node->name, 'DP_')) {
                     $className = 'PHPParser_Node_' . substr($node->name, 3);
                     $parent = $node;
                     while (null !== ($parent = $parent->getAttribute('parent'))) {
                         if ($parent instanceof $className) {
                             $this->def = $parent;
                             return;
                         }
                     }
                     throw new \RuntimeException(sprintf('Did not find any parent of class "%s".', $className));
                 }
             }
         }
     }));
     $this->assertNotNull($this->def, 'Did not find "D" (definition) label in the code.');
     $this->assertNotNull($this->use, 'Did not find "U" (usage) label in the code.');
 }
 private function computeLiveness($src)
 {
     $src = '<?php class Foo { public function foo($param1, $param2) { ' . $src . ' } }';
     $parser = new \PHPParser_Parser();
     $lexer = new \PHPParser_Lexer($src);
     $ast = $parser->parse($lexer);
     $traverser = new \PHPParser_NodeTraverser();
     $traverser->addVisitor(new \PHPParser_NodeVisitor_NameResolver());
     $traverser->addVisitor(new NormalizingNodeVisitor());
     $ast = $traverser->traverse($ast);
     $traverser = new \PHPParser_NodeTraverser();
     $traverser->addVisitor(new \PHPParser_NodeVisitor_NodeConnector());
     $traverser->traverse($ast);
     $scopeCreator = new SyntacticScopeCreator();
     $scope = $scopeCreator->createScope($ast[0]->stmts[0], new Scope($ast[0]));
     $cfa = new ControlFlowAnalysis();
     $cfa->process($ast[0]->stmts[0]);
     $cfg = $cfa->getGraph();
     $lva = new LiveVariablesAnalysis($cfg, $scope);
     $lva->analyze();
     return $lva;
 }
 private function inMethod($phpCode)
 {
     // Parse the body of the function.
     $ast = $this->parser->parse(new \PHPParser_Lexer('<?php class Foo { function foo() {' . $phpCode . '} }'));
     // Normalize the AST.
     $traverser = new \PHPParser_NodeTraverser();
     $traverser->addVisitor(new \PHPParser_NodeVisitor_NameResolver());
     $traverser->addvisitor(new NormalizingNodeVisitor());
     $ast = $traverser->traverse($ast);
     $traverser = new \PHPParser_NodeTraverser();
     $traverser->addVisitor(new \PHPParser_NodeVisitor_NodeConnector());
     $traverser->traverse($ast);
     $root = $ast[0];
     $node = $root->stmts[0]->stmts;
     // Create the scope with the assumptions.
     $scopeCreator = new TypedScopeCreator($this->registry);
     $assumedScope = $scopeCreator->createScope($node, $scopeCreator->createScope($root, null));
     foreach ($this->assumptions as $symbolName => $type) {
         $var = $assumedScope->getVar($symbolName);
         if (!$var) {
             $assumedScope->declareVar($symbolName, $type);
         } else {
             $var->setType($type);
         }
     }
     // Create the control graph.
     $cfa = new ControlFlowAnalysis();
     $cfa->process($node);
     $cfg = $cfa->getGraph();
     // Create a simple reverse abstract interpreter.
     $rai = new SemanticReverseAbstractInterpreter($this->registry);
     $fi = new ArrayFunctionInterpreter($this->registry);
     $mi = $this->getMock('Scrutinizer\\PhpAnalyzer\\DataFlow\\TypeInference\\MethodInterpreter\\MethodInterpreterInterface');
     $commentParser = new \Scrutinizer\PhpAnalyzer\PhpParser\DocCommentParser($this->registry);
     // Do the type inference by data-flow analysis.
     $dfa = new TypeInference($cfg, $rai, $fi, $mi, $commentParser, $assumedScope, $this->registry);
     $dfa->analyze();
     // Get the scope of the implicit return.
     $this->returnScope = $cfg->getImplicitReturn()->getAttribute(DataFlowAnalysis::ATTR_FLOW_STATE_IN);
     $this->astGraph = \Scrutinizer\PhpAnalyzer\PhpParser\NodeUtil::dump($node);
 }