From 19a1f3a91fc2895a7540efd3537545bac16800df Mon Sep 17 00:00:00 2001 From: Jaapio Date: Fri, 20 Sep 2019 16:52:17 +0200 Subject: [PATCH] Phpstan to max level --- phpstan.neon | 12 +++--- src/DocBlock/DescriptionFactory.php | 57 ++++++++++++---------------- src/DocBlock/ExampleFinder.php | 7 +++- src/DocBlock/StandardTagFactory.php | 59 +++++++++++++++++++---------- src/DocBlock/Tags/Covers.php | 3 ++ src/DocBlock/Tags/Deprecated.php | 3 +- src/DocBlock/Tags/Generic.php | 2 +- src/DocBlock/Tags/Link.php | 1 + src/DocBlock/Tags/Method.php | 9 +++-- src/DocBlock/Tags/Param.php | 12 +++--- src/DocBlock/Tags/Property.php | 14 ++++--- src/DocBlock/Tags/PropertyRead.php | 10 +++-- src/DocBlock/Tags/PropertyWrite.php | 9 +++-- src/DocBlock/Tags/Return_.php | 4 +- src/DocBlock/Tags/See.php | 8 ++-- src/DocBlock/Tags/Since.php | 3 +- src/DocBlock/Tags/Throws.php | 4 +- src/DocBlock/Tags/Uses.php | 5 ++- src/DocBlock/Tags/Var_.php | 15 +++++--- src/DocBlock/Tags/Version.php | 9 ++++- src/DocBlockFactory.php | 12 ++++-- 21 files changed, 156 insertions(+), 102 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 2beb983..4ebb808 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,10 +1,10 @@ +includes: + - /composer/vendor/phpstan/phpstan-mockery/extension.neon + - /composer/vendor/phpstan/phpstan-webmozart-assert/extension.neon + parameters: ignoreErrors: # false positive - - '#Call to an undefined method object::getDocComment\(\)#' + - '#Method phpDocumentor\Reflection\DocBlock\Tags\Method::filterArguments() should return array but returns array#' + - "~Parameter #1 $function of function call_user_func_array expects callable(): mixed, array(string, 'create') given.~" - '#Cannot call method render\(\) on phpDocumentor\\Reflection\\DocBlock\\Description\|string#' - - '#Calling method create\(\) on possibly null value of type phpDocumentor\\Reflection\\DocBlock\\DescriptionFactory\|null#' - - '#Calling method resolve\(\) on possibly null value of type phpDocumentor\\Reflection\\(TypeResolver|FqsenResolver)\|null#' - - # nested parents - - '#Calling method render\(\) on possibly null value of type phpDocumentor\\Reflection\\DocBlock\\Description\|string\|null#' diff --git a/src/DocBlock/DescriptionFactory.php b/src/DocBlock/DescriptionFactory.php index 458fac7..746a2c2 100644 --- a/src/DocBlock/DescriptionFactory.php +++ b/src/DocBlock/DescriptionFactory.php @@ -14,6 +14,7 @@ declare(strict_types=1); namespace phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\Types\Context as TypeContext; +use Webmozart\Assert\Assert; use const PREG_SPLIT_DELIM_CAPTURE; use function count; use function explode; @@ -62,9 +63,28 @@ class DescriptionFactory */ public function create(string $contents, ?TypeContext $context = null) : Description { - [$text, $tags] = $this->parse($this->lex($contents), $context); + $tokens = $this->lex($contents); + $count = count($tokens); + $tagCount = 0; + $tags = []; - return new Description($text, $tags); + for ($i = 1; $i < $count; $i += 2) { + $tag = $this->tagFactory->create($tokens[$i], $context); + if ($tag !== null) { + $tags[] = $tag; + } + $tokens[$i] = '%' . ++$tagCount . '$s'; + } + + //In order to allow "literal" inline tags, the otherwise invalid + //sequence "{@}" is changed to "@", and "{}" is changed to "}". + //"%" is escaped to "%%" because of vsprintf. + //See unit tests for examples. + for ($i = 0; $i < $count; $i += 2) { + $tokens[$i] = str_replace(['{@}', '{}', '%'], ['@', '}', '%%'], $tokens[$i]); + } + + return new Description(implode('', $tokens), $tags); } /** @@ -81,7 +101,7 @@ class DescriptionFactory return [$contents]; } - return preg_split( + $parts = preg_split( '/\{ # "{@}" is not a valid inline tag. This ensures that we do not treat it as one, but treat it literally. (?!@\}) @@ -110,35 +130,8 @@ class DescriptionFactory 0, PREG_SPLIT_DELIM_CAPTURE ); - } - - /** - * Parses the stream of tokens in to a new set of tokens containing Tags. - * - * @param string[] $tokens - * - * @return string[]|Tag[] - */ - private function parse(array $tokens, ?TypeContext $context = null) : array - { - $count = count($tokens); - $tagCount = 0; - $tags = []; - - for ($i = 1; $i < $count; $i += 2) { - $tags[] = $this->tagFactory->create($tokens[$i], $context); - $tokens[$i] = '%' . ++$tagCount . '$s'; - } - - //In order to allow "literal" inline tags, the otherwise invalid - //sequence "{@}" is changed to "@", and "{}" is changed to "}". - //"%" is escaped to "%%" because of vsprintf. - //See unit tests for examples. - for ($i = 0; $i < $count; $i += 2) { - $tokens[$i] = str_replace(['{@}', '{}', '%'], ['@', '}', '%%'], $tokens[$i]); - } - - return [implode('', $tokens), $tags]; + Assert::isArray($parts); + return $parts; } /** diff --git a/src/DocBlock/ExampleFinder.php b/src/DocBlock/ExampleFinder.php index 227894c..919c2b4 100644 --- a/src/DocBlock/ExampleFinder.php +++ b/src/DocBlock/ExampleFinder.php @@ -96,8 +96,10 @@ class ExampleFinder * 2. Checks the source folder for the given filename * 3. Checks the 'examples' folder in the current working directory for examples * 4. Checks the path relative to the current working directory for the given filename + * + * @return string[] all lines of the example file */ - private function getExampleFileContents(string $filename) : ?string + private function getExampleFileContents(string $filename) : ?array { $normalizedPath = null; @@ -119,7 +121,8 @@ class ExampleFinder } } - return $normalizedPath && is_readable($normalizedPath) ? file($normalizedPath) : null; + $lines = $normalizedPath && is_readable($normalizedPath) ? file($normalizedPath) : false; + return $lines !== false ? $lines : null; } /** diff --git a/src/DocBlock/StandardTagFactory.php b/src/DocBlock/StandardTagFactory.php index b26f761..7cf911a 100644 --- a/src/DocBlock/StandardTagFactory.php +++ b/src/DocBlock/StandardTagFactory.php @@ -28,6 +28,23 @@ use function count; use function get_class; use function preg_match; use function strpos; +use phpDocumentor\Reflection\DocBlock\Tags\Author; +use phpDocumentor\Reflection\DocBlock\Tags\Covers; +use phpDocumentor\Reflection\DocBlock\Tags\Deprecated; +use phpDocumentor\Reflection\DocBlock\Tags\Link; +use phpDocumentor\Reflection\DocBlock\Tags\Method; +use phpDocumentor\Reflection\DocBlock\Tags\Param; +use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead; +use phpDocumentor\Reflection\DocBlock\Tags\Property; +use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite; +use phpDocumentor\Reflection\DocBlock\Tags\Return_; +use phpDocumentor\Reflection\DocBlock\Tags\See; +use phpDocumentor\Reflection\DocBlock\Tags\Since; +use phpDocumentor\Reflection\DocBlock\Tags\Source; +use phpDocumentor\Reflection\DocBlock\Tags\Throws; +use phpDocumentor\Reflection\DocBlock\Tags\Uses; +use phpDocumentor\Reflection\DocBlock\Tags\Var_; +use phpDocumentor\Reflection\DocBlock\Tags\Version; /** * Creates a Tag object given the contents of a tag. @@ -56,25 +73,25 @@ final class StandardTagFactory implements TagFactory * FQCN to a class that handles it as an array value. */ private $tagHandlerMappings = [ - 'author' => '\phpDocumentor\Reflection\DocBlock\Tags\Author', - 'covers' => '\phpDocumentor\Reflection\DocBlock\Tags\Covers', - 'deprecated' => '\phpDocumentor\Reflection\DocBlock\Tags\Deprecated', + 'author' => Author::class, + 'covers' => Covers::class, + 'deprecated' => Deprecated::class, // 'example' => '\phpDocumentor\Reflection\DocBlock\Tags\Example', - 'link' => '\phpDocumentor\Reflection\DocBlock\Tags\Link', - 'method' => '\phpDocumentor\Reflection\DocBlock\Tags\Method', - 'param' => '\phpDocumentor\Reflection\DocBlock\Tags\Param', - 'property-read' => '\phpDocumentor\Reflection\DocBlock\Tags\PropertyRead', - 'property' => '\phpDocumentor\Reflection\DocBlock\Tags\Property', - 'property-write' => '\phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite', - 'return' => '\phpDocumentor\Reflection\DocBlock\Tags\Return_', - 'see' => '\phpDocumentor\Reflection\DocBlock\Tags\See', - 'since' => '\phpDocumentor\Reflection\DocBlock\Tags\Since', - 'source' => '\phpDocumentor\Reflection\DocBlock\Tags\Source', - 'throw' => '\phpDocumentor\Reflection\DocBlock\Tags\Throws', - 'throws' => '\phpDocumentor\Reflection\DocBlock\Tags\Throws', - 'uses' => '\phpDocumentor\Reflection\DocBlock\Tags\Uses', - 'var' => '\phpDocumentor\Reflection\DocBlock\Tags\Var_', - 'version' => '\phpDocumentor\Reflection\DocBlock\Tags\Version', + 'link' => Link::class, + 'method' => Method::class, + 'param' => Param::class, + 'property-read' => PropertyRead::class, + 'property' => Property::class, + 'property-write' => PropertyWrite::class, + 'return' => Return_::class, + 'see' => See::class, + 'since' => Since::class, + 'source' => Source::class, + 'throw' => Throws::class, + 'throws' => Throws::class, + 'uses' => Uses::class, + 'var' => Var_::class, + 'version' => Version::class, ]; /** @@ -149,7 +166,7 @@ final class StandardTagFactory implements TagFactory /** * {@inheritDoc} */ - public function addService($service, $alias = null) : void + public function addService(object $service, $alias = null) : void { $this->serviceLocator[$alias ?: get_class($service)] = $service; } @@ -215,6 +232,8 @@ final class StandardTagFactory implements TagFactory /** * Determines the Fully Qualified Class Name of the Factory or Tag (containing a Factory Method `create`). + * + * @return */ private function findHandlerClassName(string $tagName, TypeContext $context) : string { @@ -245,7 +264,7 @@ final class StandardTagFactory implements TagFactory { $arguments = []; foreach ($parameters as $parameter) { - $typeHint = $parameter->getClass() ? $parameter->getClass()->getName() : null; + $typeHint = $parameter->getClass() !== null ? $parameter->getClass()->getName() : null; if (isset($locator[$typeHint])) { $arguments[] = $locator[$typeHint]; continue; diff --git a/src/DocBlock/Tags/Covers.php b/src/DocBlock/Tags/Covers.php index 2a1ebf1..5d165f8 100644 --- a/src/DocBlock/Tags/Covers.php +++ b/src/DocBlock/Tags/Covers.php @@ -51,8 +51,11 @@ final class Covers extends BaseTag implements Factory\StaticMethod ?TypeContext $context = null ) : self { Assert::notEmpty($body); + Assert::notNull($descriptionFactory); + Assert::notNull($resolver); $parts = preg_split('/\s+/Su', $body, 2); + Assert::isArray($parts); return new static( $resolver->resolve($parts[0], $context), diff --git a/src/DocBlock/Tags/Deprecated.php b/src/DocBlock/Tags/Deprecated.php index 9883414..824ec73 100644 --- a/src/DocBlock/Tags/Deprecated.php +++ b/src/DocBlock/Tags/Deprecated.php @@ -43,7 +43,7 @@ final class Deprecated extends BaseTag implements Factory\StaticMethod [^\s\:]+\:\s*\$[^\$]+\$ )'; - /** @var string The version vector. */ + /** @var string|null The version vector. */ private $version = ''; public function __construct(?string $version = null, ?Description $description = null) @@ -74,6 +74,7 @@ final class Deprecated extends BaseTag implements Factory\StaticMethod ); } + Assert::notNull($descriptionFactory); return new static( $matches[1], $descriptionFactory->create($matches[2] ?? '', $context) diff --git a/src/DocBlock/Tags/Generic.php b/src/DocBlock/Tags/Generic.php index 713a10c..ffb4a5b 100644 --- a/src/DocBlock/Tags/Generic.php +++ b/src/DocBlock/Tags/Generic.php @@ -54,7 +54,7 @@ class Generic extends BaseTag implements Factory\StaticMethod Assert::stringNotEmpty($name); Assert::notNull($descriptionFactory); - $description = $descriptionFactory && $body !== '' ? $descriptionFactory->create($body, $context) : null; + $description = $body !== '' ? $descriptionFactory->create($body, $context) : null; return new static($name, $description); } diff --git a/src/DocBlock/Tags/Link.php b/src/DocBlock/Tags/Link.php index 475357f..2f9db50 100644 --- a/src/DocBlock/Tags/Link.php +++ b/src/DocBlock/Tags/Link.php @@ -50,6 +50,7 @@ final class Link extends BaseTag implements Factory\StaticMethod Assert::notNull($descriptionFactory); $parts = preg_split('/\s+/Su', $body, 2); + Assert::isArray($parts); $description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null; return new static($parts[0], $description); diff --git a/src/DocBlock/Tags/Method.php b/src/DocBlock/Tags/Method.php index 251cf03..0ab19e9 100644 --- a/src/DocBlock/Tags/Method.php +++ b/src/DocBlock/Tags/Method.php @@ -44,7 +44,7 @@ final class Method extends BaseTag implements Factory\StaticMethod /** @var string */ private $methodName = ''; - /** @var string[] */ + /** @var string[][] */ private $arguments = []; /** @var bool */ @@ -87,7 +87,8 @@ final class Method extends BaseTag implements Factory\StaticMethod ?TypeContext $context = null ) : ?self { Assert::stringNotEmpty($body); - Assert::allNotNull([$typeResolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); // 1. none or more whitespace // 2. optionally the keyword "static" followed by whitespace @@ -184,7 +185,7 @@ final class Method extends BaseTag implements Factory\StaticMethod } /** - * @return string[] + * @return string[][] */ public function getArguments() : array { @@ -221,7 +222,7 @@ final class Method extends BaseTag implements Factory\StaticMethod } /** - * @param mixed[][] $arguments + * @param array $arguments * * @return mixed[][] */ diff --git a/src/DocBlock/Tags/Param.php b/src/DocBlock/Tags/Param.php index 5d02cb6..430c3d7 100644 --- a/src/DocBlock/Tags/Param.php +++ b/src/DocBlock/Tags/Param.php @@ -66,32 +66,34 @@ final class Param extends BaseTag implements Factory\StaticMethod ?TypeContext $context = null ) : self { Assert::stringNotEmpty($body); - Assert::allNotNull([$typeResolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); $parts = preg_split('/(\s+)/Su', $body, 3, PREG_SPLIT_DELIM_CAPTURE); + Assert::isArray($parts); $type = null; $variableName = ''; $isVariadic = false; // if the first item that is encountered is not a variable; it is a type - if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] !== '$')) { + if (isset($parts[0]) && ($parts[0] !== '') && ($parts[0][0] !== '$')) { $type = $typeResolver->resolve(array_shift($parts), $context); array_shift($parts); } // if the next item starts with a $ or ...$ it must be the variable name - if (isset($parts[0]) && (strlen($parts[0]) > 0) && + if (isset($parts[0]) && ($parts[0] !== '') && (strpos($parts[0], '$') === 0 || strpos($parts[0], '...$') === 0) ) { $variableName = array_shift($parts); array_shift($parts); - if (substr($variableName, 0, 3) === '...') { + if ($variableName !== null && strpos($variableName, '...') === 0) { $isVariadic = true; $variableName = substr($variableName, 3); } - if (substr($variableName, 0, 1) === '$') { + if ($variableName !== null && strpos($variableName, '$') === 0) { $variableName = substr($variableName, 1); } } diff --git a/src/DocBlock/Tags/Property.php b/src/DocBlock/Tags/Property.php index a81b3f0..55f40b7 100644 --- a/src/DocBlock/Tags/Property.php +++ b/src/DocBlock/Tags/Property.php @@ -23,7 +23,7 @@ use const PREG_SPLIT_DELIM_CAPTURE; use function array_shift; use function implode; use function preg_split; -use function strlen; +use function strpos; use function substr; /** @@ -57,24 +57,26 @@ class Property extends BaseTag implements Factory\StaticMethod ?TypeContext $context = null ) : self { Assert::stringNotEmpty($body); - Assert::allNotNull([$typeResolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); - $parts = preg_split('/(\s+)/Su', $body, 3, PREG_SPLIT_DELIM_CAPTURE); + $parts = preg_split('/(\s+)/Su', $body, 3, PREG_SPLIT_DELIM_CAPTURE); + Assert::isArray($parts); $type = null; $variableName = ''; // if the first item that is encountered is not a variable; it is a type - if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] !== '$')) { + if (isset($parts[0]) && ($parts[0] !== '') && ($parts[0][0] !== '$')) { $type = $typeResolver->resolve(array_shift($parts), $context); array_shift($parts); } // if the next item starts with a $ or ...$ it must be the variable name - if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] === '$')) { + if (isset($parts[0]) && ($parts[0] !== '') && (strpos($parts[0], '$') === 0)) { $variableName = array_shift($parts); array_shift($parts); - if (substr($variableName, 0, 1) === '$') { + if ($variableName !== null && strpos($variableName, '$') === 0) { $variableName = substr($variableName, 1); } } diff --git a/src/DocBlock/Tags/PropertyRead.php b/src/DocBlock/Tags/PropertyRead.php index f98e332..5810ea8 100644 --- a/src/DocBlock/Tags/PropertyRead.php +++ b/src/DocBlock/Tags/PropertyRead.php @@ -57,24 +57,26 @@ class PropertyRead extends BaseTag implements Factory\StaticMethod ?TypeContext $context = null ) : self { Assert::stringNotEmpty($body); - Assert::allNotNull([$typeResolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); $parts = preg_split('/(\s+)/Su', $body, 3, PREG_SPLIT_DELIM_CAPTURE); + Assert::isArray($parts); $type = null; $variableName = ''; // if the first item that is encountered is not a variable; it is a type - if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] !== '$')) { + if (isset($parts[0]) && ($parts[0] !== '') && ($parts[0][0] !== '$')) { $type = $typeResolver->resolve(array_shift($parts), $context); array_shift($parts); } // if the next item starts with a $ or ...$ it must be the variable name - if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] === '$')) { + if (isset($parts[0]) && ($parts[0] !== '') && (strpos($parts[0], '$') === 0)) { $variableName = array_shift($parts); array_shift($parts); - if (substr($variableName, 0, 1) === '$') { + if ($variableName !== null && strpos($variableName, '$') === 0) { $variableName = substr($variableName, 1); } } diff --git a/src/DocBlock/Tags/PropertyWrite.php b/src/DocBlock/Tags/PropertyWrite.php index 8e45ab8..ff7367b 100644 --- a/src/DocBlock/Tags/PropertyWrite.php +++ b/src/DocBlock/Tags/PropertyWrite.php @@ -24,6 +24,7 @@ use function array_shift; use function implode; use function preg_split; use function strlen; +use function strpos; use function substr; /** @@ -57,14 +58,16 @@ class PropertyWrite extends BaseTag implements Factory\StaticMethod ?TypeContext $context = null ) : self { Assert::stringNotEmpty($body); - Assert::allNotNull([$typeResolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); $parts = preg_split('/(\s+)/Su', $body, 3, PREG_SPLIT_DELIM_CAPTURE); + Assert::isArray($parts); $type = null; $variableName = ''; // if the first item that is encountered is not a variable; it is a type - if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] !== '$')) { + if (isset($parts[0]) && ($parts[0] !== '') && ($parts[0][0] !== '$')) { $type = $typeResolver->resolve(array_shift($parts), $context); array_shift($parts); } @@ -74,7 +77,7 @@ class PropertyWrite extends BaseTag implements Factory\StaticMethod $variableName = array_shift($parts); array_shift($parts); - if (substr($variableName, 0, 1) === '$') { + if ($variableName !== null && strpos($variableName, '$') === 0) { $variableName = substr($variableName, 1); } } diff --git a/src/DocBlock/Tags/Return_.php b/src/DocBlock/Tags/Return_.php index dac5036..1efdfbb 100644 --- a/src/DocBlock/Tags/Return_.php +++ b/src/DocBlock/Tags/Return_.php @@ -47,9 +47,11 @@ final class Return_ extends BaseTag implements Factory\StaticMethod ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ) : self { - Assert::allNotNull([$typeResolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); $parts = preg_split('/\s+/Su', $body, 2); + Assert::isArray($parts); $type = $typeResolver->resolve($parts[0] ?? '', $context); $description = $descriptionFactory->create($parts[1] ?? '', $context); diff --git a/src/DocBlock/Tags/See.php b/src/DocBlock/Tags/See.php index 218309e..5db5a65 100644 --- a/src/DocBlock/Tags/See.php +++ b/src/DocBlock/Tags/See.php @@ -49,13 +49,15 @@ class See extends BaseTag implements Factory\StaticMethod */ public static function create( string $body, - ?FqsenResolver $resolver = null, + ?FqsenResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ) : self { - Assert::allNotNull([$resolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); $parts = preg_split('/\s+/Su', $body, 2); + Assert::isArray($parts); $description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null; // https://tools.ietf.org/html/rfc2396#section-3 @@ -63,7 +65,7 @@ class See extends BaseTag implements Factory\StaticMethod return new static(new Url($parts[0]), $description); } - return new static(new FqsenRef($resolver->resolve($parts[0], $context)), $description); + return new static(new FqsenRef($typeResolver->resolve($parts[0], $context)), $description); } /** diff --git a/src/DocBlock/Tags/Since.php b/src/DocBlock/Tags/Since.php index 4b96796..8e714a8 100644 --- a/src/DocBlock/Tags/Since.php +++ b/src/DocBlock/Tags/Since.php @@ -43,7 +43,7 @@ final class Since extends BaseTag implements Factory\StaticMethod [^\s\:]+\:\s*\$[^\$]+\$ )'; - /** @var string The version vector. */ + /** @var string|null The version vector. */ private $version = ''; public function __construct(?string $version = null, ?Description $description = null) @@ -68,6 +68,7 @@ final class Since extends BaseTag implements Factory\StaticMethod return null; } + Assert::notNull($descriptionFactory); return new static( $matches[1], $descriptionFactory->create($matches[2] ?? '', $context) diff --git a/src/DocBlock/Tags/Throws.php b/src/DocBlock/Tags/Throws.php index 7ac2b42..3e9047e 100644 --- a/src/DocBlock/Tags/Throws.php +++ b/src/DocBlock/Tags/Throws.php @@ -47,9 +47,11 @@ final class Throws extends BaseTag implements Factory\StaticMethod ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ) : self { - Assert::allNotNull([$typeResolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); $parts = preg_split('/\s+/Su', $body, 2); + Assert::isArray($parts); $type = $typeResolver->resolve($parts[0] ?? '', $context); $description = $descriptionFactory->create($parts[1] ?? '', $context); diff --git a/src/DocBlock/Tags/Uses.php b/src/DocBlock/Tags/Uses.php index 24c74dc..529c2b7 100644 --- a/src/DocBlock/Tags/Uses.php +++ b/src/DocBlock/Tags/Uses.php @@ -50,9 +50,12 @@ final class Uses extends BaseTag implements Factory\StaticMethod ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ) : self { - Assert::allNotNull([$resolver, $descriptionFactory]); + Assert::notNull($resolver); + Assert::notNull($descriptionFactory); $parts = preg_split('/\s+/Su', $body, 2); + Assert::isArray($parts); + Assert::allString($parts); return new static( $resolver->resolve($parts[0], $context), diff --git a/src/DocBlock/Tags/Var_.php b/src/DocBlock/Tags/Var_.php index e39d4e0..1039ffd 100644 --- a/src/DocBlock/Tags/Var_.php +++ b/src/DocBlock/Tags/Var_.php @@ -57,24 +57,29 @@ class Var_ extends BaseTag implements Factory\StaticMethod ?TypeContext $context = null ) : self { Assert::stringNotEmpty($body); - Assert::allNotNull([$typeResolver, $descriptionFactory]); + Assert::notNull($typeResolver); + Assert::notNull($descriptionFactory); $parts = preg_split('/(\s+)/Su', $body, 3, PREG_SPLIT_DELIM_CAPTURE); + Assert::isArray($parts); + Assert::allString($parts); $type = null; $variableName = ''; // if the first item that is encountered is not a variable; it is a type - if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] !== '$')) { - $type = $typeResolver->resolve(array_shift($parts), $context); + if (isset($parts[0]) && ($parts[0] !== '') && ($parts[0][0] !== '$')) { + if ($typeResolver !== null) { + $type = $typeResolver->resolve(array_shift($parts), $context); + } array_shift($parts); } // if the next item starts with a $ or ...$ it must be the variable name - if (isset($parts[0]) && (strlen($parts[0]) > 0) && ($parts[0][0] === '$')) { + if (isset($parts[0]) && ($parts[0] !== '') && (strpos($parts[0], '$') === 0)) { $variableName = array_shift($parts); array_shift($parts); - if (substr($variableName, 0, 1) === '$') { + if ($variableName !== null && strpos($variableName, '$') === 0) { $variableName = substr($variableName, 1); } } diff --git a/src/DocBlock/Tags/Version.php b/src/DocBlock/Tags/Version.php index 5a50283..28cc326 100644 --- a/src/DocBlock/Tags/Version.php +++ b/src/DocBlock/Tags/Version.php @@ -43,7 +43,7 @@ final class Version extends BaseTag implements Factory\StaticMethod [^\s\:]+\:\s*\$[^\$]+\$ )'; - /** @var string The version vector. */ + /** @var string|null The version vector. */ private $version = ''; public function __construct(?string $version = null, ?Description $description = null) @@ -68,9 +68,14 @@ final class Version extends BaseTag implements Factory\StaticMethod return null; } + $description = null; + if ($descriptionFactory !== null) { + $description = $descriptionFactory->create($matches[2] ?? '', $context); + } + return new static( $matches[1], - $descriptionFactory->create($matches[2] ?? '', $context) + $description ); } diff --git a/src/DocBlockFactory.php b/src/DocBlockFactory.php index d046a65..1ea28eb 100644 --- a/src/DocBlockFactory.php +++ b/src/DocBlockFactory.php @@ -230,7 +230,7 @@ final class DocBlockFactory implements DocBlockFactoryInterface * @param string $tags Tag block to parse. * @param Types\Context $context Context of the parsed Tag * - * @return DocBlock\Tag[]|string[]|null[] + * @return DocBlock\Tag[] */ private function parseTagBlock(string $tags, Types\Context $context) : array { @@ -239,9 +239,13 @@ final class DocBlockFactory implements DocBlockFactoryInterface return []; } - $result = $this->splitTagBlockIntoTagLines($tags); - foreach ($result as $key => $tagLine) { - $result[$key] = $this->tagFactory->create(trim($tagLine), $context); + $result = []; + $lines = $this->splitTagBlockIntoTagLines($tags); + foreach ($lines as $key => $tagLine) { + $tag = $this->tagFactory->create(trim($tagLine), $context); + if ($tag instanceof Tag) { + $result[$key] = $tag; + } } return $result;