4 * This file is part of Psy Shell.
6 * (c) 2012-2018 Justin Hileman
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Psy\CodeCleaner;
15 use PhpParser\Node\Expr;
16 use PhpParser\Node\Expr\Array_;
17 use PhpParser\Node\Expr\ArrayDimFetch;
18 use PhpParser\Node\Expr\ArrayItem;
19 use PhpParser\Node\Expr\Assign;
20 use PhpParser\Node\Expr\FuncCall;
21 use PhpParser\Node\Expr\List_;
22 use PhpParser\Node\Expr\MethodCall;
23 use PhpParser\Node\Expr\PropertyFetch;
24 use PhpParser\Node\Expr\Variable;
25 use Psy\Exception\ParseErrorException;
28 * Validate that the list assignment.
30 class ListPass extends CodeCleanerPass
32 private $atLeastPhp71;
34 public function __construct()
36 $this->atLeastPhp71 = \version_compare(PHP_VERSION, '7.1', '>=');
40 * Validate use of list assignment.
42 * @throws ParseErrorException if the user used empty with anything but a variable
46 public function enterNode(Node $node)
48 if (!$node instanceof Assign) {
52 if (!$node->var instanceof Array_ && !$node->var instanceof List_) {
56 if (!$this->atLeastPhp71 && $node->var instanceof Array_) {
57 $msg = "syntax error, unexpected '='";
58 throw new ParseErrorException($msg, $node->expr->getLine());
61 // Polyfill for PHP-Parser 2.x
62 $items = isset($node->var->items) ? $node->var->items : $node->var->vars;
64 if ($items === [] || $items === [null]) {
65 throw new ParseErrorException('Cannot use empty list', $node->var->getLine());
69 foreach ($items as $item) {
76 // List_->$vars in PHP-Parser 2.x is Variable instead of ArrayItem.
77 if (!$this->atLeastPhp71 && $item instanceof ArrayItem && $item->key !== null) {
78 $msg = 'Syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting \',\' or \')\'';
79 throw new ParseErrorException($msg, $item->key->getLine());
82 if (!self::isValidArrayItem($item)) {
83 $msg = 'Assignments can only happen to writable values';
84 throw new ParseErrorException($msg, $item->getLine());
89 throw new ParseErrorException('Cannot use empty list');
94 * Validate whether a given item in an array is valid for short assignment.
100 private static function isValidArrayItem(Expr $item)
102 $value = ($item instanceof ArrayItem) ? $item->value : $item;
104 while ($value instanceof ArrayDimFetch || $value instanceof PropertyFetch) {
105 $value = $value->var;
108 // We just kind of give up if it's a method call. We can't tell if it's
109 // valid via static analysis.
110 return $value instanceof Variable || $value instanceof MethodCall || $value instanceof FuncCall;