Skip to content

Commit

Permalink
Support goto, labels, add some missing flags to generated ast node
Browse files Browse the repository at this point in the history
fix bug analyzing namespaces with properties.

Emulate edge cases of php-ast for property visibility flags.
Emulate the way php-ast parses a `list($x,) =` expression.

Fix RETURNS_REF flag for global functions

Copy test files from php-src which revealed new bugs
  • Loading branch information
TysonAndre committed Sep 17, 2017
1 parent e7dab48 commit e722c78
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 6 deletions.
51 changes: 45 additions & 6 deletions src/ASTConverter/ASTConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,16 @@ private static final function _phpparser_node_to_ast_node($n) {
private static function _init_handle_map() : array {
$closures = [
'PhpParser\Node\Arg' => function(PhpParser\Node\Arg $n, int $startLine) {
return self::_phpparser_node_to_ast_node($n->value);
$result = self::_phpparser_node_to_ast_node($n->value);
if ($n->unpack) {
return new ast\Node(
\ast\AST_UNPACK,
0,
['expr' => $result],
$startLine
);
}
return $result;
},
'PhpParser\Node\Expr\Array_' => function(PhpParser\Node\Expr\Array_ $n, int $startLine) : ast\Node {
return self::_phpparser_array_to_ast_array($n, $startLine);
Expand Down Expand Up @@ -782,6 +791,14 @@ private static function _init_handle_map() : array {
}
return \count($globalNodes) === 1 ? $globalNodes[0] : $globalNodes;
},
'PhpParser\Node\Stmt\Goto_' => function(PhpParser\Node\Stmt\Goto_ $n, int $startLine) : ast\Node {
return new ast\Node(
\ast\AST_GOTO,
0,
['label' => $n->name],
$startLine
);
},
'PhpParser\Node\Stmt\HaltCompiler' => function(PhpParser\Node\Stmt\HaltCompiler $n, int $startLine) : ast\Node {
return new ast\Node(
\ast\AST_HALT_COMPILER,
Expand Down Expand Up @@ -810,6 +827,14 @@ private static function _init_handle_map() : array {
self::_extract_phpdoc_comment($n->getAttribute('comments'))
);
},
'PhpParser\Node\Stmt\Label' => function(PhpParser\Node\Stmt\Label $n, int $startLine) : ast\Node {
return new ast\Node(
\ast\AST_LABEL,
0,
['name' => $n->name],
$startLine
);
},
'PhpParser\Node\Stmt\For_' => function(PhpParser\Node\Stmt\For_ $n, int $startLine) : ast\Node {
return new ast\Node(
ast\AST_FOR,
Expand Down Expand Up @@ -842,8 +867,12 @@ private static function _init_handle_map() : array {
$endLineOfWrapper = ($n->getAttribute('endLine') ?: $n->getAttribute('startLine') ?: null);
$withinNamespace = $n->stmts ?? [];
if (count($withinNamespace) > 0) {
$lastStmt = end($withinNamespace);
$endLineOfContents = $lastStmt->getAttribute('endLine') ?: $lastStmt->getAttribute('startLine') ?: $endLineOfWrapper;
foreach ($withinNamespace as $s) {
$endLineOfContents = $s->getAttribute('endLine') ?: $s->getAttribute('startLine');
if ($endLineOfContents && $endLineOfContents != $endLineOfWrapper) {
break;
}
}
}
}

Expand Down Expand Up @@ -1388,6 +1417,9 @@ private static function _ast_decl_function(
?string $docComment
) : ast\Node {
$flags = 0;
if ($byRef) {
$flags |= \ast\flags\RETURNS_REF;
}
/*
if (PHP_VERSION_ID >= 70100 && self::_function_body_is_generator($stmts)) {
$flags |= 0x800000;
Expand Down Expand Up @@ -1697,15 +1729,17 @@ private static function _phpparser_visibility_to_ast_visibility(int $visibility,
return $ast_visibility;
}

private static function _phpparser_property_to_ast_node(PhpParser\Node $n, int $startLine) : ast\Node {
assert($n instanceof \PHPParser\Node\Stmt\Property);
private static function _phpparser_property_to_ast_node(PHPParser\Node\Stmt\Property $n, int $startLine) : ast\Node {

$propElems = [];
$docComment = self::_extract_phpdoc_comment($n->getAttribute('comments'));
foreach ($n->props as $i => $prop) {
$propElems[] = self::_phpparser_propelem_to_ast_propelem($prop, $i === 0 ? $docComment : null);
}
$flags = self::_phpparser_visibility_to_ast_visibility($n->flags);
$flags = self::_phpparser_visibility_to_ast_visibility($n->flags, false);
if ($flags === 0) {
$flags = ast\flags\MODIFIER_PUBLIC;
}

return new ast\Node(ast\AST_PROP_DECL, $flags, $propElems, $propElems[0]->lineno ?: $startLine);
}
Expand Down Expand Up @@ -1824,6 +1858,11 @@ private static function _phpparser_list_to_ast_list(PhpParser\Node\Expr\List_ $n
], $item->getAttribute('startLine'));
}
}

// convert list($x,) to list($x), list(,) to list(), etc.
if (\count($astItems) > 0 && end($astItems) === null) {
array_pop($astItems);
}
return new ast\Node(ast\AST_ARRAY, ast\flags\ARRAY_SYNTAX_LIST, $astItems, $startLine);
}

Expand Down
21 changes: 21 additions & 0 deletions test_files/src/php-src_tests/bug39346.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
class test
{
protected $_id;
static $instances;

public function __construct($id) {
$this->_id = $id;
self::$instances[$this->_id] = $this;
}

function __destruct() {
unset(self::$instances[$this->_id]);
}
}
$test = new test(2);
$test = new test(1);
$test = new test(2);
$test = new test(3);
echo "ok\n";
?>
10 changes: 10 additions & 0 deletions test_files/src/php-src_tests/bug43332_1.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
namespace foobar;

class foo {
public function bar(self $a) { }
}

$foo = new foo;
$foo->bar($foo); // Ok!
$foo->bar(new \stdclass); // Error, ok!
11 changes: 11 additions & 0 deletions test_files/src/php-src_tests/bug69599.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

function crash() {
sin(...[0]);
throw new \Exception();
yield;
}

iterator_to_array(crash());

?>
11 changes: 11 additions & 0 deletions test_files/src/php-src_tests/bug72767.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

function test() {}
$iterator = new LimitIterator(
new InfiniteIterator(new ArrayIterator([42])),
0, 17000
);
test(...$iterator);

?>
===DONE===
18 changes: 18 additions & 0 deletions test_files/src/php-src_tests/dereference_009.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

error_reporting(E_ALL);

$a = array();

function &a() {
return $GLOBALS['a'];
}

var_dump($h =& a());
$h[] = 1;
var_dump(a()[0]);

$h[] = array($h);
var_dump(a()[1][0][0]);

?>
8 changes: 8 additions & 0 deletions test_files/src/php-src_tests/foreach_list_004.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

$array = [['a', 'b'], 'c', 'd'];

foreach($array as $key => list()) {
}

?>
37 changes: 37 additions & 0 deletions test_files/src/php-src_tests/indirect_call_string_001.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
namespace TestNamespace
{
class TestClass
{
public static function staticMethod()
{
echo "Static method called!\n";
}

public static function staticMethodWithArgs($arg1, $arg2, $arg3)
{
printf("Static method called with args: %s, %s, %s\n", $arg1, $arg2, $arg3);
}
}
}

namespace CallNamespace
{
// Test basic call using Class::method syntax.
$callback = 'TestNamespace\TestClass::staticMethod';
$callback();

// Case should not matter.
$callback = 'testnamespace\testclass::staticmethod';
$callback();

$args = ['arg1', 'arg2', 'arg3'];
$callback = 'TestNamespace\TestClass::staticMethodWithArgs';

// Test call with args.
$callback($args[0], $args[1], $args[2]);

// Test call with splat operator.
$callback(...$args);
}
?>
20 changes: 20 additions & 0 deletions test_files/src/php-src_tests/jump13.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
goto a;
e: return;
try {
a: print 1;
goto b;
try {
b: print 2;
goto c;
}
catch(Exception $e) {
c: print 3;
goto d;
}
}
catch(Exception $e) {
d: print 4;
goto e;
}
?>

0 comments on commit e722c78

Please sign in to comment.