Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / psy / psysh / src / CodeCleaner / ImplicitReturnPass.php
1 <?php
2
3 /*
4  * This file is part of Psy Shell.
5  *
6  * (c) 2012-2018 Justin Hileman
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Psy\CodeCleaner;
13
14 use PhpParser\Node;
15 use PhpParser\Node\Expr;
16 use PhpParser\Node\Expr\Exit_;
17 use PhpParser\Node\Stmt;
18 use PhpParser\Node\Stmt\Break_;
19 use PhpParser\Node\Stmt\Expression;
20 use PhpParser\Node\Stmt\If_;
21 use PhpParser\Node\Stmt\Namespace_;
22 use PhpParser\Node\Stmt\Return_;
23 use PhpParser\Node\Stmt\Switch_;
24
25 /**
26  * Add an implicit "return" to the last statement, provided it can be returned.
27  */
28 class ImplicitReturnPass extends CodeCleanerPass
29 {
30     /**
31      * @param array $nodes
32      *
33      * @return array
34      */
35     public function beforeTraverse(array $nodes)
36     {
37         return $this->addImplicitReturn($nodes);
38     }
39
40     /**
41      * @param array $nodes
42      *
43      * @return array
44      */
45     private function addImplicitReturn(array $nodes)
46     {
47         // If nodes is empty, it can't have a return value.
48         if (empty($nodes)) {
49             return [new Return_(NoReturnValue::create())];
50         }
51
52         $last = \end($nodes);
53
54         // Special case a few types of statements to add an implicit return
55         // value (even though they technically don't have any return value)
56         // because showing a return value in these instances is useful and not
57         // very surprising.
58         if ($last instanceof If_) {
59             $last->stmts = $this->addImplicitReturn($last->stmts);
60
61             foreach ($last->elseifs as $elseif) {
62                 $elseif->stmts = $this->addImplicitReturn($elseif->stmts);
63             }
64
65             if ($last->else) {
66                 $last->else->stmts = $this->addImplicitReturn($last->else->stmts);
67             }
68         } elseif ($last instanceof Switch_) {
69             foreach ($last->cases as $case) {
70                 // only add an implicit return to cases which end in break
71                 $caseLast = \end($case->stmts);
72                 if ($caseLast instanceof Break_) {
73                     $case->stmts = $this->addImplicitReturn(\array_slice($case->stmts, 0, -1));
74                     $case->stmts[] = $caseLast;
75                 }
76             }
77         } elseif ($last instanceof Expr && !($last instanceof Exit_)) {
78             // @codeCoverageIgnoreStart
79             $nodes[\count($nodes) - 1] = new Return_($last, [
80                 'startLine' => $last->getLine(),
81                 'endLine'   => $last->getLine(),
82             ]);
83         // @codeCoverageIgnoreEnd
84         } elseif ($last instanceof Expression && !($last->expr instanceof Exit_)) {
85             // For PHP Parser 4.x
86             $nodes[\count($nodes) - 1] = new Return_($last->expr, [
87                 'startLine' => $last->getLine(),
88                 'endLine'   => $last->getLine(),
89             ]);
90         } elseif ($last instanceof Namespace_) {
91             $last->stmts = $this->addImplicitReturn($last->stmts);
92         }
93
94         // Return a "no return value" for all non-expression statements, so that
95         // PsySH can suppress the `null` that `eval()` returns otherwise.
96         //
97         // Note that statements special cased above (if/elseif/else, switch)
98         // _might_ implicitly return a value before this catch-all return is
99         // reached.
100         //
101         // We're not adding a fallback return after namespace statements,
102         // because code outside namespace statements doesn't really work, and
103         // there's already an implicit return in the namespace statement anyway.
104         if (self::isNonExpressionStmt($last)) {
105             $nodes[] = new Return_(NoReturnValue::create());
106         }
107
108         return $nodes;
109     }
110
111     /**
112      * Check whether a given node is a non-expression statement.
113      *
114      * As of PHP Parser 4.x, Expressions are now instances of Stmt as well, so
115      * we'll exclude them here.
116      *
117      * @param Node $node
118      *
119      * @return bool
120      */
121     private static function isNonExpressionStmt(Node $node)
122     {
123         return $node instanceof Stmt &&
124             !$node instanceof Expression &&
125             !$node instanceof Return_ &&
126             !$node instanceof Namespace_;
127     }
128 }