diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..374f1bd --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +.PHONY: install-phive +install-phive: + mkdir tools; \ + wget -O tools/phive.phar https://phar.io/releases/phive.phar; \ + wget -O tools/phive.phar.asc https://phar.io/releases/phive.phar.asc; \ + gpg --keyserver pool.sks-keyservers.net --recv-keys 0x9D8A98B29B2D5D79; \ + gpg --verify tools/phive.phar.asc tools/phive.phar; \ + chmod +x tools/phive.phar + +.PHONY: setup +setup: install-phive + docker run -it --rm -v${PWD}:/opt/project -w /opt/project phpdoc/phar-ga:latest php tools/phive.phar install --force-accept-unsigned + +.PHONY: phpcs +phpcs: + docker run -it --rm -v${PWD}:/opt/project -w /opt/project phpdoc/phpcs-ga:latest -d memory_limit=1024M + +.PHONY: phpstan +phpstan: + docker run -it --rm -v${PWD}:/opt/project -w /opt/project phpstan-ga:latest analyse src --debug --no-progress --level max --configuration phpstan.neon + +.PHONY: psaml +psalm: + docker run -it --rm -v${PWD}:/opt/project -w /opt/project mickaelandrieu/psalm-ga + +.PHONY: test +test: + docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:7.2 tools/phpunit + +.PHONY: pre-commit-test +pre-commit-test: test phpcs phpstan psalm + diff --git a/composer.lock b/composer.lock index cc854ec..e2ac299 100644 --- a/composer.lock +++ b/composer.lock @@ -173,32 +173,29 @@ }, { "name": "webmozart/assert", - "version": "1.4.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", + "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -220,7 +217,7 @@ "check", "validate" ], - "time": "2018-12-25T11:19:39+00:00" + "time": "2019-11-24T13:36:37+00:00" } ], "packages-dev": [ diff --git a/phive.xml b/phive.xml new file mode 100644 index 0000000..5168775 --- /dev/null +++ b/phive.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/phpstan.neon b/phpstan.neon index 4ebb808..272dd74 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -6,5 +6,3 @@ parameters: ignoreErrors: # false positive - '#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#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1460f9a..81f914c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,8 +1,9 @@ ./src/ - - ./vendor/ - diff --git a/src/DocBlock/StandardTagFactory.php b/src/DocBlock/StandardTagFactory.php index 02c3651..59caf8c 100644 --- a/src/DocBlock/StandardTagFactory.php +++ b/src/DocBlock/StandardTagFactory.php @@ -177,8 +177,8 @@ final class StandardTagFactory implements TagFactory public function registerTagHandler(string $tagName, string $handler) : void { Assert::stringNotEmpty($tagName); - Assert::stringNotEmpty($handler); Assert::classExists($handler); + /** @var object $handler stupid hack to make phpstan happy. */ Assert::implementsInterface($handler, StaticMethod::class); if (strpos($tagName, '\\') && $tagName[0] !== '\\') { @@ -224,7 +224,9 @@ final class StandardTagFactory implements TagFactory ); try { - return call_user_func_array([$handlerClassName, 'create'], $arguments); + /** @var callable $callable */ + $callable = [$handlerClassName, 'create']; + return call_user_func_array($callable, $arguments); } catch (InvalidArgumentException $e) { return null; } diff --git a/src/DocBlock/Tags/BaseTag.php b/src/DocBlock/Tags/BaseTag.php index 7a1b949..fbcd402 100644 --- a/src/DocBlock/Tags/BaseTag.php +++ b/src/DocBlock/Tags/BaseTag.php @@ -24,7 +24,7 @@ abstract class BaseTag implements DocBlock\Tag /** @var string Name of the tag */ protected $name = ''; - /** @var Description|string|null Description of the tag. */ + /** @var Description|null Description of the tag. */ protected $description; /** @@ -37,10 +37,7 @@ abstract class BaseTag implements DocBlock\Tag return $this->name; } - /** - * @return Description|string|null - */ - public function getDescription() + public function getDescription() : ?Description { return $this->description; } diff --git a/src/DocBlock/Tags/Deprecated.php b/src/DocBlock/Tags/Deprecated.php index 824ec73..130d844 100644 --- a/src/DocBlock/Tags/Deprecated.php +++ b/src/DocBlock/Tags/Deprecated.php @@ -94,6 +94,6 @@ final class Deprecated extends BaseTag implements Factory\StaticMethod */ public function __toString() : string { - return $this->version . ($this->description ? ' ' . $this->description->render() : ''); + return ($this->version ?? '') . ($this->description ? ' ' . $this->description->render() : ''); } } diff --git a/src/DocBlock/Tags/Example.php b/src/DocBlock/Tags/Example.php index 122d6d3..020145f 100644 --- a/src/DocBlock/Tags/Example.php +++ b/src/DocBlock/Tags/Example.php @@ -13,7 +13,6 @@ declare(strict_types=1); namespace phpDocumentor\Reflection\DocBlock\Tags; -use phpDocumentor\Reflection\DocBlock\Description; use phpDocumentor\Reflection\DocBlock\Tag; use Webmozart\Assert\Assert; use function array_key_exists; @@ -26,7 +25,7 @@ use function trim; /** * Reflection class for a {@}example tag in a Docblock. */ -final class Example extends BaseTag +final class Example implements Tag { /** @var string Path to a file to use as an example. May also be an absolute URI. */ private $filePath; @@ -43,10 +42,10 @@ final class Example extends BaseTag /** @var int */ private $lineCount; - /** - * @param string|Description|null $description - */ - public function __construct(string $filePath, bool $isURI, int $startingLine, int $lineCount, $description) + /** @var string|null */ + private $content; + + public function __construct(string $filePath, bool $isURI, int $startingLine, int $lineCount, ?string $content) { Assert::notEmpty($filePath); Assert::greaterThanEq($startingLine, 0); @@ -55,20 +54,16 @@ final class Example extends BaseTag $this->filePath = $filePath; $this->startingLine = $startingLine; $this->lineCount = $lineCount; - $this->name = 'example'; - if ($description !== null) { - $this->description = trim((string) $description); + if ($content !== null) { + $this->content = trim((string) $content); } $this->isURI = $isURI; } - /** - * {@inheritdoc} - */ - public function getContent() + public function getContent() : string { - if ($this->description === null) { + if ($this->content === null) { $filePath = '"' . $this->filePath . '"'; if ($this->isURI) { $filePath = $this->isUriRelative($this->filePath) @@ -76,10 +71,15 @@ final class Example extends BaseTag : $this->filePath; } - return trim($filePath . ' ' . parent::getDescription()); + return trim($filePath); } - return $this->description; + return $this->content; + } + + public function getDescription() : ?string + { + return $this->content; } /** @@ -121,7 +121,7 @@ final class Example extends BaseTag } return new static( - $filePath ?? $fileUri, + $filePath ?? ($fileUri ?? ''), $fileUri !== null, $startingLine, $lineCount, @@ -145,7 +145,7 @@ final class Example extends BaseTag */ public function __toString() : string { - return $this->filePath . ($this->description ? ' ' . $this->description : ''); + return $this->filePath . ($this->content ? ' ' . $this->content : ''); } /** @@ -165,4 +165,18 @@ final class Example extends BaseTag { return $this->lineCount; } + + public function getName() : string + { + return 'example'; + } + + public function render(?Formatter $formatter = null) : string + { + if ($formatter === null) { + $formatter = new Formatter\PassthroughFormatter(); + } + + return $formatter->format($this); + } } diff --git a/src/DocBlock/Tags/Generic.php b/src/DocBlock/Tags/Generic.php index ffb4a5b..7509ff1 100644 --- a/src/DocBlock/Tags/Generic.php +++ b/src/DocBlock/Tags/Generic.php @@ -24,7 +24,7 @@ use function preg_match; /** * Parses a tag definition for a DocBlock. */ -class Generic extends BaseTag implements Factory\StaticMethod +final class Generic extends BaseTag implements Factory\StaticMethod { /** * Parses a tag and populates the member variables. diff --git a/src/DocBlock/Tags/Method.php b/src/DocBlock/Tags/Method.php index 8f9ab59..4d42961 100644 --- a/src/DocBlock/Tags/Method.php +++ b/src/DocBlock/Tags/Method.php @@ -27,7 +27,6 @@ use function implode; use function is_string; use function preg_match; use function sort; -use function strlen; use function strpos; use function substr; use function trim; @@ -54,7 +53,9 @@ final class Method extends BaseTag implements Factory\StaticMethod private $returnType; /** - * @param mixed[][] $arguments $arguments + * @param mixed[][] $arguments + * + * @psalm-param array|string> $arguments */ public function __construct( string $methodName, @@ -64,7 +65,6 @@ final class Method extends BaseTag implements Factory\StaticMethod ?Description $description = null ) { Assert::stringNotEmpty($methodName); - Assert::boolean($static); if ($returnType === null) { $returnType = new Void_(); @@ -151,7 +151,7 @@ final class Method extends BaseTag implements Factory\StaticMethod $returnType = $typeResolver->resolve($returnType, $context); $description = $descriptionFactory->create($description, $context); - if (is_string($arguments) && strlen($arguments) > 0) { + if ($arguments !== '') { $arguments = explode(',', $arguments); foreach ($arguments as &$argument) { $argument = explode(' ', self::stripRestArg(trim($argument)), 2); @@ -222,13 +222,17 @@ final class Method extends BaseTag implements Factory\StaticMethod } /** - * @param mixed[][] $arguments + * @param mixed[][]|string[] $arguments * * @return mixed[][] + * + * @psalm-param array|string> $arguments + * @psalm-return array> $arguments */ private function filterArguments(array $arguments = []) : array { - foreach ($arguments as &$argument) { + $result = []; + foreach ($arguments as $argument) { if (is_string($argument)) { $argument = ['name' => $argument]; } @@ -244,9 +248,11 @@ final class Method extends BaseTag implements Factory\StaticMethod 'Arguments can only have the "name" and "type" fields, found: ' . var_export($keys, true) ); } + + $result[] = $argument; } - return $arguments; + return $result; } private static function stripRestArg(string $argument) : string diff --git a/src/DocBlock/Tags/Param.php b/src/DocBlock/Tags/Param.php index 74e984d..967ed84 100644 --- a/src/DocBlock/Tags/Param.php +++ b/src/DocBlock/Tags/Param.php @@ -37,14 +37,14 @@ final class Param extends BaseTag implements Factory\StaticMethod /** @var Type|null */ private $type; - /** @var string */ - private $variableName = ''; + /** @var string|null */ + private $variableName; /** @var bool determines whether this is a variadic argument */ - private $isVariadic = false; + private $isVariadic; public function __construct( - string $variableName, + ?string $variableName, ?Type $type = null, bool $isVariadic = false, ?Description $description = null @@ -105,7 +105,7 @@ final class Param extends BaseTag implements Factory\StaticMethod /** * Returns the variable's name. */ - public function getVariableName() : string + public function getVariableName() : ?string { return $this->variableName; } @@ -133,7 +133,7 @@ final class Param extends BaseTag implements Factory\StaticMethod { return ($this->type ? $this->type . ' ' : '') . ($this->isVariadic() ? '...' : '') - . '$' . $this->variableName + . ($this->variableName !== null ? '$' . $this->variableName : '') . ($this->description ? ' ' . $this->description : ''); } } diff --git a/src/DocBlock/Tags/Property.php b/src/DocBlock/Tags/Property.php index 55f40b7..290a4fa 100644 --- a/src/DocBlock/Tags/Property.php +++ b/src/DocBlock/Tags/Property.php @@ -29,7 +29,7 @@ use function substr; /** * Reflection class for a {@}property tag in a Docblock. */ -class Property extends BaseTag implements Factory\StaticMethod +final class Property extends BaseTag implements Factory\StaticMethod { /** @var string */ protected $name = 'property'; @@ -37,10 +37,10 @@ class Property extends BaseTag implements Factory\StaticMethod /** @var Type|null */ private $type; - /** @var string */ + /** @var string|null */ protected $variableName = ''; - public function __construct(string $variableName, ?Type $type = null, ?Description $description = null) + public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null) { $this->variableName = $variableName; $this->type = $type; @@ -89,7 +89,7 @@ class Property extends BaseTag implements Factory\StaticMethod /** * Returns the variable's name. */ - public function getVariableName() : string + public function getVariableName() : ?string { return $this->variableName; } @@ -108,7 +108,7 @@ class Property extends BaseTag implements Factory\StaticMethod public function __toString() : string { return ($this->type ? $this->type . ' ' : '') - . '$' . $this->variableName + . ($this->variableName ? '$' . $this->variableName : '') . ($this->description ? ' ' . $this->description : ''); } } diff --git a/src/DocBlock/Tags/PropertyRead.php b/src/DocBlock/Tags/PropertyRead.php index 9cdd4f8..4e0c904 100644 --- a/src/DocBlock/Tags/PropertyRead.php +++ b/src/DocBlock/Tags/PropertyRead.php @@ -29,7 +29,7 @@ use function substr; /** * Reflection class for a {@}property-read tag in a Docblock. */ -class PropertyRead extends BaseTag implements Factory\StaticMethod +final class PropertyRead extends BaseTag implements Factory\StaticMethod { /** @var string */ protected $name = 'property-read'; @@ -37,10 +37,10 @@ class PropertyRead extends BaseTag implements Factory\StaticMethod /** @var Type|null */ private $type; - /** @var string */ + /** @var string|null */ protected $variableName = ''; - public function __construct(string $variableName, ?Type $type = null, ?Description $description = null) + public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null) { $this->variableName = $variableName; $this->type = $type; @@ -89,7 +89,7 @@ class PropertyRead extends BaseTag implements Factory\StaticMethod /** * Returns the variable's name. */ - public function getVariableName() : string + public function getVariableName() : ?string { return $this->variableName; } @@ -108,7 +108,7 @@ class PropertyRead extends BaseTag implements Factory\StaticMethod public function __toString() : string { return ($this->type ? $this->type . ' ' : '') - . '$' . $this->variableName + . ($this->variableName ? '$' . $this->variableName : '') . ($this->description ? ' ' . $this->description : ''); } } diff --git a/src/DocBlock/Tags/PropertyWrite.php b/src/DocBlock/Tags/PropertyWrite.php index edeed5f..014b1ac 100644 --- a/src/DocBlock/Tags/PropertyWrite.php +++ b/src/DocBlock/Tags/PropertyWrite.php @@ -30,7 +30,7 @@ use function substr; /** * Reflection class for a {@}property-write tag in a Docblock. */ -class PropertyWrite extends BaseTag implements Factory\StaticMethod +final class PropertyWrite extends BaseTag implements Factory\StaticMethod { /** @var string */ protected $name = 'property-write'; @@ -38,10 +38,10 @@ class PropertyWrite extends BaseTag implements Factory\StaticMethod /** @var Type|null */ private $type; - /** @var string */ + /** @var string|null */ protected $variableName = ''; - public function __construct(string $variableName, ?Type $type = null, ?Description $description = null) + public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null) { $this->variableName = $variableName; $this->type = $type; @@ -90,7 +90,7 @@ class PropertyWrite extends BaseTag implements Factory\StaticMethod /** * Returns the variable's name. */ - public function getVariableName() : string + public function getVariableName() : ?string { return $this->variableName; } @@ -109,7 +109,7 @@ class PropertyWrite extends BaseTag implements Factory\StaticMethod public function __toString() : string { return ($this->type ? $this->type . ' ' : '') - . '$' . $this->variableName + . ($this->variableName ? '$' . $this->variableName : '') . ($this->description ? ' ' . $this->description : ''); } } diff --git a/src/DocBlock/Tags/Return_.php b/src/DocBlock/Tags/Return_.php index 1efdfbb..2fb8135 100644 --- a/src/DocBlock/Tags/Return_.php +++ b/src/DocBlock/Tags/Return_.php @@ -69,6 +69,6 @@ final class Return_ extends BaseTag implements Factory\StaticMethod public function __toString() : string { - return $this->type . ' ' . $this->description; + return $this->type . ' ' . (string) $this->description; } } diff --git a/src/DocBlock/Tags/See.php b/src/DocBlock/Tags/See.php index cb79e48..21d8591 100644 --- a/src/DocBlock/Tags/See.php +++ b/src/DocBlock/Tags/See.php @@ -27,7 +27,7 @@ use function preg_split; /** * Reflection class for an {@}see tag in a Docblock. */ -class See extends BaseTag implements Factory\StaticMethod +final class See extends BaseTag implements Factory\StaticMethod { /** @var string */ protected $name = 'see'; diff --git a/src/DocBlock/Tags/Since.php b/src/DocBlock/Tags/Since.php index 8e714a8..31ce54c 100644 --- a/src/DocBlock/Tags/Since.php +++ b/src/DocBlock/Tags/Since.php @@ -88,6 +88,6 @@ final class Since extends BaseTag implements Factory\StaticMethod */ public function __toString() : string { - return $this->version . ($this->description ? ' ' . $this->description->render() : ''); + return (string) $this->version . ($this->description ? ' ' . (string) $this->description : ''); } } diff --git a/src/DocBlock/Tags/Source.php b/src/DocBlock/Tags/Source.php index c6286fd..b678806 100644 --- a/src/DocBlock/Tags/Source.php +++ b/src/DocBlock/Tags/Source.php @@ -72,7 +72,7 @@ final class Source extends BaseTag implements Factory\StaticMethod $description = $matches[3]; } - return new static($startingLine, $lineCount, $descriptionFactory->create($description, $context)); + return new static($startingLine, $lineCount, $descriptionFactory->create($description??'', $context)); } /** @@ -101,6 +101,6 @@ final class Source extends BaseTag implements Factory\StaticMethod { return $this->startingLine . ($this->lineCount !== null ? ' ' . $this->lineCount : '') - . ($this->description ? ' ' . $this->description->render() : ''); + . ($this->description ? ' ' . (string) $this->description : ''); } } diff --git a/src/DocBlock/Tags/Throws.php b/src/DocBlock/Tags/Throws.php index 3e9047e..1a2328d 100644 --- a/src/DocBlock/Tags/Throws.php +++ b/src/DocBlock/Tags/Throws.php @@ -69,6 +69,6 @@ final class Throws extends BaseTag implements Factory\StaticMethod public function __toString() : string { - return $this->type . ' ' . $this->description; + return (string) $this->type . ' ' . (string) $this->description; } } diff --git a/src/DocBlock/Tags/Uses.php b/src/DocBlock/Tags/Uses.php index 529c2b7..7a69642 100644 --- a/src/DocBlock/Tags/Uses.php +++ b/src/DocBlock/Tags/Uses.php @@ -76,6 +76,6 @@ final class Uses extends BaseTag implements Factory\StaticMethod */ public function __toString() : string { - return $this->refers . ' ' . $this->description->render(); + return $this->refers . ' ' . (string) $this->description; } } diff --git a/src/DocBlock/Tags/Var_.php b/src/DocBlock/Tags/Var_.php index cf5b4d9..1bd5b8a 100644 --- a/src/DocBlock/Tags/Var_.php +++ b/src/DocBlock/Tags/Var_.php @@ -29,7 +29,7 @@ use function substr; /** * Reflection class for a {@}var tag in a Docblock. */ -class Var_ extends BaseTag implements Factory\StaticMethod +final class Var_ extends BaseTag implements Factory\StaticMethod { /** @var string */ protected $name = 'var'; @@ -37,10 +37,10 @@ class Var_ extends BaseTag implements Factory\StaticMethod /** @var Type|null */ private $type; - /** @var string */ + /** @var string|null */ protected $variableName = ''; - public function __construct(string $variableName, ?Type $type = null, ?Description $description = null) + public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null) { $this->variableName = $variableName; $this->type = $type; @@ -68,9 +68,7 @@ class Var_ extends BaseTag implements Factory\StaticMethod // if the first item that is encountered is not a variable; it is a type if (isset($parts[0]) && ($parts[0] !== '') && ($parts[0][0] !== '$')) { - if ($typeResolver !== null) { - $type = $typeResolver->resolve(array_shift($parts), $context); - } + $type = $typeResolver->resolve(array_shift($parts), $context); array_shift($parts); } @@ -92,7 +90,7 @@ class Var_ extends BaseTag implements Factory\StaticMethod /** * Returns the variable's name. */ - public function getVariableName() : string + public function getVariableName() : ?string { return $this->variableName; } diff --git a/tests/unit/DocBlock/ExampleFinderTest.php b/tests/unit/DocBlock/ExampleFinderTest.php index 19a32f1..d135892 100644 --- a/tests/unit/DocBlock/ExampleFinderTest.php +++ b/tests/unit/DocBlock/ExampleFinderTest.php @@ -39,7 +39,7 @@ class ExampleFinderTest extends TestCase */ public function testFileNotFound() : void { - $example = new Example('./example.php', false, 1, 0, new Description('Test')); + $example = new Example('./example.php', false, 1, 0, 'Test'); $this->assertSame('** File not found : ./example.php **', $this->fixture->find($example)); } } diff --git a/tests/unit/DocBlockFactoryTest.php b/tests/unit/DocBlockFactoryTest.php index 91f06be..1c965ad 100644 --- a/tests/unit/DocBlockFactoryTest.php +++ b/tests/unit/DocBlockFactoryTest.php @@ -221,7 +221,8 @@ DOCBLOCK; <<