Initial Commit
This commit is contained in:
26
dependencies/phpstan/phpdoc-parser/phpstan-baseline.neon
vendored
Normal file
26
dependencies/phpstan/phpdoc-parser/phpstan-baseline.neon
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Method PHPStan\\\\PhpDocParser\\\\Ast\\\\ConstExpr\\\\QuoteAwareConstExprStringNode\\:\\:escapeDoubleQuotedString\\(\\) should return string but returns string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php
|
||||
|
||||
-
|
||||
message: "#^Cannot use array destructuring on array\\<int, array\\<PHPStan\\\\PhpDocParser\\\\Ast\\\\Node\\>\\|int\\|string\\>\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Ast/NodeTraverser.php
|
||||
|
||||
-
|
||||
message: "#^Variable property access on PHPStan\\\\PhpDocParser\\\\Ast\\\\Node\\.$#"
|
||||
count: 1
|
||||
path: src/Ast/NodeTraverser.php
|
||||
|
||||
-
|
||||
message: "#^Method PHPStan\\\\PhpDocParser\\\\Parser\\\\StringUnescaper\\:\\:parseEscapeSequences\\(\\) should return string but returns string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Parser/StringUnescaper.php
|
||||
|
||||
-
|
||||
message: "#^Variable property access on PHPStan\\\\PhpDocParser\\\\Ast\\\\Node\\.$#"
|
||||
count: 2
|
||||
path: src/Printer/Printer.php
|
30
dependencies/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php
vendored
Normal file
30
dependencies/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
|
||||
/**
|
||||
* Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
|
||||
*
|
||||
* Copyright (c) 2011, Nikita Popov
|
||||
* All rights reserved.
|
||||
*/
|
||||
abstract class AbstractNodeVisitor implements NodeVisitor
|
||||
{
|
||||
public function beforeTraverse(array $nodes) : ?array
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public function afterTraverse(array $nodes) : ?array
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
13
dependencies/phpstan/phpdoc-parser/src/Ast/Attribute.php
vendored
Normal file
13
dependencies/phpstan/phpdoc-parser/src/Ast/Attribute.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
|
||||
final class Attribute
|
||||
{
|
||||
public const START_LINE = 'startLine';
|
||||
public const END_LINE = 'endLine';
|
||||
public const START_INDEX = 'startIndex';
|
||||
public const END_INDEX = 'endIndex';
|
||||
public const ORIGINAL_NODE = 'originalNode';
|
||||
}
|
27
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php
vendored
Normal file
27
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function sprintf;
|
||||
class ConstExprArrayItemNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var ConstExprNode|null */
|
||||
public $key;
|
||||
/** @var ConstExprNode */
|
||||
public $value;
|
||||
public function __construct(?ConstExprNode $key, ConstExprNode $value)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->key !== null) {
|
||||
return sprintf('%s => %s', $this->key, $this->value);
|
||||
}
|
||||
return (string) $this->value;
|
||||
}
|
||||
}
|
24
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php
vendored
Normal file
24
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function implode;
|
||||
class ConstExprArrayNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var ConstExprArrayItemNode[] */
|
||||
public $items;
|
||||
/**
|
||||
* @param ConstExprArrayItemNode[] $items
|
||||
*/
|
||||
public function __construct(array $items)
|
||||
{
|
||||
$this->items = $items;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return '[' . implode(', ', $this->items) . ']';
|
||||
}
|
||||
}
|
14
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php
vendored
Normal file
14
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ConstExprFalseNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
public function __toString() : string
|
||||
{
|
||||
return 'false';
|
||||
}
|
||||
}
|
20
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php
vendored
Normal file
20
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ConstExprFloatNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $value;
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
20
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php
vendored
Normal file
20
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ConstExprIntegerNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $value;
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
9
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php
vendored
Normal file
9
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
interface ConstExprNode extends Node
|
||||
{
|
||||
}
|
14
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php
vendored
Normal file
14
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ConstExprNullNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
public function __toString() : string
|
||||
{
|
||||
return 'null';
|
||||
}
|
||||
}
|
20
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php
vendored
Normal file
20
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ConstExprStringNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $value;
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
14
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php
vendored
Normal file
14
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ConstExprTrueNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
public function __toString() : string
|
||||
{
|
||||
return 'true';
|
||||
}
|
||||
}
|
26
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.php
vendored
Normal file
26
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ConstFetchNode implements ConstExprNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string class name for class constants or empty string for non-class constants */
|
||||
public $className;
|
||||
/** @var string */
|
||||
public $name;
|
||||
public function __construct(string $className, string $name)
|
||||
{
|
||||
$this->className = $className;
|
||||
$this->name = $name;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->className === '') {
|
||||
return $this->name;
|
||||
}
|
||||
return "{$this->className}::{$this->name}";
|
||||
}
|
||||
}
|
35
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php
vendored
Normal file
35
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
class DoctrineConstExprStringNode extends ConstExprStringNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $value;
|
||||
public function __construct(string $value)
|
||||
{
|
||||
parent::__construct($value);
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return self::escape($this->value);
|
||||
}
|
||||
public static function unescape(string $value) : string
|
||||
{
|
||||
// from https://github.com/doctrine/annotations/blob/a9ec7af212302a75d1f92fa65d3abfbd16245a2a/lib/Doctrine/Common/Annotations/DocLexer.php#L103-L107
|
||||
return str_replace('""', '"', substr($value, 1, strlen($value) - 2));
|
||||
}
|
||||
private static function escape(string $value) : string
|
||||
{
|
||||
// from https://github.com/phpstan/phpdoc-parser/issues/205#issuecomment-1662323656
|
||||
return sprintf('"%s"', str_replace('"', '""', $value));
|
||||
}
|
||||
}
|
67
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php
vendored
Normal file
67
dependencies/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function addcslashes;
|
||||
use function assert;
|
||||
use function dechex;
|
||||
use function ord;
|
||||
use function preg_replace_callback;
|
||||
use function sprintf;
|
||||
use function str_pad;
|
||||
use function strlen;
|
||||
use const STR_PAD_LEFT;
|
||||
class QuoteAwareConstExprStringNode extends ConstExprStringNode implements ConstExprNode
|
||||
{
|
||||
public const SINGLE_QUOTED = 1;
|
||||
public const DOUBLE_QUOTED = 2;
|
||||
use NodeAttributes;
|
||||
/** @var self::SINGLE_QUOTED|self::DOUBLE_QUOTED */
|
||||
public $quoteType;
|
||||
/**
|
||||
* @param self::SINGLE_QUOTED|self::DOUBLE_QUOTED $quoteType
|
||||
*/
|
||||
public function __construct(string $value, int $quoteType)
|
||||
{
|
||||
parent::__construct($value);
|
||||
$this->quoteType = $quoteType;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->quoteType === self::SINGLE_QUOTED) {
|
||||
// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1007
|
||||
return sprintf("'%s'", addcslashes($this->value, '\'\\'));
|
||||
}
|
||||
// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1010-L1040
|
||||
return sprintf('"%s"', $this->escapeDoubleQuotedString());
|
||||
}
|
||||
private function escapeDoubleQuotedString() : string
|
||||
{
|
||||
$quote = '"';
|
||||
$escaped = addcslashes($this->value, "\n\r\t\f\v\$" . $quote . '\\');
|
||||
// Escape control characters and non-UTF-8 characters.
|
||||
// Regex based on https://stackoverflow.com/a/11709412/385378.
|
||||
$regex = '/(
|
||||
[\\x00-\\x08\\x0E-\\x1F] # Control characters
|
||||
| [\\xC0-\\xC1] # Invalid UTF-8 Bytes
|
||||
| [\\xF5-\\xFF] # Invalid UTF-8 Bytes
|
||||
| \\xE0(?=[\\x80-\\x9F]) # Overlong encoding of prior code point
|
||||
| \\xF0(?=[\\x80-\\x8F]) # Overlong encoding of prior code point
|
||||
| [\\xC2-\\xDF](?![\\x80-\\xBF]) # Invalid UTF-8 Sequence Start
|
||||
| [\\xE0-\\xEF](?![\\x80-\\xBF]{2}) # Invalid UTF-8 Sequence Start
|
||||
| [\\xF0-\\xF4](?![\\x80-\\xBF]{3}) # Invalid UTF-8 Sequence Start
|
||||
| (?<=[\\x00-\\x7F\\xF5-\\xFF])[\\x80-\\xBF] # Invalid UTF-8 Sequence Middle
|
||||
| (?<![\\xC2-\\xDF]|[\\xE0-\\xEF]|[\\xE0-\\xEF][\\x80-\\xBF]|[\\xF0-\\xF4]|[\\xF0-\\xF4][\\x80-\\xBF]|[\\xF0-\\xF4][\\x80-\\xBF]{2})[\\x80-\\xBF] # Overlong Sequence
|
||||
| (?<=[\\xE0-\\xEF])[\\x80-\\xBF](?![\\x80-\\xBF]) # Short 3 byte sequence
|
||||
| (?<=[\\xF0-\\xF4])[\\x80-\\xBF](?![\\x80-\\xBF]{2}) # Short 4 byte sequence
|
||||
| (?<=[\\xF0-\\xF4][\\x80-\\xBF])[\\x80-\\xBF](?![\\x80-\\xBF]) # Short 4 byte sequence (2)
|
||||
)/x';
|
||||
return preg_replace_callback($regex, static function ($matches) {
|
||||
assert(strlen($matches[0]) === 1);
|
||||
$hex = dechex(ord($matches[0]));
|
||||
return '\\x' . str_pad($hex, 2, '0', STR_PAD_LEFT);
|
||||
}, $escaped);
|
||||
}
|
||||
}
|
18
dependencies/phpstan/phpdoc-parser/src/Ast/Node.php
vendored
Normal file
18
dependencies/phpstan/phpdoc-parser/src/Ast/Node.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
|
||||
interface Node
|
||||
{
|
||||
public function __toString() : string;
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setAttribute(string $key, $value) : void;
|
||||
public function hasAttribute(string $key) : bool;
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttribute(string $key);
|
||||
}
|
32
dependencies/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php
vendored
Normal file
32
dependencies/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
|
||||
use function array_key_exists;
|
||||
trait NodeAttributes
|
||||
{
|
||||
/** @var array<string, mixed> */
|
||||
private $attributes = [];
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setAttribute(string $key, $value) : void
|
||||
{
|
||||
$this->attributes[$key] = $value;
|
||||
}
|
||||
public function hasAttribute(string $key) : bool
|
||||
{
|
||||
return array_key_exists($key, $this->attributes);
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttribute(string $key)
|
||||
{
|
||||
if ($this->hasAttribute($key)) {
|
||||
return $this->attributes[$key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
263
dependencies/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php
vendored
Normal file
263
dependencies/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
|
||||
use LogicException;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function array_keys;
|
||||
use function array_pop;
|
||||
use function array_splice;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function get_object_vars;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function sprintf;
|
||||
/**
|
||||
* Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
|
||||
*
|
||||
* Copyright (c) 2011, Nikita Popov
|
||||
* All rights reserved.
|
||||
*/
|
||||
final class NodeTraverser
|
||||
{
|
||||
/**
|
||||
* If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes
|
||||
* of the current node will not be traversed for any visitors.
|
||||
*
|
||||
* For subsequent visitors enterNode() will still be called on the current
|
||||
* node and leaveNode() will also be invoked for the current node.
|
||||
*/
|
||||
public const DONT_TRAVERSE_CHILDREN = 1;
|
||||
/**
|
||||
* If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns
|
||||
* STOP_TRAVERSAL, traversal is aborted.
|
||||
*
|
||||
* The afterTraverse() method will still be invoked.
|
||||
*/
|
||||
public const STOP_TRAVERSAL = 2;
|
||||
/**
|
||||
* If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs
|
||||
* in an array, it will be removed from the array.
|
||||
*
|
||||
* For subsequent visitors leaveNode() will still be invoked for the
|
||||
* removed node.
|
||||
*/
|
||||
public const REMOVE_NODE = 3;
|
||||
/**
|
||||
* If NodeVisitor::enterNode() returns DONT_TRAVERSE_CURRENT_AND_CHILDREN, child nodes
|
||||
* of the current node will not be traversed for any visitors.
|
||||
*
|
||||
* For subsequent visitors enterNode() will not be called as well.
|
||||
* leaveNode() will be invoked for visitors that has enterNode() method invoked.
|
||||
*/
|
||||
public const DONT_TRAVERSE_CURRENT_AND_CHILDREN = 4;
|
||||
/** @var list<NodeVisitor> Visitors */
|
||||
private $visitors = [];
|
||||
/** @var bool Whether traversal should be stopped */
|
||||
private $stopTraversal;
|
||||
/**
|
||||
* @param list<NodeVisitor> $visitors
|
||||
*/
|
||||
public function __construct(array $visitors)
|
||||
{
|
||||
$this->visitors = $visitors;
|
||||
}
|
||||
/**
|
||||
* Traverses an array of nodes using the registered visitors.
|
||||
*
|
||||
* @param Node[] $nodes Array of nodes
|
||||
*
|
||||
* @return Node[] Traversed array of nodes
|
||||
*/
|
||||
public function traverse(array $nodes) : array
|
||||
{
|
||||
$this->stopTraversal = \false;
|
||||
foreach ($this->visitors as $visitor) {
|
||||
$return = $visitor->beforeTraverse($nodes);
|
||||
if ($return === null) {
|
||||
continue;
|
||||
}
|
||||
$nodes = $return;
|
||||
}
|
||||
$nodes = $this->traverseArray($nodes);
|
||||
foreach ($this->visitors as $visitor) {
|
||||
$return = $visitor->afterTraverse($nodes);
|
||||
if ($return === null) {
|
||||
continue;
|
||||
}
|
||||
$nodes = $return;
|
||||
}
|
||||
return $nodes;
|
||||
}
|
||||
/**
|
||||
* Recursively traverse a node.
|
||||
*
|
||||
* @param Node $node Node to traverse.
|
||||
*
|
||||
* @return Node Result of traversal (may be original node or new one)
|
||||
*/
|
||||
private function traverseNode(Node $node) : Node
|
||||
{
|
||||
$subNodeNames = array_keys(get_object_vars($node));
|
||||
foreach ($subNodeNames as $name) {
|
||||
$subNode =& $node->{$name};
|
||||
if (is_array($subNode)) {
|
||||
$subNode = $this->traverseArray($subNode);
|
||||
if ($this->stopTraversal) {
|
||||
break;
|
||||
}
|
||||
} elseif ($subNode instanceof Node) {
|
||||
$traverseChildren = \true;
|
||||
$breakVisitorIndex = null;
|
||||
foreach ($this->visitors as $visitorIndex => $visitor) {
|
||||
$return = $visitor->enterNode($subNode);
|
||||
if ($return === null) {
|
||||
continue;
|
||||
}
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($subNode, $return);
|
||||
$subNode = $return;
|
||||
} elseif ($return === self::DONT_TRAVERSE_CHILDREN) {
|
||||
$traverseChildren = \false;
|
||||
} elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) {
|
||||
$traverseChildren = \false;
|
||||
$breakVisitorIndex = $visitorIndex;
|
||||
break;
|
||||
} elseif ($return === self::STOP_TRAVERSAL) {
|
||||
$this->stopTraversal = \true;
|
||||
break 2;
|
||||
} else {
|
||||
throw new LogicException('enterNode() returned invalid value of type ' . gettype($return));
|
||||
}
|
||||
}
|
||||
if ($traverseChildren) {
|
||||
$subNode = $this->traverseNode($subNode);
|
||||
if ($this->stopTraversal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($this->visitors as $visitorIndex => $visitor) {
|
||||
$return = $visitor->leaveNode($subNode);
|
||||
if ($return !== null) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($subNode, $return);
|
||||
$subNode = $return;
|
||||
} elseif ($return === self::STOP_TRAVERSAL) {
|
||||
$this->stopTraversal = \true;
|
||||
break 2;
|
||||
} elseif (is_array($return)) {
|
||||
throw new LogicException('leaveNode() may only return an array ' . 'if the parent structure is an array');
|
||||
} else {
|
||||
throw new LogicException('leaveNode() returned invalid value of type ' . gettype($return));
|
||||
}
|
||||
}
|
||||
if ($breakVisitorIndex === $visitorIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
/**
|
||||
* Recursively traverse array (usually of nodes).
|
||||
*
|
||||
* @param mixed[] $nodes Array to traverse
|
||||
*
|
||||
* @return mixed[] Result of traversal (may be original array or changed one)
|
||||
*/
|
||||
private function traverseArray(array $nodes) : array
|
||||
{
|
||||
$doNodes = [];
|
||||
foreach ($nodes as $i => &$node) {
|
||||
if ($node instanceof Node) {
|
||||
$traverseChildren = \true;
|
||||
$breakVisitorIndex = null;
|
||||
foreach ($this->visitors as $visitorIndex => $visitor) {
|
||||
$return = $visitor->enterNode($node);
|
||||
if ($return === null) {
|
||||
continue;
|
||||
}
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($node, $return);
|
||||
$node = $return;
|
||||
} elseif (is_array($return)) {
|
||||
$doNodes[] = [$i, $return];
|
||||
continue 2;
|
||||
} elseif ($return === self::REMOVE_NODE) {
|
||||
$doNodes[] = [$i, []];
|
||||
continue 2;
|
||||
} elseif ($return === self::DONT_TRAVERSE_CHILDREN) {
|
||||
$traverseChildren = \false;
|
||||
} elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) {
|
||||
$traverseChildren = \false;
|
||||
$breakVisitorIndex = $visitorIndex;
|
||||
break;
|
||||
} elseif ($return === self::STOP_TRAVERSAL) {
|
||||
$this->stopTraversal = \true;
|
||||
break 2;
|
||||
} else {
|
||||
throw new LogicException('enterNode() returned invalid value of type ' . gettype($return));
|
||||
}
|
||||
}
|
||||
if ($traverseChildren) {
|
||||
$node = $this->traverseNode($node);
|
||||
if ($this->stopTraversal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($this->visitors as $visitorIndex => $visitor) {
|
||||
$return = $visitor->leaveNode($node);
|
||||
if ($return !== null) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($node, $return);
|
||||
$node = $return;
|
||||
} elseif (is_array($return)) {
|
||||
$doNodes[] = [$i, $return];
|
||||
break;
|
||||
} elseif ($return === self::REMOVE_NODE) {
|
||||
$doNodes[] = [$i, []];
|
||||
break;
|
||||
} elseif ($return === self::STOP_TRAVERSAL) {
|
||||
$this->stopTraversal = \true;
|
||||
break 2;
|
||||
} else {
|
||||
throw new LogicException('leaveNode() returned invalid value of type ' . gettype($return));
|
||||
}
|
||||
}
|
||||
if ($breakVisitorIndex === $visitorIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif (is_array($node)) {
|
||||
throw new LogicException('Invalid node structure: Contains nested arrays');
|
||||
}
|
||||
}
|
||||
if (count($doNodes) > 0) {
|
||||
while ([$i, $replace] = array_pop($doNodes)) {
|
||||
array_splice($nodes, $i, 1, $replace);
|
||||
}
|
||||
}
|
||||
return $nodes;
|
||||
}
|
||||
private function ensureReplacementReasonable(Node $old, Node $new) : void
|
||||
{
|
||||
if ($old instanceof TypeNode && !$new instanceof TypeNode) {
|
||||
throw new LogicException(sprintf('Trying to replace TypeNode with %s', get_class($new)));
|
||||
}
|
||||
if ($old instanceof ConstExprNode && !$new instanceof ConstExprNode) {
|
||||
throw new LogicException(sprintf('Trying to replace ConstExprNode with %s', get_class($new)));
|
||||
}
|
||||
if ($old instanceof PhpDocChildNode && !$new instanceof PhpDocChildNode) {
|
||||
throw new LogicException(sprintf('Trying to replace PhpDocChildNode with %s', get_class($new)));
|
||||
}
|
||||
if ($old instanceof PhpDocTagValueNode && !$new instanceof PhpDocTagValueNode) {
|
||||
throw new LogicException(sprintf('Trying to replace PhpDocTagValueNode with %s', get_class($new)));
|
||||
}
|
||||
}
|
||||
}
|
83
dependencies/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php
vendored
Normal file
83
dependencies/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
|
||||
/**
|
||||
* Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
|
||||
*
|
||||
* Copyright (c) 2011, Nikita Popov
|
||||
* All rights reserved.
|
||||
*/
|
||||
interface NodeVisitor
|
||||
{
|
||||
/**
|
||||
* Called once before traversal.
|
||||
*
|
||||
* Return value semantics:
|
||||
* * null: $nodes stays as-is
|
||||
* * otherwise: $nodes is set to the return value
|
||||
*
|
||||
* @param Node[] $nodes Array of nodes
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes) : ?array;
|
||||
/**
|
||||
* Called when entering a node.
|
||||
*
|
||||
* Return value semantics:
|
||||
* * null
|
||||
* => $node stays as-is
|
||||
* * array (of Nodes)
|
||||
* => The return value is merged into the parent array (at the position of the $node)
|
||||
* * NodeTraverser::REMOVE_NODE
|
||||
* => $node is removed from the parent array
|
||||
* * NodeTraverser::DONT_TRAVERSE_CHILDREN
|
||||
* => Children of $node are not traversed. $node stays as-is
|
||||
* * NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN
|
||||
* => Further visitors for the current node are skipped, and its children are not
|
||||
* traversed. $node stays as-is.
|
||||
* * NodeTraverser::STOP_TRAVERSAL
|
||||
* => Traversal is aborted. $node stays as-is
|
||||
* * otherwise
|
||||
* => $node is set to the return value
|
||||
*
|
||||
* @param Node $node Node
|
||||
*
|
||||
* @return Node|Node[]|NodeTraverser::*|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node);
|
||||
/**
|
||||
* Called when leaving a node.
|
||||
*
|
||||
* Return value semantics:
|
||||
* * null
|
||||
* => $node stays as-is
|
||||
* * NodeTraverser::REMOVE_NODE
|
||||
* => $node is removed from the parent array
|
||||
* * NodeTraverser::STOP_TRAVERSAL
|
||||
* => Traversal is aborted. $node stays as-is
|
||||
* * array (of Nodes)
|
||||
* => The return value is merged into the parent array (at the position of the $node)
|
||||
* * otherwise
|
||||
* => $node is set to the return value
|
||||
*
|
||||
* @param Node $node Node
|
||||
*
|
||||
* @return Node|Node[]|NodeTraverser::REMOVE_NODE|NodeTraverser::STOP_TRAVERSAL|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node);
|
||||
/**
|
||||
* Called once after traversal.
|
||||
*
|
||||
* Return value semantics:
|
||||
* * null: $nodes stays as-is
|
||||
* * otherwise: $nodes is set to the return value
|
||||
*
|
||||
* @param Node[] $nodes Array of nodes
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function afterTraverse(array $nodes) : ?array;
|
||||
}
|
17
dependencies/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php
vendored
Normal file
17
dependencies/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeVisitor;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\AbstractNodeVisitor;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Attribute;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
final class CloningVisitor extends AbstractNodeVisitor
|
||||
{
|
||||
public function enterNode(Node $originalNode)
|
||||
{
|
||||
$node = clone $originalNode;
|
||||
$node->setAttribute(Attribute::ORIGINAL_NODE, $originalNode);
|
||||
return $node;
|
||||
}
|
||||
}
|
39
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php
vendored
Normal file
39
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class AssertTagMethodValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string */
|
||||
public $parameter;
|
||||
/** @var string */
|
||||
public $method;
|
||||
/** @var bool */
|
||||
public $isNegated;
|
||||
/** @var bool */
|
||||
public $isEquality;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $parameter, string $method, bool $isNegated, string $description, bool $isEquality = \false)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->parameter = $parameter;
|
||||
$this->method = $method;
|
||||
$this->isNegated = $isNegated;
|
||||
$this->isEquality = $isEquality;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$isNegated = $this->isNegated ? '!' : '';
|
||||
$isEquality = $this->isEquality ? '=' : '';
|
||||
return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->method}() {$this->description}");
|
||||
}
|
||||
}
|
39
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php
vendored
Normal file
39
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class AssertTagPropertyValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string */
|
||||
public $parameter;
|
||||
/** @var string */
|
||||
public $property;
|
||||
/** @var bool */
|
||||
public $isNegated;
|
||||
/** @var bool */
|
||||
public $isEquality;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $parameter, string $property, bool $isNegated, string $description, bool $isEquality = \false)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->parameter = $parameter;
|
||||
$this->property = $property;
|
||||
$this->isNegated = $isNegated;
|
||||
$this->isEquality = $isEquality;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$isNegated = $this->isNegated ? '!' : '';
|
||||
$isEquality = $this->isEquality ? '=' : '';
|
||||
return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->property} {$this->description}");
|
||||
}
|
||||
}
|
36
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php
vendored
Normal file
36
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class AssertTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string */
|
||||
public $parameter;
|
||||
/** @var bool */
|
||||
public $isNegated;
|
||||
/** @var bool */
|
||||
public $isEquality;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $parameter, bool $isNegated, string $description, bool $isEquality = \false)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->parameter = $parameter;
|
||||
$this->isNegated = $isNegated;
|
||||
$this->isEquality = $isEquality;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$isNegated = $this->isNegated ? '!' : '';
|
||||
$isEquality = $this->isEquality ? '=' : '';
|
||||
return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter} {$this->description}");
|
||||
}
|
||||
}
|
21
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php
vendored
Normal file
21
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function trim;
|
||||
class DeprecatedTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(string $description)
|
||||
{
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim($this->description);
|
||||
}
|
||||
}
|
29
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php
vendored
Normal file
29
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function implode;
|
||||
class DoctrineAnnotation implements Node
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var list<DoctrineArgument> */
|
||||
public $arguments;
|
||||
/**
|
||||
* @param list<DoctrineArgument> $arguments
|
||||
*/
|
||||
public function __construct(string $name, array $arguments)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$arguments = implode(', ', $this->arguments);
|
||||
return $this->name . '(' . $arguments . ')';
|
||||
}
|
||||
}
|
35
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php
vendored
Normal file
35
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
/**
|
||||
* @phpstan-type ValueType = DoctrineAnnotation|IdentifierTypeNode|DoctrineArray|ConstExprNode
|
||||
*/
|
||||
class DoctrineArgument implements Node
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var IdentifierTypeNode|null */
|
||||
public $key;
|
||||
/** @var ValueType */
|
||||
public $value;
|
||||
/**
|
||||
* @param ValueType $value
|
||||
*/
|
||||
public function __construct(?IdentifierTypeNode $key, $value)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->key === null) {
|
||||
return (string) $this->value;
|
||||
}
|
||||
return $this->key . '=' . $this->value;
|
||||
}
|
||||
}
|
26
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php
vendored
Normal file
26
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function implode;
|
||||
class DoctrineArray implements Node
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var list<DoctrineArrayItem> */
|
||||
public $items;
|
||||
/**
|
||||
* @param list<DoctrineArrayItem> $items
|
||||
*/
|
||||
public function __construct(array $items)
|
||||
{
|
||||
$this->items = $items;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$items = implode(', ', $this->items);
|
||||
return '{' . $items . '}';
|
||||
}
|
||||
}
|
39
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php
vendored
Normal file
39
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
/**
|
||||
* @phpstan-import-type ValueType from DoctrineArgument
|
||||
* @phpstan-type KeyType = ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode|null
|
||||
*/
|
||||
class DoctrineArrayItem implements Node
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var KeyType */
|
||||
public $key;
|
||||
/** @var ValueType */
|
||||
public $value;
|
||||
/**
|
||||
* @param KeyType $key
|
||||
* @param ValueType $value
|
||||
*/
|
||||
public function __construct($key, $value)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->key === null) {
|
||||
return (string) $this->value;
|
||||
}
|
||||
return $this->key . '=' . $this->value;
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
|
||||
use function trim;
|
||||
class DoctrineTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var DoctrineAnnotation */
|
||||
public $annotation;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(DoctrineAnnotation $annotation, string $description)
|
||||
{
|
||||
$this->annotation = $annotation;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->annotation} {$this->description}");
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
|
||||
use function trim;
|
||||
class ExtendsTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var GenericTypeNode */
|
||||
public $type;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(GenericTypeNode $type, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} {$this->description}");
|
||||
}
|
||||
}
|
20
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php
vendored
Normal file
20
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class GenericTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string (may be empty) */
|
||||
public $value;
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
|
||||
use function trim;
|
||||
class ImplementsTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var GenericTypeNode */
|
||||
public $type;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(GenericTypeNode $type, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} {$this->description}");
|
||||
}
|
||||
}
|
38
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php
vendored
Normal file
38
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser\ParserException;
|
||||
use function sprintf;
|
||||
use function trigger_error;
|
||||
use const E_USER_WARNING;
|
||||
/**
|
||||
* @property ParserException $exception
|
||||
*/
|
||||
class InvalidTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string (may be empty) */
|
||||
public $value;
|
||||
/** @var mixed[] */
|
||||
private $exceptionArgs;
|
||||
public function __construct(string $value, ParserException $exception)
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->exceptionArgs = [$exception->getCurrentTokenValue(), $exception->getCurrentTokenType(), $exception->getCurrentOffset(), $exception->getExpectedTokenType(), $exception->getExpectedTokenValue(), $exception->getCurrentTokenLine()];
|
||||
}
|
||||
public function __get(string $name) : ?ParserException
|
||||
{
|
||||
if ($name !== 'exception') {
|
||||
trigger_error(sprintf('Undefined property: %s::$%s', self::class, $name), E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
return new ParserException(...$this->exceptionArgs);
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
47
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php
vendored
Normal file
47
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function count;
|
||||
use function implode;
|
||||
class MethodTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var bool */
|
||||
public $isStatic;
|
||||
/** @var TypeNode|null */
|
||||
public $returnType;
|
||||
/** @var string */
|
||||
public $methodName;
|
||||
/** @var TemplateTagValueNode[] */
|
||||
public $templateTypes;
|
||||
/** @var MethodTagValueParameterNode[] */
|
||||
public $parameters;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
/**
|
||||
* @param MethodTagValueParameterNode[] $parameters
|
||||
* @param TemplateTagValueNode[] $templateTypes
|
||||
*/
|
||||
public function __construct(bool $isStatic, ?TypeNode $returnType, string $methodName, array $parameters, string $description, array $templateTypes = [])
|
||||
{
|
||||
$this->isStatic = $isStatic;
|
||||
$this->returnType = $returnType;
|
||||
$this->methodName = $methodName;
|
||||
$this->parameters = $parameters;
|
||||
$this->description = $description;
|
||||
$this->templateTypes = $templateTypes;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$static = $this->isStatic ? 'static ' : '';
|
||||
$returnType = $this->returnType !== null ? "{$this->returnType} " : '';
|
||||
$parameters = implode(', ', $this->parameters);
|
||||
$description = $this->description !== '' ? " {$this->description}" : '';
|
||||
$templateTypes = count($this->templateTypes) > 0 ? '<' . implode(', ', $this->templateTypes) . '>' : '';
|
||||
return "{$static}{$returnType}{$this->methodName}{$templateTypes}({$parameters}){$description}";
|
||||
}
|
||||
}
|
39
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php
vendored
Normal file
39
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
class MethodTagValueParameterNode implements Node
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode|null */
|
||||
public $type;
|
||||
/** @var bool */
|
||||
public $isReference;
|
||||
/** @var bool */
|
||||
public $isVariadic;
|
||||
/** @var string */
|
||||
public $parameterName;
|
||||
/** @var ConstExprNode|null */
|
||||
public $defaultValue;
|
||||
public function __construct(?TypeNode $type, bool $isReference, bool $isVariadic, string $parameterName, ?ConstExprNode $defaultValue)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->isReference = $isReference;
|
||||
$this->isVariadic = $isVariadic;
|
||||
$this->parameterName = $parameterName;
|
||||
$this->defaultValue = $defaultValue;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$type = $this->type !== null ? "{$this->type} " : '';
|
||||
$isReference = $this->isReference ? '&' : '';
|
||||
$isVariadic = $this->isVariadic ? '...' : '';
|
||||
$default = $this->defaultValue !== null ? " = {$this->defaultValue}" : '';
|
||||
return "{$type}{$isReference}{$isVariadic}{$this->parameterName}{$default}";
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class MixinTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} {$this->description}");
|
||||
}
|
||||
}
|
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php
vendored
Normal file
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class ParamOutTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string */
|
||||
public $parameterName;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $parameterName, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->parameterName = $parameterName;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} {$this->parameterName} {$this->description}");
|
||||
}
|
||||
}
|
36
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php
vendored
Normal file
36
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class ParamTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var bool */
|
||||
public $isReference;
|
||||
/** @var bool */
|
||||
public $isVariadic;
|
||||
/** @var string */
|
||||
public $parameterName;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, bool $isVariadic, string $parameterName, string $description, bool $isReference = \false)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->isReference = $isReference;
|
||||
$this->isVariadic = $isVariadic;
|
||||
$this->parameterName = $parameterName;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$reference = $this->isReference ? '&' : '';
|
||||
$variadic = $this->isVariadic ? '...' : '';
|
||||
return trim("{$this->type} {$reference}{$variadic}{$this->parameterName} {$this->description}");
|
||||
}
|
||||
}
|
9
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php
vendored
Normal file
9
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
interface PhpDocChildNode extends Node
|
||||
{
|
||||
}
|
248
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php
vendored
Normal file
248
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function array_column;
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function implode;
|
||||
class PhpDocNode implements Node
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var PhpDocChildNode[] */
|
||||
public $children;
|
||||
/**
|
||||
* @param PhpDocChildNode[] $children
|
||||
*/
|
||||
public function __construct(array $children)
|
||||
{
|
||||
$this->children = $children;
|
||||
}
|
||||
/**
|
||||
* @return PhpDocTagNode[]
|
||||
*/
|
||||
public function getTags() : array
|
||||
{
|
||||
return array_filter($this->children, static function (PhpDocChildNode $child) : bool {
|
||||
return $child instanceof PhpDocTagNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return PhpDocTagNode[]
|
||||
*/
|
||||
public function getTagsByName(string $tagName) : array
|
||||
{
|
||||
return array_filter($this->getTags(), static function (PhpDocTagNode $tag) use($tagName) : bool {
|
||||
return $tag->name === $tagName;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return VarTagValueNode[]
|
||||
*/
|
||||
public function getVarTagValues(string $tagName = '@var') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof VarTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return ParamTagValueNode[]
|
||||
*/
|
||||
public function getParamTagValues(string $tagName = '@param') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof ParamTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return TypelessParamTagValueNode[]
|
||||
*/
|
||||
public function getTypelessParamTagValues(string $tagName = '@param') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof TypelessParamTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return TemplateTagValueNode[]
|
||||
*/
|
||||
public function getTemplateTagValues(string $tagName = '@template') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof TemplateTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return ExtendsTagValueNode[]
|
||||
*/
|
||||
public function getExtendsTagValues(string $tagName = '@extends') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof ExtendsTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return ImplementsTagValueNode[]
|
||||
*/
|
||||
public function getImplementsTagValues(string $tagName = '@implements') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof ImplementsTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return UsesTagValueNode[]
|
||||
*/
|
||||
public function getUsesTagValues(string $tagName = '@use') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof UsesTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return ReturnTagValueNode[]
|
||||
*/
|
||||
public function getReturnTagValues(string $tagName = '@return') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof ReturnTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return ThrowsTagValueNode[]
|
||||
*/
|
||||
public function getThrowsTagValues(string $tagName = '@throws') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof ThrowsTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return MixinTagValueNode[]
|
||||
*/
|
||||
public function getMixinTagValues(string $tagName = '@mixin') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof MixinTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return DeprecatedTagValueNode[]
|
||||
*/
|
||||
public function getDeprecatedTagValues() : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName('@deprecated'), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof DeprecatedTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return PropertyTagValueNode[]
|
||||
*/
|
||||
public function getPropertyTagValues(string $tagName = '@property') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof PropertyTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return PropertyTagValueNode[]
|
||||
*/
|
||||
public function getPropertyReadTagValues(string $tagName = '@property-read') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof PropertyTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return PropertyTagValueNode[]
|
||||
*/
|
||||
public function getPropertyWriteTagValues(string $tagName = '@property-write') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof PropertyTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return MethodTagValueNode[]
|
||||
*/
|
||||
public function getMethodTagValues(string $tagName = '@method') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof MethodTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return TypeAliasTagValueNode[]
|
||||
*/
|
||||
public function getTypeAliasTagValues(string $tagName = '@phpstan-type') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof TypeAliasTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return TypeAliasImportTagValueNode[]
|
||||
*/
|
||||
public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof TypeAliasImportTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return AssertTagValueNode[]
|
||||
*/
|
||||
public function getAssertTagValues(string $tagName = '@phpstan-assert') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof AssertTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return AssertTagPropertyValueNode[]
|
||||
*/
|
||||
public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof AssertTagPropertyValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return AssertTagMethodValueNode[]
|
||||
*/
|
||||
public function getAssertMethodTagValues(string $tagName = '@phpstan-assert') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof AssertTagMethodValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return SelfOutTagValueNode[]
|
||||
*/
|
||||
public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof SelfOutTagValueNode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return ParamOutTagValueNode[]
|
||||
*/
|
||||
public function getParamOutTypeTagValues(string $tagName = '@param-out') : array
|
||||
{
|
||||
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value) : bool {
|
||||
return $value instanceof ParamOutTagValueNode;
|
||||
});
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$children = array_map(static function (PhpDocChildNode $child) : string {
|
||||
$s = (string) $child;
|
||||
return $s === '' ? '' : ' ' . $s;
|
||||
}, $this->children);
|
||||
return "/**\n *" . implode("\n *", $children) . "\n */";
|
||||
}
|
||||
}
|
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php
vendored
Normal file
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode;
|
||||
use function trim;
|
||||
class PhpDocTagNode implements PhpDocChildNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var PhpDocTagValueNode */
|
||||
public $value;
|
||||
public function __construct(string $name, PhpDocTagValueNode $value)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->value instanceof DoctrineTagValueNode) {
|
||||
return (string) $this->value;
|
||||
}
|
||||
return trim("{$this->name} {$this->value}");
|
||||
}
|
||||
}
|
9
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php
vendored
Normal file
9
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
interface PhpDocTagValueNode extends Node
|
||||
{
|
||||
}
|
20
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php
vendored
Normal file
20
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class PhpDocTextNode implements PhpDocChildNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $text;
|
||||
public function __construct(string $text)
|
||||
{
|
||||
$this->text = $text;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
}
|
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php
vendored
Normal file
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class PropertyTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string */
|
||||
public $propertyName;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $propertyName, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->propertyName = $propertyName;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} {$this->propertyName} {$this->description}");
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class ReturnTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} {$this->description}");
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class SelfOutTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim($this->type . ' ' . $this->description);
|
||||
}
|
||||
}
|
33
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php
vendored
Normal file
33
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class TemplateTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var TypeNode|null */
|
||||
public $bound;
|
||||
/** @var TypeNode|null */
|
||||
public $default;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(string $name, ?TypeNode $bound, string $description, ?TypeNode $default = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->bound = $bound;
|
||||
$this->default = $default;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$bound = $this->bound !== null ? " of {$this->bound}" : '';
|
||||
$default = $this->default !== null ? " = {$this->default}" : '';
|
||||
return trim("{$this->name}{$bound}{$default} {$this->description}");
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class ThrowsTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} {$this->description}");
|
||||
}
|
||||
}
|
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php
vendored
Normal file
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use function trim;
|
||||
class TypeAliasImportTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $importedAlias;
|
||||
/** @var IdentifierTypeNode */
|
||||
public $importedFrom;
|
||||
/** @var string|null */
|
||||
public $importedAs;
|
||||
public function __construct(string $importedAlias, IdentifierTypeNode $importedFrom, ?string $importedAs)
|
||||
{
|
||||
$this->importedAlias = $importedAlias;
|
||||
$this->importedFrom = $importedFrom;
|
||||
$this->importedAs = $importedAs;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->importedAlias} from {$this->importedFrom}" . ($this->importedAs !== null ? " as {$this->importedAs}" : ''));
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class TypeAliasTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $alias;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
public function __construct(string $alias, TypeNode $type)
|
||||
{
|
||||
$this->alias = $alias;
|
||||
$this->type = $type;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->alias} {$this->type}");
|
||||
}
|
||||
}
|
32
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php
vendored
Normal file
32
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function trim;
|
||||
class TypelessParamTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var bool */
|
||||
public $isReference;
|
||||
/** @var bool */
|
||||
public $isVariadic;
|
||||
/** @var string */
|
||||
public $parameterName;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(bool $isVariadic, string $parameterName, string $description, bool $isReference = \false)
|
||||
{
|
||||
$this->isReference = $isReference;
|
||||
$this->isVariadic = $isVariadic;
|
||||
$this->parameterName = $parameterName;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$reference = $this->isReference ? '&' : '';
|
||||
$variadic = $this->isVariadic ? '...' : '';
|
||||
return trim("{$reference}{$variadic}{$this->parameterName} {$this->description}");
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
|
||||
use function trim;
|
||||
class UsesTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var GenericTypeNode */
|
||||
public $type;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(GenericTypeNode $type, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} {$this->description}");
|
||||
}
|
||||
}
|
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php
vendored
Normal file
28
dependencies/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use function trim;
|
||||
class VarTagValueNode implements PhpDocTagValueNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var string (may be empty) */
|
||||
public $variableName;
|
||||
/** @var string (may be empty) */
|
||||
public $description;
|
||||
public function __construct(TypeNode $type, string $variableName, string $description)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->variableName = $variableName;
|
||||
$this->description = $description;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return trim("{$this->type} " . trim("{$this->variableName} {$this->description}"));
|
||||
}
|
||||
}
|
35
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php
vendored
Normal file
35
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function sprintf;
|
||||
class ArrayShapeItemNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|null */
|
||||
public $keyName;
|
||||
/** @var bool */
|
||||
public $optional;
|
||||
/** @var TypeNode */
|
||||
public $valueType;
|
||||
/**
|
||||
* @param ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|null $keyName
|
||||
*/
|
||||
public function __construct($keyName, bool $optional, TypeNode $valueType)
|
||||
{
|
||||
$this->keyName = $keyName;
|
||||
$this->optional = $optional;
|
||||
$this->valueType = $valueType;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->keyName !== null) {
|
||||
return sprintf('%s%s: %s', (string) $this->keyName, $this->optional ? '?' : '', (string) $this->valueType);
|
||||
}
|
||||
return (string) $this->valueType;
|
||||
}
|
||||
}
|
37
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php
vendored
Normal file
37
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function implode;
|
||||
class ArrayShapeNode implements TypeNode
|
||||
{
|
||||
public const KIND_ARRAY = 'array';
|
||||
public const KIND_LIST = 'list';
|
||||
use NodeAttributes;
|
||||
/** @var ArrayShapeItemNode[] */
|
||||
public $items;
|
||||
/** @var bool */
|
||||
public $sealed;
|
||||
/** @var self::KIND_* */
|
||||
public $kind;
|
||||
/**
|
||||
* @param ArrayShapeItemNode[] $items
|
||||
* @param self::KIND_* $kind
|
||||
*/
|
||||
public function __construct(array $items, bool $sealed = \true, string $kind = self::KIND_ARRAY)
|
||||
{
|
||||
$this->items = $items;
|
||||
$this->sealed = $sealed;
|
||||
$this->kind = $kind;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$items = $this->items;
|
||||
if (!$this->sealed) {
|
||||
$items[] = '...';
|
||||
}
|
||||
return $this->kind . '{' . implode(', ', $items) . '}';
|
||||
}
|
||||
}
|
23
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php
vendored
Normal file
23
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ArrayTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
public function __construct(TypeNode $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->type instanceof CallableTypeNode || $this->type instanceof ConstTypeNode || $this->type instanceof NullableTypeNode) {
|
||||
return '(' . $this->type . ')[]';
|
||||
}
|
||||
return $this->type . '[]';
|
||||
}
|
||||
}
|
35
dependencies/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php
vendored
Normal file
35
dependencies/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function implode;
|
||||
class CallableTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var IdentifierTypeNode */
|
||||
public $identifier;
|
||||
/** @var CallableTypeParameterNode[] */
|
||||
public $parameters;
|
||||
/** @var TypeNode */
|
||||
public $returnType;
|
||||
/**
|
||||
* @param CallableTypeParameterNode[] $parameters
|
||||
*/
|
||||
public function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
$this->parameters = $parameters;
|
||||
$this->returnType = $returnType;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$returnType = $this->returnType;
|
||||
if ($returnType instanceof self) {
|
||||
$returnType = "({$returnType})";
|
||||
}
|
||||
$parameters = implode(', ', $this->parameters);
|
||||
return "{$this->identifier}({$parameters}): {$returnType}";
|
||||
}
|
||||
}
|
38
dependencies/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php
vendored
Normal file
38
dependencies/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function trim;
|
||||
class CallableTypeParameterNode implements Node
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var bool */
|
||||
public $isReference;
|
||||
/** @var bool */
|
||||
public $isVariadic;
|
||||
/** @var string (may be empty) */
|
||||
public $parameterName;
|
||||
/** @var bool */
|
||||
public $isOptional;
|
||||
public function __construct(TypeNode $type, bool $isReference, bool $isVariadic, string $parameterName, bool $isOptional)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->isReference = $isReference;
|
||||
$this->isVariadic = $isVariadic;
|
||||
$this->parameterName = $parameterName;
|
||||
$this->isOptional = $isOptional;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$type = "{$this->type} ";
|
||||
$isReference = $this->isReference ? '&' : '';
|
||||
$isVariadic = $this->isVariadic ? '...' : '';
|
||||
$isOptional = $this->isOptional ? '=' : '';
|
||||
return trim("{$type}{$isReference}{$isVariadic}{$this->parameterName}") . $isOptional;
|
||||
}
|
||||
}
|
33
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php
vendored
Normal file
33
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function sprintf;
|
||||
class ConditionalTypeForParameterNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $parameterName;
|
||||
/** @var TypeNode */
|
||||
public $targetType;
|
||||
/** @var TypeNode */
|
||||
public $if;
|
||||
/** @var TypeNode */
|
||||
public $else;
|
||||
/** @var bool */
|
||||
public $negated;
|
||||
public function __construct(string $parameterName, TypeNode $targetType, TypeNode $if, TypeNode $else, bool $negated)
|
||||
{
|
||||
$this->parameterName = $parameterName;
|
||||
$this->targetType = $targetType;
|
||||
$this->if = $if;
|
||||
$this->else = $else;
|
||||
$this->negated = $negated;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return sprintf('(%s %s %s ? %s : %s)', $this->parameterName, $this->negated ? 'is not' : 'is', $this->targetType, $this->if, $this->else);
|
||||
}
|
||||
}
|
33
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php
vendored
Normal file
33
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function sprintf;
|
||||
class ConditionalTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $subjectType;
|
||||
/** @var TypeNode */
|
||||
public $targetType;
|
||||
/** @var TypeNode */
|
||||
public $if;
|
||||
/** @var TypeNode */
|
||||
public $else;
|
||||
/** @var bool */
|
||||
public $negated;
|
||||
public function __construct(TypeNode $subjectType, TypeNode $targetType, TypeNode $if, TypeNode $else, bool $negated)
|
||||
{
|
||||
$this->subjectType = $subjectType;
|
||||
$this->targetType = $targetType;
|
||||
$this->if = $if;
|
||||
$this->else = $else;
|
||||
$this->negated = $negated;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return sprintf('(%s %s %s ? %s : %s)', $this->subjectType, $this->negated ? 'is not' : 'is', $this->targetType, $this->if, $this->else);
|
||||
}
|
||||
}
|
21
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php
vendored
Normal file
21
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ConstTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var ConstExprNode */
|
||||
public $constExpr;
|
||||
public function __construct(ConstExprNode $constExpr)
|
||||
{
|
||||
$this->constExpr = $constExpr;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->constExpr->__toString();
|
||||
}
|
||||
}
|
47
dependencies/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php
vendored
Normal file
47
dependencies/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function implode;
|
||||
use function sprintf;
|
||||
class GenericTypeNode implements TypeNode
|
||||
{
|
||||
public const VARIANCE_INVARIANT = 'invariant';
|
||||
public const VARIANCE_COVARIANT = 'covariant';
|
||||
public const VARIANCE_CONTRAVARIANT = 'contravariant';
|
||||
public const VARIANCE_BIVARIANT = 'bivariant';
|
||||
use NodeAttributes;
|
||||
/** @var IdentifierTypeNode */
|
||||
public $type;
|
||||
/** @var TypeNode[] */
|
||||
public $genericTypes;
|
||||
/** @var (self::VARIANCE_*)[] */
|
||||
public $variances;
|
||||
/**
|
||||
* @param TypeNode[] $genericTypes
|
||||
* @param (self::VARIANCE_*)[] $variances
|
||||
*/
|
||||
public function __construct(IdentifierTypeNode $type, array $genericTypes, array $variances = [])
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->genericTypes = $genericTypes;
|
||||
$this->variances = $variances;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$genericTypes = [];
|
||||
foreach ($this->genericTypes as $index => $type) {
|
||||
$variance = $this->variances[$index] ?? self::VARIANCE_INVARIANT;
|
||||
if ($variance === self::VARIANCE_INVARIANT) {
|
||||
$genericTypes[] = (string) $type;
|
||||
} elseif ($variance === self::VARIANCE_BIVARIANT) {
|
||||
$genericTypes[] = '*';
|
||||
} else {
|
||||
$genericTypes[] = sprintf('%s %s', $variance, $type);
|
||||
}
|
||||
}
|
||||
return $this->type . '<' . implode(', ', $genericTypes) . '>';
|
||||
}
|
||||
}
|
20
dependencies/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php
vendored
Normal file
20
dependencies/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class IdentifierTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var string */
|
||||
public $name;
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
30
dependencies/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php
vendored
Normal file
30
dependencies/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function array_map;
|
||||
use function implode;
|
||||
class IntersectionTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode[] */
|
||||
public $types;
|
||||
/**
|
||||
* @param TypeNode[] $types
|
||||
*/
|
||||
public function __construct(array $types)
|
||||
{
|
||||
$this->types = $types;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return '(' . implode(' & ', array_map(static function (TypeNode $type) : string {
|
||||
if ($type instanceof NullableTypeNode) {
|
||||
return '(' . $type . ')';
|
||||
}
|
||||
return (string) $type;
|
||||
}, $this->types)) . ')';
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser\ParserException;
|
||||
class InvalidTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var mixed[] */
|
||||
private $exceptionArgs;
|
||||
public function __construct(ParserException $exception)
|
||||
{
|
||||
$this->exceptionArgs = [$exception->getCurrentTokenValue(), $exception->getCurrentTokenType(), $exception->getCurrentOffset(), $exception->getExpectedTokenType(), $exception->getExpectedTokenValue(), $exception->getCurrentTokenLine()];
|
||||
}
|
||||
public function getException() : ParserException
|
||||
{
|
||||
return new ParserException(...$this->exceptionArgs);
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return '*Invalid type*';
|
||||
}
|
||||
}
|
20
dependencies/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php
vendored
Normal file
20
dependencies/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class NullableTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
public function __construct(TypeNode $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return '?' . $this->type;
|
||||
}
|
||||
}
|
34
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php
vendored
Normal file
34
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function sprintf;
|
||||
class ObjectShapeItemNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var ConstExprStringNode|IdentifierTypeNode */
|
||||
public $keyName;
|
||||
/** @var bool */
|
||||
public $optional;
|
||||
/** @var TypeNode */
|
||||
public $valueType;
|
||||
/**
|
||||
* @param ConstExprStringNode|IdentifierTypeNode $keyName
|
||||
*/
|
||||
public function __construct($keyName, bool $optional, TypeNode $valueType)
|
||||
{
|
||||
$this->keyName = $keyName;
|
||||
$this->optional = $optional;
|
||||
$this->valueType = $valueType;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->keyName !== null) {
|
||||
return sprintf('%s%s: %s', (string) $this->keyName, $this->optional ? '?' : '', (string) $this->valueType);
|
||||
}
|
||||
return (string) $this->valueType;
|
||||
}
|
||||
}
|
25
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php
vendored
Normal file
25
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function implode;
|
||||
class ObjectShapeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var ObjectShapeItemNode[] */
|
||||
public $items;
|
||||
/**
|
||||
* @param ObjectShapeItemNode[] $items
|
||||
*/
|
||||
public function __construct(array $items)
|
||||
{
|
||||
$this->items = $items;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
$items = $this->items;
|
||||
return 'object{' . implode(', ', $items) . '}';
|
||||
}
|
||||
}
|
26
dependencies/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php
vendored
Normal file
26
dependencies/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class OffsetAccessTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode */
|
||||
public $type;
|
||||
/** @var TypeNode */
|
||||
public $offset;
|
||||
public function __construct(TypeNode $type, TypeNode $offset)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->offset = $offset;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->type instanceof CallableTypeNode || $this->type instanceof ConstTypeNode || $this->type instanceof NullableTypeNode) {
|
||||
return '(' . $this->type . ')[' . $this->offset . ']';
|
||||
}
|
||||
return $this->type . '[' . $this->offset . ']';
|
||||
}
|
||||
}
|
14
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php
vendored
Normal file
14
dependencies/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
class ThisTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
public function __toString() : string
|
||||
{
|
||||
return '$this';
|
||||
}
|
||||
}
|
9
dependencies/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php
vendored
Normal file
9
dependencies/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
interface TypeNode extends Node
|
||||
{
|
||||
}
|
30
dependencies/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php
vendored
Normal file
30
dependencies/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\NodeAttributes;
|
||||
use function array_map;
|
||||
use function implode;
|
||||
class UnionTypeNode implements TypeNode
|
||||
{
|
||||
use NodeAttributes;
|
||||
/** @var TypeNode[] */
|
||||
public $types;
|
||||
/**
|
||||
* @param TypeNode[] $types
|
||||
*/
|
||||
public function __construct(array $types)
|
||||
{
|
||||
$this->types = $types;
|
||||
}
|
||||
public function __toString() : string
|
||||
{
|
||||
return '(' . implode(' | ', array_map(static function (TypeNode $type) : string {
|
||||
if ($type instanceof NullableTypeNode) {
|
||||
return '(' . $type . ')';
|
||||
}
|
||||
return (string) $type;
|
||||
}, $this->types)) . ')';
|
||||
}
|
||||
}
|
134
dependencies/phpstan/phpdoc-parser/src/Lexer/Lexer.php
vendored
Normal file
134
dependencies/phpstan/phpdoc-parser/src/Lexer/Lexer.php
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Lexer;
|
||||
|
||||
use function implode;
|
||||
use function preg_match_all;
|
||||
use const PREG_SET_ORDER;
|
||||
/**
|
||||
* Implementation based on Nette Tokenizer (New BSD License; https://github.com/nette/tokenizer)
|
||||
*/
|
||||
class Lexer
|
||||
{
|
||||
public const TOKEN_REFERENCE = 0;
|
||||
public const TOKEN_UNION = 1;
|
||||
public const TOKEN_INTERSECTION = 2;
|
||||
public const TOKEN_NULLABLE = 3;
|
||||
public const TOKEN_OPEN_PARENTHESES = 4;
|
||||
public const TOKEN_CLOSE_PARENTHESES = 5;
|
||||
public const TOKEN_OPEN_ANGLE_BRACKET = 6;
|
||||
public const TOKEN_CLOSE_ANGLE_BRACKET = 7;
|
||||
public const TOKEN_OPEN_SQUARE_BRACKET = 8;
|
||||
public const TOKEN_CLOSE_SQUARE_BRACKET = 9;
|
||||
public const TOKEN_COMMA = 10;
|
||||
public const TOKEN_VARIADIC = 11;
|
||||
public const TOKEN_DOUBLE_COLON = 12;
|
||||
public const TOKEN_DOUBLE_ARROW = 13;
|
||||
public const TOKEN_EQUAL = 14;
|
||||
public const TOKEN_OPEN_PHPDOC = 15;
|
||||
public const TOKEN_CLOSE_PHPDOC = 16;
|
||||
public const TOKEN_PHPDOC_TAG = 17;
|
||||
public const TOKEN_DOCTRINE_TAG = 18;
|
||||
public const TOKEN_FLOAT = 19;
|
||||
public const TOKEN_INTEGER = 20;
|
||||
public const TOKEN_SINGLE_QUOTED_STRING = 21;
|
||||
public const TOKEN_DOUBLE_QUOTED_STRING = 22;
|
||||
public const TOKEN_DOCTRINE_ANNOTATION_STRING = 23;
|
||||
public const TOKEN_IDENTIFIER = 24;
|
||||
public const TOKEN_THIS_VARIABLE = 25;
|
||||
public const TOKEN_VARIABLE = 26;
|
||||
public const TOKEN_HORIZONTAL_WS = 27;
|
||||
public const TOKEN_PHPDOC_EOL = 28;
|
||||
public const TOKEN_OTHER = 29;
|
||||
public const TOKEN_END = 30;
|
||||
public const TOKEN_COLON = 31;
|
||||
public const TOKEN_WILDCARD = 32;
|
||||
public const TOKEN_OPEN_CURLY_BRACKET = 33;
|
||||
public const TOKEN_CLOSE_CURLY_BRACKET = 34;
|
||||
public const TOKEN_NEGATED = 35;
|
||||
public const TOKEN_ARROW = 36;
|
||||
public const TOKEN_LABELS = [self::TOKEN_REFERENCE => '\'&\'', self::TOKEN_UNION => '\'|\'', self::TOKEN_INTERSECTION => '\'&\'', self::TOKEN_NULLABLE => '\'?\'', self::TOKEN_NEGATED => '\'!\'', self::TOKEN_OPEN_PARENTHESES => '\'(\'', self::TOKEN_CLOSE_PARENTHESES => '\')\'', self::TOKEN_OPEN_ANGLE_BRACKET => '\'<\'', self::TOKEN_CLOSE_ANGLE_BRACKET => '\'>\'', self::TOKEN_OPEN_SQUARE_BRACKET => '\'[\'', self::TOKEN_CLOSE_SQUARE_BRACKET => '\']\'', self::TOKEN_OPEN_CURLY_BRACKET => '\'{\'', self::TOKEN_CLOSE_CURLY_BRACKET => '\'}\'', self::TOKEN_COMMA => '\',\'', self::TOKEN_COLON => '\':\'', self::TOKEN_VARIADIC => '\'...\'', self::TOKEN_DOUBLE_COLON => '\'::\'', self::TOKEN_DOUBLE_ARROW => '\'=>\'', self::TOKEN_ARROW => '\'->\'', self::TOKEN_EQUAL => '\'=\'', self::TOKEN_OPEN_PHPDOC => '\'/**\'', self::TOKEN_CLOSE_PHPDOC => '\'*/\'', self::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG', self::TOKEN_DOCTRINE_TAG => 'TOKEN_DOCTRINE_TAG', self::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL', self::TOKEN_FLOAT => 'TOKEN_FLOAT', self::TOKEN_INTEGER => 'TOKEN_INTEGER', self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING', self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING', self::TOKEN_DOCTRINE_ANNOTATION_STRING => 'TOKEN_DOCTRINE_ANNOTATION_STRING', self::TOKEN_IDENTIFIER => 'type', self::TOKEN_THIS_VARIABLE => '\'$this\'', self::TOKEN_VARIABLE => 'variable', self::TOKEN_HORIZONTAL_WS => 'TOKEN_HORIZONTAL_WS', self::TOKEN_OTHER => 'TOKEN_OTHER', self::TOKEN_END => 'TOKEN_END', self::TOKEN_WILDCARD => '*'];
|
||||
public const VALUE_OFFSET = 0;
|
||||
public const TYPE_OFFSET = 1;
|
||||
public const LINE_OFFSET = 2;
|
||||
/** @var bool */
|
||||
private $parseDoctrineAnnotations;
|
||||
/** @var string|null */
|
||||
private $regexp;
|
||||
public function __construct(bool $parseDoctrineAnnotations = \false)
|
||||
{
|
||||
$this->parseDoctrineAnnotations = $parseDoctrineAnnotations;
|
||||
}
|
||||
/**
|
||||
* @return list<array{string, int, int}>
|
||||
*/
|
||||
public function tokenize(string $s) : array
|
||||
{
|
||||
if ($this->regexp === null) {
|
||||
$this->regexp = $this->generateRegexp();
|
||||
}
|
||||
preg_match_all($this->regexp, $s, $matches, PREG_SET_ORDER);
|
||||
$tokens = [];
|
||||
$line = 1;
|
||||
foreach ($matches as $match) {
|
||||
$type = (int) $match['MARK'];
|
||||
$tokens[] = [$match[0], $type, $line];
|
||||
if ($type !== self::TOKEN_PHPDOC_EOL) {
|
||||
continue;
|
||||
}
|
||||
$line++;
|
||||
}
|
||||
$tokens[] = ['', self::TOKEN_END, $line];
|
||||
return $tokens;
|
||||
}
|
||||
private function generateRegexp() : string
|
||||
{
|
||||
$patterns = [
|
||||
self::TOKEN_HORIZONTAL_WS => '[\\x09\\x20]++',
|
||||
self::TOKEN_IDENTIFIER => '(?:[\\\\]?+[a-z_\\x80-\\xFF][0-9a-z_\\x80-\\xFF-]*+)++',
|
||||
self::TOKEN_THIS_VARIABLE => '\\$this(?![0-9a-z_\\x80-\\xFF])',
|
||||
self::TOKEN_VARIABLE => '\\$[a-z_\\x80-\\xFF][0-9a-z_\\x80-\\xFF]*+',
|
||||
// '&' followed by TOKEN_VARIADIC, TOKEN_VARIABLE, TOKEN_EQUAL, TOKEN_EQUAL or TOKEN_CLOSE_PARENTHESES
|
||||
self::TOKEN_REFERENCE => '&(?=\\s*+(?:[.,=)]|(?:\\$(?!this(?![0-9a-z_\\x80-\\xFF])))))',
|
||||
self::TOKEN_UNION => '\\|',
|
||||
self::TOKEN_INTERSECTION => '&',
|
||||
self::TOKEN_NULLABLE => '\\?',
|
||||
self::TOKEN_NEGATED => '!',
|
||||
self::TOKEN_OPEN_PARENTHESES => '\\(',
|
||||
self::TOKEN_CLOSE_PARENTHESES => '\\)',
|
||||
self::TOKEN_OPEN_ANGLE_BRACKET => '<',
|
||||
self::TOKEN_CLOSE_ANGLE_BRACKET => '>',
|
||||
self::TOKEN_OPEN_SQUARE_BRACKET => '\\[',
|
||||
self::TOKEN_CLOSE_SQUARE_BRACKET => '\\]',
|
||||
self::TOKEN_OPEN_CURLY_BRACKET => '\\{',
|
||||
self::TOKEN_CLOSE_CURLY_BRACKET => '\\}',
|
||||
self::TOKEN_COMMA => ',',
|
||||
self::TOKEN_VARIADIC => '\\.\\.\\.',
|
||||
self::TOKEN_DOUBLE_COLON => '::',
|
||||
self::TOKEN_DOUBLE_ARROW => '=>',
|
||||
self::TOKEN_ARROW => '->',
|
||||
self::TOKEN_EQUAL => '=',
|
||||
self::TOKEN_COLON => ':',
|
||||
self::TOKEN_OPEN_PHPDOC => '/\\*\\*(?=\\s)\\x20?+',
|
||||
self::TOKEN_CLOSE_PHPDOC => '\\*/',
|
||||
self::TOKEN_PHPDOC_TAG => '@(?:[a-z][a-z0-9-\\\\]+:)?[a-z][a-z0-9-\\\\]*+',
|
||||
self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/)\\x20?+)?',
|
||||
self::TOKEN_FLOAT => '[+\\-]?(?:(?:[0-9]++(_[0-9]++)*\\.[0-9]*+(_[0-9]++)*(?:e[+\\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e[+\\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]++(_[0-9]++)*e[+\\-]?[0-9]++(_[0-9]++)*))',
|
||||
self::TOKEN_INTEGER => '[+\\-]?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))',
|
||||
self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\])*+\'',
|
||||
self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\])*+"',
|
||||
self::TOKEN_WILDCARD => '\\*',
|
||||
];
|
||||
if ($this->parseDoctrineAnnotations) {
|
||||
$patterns[self::TOKEN_DOCTRINE_TAG] = '@[a-z_\\\\][a-z0-9_\\:\\\\]*[a-z_][a-z0-9_]*';
|
||||
$patterns[self::TOKEN_DOCTRINE_ANNOTATION_STRING] = '"(?:""|[^"])*+"';
|
||||
}
|
||||
// anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL
|
||||
$patterns[self::TOKEN_OTHER] = '(?:(?!\\*/)[^\\s])++';
|
||||
foreach ($patterns as $type => &$pattern) {
|
||||
$pattern = '(?:' . $pattern . ')(*MARK:' . $type . ')';
|
||||
}
|
||||
return '~' . implode('|', $patterns) . '~Asi';
|
||||
}
|
||||
}
|
188
dependencies/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php
vendored
Normal file
188
dependencies/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser;
|
||||
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Lexer\Lexer;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
class ConstExprParser
|
||||
{
|
||||
/** @var bool */
|
||||
private $unescapeStrings;
|
||||
/** @var bool */
|
||||
private $quoteAwareConstExprString;
|
||||
/** @var bool */
|
||||
private $useLinesAttributes;
|
||||
/** @var bool */
|
||||
private $useIndexAttributes;
|
||||
/** @var bool */
|
||||
private $parseDoctrineStrings;
|
||||
/**
|
||||
* @param array{lines?: bool, indexes?: bool} $usedAttributes
|
||||
*/
|
||||
public function __construct(bool $unescapeStrings = \false, bool $quoteAwareConstExprString = \false, array $usedAttributes = [])
|
||||
{
|
||||
$this->unescapeStrings = $unescapeStrings;
|
||||
$this->quoteAwareConstExprString = $quoteAwareConstExprString;
|
||||
$this->useLinesAttributes = $usedAttributes['lines'] ?? \false;
|
||||
$this->useIndexAttributes = $usedAttributes['indexes'] ?? \false;
|
||||
$this->parseDoctrineStrings = \false;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function toDoctrine() : self
|
||||
{
|
||||
$self = new self($this->unescapeStrings, $this->quoteAwareConstExprString, ['lines' => $this->useLinesAttributes, 'indexes' => $this->useIndexAttributes]);
|
||||
$self->parseDoctrineStrings = \true;
|
||||
return $self;
|
||||
}
|
||||
public function parse(TokenIterator $tokens, bool $trimStrings = \false) : Ast\ConstExpr\ConstExprNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_FLOAT)) {
|
||||
$value = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprFloatNode(str_replace('_', '', $value)), $startLine, $startIndex);
|
||||
}
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {
|
||||
$value = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $value)), $startLine, $startIndex);
|
||||
}
|
||||
if ($this->parseDoctrineStrings && $tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
|
||||
$value = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($value)), $startLine, $startIndex);
|
||||
}
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
|
||||
if ($this->parseDoctrineStrings) {
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
|
||||
throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_DOUBLE_QUOTED_STRING, null, $tokens->currentTokenLine());
|
||||
}
|
||||
$value = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
return $this->enrichWithAttributes($tokens, $this->parseDoctrineString($value, $tokens), $startLine, $startIndex);
|
||||
}
|
||||
$value = $tokens->currentTokenValue();
|
||||
$type = $tokens->currentTokenType();
|
||||
if ($trimStrings) {
|
||||
if ($this->unescapeStrings) {
|
||||
$value = StringUnescaper::unescapeString($value);
|
||||
} else {
|
||||
$value = substr($value, 1, -1);
|
||||
}
|
||||
}
|
||||
$tokens->next();
|
||||
if ($this->quoteAwareConstExprString) {
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\QuoteAwareConstExprStringNode($value, $type === Lexer::TOKEN_SINGLE_QUOTED_STRING ? Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED : Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED), $startLine, $startIndex);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprStringNode($value), $startLine, $startIndex);
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||
$identifier = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
switch (strtolower($identifier)) {
|
||||
case 'true':
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprTrueNode(), $startLine, $startIndex);
|
||||
case 'false':
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprFalseNode(), $startLine, $startIndex);
|
||||
case 'null':
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprNullNode(), $startLine, $startIndex);
|
||||
case 'array':
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
|
||||
return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES, $startIndex);
|
||||
}
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
|
||||
$classConstantName = '';
|
||||
$lastType = null;
|
||||
while (\true) {
|
||||
if ($lastType !== Lexer::TOKEN_IDENTIFIER && $tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) {
|
||||
$classConstantName .= $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
$lastType = Lexer::TOKEN_IDENTIFIER;
|
||||
continue;
|
||||
}
|
||||
if ($lastType !== Lexer::TOKEN_WILDCARD && $tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) {
|
||||
$classConstantName .= '*';
|
||||
$lastType = Lexer::TOKEN_WILDCARD;
|
||||
if ($tokens->getSkippedHorizontalWhiteSpaceIfAny() !== '') {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($lastType === null) {
|
||||
// trigger parse error if nothing valid was consumed
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_WILDCARD);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName), $startLine, $startIndex);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstFetchNode('', $identifier), $startLine, $startIndex);
|
||||
} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_SQUARE_BRACKET, $startIndex);
|
||||
}
|
||||
throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_IDENTIFIER, null, $tokens->currentTokenLine());
|
||||
}
|
||||
private function parseArray(TokenIterator $tokens, int $endToken, int $startIndex) : Ast\ConstExpr\ConstExprArrayNode
|
||||
{
|
||||
$items = [];
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
if (!$tokens->tryConsumeTokenType($endToken)) {
|
||||
do {
|
||||
$items[] = $this->parseArrayItem($tokens);
|
||||
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA) && !$tokens->isCurrentTokenType($endToken));
|
||||
$tokens->consumeTokenType($endToken);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprArrayNode($items), $startLine, $startIndex);
|
||||
}
|
||||
/**
|
||||
* This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting
|
||||
* to the next token.
|
||||
*/
|
||||
public function parseDoctrineString(string $text, TokenIterator $tokens) : Ast\ConstExpr\DoctrineConstExprStringNode
|
||||
{
|
||||
// Because of how Lexer works, a valid Doctrine string
|
||||
// can consist of a sequence of TOKEN_DOUBLE_QUOTED_STRING and TOKEN_DOCTRINE_ANNOTATION_STRING
|
||||
while ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING, Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
|
||||
$text .= $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
}
|
||||
return new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($text));
|
||||
}
|
||||
private function parseArrayItem(TokenIterator $tokens) : Ast\ConstExpr\ConstExprArrayItemNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$expr = $this->parse($tokens);
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_ARROW)) {
|
||||
$key = $expr;
|
||||
$value = $this->parse($tokens);
|
||||
} else {
|
||||
$key = null;
|
||||
$value = $expr;
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprArrayItemNode($key, $value), $startLine, $startIndex);
|
||||
}
|
||||
/**
|
||||
* @template T of Ast\ConstExpr\ConstExprNode
|
||||
* @param T $node
|
||||
* @return T
|
||||
*/
|
||||
private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex) : Ast\ConstExpr\ConstExprNode
|
||||
{
|
||||
if ($this->useLinesAttributes) {
|
||||
$node->setAttribute(Ast\Attribute::START_LINE, $startLine);
|
||||
$node->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
|
||||
}
|
||||
if ($this->useIndexAttributes) {
|
||||
$node->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
|
||||
$node->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
}
|
68
dependencies/phpstan/phpdoc-parser/src/Parser/ParserException.php
vendored
Normal file
68
dependencies/phpstan/phpdoc-parser/src/Parser/ParserException.php
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser;
|
||||
|
||||
use Exception;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Lexer\Lexer;
|
||||
use function assert;
|
||||
use function json_encode;
|
||||
use function sprintf;
|
||||
use const JSON_INVALID_UTF8_SUBSTITUTE;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
use const JSON_UNESCAPED_UNICODE;
|
||||
class ParserException extends Exception
|
||||
{
|
||||
/** @var string */
|
||||
private $currentTokenValue;
|
||||
/** @var int */
|
||||
private $currentTokenType;
|
||||
/** @var int */
|
||||
private $currentOffset;
|
||||
/** @var int */
|
||||
private $expectedTokenType;
|
||||
/** @var string|null */
|
||||
private $expectedTokenValue;
|
||||
/** @var int|null */
|
||||
private $currentTokenLine;
|
||||
public function __construct(string $currentTokenValue, int $currentTokenType, int $currentOffset, int $expectedTokenType, ?string $expectedTokenValue = null, ?int $currentTokenLine = null)
|
||||
{
|
||||
$this->currentTokenValue = $currentTokenValue;
|
||||
$this->currentTokenType = $currentTokenType;
|
||||
$this->currentOffset = $currentOffset;
|
||||
$this->expectedTokenType = $expectedTokenType;
|
||||
$this->expectedTokenValue = $expectedTokenValue;
|
||||
$this->currentTokenLine = $currentTokenLine;
|
||||
parent::__construct(sprintf('Unexpected token %s, expected %s%s at offset %d%s', $this->formatValue($currentTokenValue), Lexer::TOKEN_LABELS[$expectedTokenType], $expectedTokenValue !== null ? sprintf(' (%s)', $this->formatValue($expectedTokenValue)) : '', $currentOffset, $currentTokenLine === null ? '' : sprintf(' on line %d', $currentTokenLine)));
|
||||
}
|
||||
public function getCurrentTokenValue() : string
|
||||
{
|
||||
return $this->currentTokenValue;
|
||||
}
|
||||
public function getCurrentTokenType() : int
|
||||
{
|
||||
return $this->currentTokenType;
|
||||
}
|
||||
public function getCurrentOffset() : int
|
||||
{
|
||||
return $this->currentOffset;
|
||||
}
|
||||
public function getExpectedTokenType() : int
|
||||
{
|
||||
return $this->expectedTokenType;
|
||||
}
|
||||
public function getExpectedTokenValue() : ?string
|
||||
{
|
||||
return $this->expectedTokenValue;
|
||||
}
|
||||
public function getCurrentTokenLine() : ?int
|
||||
{
|
||||
return $this->currentTokenLine;
|
||||
}
|
||||
private function formatValue(string $value) : string
|
||||
{
|
||||
$json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE);
|
||||
assert($json !== \false);
|
||||
return $json;
|
||||
}
|
||||
}
|
854
dependencies/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php
vendored
Normal file
854
dependencies/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php
vendored
Normal file
@ -0,0 +1,854 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser;
|
||||
|
||||
use LogicException;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Lexer\Lexer;
|
||||
use WP_Ultimo\Dependencies\PHPStan\ShouldNotHappenException;
|
||||
use function array_key_exists;
|
||||
use function array_values;
|
||||
use function count;
|
||||
use function rtrim;
|
||||
use function str_replace;
|
||||
use function trim;
|
||||
/**
|
||||
* @phpstan-import-type ValueType from Doctrine\DoctrineArgument as DoctrineValueType
|
||||
*/
|
||||
class PhpDocParser
|
||||
{
|
||||
private const DISALLOWED_DESCRIPTION_START_TOKENS = [Lexer::TOKEN_UNION, Lexer::TOKEN_INTERSECTION];
|
||||
/** @var TypeParser */
|
||||
private $typeParser;
|
||||
/** @var ConstExprParser */
|
||||
private $constantExprParser;
|
||||
/** @var ConstExprParser */
|
||||
private $doctrineConstantExprParser;
|
||||
/** @var bool */
|
||||
private $requireWhitespaceBeforeDescription;
|
||||
/** @var bool */
|
||||
private $preserveTypeAliasesWithInvalidTypes;
|
||||
/** @var bool */
|
||||
private $parseDoctrineAnnotations;
|
||||
/** @var bool */
|
||||
private $useLinesAttributes;
|
||||
/** @var bool */
|
||||
private $useIndexAttributes;
|
||||
/** @var bool */
|
||||
private $textBetweenTagsBelongsToDescription;
|
||||
/**
|
||||
* @param array{lines?: bool, indexes?: bool} $usedAttributes
|
||||
*/
|
||||
public function __construct(TypeParser $typeParser, ConstExprParser $constantExprParser, bool $requireWhitespaceBeforeDescription = \false, bool $preserveTypeAliasesWithInvalidTypes = \false, array $usedAttributes = [], bool $parseDoctrineAnnotations = \false, bool $textBetweenTagsBelongsToDescription = \false)
|
||||
{
|
||||
$this->typeParser = $typeParser;
|
||||
$this->constantExprParser = $constantExprParser;
|
||||
$this->doctrineConstantExprParser = $constantExprParser->toDoctrine();
|
||||
$this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription;
|
||||
$this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes;
|
||||
$this->parseDoctrineAnnotations = $parseDoctrineAnnotations;
|
||||
$this->useLinesAttributes = $usedAttributes['lines'] ?? \false;
|
||||
$this->useIndexAttributes = $usedAttributes['indexes'] ?? \false;
|
||||
$this->textBetweenTagsBelongsToDescription = $textBetweenTagsBelongsToDescription;
|
||||
}
|
||||
public function parse(TokenIterator $tokens) : Ast\PhpDoc\PhpDocNode
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PHPDOC);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$children = [];
|
||||
if ($this->parseDoctrineAnnotations) {
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
|
||||
$lastChild = $this->parseChild($tokens);
|
||||
$children[] = $lastChild;
|
||||
while (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
|
||||
if ($lastChild instanceof Ast\PhpDoc\PhpDocTagNode && ($lastChild->value instanceof Doctrine\DoctrineTagValueNode || $lastChild->value instanceof Ast\PhpDoc\GenericTagValueNode)) {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
|
||||
break;
|
||||
}
|
||||
$lastChild = $this->parseChild($tokens);
|
||||
$children[] = $lastChild;
|
||||
continue;
|
||||
}
|
||||
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
|
||||
break;
|
||||
}
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
|
||||
break;
|
||||
}
|
||||
$lastChild = $this->parseChild($tokens);
|
||||
$children[] = $lastChild;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
|
||||
$children[] = $this->parseChild($tokens);
|
||||
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
|
||||
$children[] = $this->parseChild($tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PHPDOC);
|
||||
} catch (ParserException $e) {
|
||||
$name = '';
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if (count($children) > 0) {
|
||||
$lastChild = $children[count($children) - 1];
|
||||
if ($lastChild instanceof Ast\PhpDoc\PhpDocTagNode) {
|
||||
$name = $lastChild->name;
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
}
|
||||
}
|
||||
$tag = new Ast\PhpDoc\PhpDocTagNode($name, $this->enrichWithAttributes($tokens, new Ast\PhpDoc\InvalidTagValueNode($e->getMessage(), $e), $startLine, $startIndex));
|
||||
$tokens->forwardToTheEnd();
|
||||
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode(array_values($children)), 1, 0);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseChild(TokenIterator $tokens) : Ast\PhpDoc\PhpDocChildNode
|
||||
{
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
return $this->enrichWithAttributes($tokens, $this->parseTag($tokens), $startLine, $startIndex);
|
||||
}
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_TAG)) {
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$tag = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
$tagStartLine = $tokens->currentTokenLine();
|
||||
$tagStartIndex = $tokens->currentTokenIndex();
|
||||
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocTagNode($tag, $this->enrichWithAttributes($tokens, $this->parseDoctrineTagValue($tokens, $tag), $tagStartLine, $tagStartIndex)), $startLine, $startIndex);
|
||||
}
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$text = $this->parseText($tokens);
|
||||
return $this->enrichWithAttributes($tokens, $text, $startLine, $startIndex);
|
||||
}
|
||||
/**
|
||||
* @template T of Ast\Node
|
||||
* @param T $tag
|
||||
* @return T
|
||||
*/
|
||||
private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $tag, int $startLine, int $startIndex) : Ast\Node
|
||||
{
|
||||
if ($this->useLinesAttributes) {
|
||||
$tag->setAttribute(Ast\Attribute::START_LINE, $startLine);
|
||||
$tag->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
|
||||
}
|
||||
if ($this->useIndexAttributes) {
|
||||
$tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
|
||||
$tag->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
|
||||
}
|
||||
return $tag;
|
||||
}
|
||||
private function parseText(TokenIterator $tokens) : Ast\PhpDoc\PhpDocTextNode
|
||||
{
|
||||
$text = '';
|
||||
$endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
|
||||
if ($this->textBetweenTagsBelongsToDescription) {
|
||||
$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
|
||||
}
|
||||
$savepoint = \false;
|
||||
// if the next token is EOL, everything below is skipped and empty string is returned
|
||||
while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
|
||||
$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);
|
||||
$text .= $tmpText;
|
||||
// stop if we're not at EOL - meaning it's the end of PHPDoc
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
|
||||
break;
|
||||
}
|
||||
if ($this->textBetweenTagsBelongsToDescription) {
|
||||
if (!$savepoint) {
|
||||
$tokens->pushSavePoint();
|
||||
$savepoint = \true;
|
||||
} elseif ($tmpText !== '') {
|
||||
$tokens->dropSavePoint();
|
||||
$tokens->pushSavePoint();
|
||||
}
|
||||
}
|
||||
$tokens->pushSavePoint();
|
||||
$tokens->next();
|
||||
// if we're at EOL, check what's next
|
||||
// if next is a PHPDoc tag, EOL, or end of PHPDoc, stop
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) {
|
||||
$tokens->rollback();
|
||||
break;
|
||||
}
|
||||
// otherwise if the next is text, continue building the description string
|
||||
$tokens->dropSavePoint();
|
||||
$text .= $tokens->getDetectedNewline() ?? "\n";
|
||||
}
|
||||
if ($savepoint) {
|
||||
$tokens->rollback();
|
||||
$text = rtrim($text, $tokens->getDetectedNewline() ?? "\n");
|
||||
}
|
||||
return new Ast\PhpDoc\PhpDocTextNode(trim($text, " \t"));
|
||||
}
|
||||
private function parseOptionalDescriptionAfterDoctrineTag(TokenIterator $tokens) : string
|
||||
{
|
||||
$text = '';
|
||||
$endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
|
||||
if ($this->textBetweenTagsBelongsToDescription) {
|
||||
$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
|
||||
}
|
||||
$savepoint = \false;
|
||||
// if the next token is EOL, everything below is skipped and empty string is returned
|
||||
while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
|
||||
$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);
|
||||
$text .= $tmpText;
|
||||
// stop if we're not at EOL - meaning it's the end of PHPDoc
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
|
||||
if (!$tokens->isPrecededByHorizontalWhitespace()) {
|
||||
return trim($text . $this->parseText($tokens)->text, " \t");
|
||||
}
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {
|
||||
$tokens->pushSavePoint();
|
||||
$child = $this->parseChild($tokens);
|
||||
if ($child instanceof Ast\PhpDoc\PhpDocTagNode) {
|
||||
if ($child->value instanceof Ast\PhpDoc\GenericTagValueNode || $child->value instanceof Doctrine\DoctrineTagValueNode) {
|
||||
$tokens->rollback();
|
||||
break;
|
||||
}
|
||||
if ($child->value instanceof Ast\PhpDoc\InvalidTagValueNode) {
|
||||
$tokens->rollback();
|
||||
$tokens->pushSavePoint();
|
||||
$tokens->next();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
||||
$tokens->rollback();
|
||||
break;
|
||||
}
|
||||
$tokens->rollback();
|
||||
return trim($text . $this->parseText($tokens)->text, " \t");
|
||||
}
|
||||
}
|
||||
$tokens->rollback();
|
||||
return trim($text . $this->parseText($tokens)->text, " \t");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ($this->textBetweenTagsBelongsToDescription) {
|
||||
if (!$savepoint) {
|
||||
$tokens->pushSavePoint();
|
||||
$savepoint = \true;
|
||||
} elseif ($tmpText !== '') {
|
||||
$tokens->dropSavePoint();
|
||||
$tokens->pushSavePoint();
|
||||
}
|
||||
}
|
||||
$tokens->pushSavePoint();
|
||||
$tokens->next();
|
||||
// if we're at EOL, check what's next
|
||||
// if next is a PHPDoc tag, EOL, or end of PHPDoc, stop
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) {
|
||||
$tokens->rollback();
|
||||
break;
|
||||
}
|
||||
// otherwise if the next is text, continue building the description string
|
||||
$tokens->dropSavePoint();
|
||||
$text .= $tokens->getDetectedNewline() ?? "\n";
|
||||
}
|
||||
if ($savepoint) {
|
||||
$tokens->rollback();
|
||||
$text = rtrim($text, $tokens->getDetectedNewline() ?? "\n");
|
||||
}
|
||||
return trim($text, " \t");
|
||||
}
|
||||
public function parseTag(TokenIterator $tokens) : Ast\PhpDoc\PhpDocTagNode
|
||||
{
|
||||
$tag = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
$value = $this->parseTagValue($tokens, $tag);
|
||||
return new Ast\PhpDoc\PhpDocTagNode($tag, $value);
|
||||
}
|
||||
public function parseTagValue(TokenIterator $tokens, string $tag) : Ast\PhpDoc\PhpDocTagValueNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
try {
|
||||
$tokens->pushSavePoint();
|
||||
switch ($tag) {
|
||||
case '@param':
|
||||
case '@phpstan-param':
|
||||
case '@psalm-param':
|
||||
$tagValue = $this->parseParamTagValue($tokens);
|
||||
break;
|
||||
case '@var':
|
||||
case '@phpstan-var':
|
||||
case '@psalm-var':
|
||||
$tagValue = $this->parseVarTagValue($tokens);
|
||||
break;
|
||||
case '@return':
|
||||
case '@phpstan-return':
|
||||
case '@psalm-return':
|
||||
$tagValue = $this->parseReturnTagValue($tokens);
|
||||
break;
|
||||
case '@throws':
|
||||
case '@phpstan-throws':
|
||||
$tagValue = $this->parseThrowsTagValue($tokens);
|
||||
break;
|
||||
case '@mixin':
|
||||
$tagValue = $this->parseMixinTagValue($tokens);
|
||||
break;
|
||||
case '@deprecated':
|
||||
$tagValue = $this->parseDeprecatedTagValue($tokens);
|
||||
break;
|
||||
case '@property':
|
||||
case '@property-read':
|
||||
case '@property-write':
|
||||
case '@phpstan-property':
|
||||
case '@phpstan-property-read':
|
||||
case '@phpstan-property-write':
|
||||
case '@psalm-property':
|
||||
case '@psalm-property-read':
|
||||
case '@psalm-property-write':
|
||||
$tagValue = $this->parsePropertyTagValue($tokens);
|
||||
break;
|
||||
case '@method':
|
||||
case '@phpstan-method':
|
||||
case '@psalm-method':
|
||||
$tagValue = $this->parseMethodTagValue($tokens);
|
||||
break;
|
||||
case '@template':
|
||||
case '@phpstan-template':
|
||||
case '@psalm-template':
|
||||
case '@template-covariant':
|
||||
case '@phpstan-template-covariant':
|
||||
case '@psalm-template-covariant':
|
||||
case '@template-contravariant':
|
||||
case '@phpstan-template-contravariant':
|
||||
case '@psalm-template-contravariant':
|
||||
$tagValue = $this->parseTemplateTagValue($tokens, \true);
|
||||
break;
|
||||
case '@extends':
|
||||
case '@phpstan-extends':
|
||||
case '@template-extends':
|
||||
$tagValue = $this->parseExtendsTagValue('@extends', $tokens);
|
||||
break;
|
||||
case '@implements':
|
||||
case '@phpstan-implements':
|
||||
case '@template-implements':
|
||||
$tagValue = $this->parseExtendsTagValue('@implements', $tokens);
|
||||
break;
|
||||
case '@use':
|
||||
case '@phpstan-use':
|
||||
case '@template-use':
|
||||
$tagValue = $this->parseExtendsTagValue('@use', $tokens);
|
||||
break;
|
||||
case '@phpstan-type':
|
||||
case '@psalm-type':
|
||||
$tagValue = $this->parseTypeAliasTagValue($tokens);
|
||||
break;
|
||||
case '@phpstan-import-type':
|
||||
case '@psalm-import-type':
|
||||
$tagValue = $this->parseTypeAliasImportTagValue($tokens);
|
||||
break;
|
||||
case '@phpstan-assert':
|
||||
case '@phpstan-assert-if-true':
|
||||
case '@phpstan-assert-if-false':
|
||||
case '@psalm-assert':
|
||||
case '@psalm-assert-if-true':
|
||||
case '@psalm-assert-if-false':
|
||||
$tagValue = $this->parseAssertTagValue($tokens);
|
||||
break;
|
||||
case '@phpstan-this-out':
|
||||
case '@phpstan-self-out':
|
||||
case '@psalm-this-out':
|
||||
case '@psalm-self-out':
|
||||
$tagValue = $this->parseSelfOutTagValue($tokens);
|
||||
break;
|
||||
case '@param-out':
|
||||
case '@phpstan-param-out':
|
||||
case '@psalm-param-out':
|
||||
$tagValue = $this->parseParamOutTagValue($tokens);
|
||||
break;
|
||||
default:
|
||||
if ($this->parseDoctrineAnnotations) {
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
||||
$tagValue = $this->parseDoctrineTagValue($tokens, $tag);
|
||||
} else {
|
||||
$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens));
|
||||
}
|
||||
break;
|
||||
}
|
||||
$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens));
|
||||
break;
|
||||
}
|
||||
$tokens->dropSavePoint();
|
||||
} catch (ParserException $e) {
|
||||
$tokens->rollback();
|
||||
$tagValue = new Ast\PhpDoc\InvalidTagValueNode($this->parseOptionalDescription($tokens), $e);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $tagValue, $startLine, $startIndex);
|
||||
}
|
||||
private function parseDoctrineTagValue(TokenIterator $tokens, string $tag) : Ast\PhpDoc\PhpDocTagValueNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
return new Doctrine\DoctrineTagValueNode($this->enrichWithAttributes($tokens, new Doctrine\DoctrineAnnotation($tag, $this->parseDoctrineArguments($tokens, \false)), $startLine, $startIndex), $this->parseOptionalDescriptionAfterDoctrineTag($tokens));
|
||||
}
|
||||
/**
|
||||
* @return list<Doctrine\DoctrineArgument>
|
||||
*/
|
||||
private function parseDoctrineArguments(TokenIterator $tokens, bool $deep) : array
|
||||
{
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
||||
return [];
|
||||
}
|
||||
if (!$deep) {
|
||||
$tokens->addEndOfLineToSkippedTokens();
|
||||
}
|
||||
$arguments = [];
|
||||
try {
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
|
||||
do {
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
|
||||
break;
|
||||
}
|
||||
$arguments[] = $this->parseDoctrineArgument($tokens);
|
||||
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
|
||||
} finally {
|
||||
if (!$deep) {
|
||||
$tokens->removeEndOfLineFromSkippedTokens();
|
||||
}
|
||||
}
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
|
||||
return $arguments;
|
||||
}
|
||||
private function parseDoctrineArgument(TokenIterator $tokens) : Doctrine\DoctrineArgument
|
||||
{
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)), $startLine, $startIndex);
|
||||
}
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
try {
|
||||
$tokens->pushSavePoint();
|
||||
$currentValue = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
$key = $this->enrichWithAttributes($tokens, new IdentifierTypeNode($currentValue), $startLine, $startIndex);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_EQUAL);
|
||||
$value = $this->parseDoctrineArgumentValue($tokens);
|
||||
$tokens->dropSavePoint();
|
||||
return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArgument($key, $value), $startLine, $startIndex);
|
||||
} catch (ParserException $e) {
|
||||
$tokens->rollback();
|
||||
return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)), $startLine, $startIndex);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return DoctrineValueType
|
||||
*/
|
||||
private function parseDoctrineArgumentValue(TokenIterator $tokens)
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG)) {
|
||||
$name = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineAnnotation($name, $this->parseDoctrineArguments($tokens, \true)), $startLine, $startIndex);
|
||||
}
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) {
|
||||
$items = [];
|
||||
do {
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
|
||||
break;
|
||||
}
|
||||
$items[] = $this->parseDoctrineArrayItem($tokens);
|
||||
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
|
||||
return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArray($items), $startLine, $startIndex);
|
||||
}
|
||||
$currentTokenValue = $tokens->currentTokenValue();
|
||||
$tokens->pushSavePoint();
|
||||
// because of ConstFetchNode
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||
$identifier = $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex);
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
|
||||
$tokens->dropSavePoint();
|
||||
return $identifier;
|
||||
}
|
||||
$tokens->rollback();
|
||||
// because of ConstFetchNode
|
||||
} else {
|
||||
$tokens->dropSavePoint();
|
||||
// because of ConstFetchNode
|
||||
}
|
||||
$currentTokenValue = $tokens->currentTokenValue();
|
||||
$currentTokenType = $tokens->currentTokenType();
|
||||
$currentTokenOffset = $tokens->currentTokenOffset();
|
||||
$currentTokenLine = $tokens->currentTokenLine();
|
||||
try {
|
||||
$constExpr = $this->doctrineConstantExprParser->parse($tokens, \true);
|
||||
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
|
||||
throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine);
|
||||
}
|
||||
return $constExpr;
|
||||
} catch (LogicException $e) {
|
||||
throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine);
|
||||
}
|
||||
}
|
||||
private function parseDoctrineArrayItem(TokenIterator $tokens) : Doctrine\DoctrineArrayItem
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
try {
|
||||
$tokens->pushSavePoint();
|
||||
$key = $this->parseDoctrineArrayKey($tokens);
|
||||
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) {
|
||||
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COLON)) {
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_EQUAL);
|
||||
// will throw exception
|
||||
}
|
||||
}
|
||||
$value = $this->parseDoctrineArgumentValue($tokens);
|
||||
$tokens->dropSavePoint();
|
||||
return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArrayItem($key, $value), $startLine, $startIndex);
|
||||
} catch (ParserException $e) {
|
||||
$tokens->rollback();
|
||||
return $this->enrichWithAttributes($tokens, new Doctrine\DoctrineArrayItem(null, $this->parseDoctrineArgumentValue($tokens)), $startLine, $startIndex);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode
|
||||
*/
|
||||
private function parseDoctrineArrayKey(TokenIterator $tokens)
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {
|
||||
$key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue()));
|
||||
$tokens->next();
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
|
||||
$key = new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($tokens->currentTokenValue()));
|
||||
$tokens->next();
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
|
||||
$value = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
$key = $this->doctrineConstantExprParser->parseDoctrineString($value, $tokens);
|
||||
} else {
|
||||
$currentTokenValue = $tokens->currentTokenValue();
|
||||
$tokens->pushSavePoint();
|
||||
// because of ConstFetchNode
|
||||
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||
$tokens->dropSavePoint();
|
||||
throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_IDENTIFIER, null, $tokens->currentTokenLine());
|
||||
}
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
|
||||
$tokens->dropSavePoint();
|
||||
return $this->enrichWithAttributes($tokens, new IdentifierTypeNode($currentTokenValue), $startLine, $startIndex);
|
||||
}
|
||||
$tokens->rollback();
|
||||
$constExpr = $this->doctrineConstantExprParser->parse($tokens, \true);
|
||||
if (!$constExpr instanceof Ast\ConstExpr\ConstFetchNode) {
|
||||
throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_IDENTIFIER, null, $tokens->currentTokenLine());
|
||||
}
|
||||
return $constExpr;
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex);
|
||||
}
|
||||
/**
|
||||
* @return Ast\PhpDoc\ParamTagValueNode|Ast\PhpDoc\TypelessParamTagValueNode
|
||||
*/
|
||||
private function parseParamTagValue(TokenIterator $tokens) : Ast\PhpDoc\PhpDocTagValueNode
|
||||
{
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_REFERENCE, Lexer::TOKEN_VARIADIC, Lexer::TOKEN_VARIABLE)) {
|
||||
$type = null;
|
||||
} else {
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
}
|
||||
$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);
|
||||
$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);
|
||||
$parameterName = $this->parseRequiredVariableName($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
if ($type !== null) {
|
||||
return new Ast\PhpDoc\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference);
|
||||
}
|
||||
return new Ast\PhpDoc\TypelessParamTagValueNode($isVariadic, $parameterName, $description, $isReference);
|
||||
}
|
||||
private function parseVarTagValue(TokenIterator $tokens) : Ast\PhpDoc\VarTagValueNode
|
||||
{
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
$variableName = $this->parseOptionalVariableName($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens, $variableName === '');
|
||||
return new Ast\PhpDoc\VarTagValueNode($type, $variableName, $description);
|
||||
}
|
||||
private function parseReturnTagValue(TokenIterator $tokens) : Ast\PhpDoc\ReturnTagValueNode
|
||||
{
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens, \true);
|
||||
return new Ast\PhpDoc\ReturnTagValueNode($type, $description);
|
||||
}
|
||||
private function parseThrowsTagValue(TokenIterator $tokens) : Ast\PhpDoc\ThrowsTagValueNode
|
||||
{
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens, \true);
|
||||
return new Ast\PhpDoc\ThrowsTagValueNode($type, $description);
|
||||
}
|
||||
private function parseMixinTagValue(TokenIterator $tokens) : Ast\PhpDoc\MixinTagValueNode
|
||||
{
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens, \true);
|
||||
return new Ast\PhpDoc\MixinTagValueNode($type, $description);
|
||||
}
|
||||
private function parseDeprecatedTagValue(TokenIterator $tokens) : Ast\PhpDoc\DeprecatedTagValueNode
|
||||
{
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
return new Ast\PhpDoc\DeprecatedTagValueNode($description);
|
||||
}
|
||||
private function parsePropertyTagValue(TokenIterator $tokens) : Ast\PhpDoc\PropertyTagValueNode
|
||||
{
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
$parameterName = $this->parseRequiredVariableName($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
return new Ast\PhpDoc\PropertyTagValueNode($type, $parameterName, $description);
|
||||
}
|
||||
private function parseMethodTagValue(TokenIterator $tokens) : Ast\PhpDoc\MethodTagValueNode
|
||||
{
|
||||
$isStatic = $tokens->tryConsumeTokenValue('static');
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$returnTypeOrMethodName = $this->typeParser->parse($tokens);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||
$returnType = $returnTypeOrMethodName;
|
||||
$methodName = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
} elseif ($returnTypeOrMethodName instanceof Ast\Type\IdentifierTypeNode) {
|
||||
$returnType = $isStatic ? $this->typeParser->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('static'), $startLine, $startIndex) : null;
|
||||
$methodName = $returnTypeOrMethodName->name;
|
||||
$isStatic = \false;
|
||||
} else {
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
// will throw exception
|
||||
exit;
|
||||
}
|
||||
$templateTypes = [];
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
|
||||
do {
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$templateTypes[] = $this->enrichWithAttributes($tokens, $this->parseTemplateTagValue($tokens, \false), $startLine, $startIndex);
|
||||
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
|
||||
}
|
||||
$parameters = [];
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
|
||||
$parameters[] = $this->parseMethodTagValueParameter($tokens);
|
||||
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
|
||||
$parameters[] = $this->parseMethodTagValueParameter($tokens);
|
||||
}
|
||||
}
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
return new Ast\PhpDoc\MethodTagValueNode($isStatic, $returnType, $methodName, $parameters, $description, $templateTypes);
|
||||
}
|
||||
private function parseMethodTagValueParameter(TokenIterator $tokens) : Ast\PhpDoc\MethodTagValueParameterNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
switch ($tokens->currentTokenType()) {
|
||||
case Lexer::TOKEN_IDENTIFIER:
|
||||
case Lexer::TOKEN_OPEN_PARENTHESES:
|
||||
case Lexer::TOKEN_NULLABLE:
|
||||
$parameterType = $this->typeParser->parse($tokens);
|
||||
break;
|
||||
default:
|
||||
$parameterType = null;
|
||||
}
|
||||
$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);
|
||||
$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);
|
||||
$parameterName = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) {
|
||||
$defaultValue = $this->constantExprParser->parse($tokens);
|
||||
} else {
|
||||
$defaultValue = null;
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\MethodTagValueParameterNode($parameterType, $isReference, $isVariadic, $parameterName, $defaultValue), $startLine, $startIndex);
|
||||
}
|
||||
private function parseTemplateTagValue(TokenIterator $tokens, bool $parseDescription) : Ast\PhpDoc\TemplateTagValueNode
|
||||
{
|
||||
$name = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) {
|
||||
$bound = $this->typeParser->parse($tokens);
|
||||
} else {
|
||||
$bound = null;
|
||||
}
|
||||
if ($tokens->tryConsumeTokenValue('=')) {
|
||||
$default = $this->typeParser->parse($tokens);
|
||||
} else {
|
||||
$default = null;
|
||||
}
|
||||
if ($parseDescription) {
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
} else {
|
||||
$description = '';
|
||||
}
|
||||
return new Ast\PhpDoc\TemplateTagValueNode($name, $bound, $description, $default);
|
||||
}
|
||||
private function parseExtendsTagValue(string $tagName, TokenIterator $tokens) : Ast\PhpDoc\PhpDocTagValueNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$baseType = new IdentifierTypeNode($tokens->currentTokenValue());
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
$type = $this->typeParser->parseGeneric($tokens, $this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex));
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
switch ($tagName) {
|
||||
case '@extends':
|
||||
return new Ast\PhpDoc\ExtendsTagValueNode($type, $description);
|
||||
case '@implements':
|
||||
return new Ast\PhpDoc\ImplementsTagValueNode($type, $description);
|
||||
case '@use':
|
||||
return new Ast\PhpDoc\UsesTagValueNode($type, $description);
|
||||
}
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
private function parseTypeAliasTagValue(TokenIterator $tokens) : Ast\PhpDoc\TypeAliasTagValueNode
|
||||
{
|
||||
$alias = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
// support psalm-type syntax
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);
|
||||
if ($this->preserveTypeAliasesWithInvalidTypes) {
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
try {
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
|
||||
throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_PHPDOC_EOL, null, $tokens->currentTokenLine());
|
||||
}
|
||||
}
|
||||
return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type);
|
||||
} catch (ParserException $e) {
|
||||
$this->parseOptionalDescription($tokens);
|
||||
return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $this->enrichWithAttributes($tokens, new Ast\Type\InvalidTypeNode($e), $startLine, $startIndex));
|
||||
}
|
||||
}
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type);
|
||||
}
|
||||
private function parseTypeAliasImportTagValue(TokenIterator $tokens) : Ast\PhpDoc\TypeAliasImportTagValueNode
|
||||
{
|
||||
$importedAlias = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
$tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'from');
|
||||
$identifierStartLine = $tokens->currentTokenLine();
|
||||
$identifierStartIndex = $tokens->currentTokenIndex();
|
||||
$importedFrom = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
$importedFromType = $this->enrichWithAttributes($tokens, new IdentifierTypeNode($importedFrom), $identifierStartLine, $identifierStartIndex);
|
||||
$importedAs = null;
|
||||
if ($tokens->tryConsumeTokenValue('as')) {
|
||||
$importedAs = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
}
|
||||
return new Ast\PhpDoc\TypeAliasImportTagValueNode($importedAlias, $importedFromType, $importedAs);
|
||||
}
|
||||
/**
|
||||
* @return Ast\PhpDoc\AssertTagValueNode|Ast\PhpDoc\AssertTagPropertyValueNode|Ast\PhpDoc\AssertTagMethodValueNode
|
||||
*/
|
||||
private function parseAssertTagValue(TokenIterator $tokens) : Ast\PhpDoc\PhpDocTagValueNode
|
||||
{
|
||||
$isNegated = $tokens->tryConsumeTokenType(Lexer::TOKEN_NEGATED);
|
||||
$isEquality = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
$parameter = $this->parseAssertParameter($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
if (array_key_exists('method', $parameter)) {
|
||||
return new Ast\PhpDoc\AssertTagMethodValueNode($type, $parameter['parameter'], $parameter['method'], $isNegated, $description, $isEquality);
|
||||
} elseif (array_key_exists('property', $parameter)) {
|
||||
return new Ast\PhpDoc\AssertTagPropertyValueNode($type, $parameter['parameter'], $parameter['property'], $isNegated, $description, $isEquality);
|
||||
}
|
||||
return new Ast\PhpDoc\AssertTagValueNode($type, $parameter['parameter'], $isNegated, $description, $isEquality);
|
||||
}
|
||||
/**
|
||||
* @return array{parameter: string}|array{parameter: string, property: string}|array{parameter: string, method: string}
|
||||
*/
|
||||
private function parseAssertParameter(TokenIterator $tokens) : array
|
||||
{
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
|
||||
$parameter = '$this';
|
||||
$tokens->next();
|
||||
} else {
|
||||
$parameter = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
|
||||
}
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) {
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_ARROW);
|
||||
$propertyOrMethod = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
|
||||
return ['parameter' => $parameter, 'method' => $propertyOrMethod];
|
||||
}
|
||||
return ['parameter' => $parameter, 'property' => $propertyOrMethod];
|
||||
}
|
||||
return ['parameter' => $parameter];
|
||||
}
|
||||
private function parseSelfOutTagValue(TokenIterator $tokens) : Ast\PhpDoc\SelfOutTagValueNode
|
||||
{
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
return new Ast\PhpDoc\SelfOutTagValueNode($type, $description);
|
||||
}
|
||||
private function parseParamOutTagValue(TokenIterator $tokens) : Ast\PhpDoc\ParamOutTagValueNode
|
||||
{
|
||||
$type = $this->typeParser->parse($tokens);
|
||||
$parameterName = $this->parseRequiredVariableName($tokens);
|
||||
$description = $this->parseOptionalDescription($tokens);
|
||||
return new Ast\PhpDoc\ParamOutTagValueNode($type, $parameterName, $description);
|
||||
}
|
||||
private function parseOptionalVariableName(TokenIterator $tokens) : string
|
||||
{
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {
|
||||
$parameterName = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
|
||||
$parameterName = '$this';
|
||||
$tokens->next();
|
||||
} else {
|
||||
$parameterName = '';
|
||||
}
|
||||
return $parameterName;
|
||||
}
|
||||
private function parseRequiredVariableName(TokenIterator $tokens) : string
|
||||
{
|
||||
$parameterName = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
|
||||
return $parameterName;
|
||||
}
|
||||
private function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken = \false) : string
|
||||
{
|
||||
if ($limitStartToken) {
|
||||
foreach (self::DISALLOWED_DESCRIPTION_START_TOKENS as $disallowedStartToken) {
|
||||
if (!$tokens->isCurrentTokenType($disallowedStartToken)) {
|
||||
continue;
|
||||
}
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OTHER);
|
||||
// will throw exception
|
||||
}
|
||||
if ($this->requireWhitespaceBeforeDescription && !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END) && !$tokens->isPrecededByHorizontalWhitespace()) {
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_HORIZONTAL_WS);
|
||||
// will throw exception
|
||||
}
|
||||
}
|
||||
return $this->parseText($tokens)->text;
|
||||
}
|
||||
}
|
63
dependencies/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php
vendored
Normal file
63
dependencies/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser;
|
||||
|
||||
use function chr;
|
||||
use function hexdec;
|
||||
use function octdec;
|
||||
use function preg_replace_callback;
|
||||
use function str_replace;
|
||||
use function substr;
|
||||
class StringUnescaper
|
||||
{
|
||||
private const REPLACEMENTS = ['\\' => '\\', 'n' => "\n", 'r' => "\r", 't' => "\t", 'f' => "\f", 'v' => "\v", 'e' => "\x1b"];
|
||||
public static function unescapeString(string $string) : string
|
||||
{
|
||||
$quote = $string[0];
|
||||
if ($quote === '\'') {
|
||||
return str_replace(['\\\\', '\\\''], ['\\', '\''], substr($string, 1, -1));
|
||||
}
|
||||
return self::parseEscapeSequences(substr($string, 1, -1), '"');
|
||||
}
|
||||
/**
|
||||
* Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L90-L130
|
||||
*/
|
||||
private static function parseEscapeSequences(string $str, string $quote) : string
|
||||
{
|
||||
$str = str_replace('\\' . $quote, $quote, $str);
|
||||
return preg_replace_callback('~\\\\([\\\\nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u\\{([0-9a-fA-F]+)\\})~', static function ($matches) {
|
||||
$str = $matches[1];
|
||||
if (isset(self::REPLACEMENTS[$str])) {
|
||||
return self::REPLACEMENTS[$str];
|
||||
}
|
||||
if ($str[0] === 'x' || $str[0] === 'X') {
|
||||
return chr((int) hexdec(substr($str, 1)));
|
||||
}
|
||||
if ($str[0] === 'u') {
|
||||
return self::codePointToUtf8((int) hexdec($matches[2]));
|
||||
}
|
||||
return chr((int) octdec($str));
|
||||
}, $str);
|
||||
}
|
||||
/**
|
||||
* Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L132-L154
|
||||
*/
|
||||
private static function codePointToUtf8(int $num) : string
|
||||
{
|
||||
if ($num <= 0x7f) {
|
||||
return chr($num);
|
||||
}
|
||||
if ($num <= 0x7ff) {
|
||||
return chr(($num >> 6) + 0xc0) . chr(($num & 0x3f) + 0x80);
|
||||
}
|
||||
if ($num <= 0xffff) {
|
||||
return chr(($num >> 12) + 0xe0) . chr(($num >> 6 & 0x3f) + 0x80) . chr(($num & 0x3f) + 0x80);
|
||||
}
|
||||
if ($num <= 0x1fffff) {
|
||||
return chr(($num >> 18) + 0xf0) . chr(($num >> 12 & 0x3f) + 0x80) . chr(($num >> 6 & 0x3f) + 0x80) . chr(($num & 0x3f) + 0x80);
|
||||
}
|
||||
// Invalid UTF-8 codepoint escape sequence: Codepoint too large
|
||||
return "<EFBFBD>";
|
||||
}
|
||||
}
|
287
dependencies/phpstan/phpdoc-parser/src/Parser/TokenIterator.php
vendored
Normal file
287
dependencies/phpstan/phpdoc-parser/src/Parser/TokenIterator.php
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser;
|
||||
|
||||
use LogicException;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Lexer\Lexer;
|
||||
use function array_pop;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
class TokenIterator
|
||||
{
|
||||
/** @var list<array{string, int, int}> */
|
||||
private $tokens;
|
||||
/** @var int */
|
||||
private $index;
|
||||
/** @var int[] */
|
||||
private $savePoints = [];
|
||||
/** @var list<int> */
|
||||
private $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];
|
||||
/** @var string|null */
|
||||
private $newline = null;
|
||||
/**
|
||||
* @param list<array{string, int, int}> $tokens
|
||||
*/
|
||||
public function __construct(array $tokens, int $index = 0)
|
||||
{
|
||||
$this->tokens = $tokens;
|
||||
$this->index = $index;
|
||||
$this->skipIrrelevantTokens();
|
||||
}
|
||||
/**
|
||||
* @return list<array{string, int, int}>
|
||||
*/
|
||||
public function getTokens() : array
|
||||
{
|
||||
return $this->tokens;
|
||||
}
|
||||
public function getContentBetween(int $startPos, int $endPos) : string
|
||||
{
|
||||
if ($startPos < 0 || $endPos > count($this->tokens)) {
|
||||
throw new LogicException();
|
||||
}
|
||||
$content = '';
|
||||
for ($i = $startPos; $i < $endPos; $i++) {
|
||||
$content .= $this->tokens[$i][Lexer::VALUE_OFFSET];
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
public function getTokenCount() : int
|
||||
{
|
||||
return count($this->tokens);
|
||||
}
|
||||
public function currentTokenValue() : string
|
||||
{
|
||||
return $this->tokens[$this->index][Lexer::VALUE_OFFSET];
|
||||
}
|
||||
public function currentTokenType() : int
|
||||
{
|
||||
return $this->tokens[$this->index][Lexer::TYPE_OFFSET];
|
||||
}
|
||||
public function currentTokenOffset() : int
|
||||
{
|
||||
$offset = 0;
|
||||
for ($i = 0; $i < $this->index; $i++) {
|
||||
$offset += strlen($this->tokens[$i][Lexer::VALUE_OFFSET]);
|
||||
}
|
||||
return $offset;
|
||||
}
|
||||
public function currentTokenLine() : int
|
||||
{
|
||||
return $this->tokens[$this->index][Lexer::LINE_OFFSET];
|
||||
}
|
||||
public function currentTokenIndex() : int
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
public function endIndexOfLastRelevantToken() : int
|
||||
{
|
||||
$endIndex = $this->currentTokenIndex();
|
||||
$endIndex--;
|
||||
while (in_array($this->tokens[$endIndex][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, \true)) {
|
||||
if (!isset($this->tokens[$endIndex - 1])) {
|
||||
break;
|
||||
}
|
||||
$endIndex--;
|
||||
}
|
||||
return $endIndex;
|
||||
}
|
||||
public function isCurrentTokenValue(string $tokenValue) : bool
|
||||
{
|
||||
return $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue;
|
||||
}
|
||||
public function isCurrentTokenType(int ...$tokenType) : bool
|
||||
{
|
||||
return in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, \true);
|
||||
}
|
||||
public function isPrecededByHorizontalWhitespace() : bool
|
||||
{
|
||||
return ($this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] ?? -1) === Lexer::TOKEN_HORIZONTAL_WS;
|
||||
}
|
||||
/**
|
||||
* @throws ParserException
|
||||
*/
|
||||
public function consumeTokenType(int $tokenType) : void
|
||||
{
|
||||
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) {
|
||||
$this->throwError($tokenType);
|
||||
}
|
||||
if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) {
|
||||
if ($this->newline === null) {
|
||||
$this->detectNewline();
|
||||
}
|
||||
}
|
||||
$this->index++;
|
||||
$this->skipIrrelevantTokens();
|
||||
}
|
||||
/**
|
||||
* @throws ParserException
|
||||
*/
|
||||
public function consumeTokenValue(int $tokenType, string $tokenValue) : void
|
||||
{
|
||||
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType || $this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {
|
||||
$this->throwError($tokenType, $tokenValue);
|
||||
}
|
||||
$this->index++;
|
||||
$this->skipIrrelevantTokens();
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
public function tryConsumeTokenValue(string $tokenValue) : bool
|
||||
{
|
||||
if ($this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {
|
||||
return \false;
|
||||
}
|
||||
$this->index++;
|
||||
$this->skipIrrelevantTokens();
|
||||
return \true;
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
public function tryConsumeTokenType(int $tokenType) : bool
|
||||
{
|
||||
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) {
|
||||
return \false;
|
||||
}
|
||||
if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) {
|
||||
if ($this->newline === null) {
|
||||
$this->detectNewline();
|
||||
}
|
||||
}
|
||||
$this->index++;
|
||||
$this->skipIrrelevantTokens();
|
||||
return \true;
|
||||
}
|
||||
private function detectNewline() : void
|
||||
{
|
||||
$value = $this->currentTokenValue();
|
||||
if (substr($value, 0, 2) === "\r\n") {
|
||||
$this->newline = "\r\n";
|
||||
} elseif (substr($value, 0, 1) === "\n") {
|
||||
$this->newline = "\n";
|
||||
}
|
||||
}
|
||||
public function getSkippedHorizontalWhiteSpaceIfAny() : string
|
||||
{
|
||||
if ($this->index > 0 && $this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {
|
||||
return $this->tokens[$this->index - 1][Lexer::VALUE_OFFSET];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
public function joinUntil(int ...$tokenType) : string
|
||||
{
|
||||
$s = '';
|
||||
while (!in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, \true)) {
|
||||
$s .= $this->tokens[$this->index++][Lexer::VALUE_OFFSET];
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
public function next() : void
|
||||
{
|
||||
$this->index++;
|
||||
$this->skipIrrelevantTokens();
|
||||
}
|
||||
private function skipIrrelevantTokens() : void
|
||||
{
|
||||
if (!isset($this->tokens[$this->index])) {
|
||||
return;
|
||||
}
|
||||
while (in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, \true)) {
|
||||
if (!isset($this->tokens[$this->index + 1])) {
|
||||
break;
|
||||
}
|
||||
$this->index++;
|
||||
}
|
||||
}
|
||||
public function addEndOfLineToSkippedTokens() : void
|
||||
{
|
||||
$this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL];
|
||||
}
|
||||
public function removeEndOfLineFromSkippedTokens() : void
|
||||
{
|
||||
$this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
public function forwardToTheEnd() : void
|
||||
{
|
||||
$lastToken = count($this->tokens) - 1;
|
||||
$this->index = $lastToken;
|
||||
}
|
||||
public function pushSavePoint() : void
|
||||
{
|
||||
$this->savePoints[] = $this->index;
|
||||
}
|
||||
public function dropSavePoint() : void
|
||||
{
|
||||
array_pop($this->savePoints);
|
||||
}
|
||||
public function rollback() : void
|
||||
{
|
||||
$index = array_pop($this->savePoints);
|
||||
assert($index !== null);
|
||||
$this->index = $index;
|
||||
}
|
||||
/**
|
||||
* @throws ParserException
|
||||
*/
|
||||
private function throwError(int $expectedTokenType, ?string $expectedTokenValue = null) : void
|
||||
{
|
||||
throw new ParserException($this->currentTokenValue(), $this->currentTokenType(), $this->currentTokenOffset(), $expectedTokenType, $expectedTokenValue, $this->currentTokenLine());
|
||||
}
|
||||
/**
|
||||
* Check whether the position is directly preceded by a certain token type.
|
||||
*
|
||||
* During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped
|
||||
*/
|
||||
public function hasTokenImmediatelyBefore(int $pos, int $expectedTokenType) : bool
|
||||
{
|
||||
$tokens = $this->tokens;
|
||||
$pos--;
|
||||
for (; $pos >= 0; $pos--) {
|
||||
$token = $tokens[$pos];
|
||||
$type = $token[Lexer::TYPE_OFFSET];
|
||||
if ($type === $expectedTokenType) {
|
||||
return \true;
|
||||
}
|
||||
if (!in_array($type, [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL], \true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Check whether the position is directly followed by a certain token type.
|
||||
*
|
||||
* During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped
|
||||
*/
|
||||
public function hasTokenImmediatelyAfter(int $pos, int $expectedTokenType) : bool
|
||||
{
|
||||
$tokens = $this->tokens;
|
||||
$pos++;
|
||||
for ($c = count($tokens); $pos < $c; $pos++) {
|
||||
$token = $tokens[$pos];
|
||||
$type = $token[Lexer::TYPE_OFFSET];
|
||||
if ($type === $expectedTokenType) {
|
||||
return \true;
|
||||
}
|
||||
if (!in_array($type, [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL], \true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
public function getDetectedNewline() : ?string
|
||||
{
|
||||
return $this->newline;
|
||||
}
|
||||
/**
|
||||
* Whether the given position is immediately surrounded by parenthesis.
|
||||
*/
|
||||
public function hasParentheses(int $startPos, int $endPos) : bool
|
||||
{
|
||||
return $this->hasTokenImmediatelyBefore($startPos, Lexer::TOKEN_OPEN_PARENTHESES) && $this->hasTokenImmediatelyAfter($endPos, Lexer::TOKEN_CLOSE_PARENTHESES);
|
||||
}
|
||||
}
|
624
dependencies/phpstan/phpdoc-parser/src/Parser/TypeParser.php
vendored
Normal file
624
dependencies/phpstan/phpdoc-parser/src/Parser/TypeParser.php
vendored
Normal file
@ -0,0 +1,624 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser;
|
||||
|
||||
use LogicException;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Lexer\Lexer;
|
||||
use function in_array;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
use function trim;
|
||||
class TypeParser
|
||||
{
|
||||
/** @var ConstExprParser|null */
|
||||
private $constExprParser;
|
||||
/** @var bool */
|
||||
private $quoteAwareConstExprString;
|
||||
/** @var bool */
|
||||
private $useLinesAttributes;
|
||||
/** @var bool */
|
||||
private $useIndexAttributes;
|
||||
/**
|
||||
* @param array{lines?: bool, indexes?: bool} $usedAttributes
|
||||
*/
|
||||
public function __construct(?ConstExprParser $constExprParser = null, bool $quoteAwareConstExprString = \false, array $usedAttributes = [])
|
||||
{
|
||||
$this->constExprParser = $constExprParser;
|
||||
$this->quoteAwareConstExprString = $quoteAwareConstExprString;
|
||||
$this->useLinesAttributes = $usedAttributes['lines'] ?? \false;
|
||||
$this->useIndexAttributes = $usedAttributes['indexes'] ?? \false;
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
public function parse(TokenIterator $tokens) : Ast\Type\TypeNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
|
||||
$type = $this->parseNullable($tokens);
|
||||
} else {
|
||||
$type = $this->parseAtomic($tokens);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
|
||||
$type = $this->parseUnion($tokens, $type);
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
|
||||
$type = $this->parseIntersection($tokens, $type);
|
||||
}
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
* @template T of Ast\Node
|
||||
* @param T $type
|
||||
* @return T
|
||||
*/
|
||||
public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex) : Ast\Node
|
||||
{
|
||||
if ($this->useLinesAttributes) {
|
||||
$type->setAttribute(Ast\Attribute::START_LINE, $startLine);
|
||||
$type->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
|
||||
}
|
||||
if ($this->useIndexAttributes) {
|
||||
$type->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
|
||||
$type->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function subParse(TokenIterator $tokens) : Ast\Type\TypeNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
|
||||
$type = $this->parseNullable($tokens);
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {
|
||||
$type = $this->parseConditionalForParameter($tokens, $tokens->currentTokenValue());
|
||||
} else {
|
||||
$type = $this->parseAtomic($tokens);
|
||||
if ($tokens->isCurrentTokenValue('is')) {
|
||||
$type = $this->parseConditional($tokens, $type);
|
||||
} else {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
|
||||
$type = $this->subParseUnion($tokens, $type);
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
|
||||
$type = $this->subParseIntersection($tokens, $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseAtomic(TokenIterator $tokens) : Ast\Type\TypeNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$type = $this->subParse($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
|
||||
}
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
|
||||
$type = $this->enrichWithAttributes($tokens, new Ast\Type\ThisTypeNode(), $startLine, $startIndex);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
|
||||
}
|
||||
$currentTokenValue = $tokens->currentTokenValue();
|
||||
$tokens->pushSavePoint();
|
||||
// because of ConstFetchNode
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||
$type = $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex);
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
|
||||
$tokens->dropSavePoint();
|
||||
// because of ConstFetchNode
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
|
||||
$tokens->pushSavePoint();
|
||||
$isHtml = $this->isHtml($tokens);
|
||||
$tokens->rollback();
|
||||
if ($isHtml) {
|
||||
return $type;
|
||||
}
|
||||
$type = $this->parseGeneric($tokens, $type);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
|
||||
}
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
||||
$type = $this->tryParseCallable($tokens, $type);
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
|
||||
} elseif (in_array($type->name, ['array', 'list', 'object'], \true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
|
||||
if ($type->name === 'object') {
|
||||
$type = $this->parseObjectShape($tokens);
|
||||
} else {
|
||||
$type = $this->parseArrayShape($tokens, $type, $type->name);
|
||||
}
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex));
|
||||
}
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
|
||||
} else {
|
||||
$tokens->rollback();
|
||||
// because of ConstFetchNode
|
||||
}
|
||||
} else {
|
||||
$tokens->dropSavePoint();
|
||||
// because of ConstFetchNode
|
||||
}
|
||||
$currentTokenValue = $tokens->currentTokenValue();
|
||||
$currentTokenType = $tokens->currentTokenType();
|
||||
$currentTokenOffset = $tokens->currentTokenOffset();
|
||||
$currentTokenLine = $tokens->currentTokenLine();
|
||||
if ($this->constExprParser === null) {
|
||||
throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine);
|
||||
}
|
||||
try {
|
||||
$constExpr = $this->constExprParser->parse($tokens, \true);
|
||||
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
|
||||
throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex);
|
||||
} catch (LogicException $e) {
|
||||
throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine);
|
||||
}
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode
|
||||
{
|
||||
$types = [$type];
|
||||
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
|
||||
$types[] = $this->parseAtomic($tokens);
|
||||
}
|
||||
return new Ast\Type\UnionTypeNode($types);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function subParseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode
|
||||
{
|
||||
$types = [$type];
|
||||
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$types[] = $this->parseAtomic($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
}
|
||||
return new Ast\Type\UnionTypeNode($types);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode
|
||||
{
|
||||
$types = [$type];
|
||||
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
|
||||
$types[] = $this->parseAtomic($tokens);
|
||||
}
|
||||
return new Ast\Type\IntersectionTypeNode($types);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function subParseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode
|
||||
{
|
||||
$types = [$type];
|
||||
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$types[] = $this->parseAtomic($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
}
|
||||
return new Ast\Type\IntersectionTypeNode($types);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseConditional(TokenIterator $tokens, Ast\Type\TypeNode $subjectType) : Ast\Type\TypeNode
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
$negated = \false;
|
||||
if ($tokens->isCurrentTokenValue('not')) {
|
||||
$negated = \true;
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
}
|
||||
$targetType = $this->parse($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$ifType = $this->parse($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$elseType = $this->subParse($tokens);
|
||||
return new Ast\Type\ConditionalTypeNode($subjectType, $targetType, $ifType, $elseType, $negated);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseConditionalForParameter(TokenIterator $tokens, string $parameterName) : Ast\Type\TypeNode
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
|
||||
$tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'is');
|
||||
$negated = \false;
|
||||
if ($tokens->isCurrentTokenValue('not')) {
|
||||
$negated = \true;
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
}
|
||||
$targetType = $this->parse($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$ifType = $this->parse($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$elseType = $this->subParse($tokens);
|
||||
return new Ast\Type\ConditionalTypeForParameterNode($parameterName, $targetType, $ifType, $elseType, $negated);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseNullable(TokenIterator $tokens) : Ast\Type\TypeNode
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
|
||||
$type = $this->parseAtomic($tokens);
|
||||
return new Ast\Type\NullableTypeNode($type);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
public function isHtml(TokenIterator $tokens) : bool
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||
return \false;
|
||||
}
|
||||
$htmlTagName = $tokens->currentTokenValue();
|
||||
$tokens->next();
|
||||
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
|
||||
return \false;
|
||||
}
|
||||
while (!$tokens->isCurrentTokenType(Lexer::TOKEN_END)) {
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET) && strpos($tokens->currentTokenValue(), '/' . $htmlTagName . '>') !== \false) {
|
||||
return \true;
|
||||
}
|
||||
$tokens->next();
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $baseType) : Ast\Type\GenericTypeNode
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
|
||||
$startLine = $baseType->getAttribute(Ast\Attribute::START_LINE);
|
||||
$startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX);
|
||||
$genericTypes = [];
|
||||
$variances = [];
|
||||
$isFirst = \true;
|
||||
while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
// trailing comma case
|
||||
if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
|
||||
break;
|
||||
}
|
||||
$isFirst = \false;
|
||||
[$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
}
|
||||
$type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
|
||||
if ($startLine !== null && $startIndex !== null) {
|
||||
$type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
|
||||
}
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
|
||||
return $type;
|
||||
}
|
||||
/**
|
||||
* @phpstan-impure
|
||||
* @return array{Ast\Type\TypeNode, Ast\Type\GenericTypeNode::VARIANCE_*}
|
||||
*/
|
||||
public function parseGenericTypeArgument(TokenIterator $tokens) : array
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) {
|
||||
return [$this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('mixed'), $startLine, $startIndex), Ast\Type\GenericTypeNode::VARIANCE_BIVARIANT];
|
||||
}
|
||||
if ($tokens->tryConsumeTokenValue('contravariant')) {
|
||||
$variance = Ast\Type\GenericTypeNode::VARIANCE_CONTRAVARIANT;
|
||||
} elseif ($tokens->tryConsumeTokenValue('covariant')) {
|
||||
$variance = Ast\Type\GenericTypeNode::VARIANCE_COVARIANT;
|
||||
} else {
|
||||
$variance = Ast\Type\GenericTypeNode::VARIANCE_INVARIANT;
|
||||
}
|
||||
$type = $this->parse($tokens);
|
||||
return [$type, $variance];
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier) : Ast\Type\TypeNode
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$parameters = [];
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
|
||||
$parameters[] = $this->parseCallableParameter($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
|
||||
break;
|
||||
}
|
||||
$parameters[] = $this->parseCallableParameter($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
}
|
||||
}
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$returnType = $this->enrichWithAttributes($tokens, $this->parseCallableReturnType($tokens), $startLine, $startIndex);
|
||||
return new Ast\Type\CallableTypeNode($identifier, $parameters, $returnType);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseCallableParameter(TokenIterator $tokens) : Ast\Type\CallableTypeParameterNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$type = $this->parse($tokens);
|
||||
$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);
|
||||
$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {
|
||||
$parameterName = $tokens->currentTokenValue();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
|
||||
} else {
|
||||
$parameterName = '';
|
||||
}
|
||||
$isOptional = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);
|
||||
return $this->enrichWithAttributes($tokens, new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional), $startLine, $startIndex);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseCallableReturnType(TokenIterator $tokens) : Ast\Type\TypeNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
|
||||
return $this->parseNullable($tokens);
|
||||
} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
||||
$type = $this->subParse($tokens);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
|
||||
}
|
||||
return $type;
|
||||
} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
|
||||
$type = new Ast\Type\ThisTypeNode();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex));
|
||||
}
|
||||
return $type;
|
||||
} else {
|
||||
$currentTokenValue = $tokens->currentTokenValue();
|
||||
$tokens->pushSavePoint();
|
||||
// because of ConstFetchNode
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||
$type = new Ast\Type\IdentifierTypeNode($currentTokenValue);
|
||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
|
||||
$type = $this->parseGeneric($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex));
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex));
|
||||
}
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex));
|
||||
} elseif (in_array($type->name, ['array', 'list', 'object'], \true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
|
||||
if ($type->name === 'object') {
|
||||
$type = $this->parseObjectShape($tokens);
|
||||
} else {
|
||||
$type = $this->parseArrayShape($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex), $type->name);
|
||||
}
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex));
|
||||
}
|
||||
}
|
||||
return $type;
|
||||
} else {
|
||||
$tokens->rollback();
|
||||
// because of ConstFetchNode
|
||||
}
|
||||
} else {
|
||||
$tokens->dropSavePoint();
|
||||
// because of ConstFetchNode
|
||||
}
|
||||
}
|
||||
$currentTokenValue = $tokens->currentTokenValue();
|
||||
$currentTokenType = $tokens->currentTokenType();
|
||||
$currentTokenOffset = $tokens->currentTokenOffset();
|
||||
$currentTokenLine = $tokens->currentTokenLine();
|
||||
if ($this->constExprParser === null) {
|
||||
throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine);
|
||||
}
|
||||
try {
|
||||
$constExpr = $this->constExprParser->parse($tokens, \true);
|
||||
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
|
||||
throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine);
|
||||
}
|
||||
$type = new Ast\Type\ConstTypeNode($constExpr);
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex));
|
||||
}
|
||||
return $type;
|
||||
} catch (LogicException $e) {
|
||||
throw new ParserException($currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine);
|
||||
}
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function tryParseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier) : Ast\Type\TypeNode
|
||||
{
|
||||
try {
|
||||
$tokens->pushSavePoint();
|
||||
$type = $this->parseCallable($tokens, $identifier);
|
||||
$tokens->dropSavePoint();
|
||||
} catch (ParserException $e) {
|
||||
$tokens->rollback();
|
||||
$type = $identifier;
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\TypeNode $type) : Ast\Type\TypeNode
|
||||
{
|
||||
$startLine = $type->getAttribute(Ast\Attribute::START_LINE);
|
||||
$startIndex = $type->getAttribute(Ast\Attribute::START_INDEX);
|
||||
try {
|
||||
while ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||
$tokens->pushSavePoint();
|
||||
$canBeOffsetAccessType = !$tokens->isPrecededByHorizontalWhitespace();
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET);
|
||||
if ($canBeOffsetAccessType && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET)) {
|
||||
$offset = $this->parse($tokens);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET);
|
||||
$tokens->dropSavePoint();
|
||||
$type = new Ast\Type\OffsetAccessTypeNode($type, $offset);
|
||||
if ($startLine !== null && $startIndex !== null) {
|
||||
$type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
|
||||
}
|
||||
} else {
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET);
|
||||
$tokens->dropSavePoint();
|
||||
$type = new Ast\Type\ArrayTypeNode($type);
|
||||
if ($startLine !== null && $startIndex !== null) {
|
||||
$type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ParserException $e) {
|
||||
$tokens->rollback();
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
/**
|
||||
* @phpstan-impure
|
||||
* @param Ast\Type\ArrayShapeNode::KIND_* $kind
|
||||
*/
|
||||
private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type, string $kind) : Ast\Type\ArrayShapeNode
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);
|
||||
$items = [];
|
||||
$sealed = \true;
|
||||
do {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
|
||||
return new Ast\Type\ArrayShapeNode($items, \true, $kind);
|
||||
}
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) {
|
||||
$sealed = \false;
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA);
|
||||
break;
|
||||
}
|
||||
$items[] = $this->parseArrayShapeItem($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
|
||||
return new Ast\Type\ArrayShapeNode($items, $sealed, $kind);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseArrayShapeItem(TokenIterator $tokens) : Ast\Type\ArrayShapeItemNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
try {
|
||||
$tokens->pushSavePoint();
|
||||
$key = $this->parseArrayShapeKey($tokens);
|
||||
$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
|
||||
$value = $this->parse($tokens);
|
||||
$tokens->dropSavePoint();
|
||||
return $this->enrichWithAttributes($tokens, new Ast\Type\ArrayShapeItemNode($key, $optional, $value), $startLine, $startIndex);
|
||||
} catch (ParserException $e) {
|
||||
$tokens->rollback();
|
||||
$value = $this->parse($tokens);
|
||||
return $this->enrichWithAttributes($tokens, new Ast\Type\ArrayShapeItemNode(null, \false, $value), $startLine, $startIndex);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @phpstan-impure
|
||||
* @return Ast\ConstExpr\ConstExprIntegerNode|Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode
|
||||
*/
|
||||
private function parseArrayShapeKey(TokenIterator $tokens)
|
||||
{
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {
|
||||
$key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue()));
|
||||
$tokens->next();
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
|
||||
if ($this->quoteAwareConstExprString) {
|
||||
$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED);
|
||||
} else {
|
||||
$key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'"));
|
||||
}
|
||||
$tokens->next();
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
|
||||
if ($this->quoteAwareConstExprString) {
|
||||
$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED);
|
||||
} else {
|
||||
$key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"'));
|
||||
}
|
||||
$tokens->next();
|
||||
} else {
|
||||
$key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue());
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex);
|
||||
}
|
||||
/**
|
||||
* @phpstan-impure
|
||||
*/
|
||||
private function parseObjectShape(TokenIterator $tokens) : Ast\Type\ObjectShapeNode
|
||||
{
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);
|
||||
$items = [];
|
||||
do {
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
|
||||
return new Ast\Type\ObjectShapeNode($items);
|
||||
}
|
||||
$items[] = $this->parseObjectShapeItem($tokens);
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
|
||||
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
|
||||
return new Ast\Type\ObjectShapeNode($items);
|
||||
}
|
||||
/** @phpstan-impure */
|
||||
private function parseObjectShapeItem(TokenIterator $tokens) : Ast\Type\ObjectShapeItemNode
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
$key = $this->parseObjectShapeKey($tokens);
|
||||
$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
|
||||
$value = $this->parse($tokens);
|
||||
return $this->enrichWithAttributes($tokens, new Ast\Type\ObjectShapeItemNode($key, $optional, $value), $startLine, $startIndex);
|
||||
}
|
||||
/**
|
||||
* @phpstan-impure
|
||||
* @return Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode
|
||||
*/
|
||||
private function parseObjectShapeKey(TokenIterator $tokens)
|
||||
{
|
||||
$startLine = $tokens->currentTokenLine();
|
||||
$startIndex = $tokens->currentTokenIndex();
|
||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
|
||||
if ($this->quoteAwareConstExprString) {
|
||||
$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED);
|
||||
} else {
|
||||
$key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'"));
|
||||
}
|
||||
$tokens->next();
|
||||
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
|
||||
if ($this->quoteAwareConstExprString) {
|
||||
$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED);
|
||||
} else {
|
||||
$key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"'));
|
||||
}
|
||||
$tokens->next();
|
||||
} else {
|
||||
$key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue());
|
||||
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
|
||||
}
|
||||
return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex);
|
||||
}
|
||||
}
|
39
dependencies/phpstan/phpdoc-parser/src/Printer/DiffElem.php
vendored
Normal file
39
dependencies/phpstan/phpdoc-parser/src/Printer/DiffElem.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Printer;
|
||||
|
||||
/**
|
||||
* Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
|
||||
*
|
||||
* Copyright (c) 2011, Nikita Popov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Implements the Myers diff algorithm.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DiffElem
|
||||
{
|
||||
public const TYPE_KEEP = 0;
|
||||
public const TYPE_REMOVE = 1;
|
||||
public const TYPE_ADD = 2;
|
||||
public const TYPE_REPLACE = 3;
|
||||
/** @var self::TYPE_* */
|
||||
public $type;
|
||||
/** @var mixed Is null for add operations */
|
||||
public $old;
|
||||
/** @var mixed Is null for remove operations */
|
||||
public $new;
|
||||
/**
|
||||
* @param self::TYPE_* $type
|
||||
* @param mixed $old Is null for add operations
|
||||
* @param mixed $new Is null for remove operations
|
||||
*/
|
||||
public function __construct(int $type, $old, $new)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->old = $old;
|
||||
$this->new = $new;
|
||||
}
|
||||
}
|
173
dependencies/phpstan/phpdoc-parser/src/Printer/Differ.php
vendored
Normal file
173
dependencies/phpstan/phpdoc-parser/src/Printer/Differ.php
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Printer;
|
||||
|
||||
use Exception;
|
||||
use function array_reverse;
|
||||
use function count;
|
||||
/**
|
||||
* Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
|
||||
*
|
||||
* Copyright (c) 2011, Nikita Popov
|
||||
* All rights reserved.
|
||||
*
|
||||
* Implements the Myers diff algorithm.
|
||||
*
|
||||
* Myers, Eugene W. "An O (ND) difference algorithm and its variations."
|
||||
* Algorithmica 1.1 (1986): 251-266.
|
||||
*
|
||||
* @template T
|
||||
* @internal
|
||||
*/
|
||||
class Differ
|
||||
{
|
||||
/** @var callable(T, T): bool */
|
||||
private $isEqual;
|
||||
/**
|
||||
* Create differ over the given equality relation.
|
||||
*
|
||||
* @param callable(T, T): bool $isEqual Equality relation
|
||||
*/
|
||||
public function __construct(callable $isEqual)
|
||||
{
|
||||
$this->isEqual = $isEqual;
|
||||
}
|
||||
/**
|
||||
* Calculate diff (edit script) from $old to $new.
|
||||
*
|
||||
* @param T[] $old Original array
|
||||
* @param T[] $new New array
|
||||
*
|
||||
* @return DiffElem[] Diff (edit script)
|
||||
*/
|
||||
public function diff(array $old, array $new) : array
|
||||
{
|
||||
[$trace, $x, $y] = $this->calculateTrace($old, $new);
|
||||
return $this->extractDiff($trace, $x, $y, $old, $new);
|
||||
}
|
||||
/**
|
||||
* Calculate diff, including "replace" operations.
|
||||
*
|
||||
* If a sequence of remove operations is followed by the same number of add operations, these
|
||||
* will be coalesced into replace operations.
|
||||
*
|
||||
* @param T[] $old Original array
|
||||
* @param T[] $new New array
|
||||
*
|
||||
* @return DiffElem[] Diff (edit script), including replace operations
|
||||
*/
|
||||
public function diffWithReplacements(array $old, array $new) : array
|
||||
{
|
||||
return $this->coalesceReplacements($this->diff($old, $new));
|
||||
}
|
||||
/**
|
||||
* @param T[] $old
|
||||
* @param T[] $new
|
||||
* @return array{array<int, array<int, int>>, int, int}
|
||||
*/
|
||||
private function calculateTrace(array $old, array $new) : array
|
||||
{
|
||||
$n = count($old);
|
||||
$m = count($new);
|
||||
$max = $n + $m;
|
||||
$v = [1 => 0];
|
||||
$trace = [];
|
||||
for ($d = 0; $d <= $max; $d++) {
|
||||
$trace[] = $v;
|
||||
for ($k = -$d; $k <= $d; $k += 2) {
|
||||
if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) {
|
||||
$x = $v[$k + 1];
|
||||
} else {
|
||||
$x = $v[$k - 1] + 1;
|
||||
}
|
||||
$y = $x - $k;
|
||||
while ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) {
|
||||
$x++;
|
||||
$y++;
|
||||
}
|
||||
$v[$k] = $x;
|
||||
if ($x >= $n && $y >= $m) {
|
||||
return [$trace, $x, $y];
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Exception('Should not happen');
|
||||
}
|
||||
/**
|
||||
* @param array<int, array<int, int>> $trace
|
||||
* @param T[] $old
|
||||
* @param T[] $new
|
||||
* @return DiffElem[]
|
||||
*/
|
||||
private function extractDiff(array $trace, int $x, int $y, array $old, array $new) : array
|
||||
{
|
||||
$result = [];
|
||||
for ($d = count($trace) - 1; $d >= 0; $d--) {
|
||||
$v = $trace[$d];
|
||||
$k = $x - $y;
|
||||
if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) {
|
||||
$prevK = $k + 1;
|
||||
} else {
|
||||
$prevK = $k - 1;
|
||||
}
|
||||
$prevX = $v[$prevK];
|
||||
$prevY = $prevX - $prevK;
|
||||
while ($x > $prevX && $y > $prevY) {
|
||||
$result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]);
|
||||
$x--;
|
||||
$y--;
|
||||
}
|
||||
if ($d === 0) {
|
||||
break;
|
||||
}
|
||||
while ($x > $prevX) {
|
||||
$result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null);
|
||||
$x--;
|
||||
}
|
||||
while ($y > $prevY) {
|
||||
$result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]);
|
||||
$y--;
|
||||
}
|
||||
}
|
||||
return array_reverse($result);
|
||||
}
|
||||
/**
|
||||
* Coalesce equal-length sequences of remove+add into a replace operation.
|
||||
*
|
||||
* @param DiffElem[] $diff
|
||||
* @return DiffElem[]
|
||||
*/
|
||||
private function coalesceReplacements(array $diff) : array
|
||||
{
|
||||
$newDiff = [];
|
||||
$c = count($diff);
|
||||
for ($i = 0; $i < $c; $i++) {
|
||||
$diffType = $diff[$i]->type;
|
||||
if ($diffType !== DiffElem::TYPE_REMOVE) {
|
||||
$newDiff[] = $diff[$i];
|
||||
continue;
|
||||
}
|
||||
$j = $i;
|
||||
while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) {
|
||||
$j++;
|
||||
}
|
||||
$k = $j;
|
||||
while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) {
|
||||
$k++;
|
||||
}
|
||||
if ($j - $i === $k - $j) {
|
||||
$len = $j - $i;
|
||||
for ($n = 0; $n < $len; $n++) {
|
||||
$newDiff[] = new DiffElem(DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new);
|
||||
}
|
||||
} else {
|
||||
for (; $i < $k; $i++) {
|
||||
$newDiff[] = $diff[$i];
|
||||
}
|
||||
}
|
||||
$i = $k - 1;
|
||||
}
|
||||
return $newDiff;
|
||||
}
|
||||
}
|
633
dependencies/phpstan/phpdoc-parser/src/Printer/Printer.php
vendored
Normal file
633
dependencies/phpstan/phpdoc-parser/src/Printer/Printer.php
vendored
Normal file
@ -0,0 +1,633 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Printer;
|
||||
|
||||
use LogicException;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Attribute;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Node;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagMethodValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagPropertyValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineAnnotation;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArgument;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArray;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArrayItem;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\ImplementsTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueParameterNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\ParamOutTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\SelfOutTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasImportTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\UsesTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\InvalidTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ObjectShapeItemNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Lexer\Lexer;
|
||||
use WP_Ultimo\Dependencies\PHPStan\PhpDocParser\Parser\TokenIterator;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function get_object_vars;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function preg_match_all;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function trim;
|
||||
use const PREG_SET_ORDER;
|
||||
/**
|
||||
* Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1
|
||||
*
|
||||
* Copyright (c) 2011, Nikita Popov
|
||||
* All rights reserved.
|
||||
*/
|
||||
final class Printer
|
||||
{
|
||||
/** @var Differ<Node> */
|
||||
private $differ;
|
||||
/**
|
||||
* Map From "{$class}->{$subNode}" to string that should be inserted
|
||||
* between elements of this list subnode
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $listInsertionMap = [PhpDocNode::class . '->children' => "\n * ", UnionTypeNode::class . '->types' => '|', IntersectionTypeNode::class . '->types' => '&', ArrayShapeNode::class . '->items' => ', ', ObjectShapeNode::class . '->items' => ', ', CallableTypeNode::class . '->parameters' => ', ', GenericTypeNode::class . '->genericTypes' => ', ', ConstExprArrayNode::class . '->items' => ', ', MethodTagValueNode::class . '->parameters' => ', ', DoctrineArray::class . '->items' => ', ', DoctrineAnnotation::class . '->arguments' => ', '];
|
||||
/**
|
||||
* [$find, $extraLeft, $extraRight]
|
||||
*
|
||||
* @var array<string, array{string|null, string, string}>
|
||||
*/
|
||||
private $emptyListInsertionMap = [CallableTypeNode::class . '->parameters' => ['(', '', ''], ArrayShapeNode::class . '->items' => ['{', '', ''], ObjectShapeNode::class . '->items' => ['{', '', ''], DoctrineArray::class . '->items' => ['{', '', ''], DoctrineAnnotation::class . '->arguments' => ['(', '', '']];
|
||||
/** @var array<string, list<class-string<TypeNode>>> */
|
||||
private $parenthesesMap = [CallableTypeNode::class . '->returnType' => [CallableTypeNode::class, UnionTypeNode::class, IntersectionTypeNode::class], ArrayTypeNode::class . '->type' => [CallableTypeNode::class, UnionTypeNode::class, IntersectionTypeNode::class, ConstTypeNode::class, NullableTypeNode::class], OffsetAccessTypeNode::class . '->type' => [CallableTypeNode::class, UnionTypeNode::class, IntersectionTypeNode::class, ConstTypeNode::class, NullableTypeNode::class]];
|
||||
/** @var array<string, list<class-string<TypeNode>>> */
|
||||
private $parenthesesListMap = [IntersectionTypeNode::class . '->types' => [IntersectionTypeNode::class, UnionTypeNode::class, NullableTypeNode::class], UnionTypeNode::class . '->types' => [IntersectionTypeNode::class, UnionTypeNode::class, NullableTypeNode::class]];
|
||||
public function printFormatPreserving(PhpDocNode $node, PhpDocNode $originalNode, TokenIterator $originalTokens) : string
|
||||
{
|
||||
$this->differ = new Differ(static function ($a, $b) {
|
||||
if ($a instanceof Node && $b instanceof Node) {
|
||||
return $a === $b->getAttribute(Attribute::ORIGINAL_NODE);
|
||||
}
|
||||
return \false;
|
||||
});
|
||||
$tokenIndex = 0;
|
||||
$result = $this->printArrayFormatPreserving($node->children, $originalNode->children, $originalTokens, $tokenIndex, PhpDocNode::class, 'children');
|
||||
if ($result !== null) {
|
||||
return $result . $originalTokens->getContentBetween($tokenIndex, $originalTokens->getTokenCount());
|
||||
}
|
||||
return $this->print($node);
|
||||
}
|
||||
public function print(Node $node) : string
|
||||
{
|
||||
if ($node instanceof PhpDocNode) {
|
||||
return "/**\n *" . implode("\n *", array_map(function (PhpDocChildNode $child) : string {
|
||||
$s = $this->print($child);
|
||||
return $s === '' ? '' : ' ' . $s;
|
||||
}, $node->children)) . "\n */";
|
||||
}
|
||||
if ($node instanceof PhpDocTextNode) {
|
||||
return $node->text;
|
||||
}
|
||||
if ($node instanceof PhpDocTagNode) {
|
||||
if ($node->value instanceof DoctrineTagValueNode) {
|
||||
return $this->print($node->value);
|
||||
}
|
||||
return trim(sprintf('%s %s', $node->name, $this->print($node->value)));
|
||||
}
|
||||
if ($node instanceof PhpDocTagValueNode) {
|
||||
return $this->printTagValue($node);
|
||||
}
|
||||
if ($node instanceof TypeNode) {
|
||||
return $this->printType($node);
|
||||
}
|
||||
if ($node instanceof ConstExprNode) {
|
||||
return $this->printConstExpr($node);
|
||||
}
|
||||
if ($node instanceof MethodTagValueParameterNode) {
|
||||
$type = $node->type !== null ? $this->print($node->type) . ' ' : '';
|
||||
$isReference = $node->isReference ? '&' : '';
|
||||
$isVariadic = $node->isVariadic ? '...' : '';
|
||||
$default = $node->defaultValue !== null ? ' = ' . $this->print($node->defaultValue) : '';
|
||||
return "{$type}{$isReference}{$isVariadic}{$node->parameterName}{$default}";
|
||||
}
|
||||
if ($node instanceof CallableTypeParameterNode) {
|
||||
$type = $this->print($node->type) . ' ';
|
||||
$isReference = $node->isReference ? '&' : '';
|
||||
$isVariadic = $node->isVariadic ? '...' : '';
|
||||
$isOptional = $node->isOptional ? '=' : '';
|
||||
return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional;
|
||||
}
|
||||
if ($node instanceof DoctrineAnnotation) {
|
||||
return (string) $node;
|
||||
}
|
||||
if ($node instanceof DoctrineArgument) {
|
||||
return (string) $node;
|
||||
}
|
||||
if ($node instanceof DoctrineArray) {
|
||||
return (string) $node;
|
||||
}
|
||||
if ($node instanceof DoctrineArrayItem) {
|
||||
return (string) $node;
|
||||
}
|
||||
throw new LogicException(sprintf('Unknown node type %s', get_class($node)));
|
||||
}
|
||||
private function printTagValue(PhpDocTagValueNode $node) : string
|
||||
{
|
||||
// only nodes that contain another node are handled here
|
||||
// the rest falls back on (string) $node
|
||||
if ($node instanceof AssertTagMethodValueNode) {
|
||||
$isNegated = $node->isNegated ? '!' : '';
|
||||
$isEquality = $node->isEquality ? '=' : '';
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->method}() {$node->description}");
|
||||
}
|
||||
if ($node instanceof AssertTagPropertyValueNode) {
|
||||
$isNegated = $node->isNegated ? '!' : '';
|
||||
$isEquality = $node->isEquality ? '=' : '';
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->property} {$node->description}");
|
||||
}
|
||||
if ($node instanceof AssertTagValueNode) {
|
||||
$isNegated = $node->isNegated ? '!' : '';
|
||||
$isEquality = $node->isEquality ? '=' : '';
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$isNegated}{$isEquality}{$type} {$node->parameter} {$node->description}");
|
||||
}
|
||||
if ($node instanceof ExtendsTagValueNode || $node instanceof ImplementsTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} {$node->description}");
|
||||
}
|
||||
if ($node instanceof MethodTagValueNode) {
|
||||
$static = $node->isStatic ? 'static ' : '';
|
||||
$returnType = $node->returnType !== null ? $this->printType($node->returnType) . ' ' : '';
|
||||
$parameters = implode(', ', array_map(function (MethodTagValueParameterNode $parameter) : string {
|
||||
return $this->print($parameter);
|
||||
}, $node->parameters));
|
||||
$description = $node->description !== '' ? " {$node->description}" : '';
|
||||
$templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateTag) : string {
|
||||
return $this->print($templateTag);
|
||||
}, $node->templateTypes)) . '>' : '';
|
||||
return "{$static}{$returnType}{$node->methodName}{$templateTypes}({$parameters}){$description}";
|
||||
}
|
||||
if ($node instanceof MixinTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} {$node->description}");
|
||||
}
|
||||
if ($node instanceof ParamOutTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} {$node->parameterName} {$node->description}");
|
||||
}
|
||||
if ($node instanceof ParamTagValueNode) {
|
||||
$reference = $node->isReference ? '&' : '';
|
||||
$variadic = $node->isVariadic ? '...' : '';
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} {$reference}{$variadic}{$node->parameterName} {$node->description}");
|
||||
}
|
||||
if ($node instanceof PropertyTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} {$node->propertyName} {$node->description}");
|
||||
}
|
||||
if ($node instanceof ReturnTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} {$node->description}");
|
||||
}
|
||||
if ($node instanceof SelfOutTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim($type . ' ' . $node->description);
|
||||
}
|
||||
if ($node instanceof TemplateTagValueNode) {
|
||||
$bound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : '';
|
||||
$default = $node->default !== null ? ' = ' . $this->printType($node->default) : '';
|
||||
return trim("{$node->name}{$bound}{$default} {$node->description}");
|
||||
}
|
||||
if ($node instanceof ThrowsTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} {$node->description}");
|
||||
}
|
||||
if ($node instanceof TypeAliasImportTagValueNode) {
|
||||
return trim("{$node->importedAlias} from " . $this->printType($node->importedFrom) . ($node->importedAs !== null ? " as {$node->importedAs}" : ''));
|
||||
}
|
||||
if ($node instanceof TypeAliasTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$node->alias} {$type}");
|
||||
}
|
||||
if ($node instanceof UsesTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} {$node->description}");
|
||||
}
|
||||
if ($node instanceof VarTagValueNode) {
|
||||
$type = $this->printType($node->type);
|
||||
return trim("{$type} " . trim("{$node->variableName} {$node->description}"));
|
||||
}
|
||||
return (string) $node;
|
||||
}
|
||||
private function printType(TypeNode $node) : string
|
||||
{
|
||||
if ($node instanceof ArrayShapeNode) {
|
||||
$items = array_map(function (ArrayShapeItemNode $item) : string {
|
||||
return $this->printType($item);
|
||||
}, $node->items);
|
||||
if (!$node->sealed) {
|
||||
$items[] = '...';
|
||||
}
|
||||
return $node->kind . '{' . implode(', ', $items) . '}';
|
||||
}
|
||||
if ($node instanceof ArrayShapeItemNode) {
|
||||
if ($node->keyName !== null) {
|
||||
return sprintf('%s%s: %s', $this->print($node->keyName), $node->optional ? '?' : '', $this->printType($node->valueType));
|
||||
}
|
||||
return $this->printType($node->valueType);
|
||||
}
|
||||
if ($node instanceof ArrayTypeNode) {
|
||||
return $this->printOffsetAccessType($node->type) . '[]';
|
||||
}
|
||||
if ($node instanceof CallableTypeNode) {
|
||||
if ($node->returnType instanceof CallableTypeNode || $node->returnType instanceof UnionTypeNode || $node->returnType instanceof IntersectionTypeNode) {
|
||||
$returnType = $this->wrapInParentheses($node->returnType);
|
||||
} else {
|
||||
$returnType = $this->printType($node->returnType);
|
||||
}
|
||||
$parameters = implode(', ', array_map(function (CallableTypeParameterNode $parameterNode) : string {
|
||||
return $this->print($parameterNode);
|
||||
}, $node->parameters));
|
||||
return "{$node->identifier}({$parameters}): {$returnType}";
|
||||
}
|
||||
if ($node instanceof ConditionalTypeForParameterNode) {
|
||||
return sprintf('(%s %s %s ? %s : %s)', $node->parameterName, $node->negated ? 'is not' : 'is', $this->printType($node->targetType), $this->printType($node->if), $this->printType($node->else));
|
||||
}
|
||||
if ($node instanceof ConditionalTypeNode) {
|
||||
return sprintf('(%s %s %s ? %s : %s)', $this->printType($node->subjectType), $node->negated ? 'is not' : 'is', $this->printType($node->targetType), $this->printType($node->if), $this->printType($node->else));
|
||||
}
|
||||
if ($node instanceof ConstTypeNode) {
|
||||
return $this->printConstExpr($node->constExpr);
|
||||
}
|
||||
if ($node instanceof GenericTypeNode) {
|
||||
$genericTypes = [];
|
||||
foreach ($node->genericTypes as $index => $type) {
|
||||
$variance = $node->variances[$index] ?? GenericTypeNode::VARIANCE_INVARIANT;
|
||||
if ($variance === GenericTypeNode::VARIANCE_INVARIANT) {
|
||||
$genericTypes[] = $this->printType($type);
|
||||
} elseif ($variance === GenericTypeNode::VARIANCE_BIVARIANT) {
|
||||
$genericTypes[] = '*';
|
||||
} else {
|
||||
$genericTypes[] = sprintf('%s %s', $variance, $this->print($type));
|
||||
}
|
||||
}
|
||||
return $node->type . '<' . implode(', ', $genericTypes) . '>';
|
||||
}
|
||||
if ($node instanceof IdentifierTypeNode) {
|
||||
return $node->name;
|
||||
}
|
||||
if ($node instanceof IntersectionTypeNode || $node instanceof UnionTypeNode) {
|
||||
$items = [];
|
||||
foreach ($node->types as $type) {
|
||||
if ($type instanceof IntersectionTypeNode || $type instanceof UnionTypeNode || $type instanceof NullableTypeNode) {
|
||||
$items[] = $this->wrapInParentheses($type);
|
||||
continue;
|
||||
}
|
||||
$items[] = $this->printType($type);
|
||||
}
|
||||
return implode($node instanceof IntersectionTypeNode ? '&' : '|', $items);
|
||||
}
|
||||
if ($node instanceof InvalidTypeNode) {
|
||||
return (string) $node;
|
||||
}
|
||||
if ($node instanceof NullableTypeNode) {
|
||||
if ($node->type instanceof IntersectionTypeNode || $node->type instanceof UnionTypeNode) {
|
||||
return '?(' . $this->printType($node->type) . ')';
|
||||
}
|
||||
return '?' . $this->printType($node->type);
|
||||
}
|
||||
if ($node instanceof ObjectShapeNode) {
|
||||
$items = array_map(function (ObjectShapeItemNode $item) : string {
|
||||
return $this->printType($item);
|
||||
}, $node->items);
|
||||
return 'object{' . implode(', ', $items) . '}';
|
||||
}
|
||||
if ($node instanceof ObjectShapeItemNode) {
|
||||
if ($node->keyName !== null) {
|
||||
return sprintf('%s%s: %s', $this->print($node->keyName), $node->optional ? '?' : '', $this->printType($node->valueType));
|
||||
}
|
||||
return $this->printType($node->valueType);
|
||||
}
|
||||
if ($node instanceof OffsetAccessTypeNode) {
|
||||
return $this->printOffsetAccessType($node->type) . '[' . $this->printType($node->offset) . ']';
|
||||
}
|
||||
if ($node instanceof ThisTypeNode) {
|
||||
return (string) $node;
|
||||
}
|
||||
throw new LogicException(sprintf('Unknown node type %s', get_class($node)));
|
||||
}
|
||||
private function wrapInParentheses(TypeNode $node) : string
|
||||
{
|
||||
return '(' . $this->printType($node) . ')';
|
||||
}
|
||||
private function printOffsetAccessType(TypeNode $type) : string
|
||||
{
|
||||
if ($type instanceof CallableTypeNode || $type instanceof UnionTypeNode || $type instanceof IntersectionTypeNode || $type instanceof ConstTypeNode || $type instanceof NullableTypeNode) {
|
||||
return $this->wrapInParentheses($type);
|
||||
}
|
||||
return $this->printType($type);
|
||||
}
|
||||
private function printConstExpr(ConstExprNode $node) : string
|
||||
{
|
||||
// this is fine - ConstExprNode classes do not contain nodes that need smart printer logic
|
||||
return (string) $node;
|
||||
}
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
* @param Node[] $originalNodes
|
||||
*/
|
||||
private function printArrayFormatPreserving(array $nodes, array $originalNodes, TokenIterator $originalTokens, int &$tokenIndex, string $parentNodeClass, string $subNodeName) : ?string
|
||||
{
|
||||
$diff = $this->differ->diffWithReplacements($originalNodes, $nodes);
|
||||
$mapKey = $parentNodeClass . '->' . $subNodeName;
|
||||
$insertStr = $this->listInsertionMap[$mapKey] ?? null;
|
||||
$result = '';
|
||||
$beforeFirstKeepOrReplace = \true;
|
||||
$delayedAdd = [];
|
||||
$insertNewline = \false;
|
||||
[$isMultiline, $beforeAsteriskIndent, $afterAsteriskIndent] = $this->isMultiline($tokenIndex, $originalNodes, $originalTokens);
|
||||
if ($insertStr === "\n * ") {
|
||||
$insertStr = sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
|
||||
}
|
||||
foreach ($diff as $i => $diffElem) {
|
||||
$diffType = $diffElem->type;
|
||||
$newNode = $diffElem->new;
|
||||
$originalNode = $diffElem->old;
|
||||
if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) {
|
||||
$beforeFirstKeepOrReplace = \false;
|
||||
if (!$newNode instanceof Node || !$originalNode instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
$itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX);
|
||||
$itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX);
|
||||
if ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) {
|
||||
throw new LogicException();
|
||||
}
|
||||
$result .= $originalTokens->getContentBetween($tokenIndex, $itemStartPos);
|
||||
if (count($delayedAdd) > 0) {
|
||||
foreach ($delayedAdd as $delayedAddNode) {
|
||||
$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($delayedAddNode), $this->parenthesesListMap[$mapKey], \true);
|
||||
if ($parenthesesNeeded) {
|
||||
$result .= '(';
|
||||
}
|
||||
$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);
|
||||
if ($parenthesesNeeded) {
|
||||
$result .= ')';
|
||||
}
|
||||
if ($insertNewline) {
|
||||
$result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
|
||||
} else {
|
||||
$result .= $insertStr;
|
||||
}
|
||||
}
|
||||
$delayedAdd = [];
|
||||
}
|
||||
$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], \true) && !in_array(get_class($originalNode), $this->parenthesesListMap[$mapKey], \true);
|
||||
$addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos);
|
||||
if ($addParentheses) {
|
||||
$result .= '(';
|
||||
}
|
||||
$result .= $this->printNodeFormatPreserving($newNode, $originalTokens);
|
||||
if ($addParentheses) {
|
||||
$result .= ')';
|
||||
}
|
||||
$tokenIndex = $itemEndPos + 1;
|
||||
} elseif ($diffType === DiffElem::TYPE_ADD) {
|
||||
if ($insertStr === null) {
|
||||
return null;
|
||||
}
|
||||
if (!$newNode instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
if ($insertStr === ', ' && $isMultiline) {
|
||||
$insertStr = ',';
|
||||
$insertNewline = \true;
|
||||
}
|
||||
if ($beforeFirstKeepOrReplace) {
|
||||
// Will be inserted at the next "replace" or "keep" element
|
||||
$delayedAdd[] = $newNode;
|
||||
continue;
|
||||
}
|
||||
$itemEndPos = $tokenIndex - 1;
|
||||
if ($insertNewline) {
|
||||
$result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
|
||||
} else {
|
||||
$result .= $insertStr;
|
||||
}
|
||||
$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], \true);
|
||||
if ($parenthesesNeeded) {
|
||||
$result .= '(';
|
||||
}
|
||||
$result .= $this->printNodeFormatPreserving($newNode, $originalTokens);
|
||||
if ($parenthesesNeeded) {
|
||||
$result .= ')';
|
||||
}
|
||||
$tokenIndex = $itemEndPos + 1;
|
||||
} elseif ($diffType === DiffElem::TYPE_REMOVE) {
|
||||
if (!$originalNode instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
$itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX);
|
||||
$itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX);
|
||||
if ($itemStartPos < 0 || $itemEndPos < 0) {
|
||||
throw new LogicException();
|
||||
}
|
||||
if ($i === 0) {
|
||||
// If we're removing from the start, keep the tokens before the node and drop those after it,
|
||||
// instead of the other way around.
|
||||
$originalTokensArray = $originalTokens->getTokens();
|
||||
for ($j = $tokenIndex; $j < $itemStartPos; $j++) {
|
||||
if ($originalTokensArray[$j][Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) {
|
||||
break;
|
||||
}
|
||||
$result .= $originalTokensArray[$j][Lexer::VALUE_OFFSET];
|
||||
}
|
||||
}
|
||||
$tokenIndex = $itemEndPos + 1;
|
||||
}
|
||||
}
|
||||
if (count($delayedAdd) > 0) {
|
||||
if (!isset($this->emptyListInsertionMap[$mapKey])) {
|
||||
return null;
|
||||
}
|
||||
[$findToken, $extraLeft, $extraRight] = $this->emptyListInsertionMap[$mapKey];
|
||||
if ($findToken !== null) {
|
||||
$originalTokensArray = $originalTokens->getTokens();
|
||||
for (; $tokenIndex < count($originalTokensArray); $tokenIndex++) {
|
||||
$result .= $originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET];
|
||||
if ($originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET] !== $findToken) {
|
||||
continue;
|
||||
}
|
||||
$tokenIndex++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$first = \true;
|
||||
$result .= $extraLeft;
|
||||
foreach ($delayedAdd as $delayedAddNode) {
|
||||
if (!$first) {
|
||||
$result .= $insertStr;
|
||||
if ($insertNewline) {
|
||||
$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
|
||||
}
|
||||
}
|
||||
$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);
|
||||
$first = \false;
|
||||
}
|
||||
$result .= $extraRight;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
* @return array{bool, string, string}
|
||||
*/
|
||||
private function isMultiline(int $initialIndex, array $nodes, TokenIterator $originalTokens) : array
|
||||
{
|
||||
$isMultiline = count($nodes) > 1;
|
||||
$pos = $initialIndex;
|
||||
$allText = '';
|
||||
/** @var Node|null $node */
|
||||
foreach ($nodes as $node) {
|
||||
if (!$node instanceof Node) {
|
||||
continue;
|
||||
}
|
||||
$endPos = $node->getAttribute(Attribute::END_INDEX) + 1;
|
||||
$text = $originalTokens->getContentBetween($pos, $endPos);
|
||||
$allText .= $text;
|
||||
if (strpos($text, "\n") === \false) {
|
||||
// We require that a newline is present between *every* item. If the formatting
|
||||
// is inconsistent, with only some items having newlines, we don't consider it
|
||||
// as multiline
|
||||
$isMultiline = \false;
|
||||
}
|
||||
$pos = $endPos;
|
||||
}
|
||||
$c = preg_match_all('~\\n(?<before>[\\x09\\x20]*)\\*(?<after>\\x20*)~', $allText, $matches, PREG_SET_ORDER);
|
||||
if ($c === 0) {
|
||||
return [$isMultiline, '', ''];
|
||||
}
|
||||
$before = '';
|
||||
$after = '';
|
||||
foreach ($matches as $match) {
|
||||
if (strlen($match['before']) > strlen($before)) {
|
||||
$before = $match['before'];
|
||||
}
|
||||
if (strlen($match['after']) <= strlen($after)) {
|
||||
continue;
|
||||
}
|
||||
$after = $match['after'];
|
||||
}
|
||||
return [$isMultiline, $before, $after];
|
||||
}
|
||||
private function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens) : string
|
||||
{
|
||||
/** @var Node|null $originalNode */
|
||||
$originalNode = $node->getAttribute(Attribute::ORIGINAL_NODE);
|
||||
if ($originalNode === null) {
|
||||
return $this->print($node);
|
||||
}
|
||||
$class = get_class($node);
|
||||
if ($class !== get_class($originalNode)) {
|
||||
throw new LogicException();
|
||||
}
|
||||
$startPos = $originalNode->getAttribute(Attribute::START_INDEX);
|
||||
$endPos = $originalNode->getAttribute(Attribute::END_INDEX);
|
||||
if ($startPos < 0 || $endPos < 0) {
|
||||
throw new LogicException();
|
||||
}
|
||||
$result = '';
|
||||
$pos = $startPos;
|
||||
$subNodeNames = array_keys(get_object_vars($node));
|
||||
foreach ($subNodeNames as $subNodeName) {
|
||||
$subNode = $node->{$subNodeName};
|
||||
$origSubNode = $originalNode->{$subNodeName};
|
||||
if (!$subNode instanceof Node && $subNode !== null || !$origSubNode instanceof Node && $origSubNode !== null) {
|
||||
if ($subNode === $origSubNode) {
|
||||
// Unchanged, can reuse old code
|
||||
continue;
|
||||
}
|
||||
if (is_array($subNode) && is_array($origSubNode)) {
|
||||
// Array subnode changed, we might be able to reconstruct it
|
||||
$listResult = $this->printArrayFormatPreserving($subNode, $origSubNode, $originalTokens, $pos, $class, $subNodeName);
|
||||
if ($listResult === null) {
|
||||
return $this->print($node);
|
||||
}
|
||||
$result .= $listResult;
|
||||
continue;
|
||||
}
|
||||
return $this->print($node);
|
||||
}
|
||||
if ($origSubNode === null) {
|
||||
if ($subNode === null) {
|
||||
// Both null, nothing to do
|
||||
continue;
|
||||
}
|
||||
return $this->print($node);
|
||||
}
|
||||
$subStartPos = $origSubNode->getAttribute(Attribute::START_INDEX);
|
||||
$subEndPos = $origSubNode->getAttribute(Attribute::END_INDEX);
|
||||
if ($subStartPos < 0 || $subEndPos < 0) {
|
||||
throw new LogicException();
|
||||
}
|
||||
if ($subNode === null) {
|
||||
return $this->print($node);
|
||||
}
|
||||
$result .= $originalTokens->getContentBetween($pos, $subStartPos);
|
||||
$mapKey = get_class($node) . '->' . $subNodeName;
|
||||
$parenthesesNeeded = isset($this->parenthesesMap[$mapKey]) && in_array(get_class($subNode), $this->parenthesesMap[$mapKey], \true);
|
||||
if ($subNode->getAttribute(Attribute::ORIGINAL_NODE) !== null) {
|
||||
$parenthesesNeeded = $parenthesesNeeded && !in_array(get_class($subNode->getAttribute(Attribute::ORIGINAL_NODE)), $this->parenthesesMap[$mapKey], \true);
|
||||
}
|
||||
$addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($subStartPos, $subEndPos);
|
||||
if ($addParentheses) {
|
||||
$result .= '(';
|
||||
}
|
||||
$result .= $this->printNodeFormatPreserving($subNode, $originalTokens);
|
||||
if ($addParentheses) {
|
||||
$result .= ')';
|
||||
}
|
||||
$pos = $subEndPos + 1;
|
||||
}
|
||||
return $result . $originalTokens->getContentBetween($pos, $endPos + 1);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user