From 16be9fe1318c53457ac723dc6abb1739e5ec6097 Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Sun, 13 Oct 2019 17:32:41 +0200 Subject: [PATCH] Add PhpdocToPropertyTypeFixer --- README.rst | 14 +- src/AbstractPhpdocToTypeDeclarationFixer.php | 28 +- src/Fixer/Comment/CommentToPhpdocFixer.php | 2 +- .../PhpdocToParamTypeFixer.php | 8 +- .../PhpdocToPropertyTypeFixer.php | 244 +++++++++ .../PhpdocToReturnTypeFixer.php | 9 +- src/Fixer/Phpdoc/PhpdocAlignFixer.php | 2 +- src/Fixer/Phpdoc/PhpdocIndentFixer.php | 2 +- src/Fixer/Phpdoc/PhpdocScalarFixer.php | 2 +- src/Fixer/Phpdoc/PhpdocToCommentFixer.php | 2 +- src/Fixer/Phpdoc/PhpdocTypesFixer.php | 2 +- tests/AutoReview/FixerTest.php | 13 +- .../PhpdocToPropertyTypeFixerTest.php | 477 ++++++++++++++++++ 13 files changed, 780 insertions(+), 25 deletions(-) create mode 100644 src/Fixer/FunctionNotation/PhpdocToPropertyTypeFixer.php create mode 100644 tests/Fixer/FunctionNotation/PhpdocToPropertyTypeFixerTest.php diff --git a/README.rst b/README.rst index 6a64fc9fd00..c1f16585ebc 100644 --- a/README.rst +++ b/README.rst @@ -1759,12 +1759,24 @@ Choose from the list of available rules: - ``scalar_types`` (``bool``): fix also scalar types; may have unexpected behaviour due to PHP bad type coercion system; defaults to ``true`` +* **phpdoc_to_property_type** + + EXPERIMENTAL: Takes ``@var`` annotation of non-mixed types and adjusts + accordingly the property signature. Requires PHP >= 7.4. + + *Risky rule: this rule is EXPERIMENTAL and [1] is not covered with backward compatibility promise. [2] ``@var`` annotation is mandatory for the fixer to make changes, signatures of properties without it (no docblock) will not be fixed. [3] Manual actions might be required for newly typed properties that are read before initialization.* + + Configuration options: + + - ``scalar_types`` (``bool``): fix also scalar types; may have unexpected + behaviour due to PHP bad type coercion system; defaults to ``true`` + * **phpdoc_to_return_type** EXPERIMENTAL: Takes ``@return`` annotation of non-mixed types and adjusts accordingly the function signature. Requires PHP >= 7.0. - *Risky rule: this rule is EXPERIMENTAL and [1] is not covered with backward compatibility promise. [2] ``@return`` annotation is mandatory for the fixer to make changes, signatures of methods without it (no docblock, inheritdocs) will not be fixed. [3] Manual actions are required if inherited signatures are not properly documented. [4] ``@inheritdocs`` support is under construction.* + *Risky rule: this rule is EXPERIMENTAL and [1] is not covered with backward compatibility promise. [2] ``@return`` annotation is mandatory for the fixer to make changes, signatures of methods without it (no docblock, inheritdocs) will not be fixed. [3] Manual actions are required if inherited signatures are not properly documented.* Configuration options: diff --git a/src/AbstractPhpdocToTypeDeclarationFixer.php b/src/AbstractPhpdocToTypeDeclarationFixer.php index a1712b77c7a..8b5d46df9bc 100644 --- a/src/AbstractPhpdocToTypeDeclarationFixer.php +++ b/src/AbstractPhpdocToTypeDeclarationFixer.php @@ -86,14 +86,11 @@ protected function createConfigurationDefinition() } /** - * Find all the annotations of given type in the function's PHPDoc comment. + * @param int $index The index of the function token * - * @param string $name - * @param int $index The index of the function token - * - * @return Annotation[] + * @return null|int */ - protected function findAnnotations($name, Tokens $tokens, $index) + protected function findFunctionDocComment(Tokens $tokens, $index) { do { $index = $tokens->getPrevNonWhitespace($index); @@ -107,18 +104,29 @@ protected function findAnnotations($name, Tokens $tokens, $index) T_STATIC, ])); - if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT)) { - return []; + if ($tokens[$index]->isGivenKind(T_DOC_COMMENT)) { + return $index; } + return null; + } + + /** + * @param string $name + * @param int $docCommentIndex + * + * @return Annotation[] + */ + protected function getAnnotationsFromDocComment($name, Tokens $tokens, $docCommentIndex) + { $namespacesAnalyzer = new NamespacesAnalyzer(); - $namespace = $namespacesAnalyzer->getNamespaceAt($tokens, $index); + $namespace = $namespacesAnalyzer->getNamespaceAt($tokens, $docCommentIndex); $namespaceUsesAnalyzer = new NamespaceUsesAnalyzer(); $namespaceUses = $namespaceUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace); $doc = new DocBlock( - $tokens[$index]->getContent(), + $tokens[$docCommentIndex]->getContent(), $namespace, $namespaceUses ); diff --git a/src/Fixer/Comment/CommentToPhpdocFixer.php b/src/Fixer/Comment/CommentToPhpdocFixer.php index 290e0570c89..b3a35d00ff8 100644 --- a/src/Fixer/Comment/CommentToPhpdocFixer.php +++ b/src/Fixer/Comment/CommentToPhpdocFixer.php @@ -54,7 +54,7 @@ public function isRisky() /** * {@inheritdoc} * - * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocAnnotationWithoutDotFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToCommentFixer, PhpdocToParamTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. + * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocAnnotationWithoutDotFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToCommentFixer, PhpdocToParamTypeFixer, PhpdocToPropertyTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. */ public function getPriority() { diff --git a/src/Fixer/FunctionNotation/PhpdocToParamTypeFixer.php b/src/Fixer/FunctionNotation/PhpdocToParamTypeFixer.php index 3c9c0ae2259..8aab0590caf 100644 --- a/src/Fixer/FunctionNotation/PhpdocToParamTypeFixer.php +++ b/src/Fixer/FunctionNotation/PhpdocToParamTypeFixer.php @@ -114,9 +114,13 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens) continue; } - $paramTypeAnnotations = $this->findAnnotations('param', $tokens, $index); + $docCommentIndex = $this->findFunctionDocComment($tokens, $index); - foreach ($paramTypeAnnotations as $paramTypeAnnotation) { + if (null === $docCommentIndex) { + continue; + } + + foreach ($this->getAnnotationsFromDocComment('param', $tokens, $docCommentIndex) as $paramTypeAnnotation) { $typeInfo = $this->getCommonTypeFromAnnotation($paramTypeAnnotation); if (null === $typeInfo) { diff --git a/src/Fixer/FunctionNotation/PhpdocToPropertyTypeFixer.php b/src/Fixer/FunctionNotation/PhpdocToPropertyTypeFixer.php new file mode 100644 index 00000000000..9aaac3fe3fd --- /dev/null +++ b/src/Fixer/FunctionNotation/PhpdocToPropertyTypeFixer.php @@ -0,0 +1,244 @@ + + * Dariusz Rumiński + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace PhpCsFixer\Fixer\FunctionNotation; + +use PhpCsFixer\AbstractPhpdocToTypeDeclarationFixer; +use PhpCsFixer\DocBlock\Annotation; +use PhpCsFixer\FixerDefinition\FixerDefinition; +use PhpCsFixer\FixerDefinition\VersionSpecification; +use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample; +use PhpCsFixer\Tokenizer\Token; +use PhpCsFixer\Tokenizer\Tokens; + +final class PhpdocToPropertyTypeFixer extends AbstractPhpdocToTypeDeclarationFixer +{ + /** + * @var array + */ + private $skippedTypes = [ + 'mixed' => true, + 'resource' => true, + 'null' => true, + ]; + + /** + * {@inheritdoc} + */ + public function getDefinition() + { + return new FixerDefinition( + 'EXPERIMENTAL: Takes `@var` annotation of non-mixed types and adjusts accordingly the property signature. Requires PHP >= 7.4.', + [ + new VersionSpecificCodeSample( + ' false] + ), + ], + null, + 'This rule is EXPERIMENTAL and [1] is not covered with backward compatibility promise. [2] `@var` annotation is mandatory for the fixer to make changes, signatures of properties without it (no docblock) will not be fixed. [3] Manual actions might be required for newly typed properties that are read before initialization.' + ); + } + + /** + * {@inheritdoc} + */ + public function isCandidate(Tokens $tokens) + { + return \PHP_VERSION_ID >= 70400 && $tokens->isTokenKindFound(T_DOC_COMMENT); + } + + /** + * {@inheritdoc} + * + * Must run before PhpdocAlignFixer. + * Must run after CommentToPhpdocFixer, PhpdocIndentFixer, PhpdocScalarFixer, PhpdocToCommentFixer, PhpdocTypesFixer. + */ + public function getPriority() + { + return parent::getPriority(); + } + + protected function isSkippedType($type) + { + return isset($this->skippedTypes[$type]); + } + + /** + * {@inheritdoc} + */ + protected function applyFix(\SplFileInfo $file, Tokens $tokens) + { + for ($index = $tokens->count() - 1; 0 < $index; --$index) { + if ($tokens[$index]->isGivenKind([T_CLASS, T_TRAIT])) { + $this->fixClass($tokens, $index); + } + } + } + + /** + * @param int $index + */ + private function fixClass(Tokens $tokens, $index) + { + $index = $tokens->getNextTokenOfKind($index, ['{']); + $classEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index); + + for (; $index < $classEndIndex; ++$index) { + if ($tokens[$index]->isGivenKind(T_FUNCTION)) { + $index = $tokens->getNextTokenOfKind($index, ['{', ';']); + + if ($tokens[$index]->equals('{')) { + $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index); + } + + continue; + } + + if (!$tokens[$index]->isGivenKind(T_DOC_COMMENT)) { + continue; + } + + $docCommentIndex = $index; + $propertyIndexes = $this->findNextUntypedPropertiesDeclaration($tokens, $docCommentIndex); + + if ([] === $propertyIndexes) { + continue; + } + + $typeInfo = $this->resolveAppliableType( + $propertyIndexes, + $this->getAnnotationsFromDocComment('var', $tokens, $docCommentIndex) + ); + + if (null === $typeInfo) { + continue; + } + + list($propertyType, $isNullable) = $typeInfo; + + if (\in_array($propertyType, ['void', 'callable'], true)) { + continue; + } + + $newTokens = array_merge( + $this->createTypeDeclarationTokens($propertyType, $isNullable), + [new Token([T_WHITESPACE, ' '])] + ); + + $tokens->insertAt(current($propertyIndexes), $newTokens); + + $index = max($propertyIndexes) + \count($newTokens) + 1; + $classEndIndex += \count($newTokens); + } + } + + /** + * @param int $index + * + * @return array + */ + private function findNextUntypedPropertiesDeclaration(Tokens $tokens, $index) + { + do { + $index = $tokens->getNextMeaningfulToken($index); + } while ($tokens[$index]->isGivenKind([ + T_PRIVATE, + T_PROTECTED, + T_PUBLIC, + T_STATIC, + T_VAR, + ])); + + if (!$tokens[$index]->isGivenKind(T_VARIABLE)) { + return []; + } + + $properties = []; + while (!$tokens[$index]->equals(';')) { + if ($tokens[$index]->isGivenKind(T_VARIABLE)) { + $properties[$tokens[$index]->getContent()] = $index; + } + + $index = $tokens->getNextMeaningfulToken($index); + } + + return $properties; + } + + /** + * @param array $propertyIndexes + * @param Annotation[] $annotations + */ + private function resolveAppliableType(array $propertyIndexes, array $annotations) + { + $propertyTypes = []; + + foreach ($annotations as $annotation) { + $propertyName = $annotation->getVariableName(); + + if (null === $propertyName) { + if (1 !== \count($propertyIndexes)) { + continue; + } + + $propertyName = key($propertyIndexes); + } + + if (!isset($propertyIndexes[$propertyName])) { + continue; + } + + $typeInfo = $this->getCommonTypeFromAnnotation($annotation); + + if (!isset($propertyTypes[$propertyName])) { + $propertyTypes[$propertyName] = []; + } elseif ($typeInfo !== $propertyTypes[$propertyName]) { + return null; + } + + $propertyTypes[$propertyName] = $typeInfo; + } + + if (\count($propertyTypes) !== \count($propertyIndexes)) { + return null; + } + + $type = array_shift($propertyTypes); + foreach ($propertyTypes as $propertyType) { + if ($propertyType !== $type) { + return null; + } + } + + return $type; + } +} diff --git a/src/Fixer/FunctionNotation/PhpdocToReturnTypeFixer.php b/src/Fixer/FunctionNotation/PhpdocToReturnTypeFixer.php index 2a0415f51fe..73a88fcde24 100644 --- a/src/Fixer/FunctionNotation/PhpdocToReturnTypeFixer.php +++ b/src/Fixer/FunctionNotation/PhpdocToReturnTypeFixer.php @@ -90,7 +90,7 @@ function bar() {} ), ], null, - 'This rule is EXPERIMENTAL and [1] is not covered with backward compatibility promise. [2] `@return` annotation is mandatory for the fixer to make changes, signatures of methods without it (no docblock, inheritdocs) will not be fixed. [3] Manual actions are required if inherited signatures are not properly documented. [4] `@inheritdocs` support is under construction.' + 'This rule is EXPERIMENTAL and [1] is not covered with backward compatibility promise. [2] `@return` annotation is mandatory for the fixer to make changes, signatures of methods without it (no docblock, inheritdocs) will not be fixed. [3] Manual actions are required if inherited signatures are not properly documented.' ); } @@ -140,7 +140,12 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens) continue; } - $returnTypeAnnotation = $this->findAnnotations('return', $tokens, $index); + $docCommentIndex = $this->findFunctionDocComment($tokens, $index); + if (null === $docCommentIndex) { + continue; + } + + $returnTypeAnnotation = $this->getAnnotationsFromDocComment('return', $tokens, $docCommentIndex); if (1 !== \count($returnTypeAnnotation)) { continue; } diff --git a/src/Fixer/Phpdoc/PhpdocAlignFixer.php b/src/Fixer/Phpdoc/PhpdocAlignFixer.php index 9943ec631fa..329ea9f031e 100644 --- a/src/Fixer/Phpdoc/PhpdocAlignFixer.php +++ b/src/Fixer/Phpdoc/PhpdocAlignFixer.php @@ -146,7 +146,7 @@ public function getDefinition() /** * {@inheritdoc} * - * Must run after CommentToPhpdocFixer, CommentToPhpdocFixer, GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAnnotationWithoutDotFixer, PhpdocIndentFixer, PhpdocIndentFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocScalarFixer, PhpdocScalarFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToCommentFixer, PhpdocToCommentFixer, PhpdocToParamTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesFixer, PhpdocTypesFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. + * Must run after CommentToPhpdocFixer, CommentToPhpdocFixer, GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAnnotationWithoutDotFixer, PhpdocIndentFixer, PhpdocIndentFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocScalarFixer, PhpdocScalarFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToCommentFixer, PhpdocToCommentFixer, PhpdocToParamTypeFixer, PhpdocToPropertyTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesFixer, PhpdocTypesFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. */ public function getPriority() { diff --git a/src/Fixer/Phpdoc/PhpdocIndentFixer.php b/src/Fixer/Phpdoc/PhpdocIndentFixer.php index 8a958080331..1e7f151dbd1 100644 --- a/src/Fixer/Phpdoc/PhpdocIndentFixer.php +++ b/src/Fixer/Phpdoc/PhpdocIndentFixer.php @@ -48,7 +48,7 @@ class DocBlocks /** * {@inheritdoc} * - * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocAnnotationWithoutDotFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToParamTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. + * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocAnnotationWithoutDotFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToParamTypeFixer, PhpdocToPropertyTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. * Must run after IndentationTypeFixer, PhpdocToCommentFixer. */ public function getPriority() diff --git a/src/Fixer/Phpdoc/PhpdocScalarFixer.php b/src/Fixer/Phpdoc/PhpdocScalarFixer.php index cee6096e9b1..9a538b715c1 100644 --- a/src/Fixer/Phpdoc/PhpdocScalarFixer.php +++ b/src/Fixer/Phpdoc/PhpdocScalarFixer.php @@ -81,7 +81,7 @@ function sample($a, $b, $c) /** * {@inheritdoc} * - * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToParamTypeFixer, PhpdocToReturnTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. + * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToParamTypeFixer, PhpdocToPropertyTypeFixer, PhpdocToReturnTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. * Must run after PhpdocTypesFixer. */ public function getPriority() diff --git a/src/Fixer/Phpdoc/PhpdocToCommentFixer.php b/src/Fixer/Phpdoc/PhpdocToCommentFixer.php index e4c7dad8ab8..f9e2e0eb813 100644 --- a/src/Fixer/Phpdoc/PhpdocToCommentFixer.php +++ b/src/Fixer/Phpdoc/PhpdocToCommentFixer.php @@ -36,7 +36,7 @@ public function isCandidate(Tokens $tokens) /** * {@inheritdoc} * - * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyCommentFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocAnnotationWithoutDotFixer, PhpdocIndentFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToParamTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. + * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyCommentFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocAnnotationWithoutDotFixer, PhpdocIndentFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToParamTypeFixer, PhpdocToPropertyTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. * Must run after CommentToPhpdocFixer. */ public function getPriority() diff --git a/src/Fixer/Phpdoc/PhpdocTypesFixer.php b/src/Fixer/Phpdoc/PhpdocTypesFixer.php index e9e62dabe81..d5e31f0e03b 100644 --- a/src/Fixer/Phpdoc/PhpdocTypesFixer.php +++ b/src/Fixer/Phpdoc/PhpdocTypesFixer.php @@ -115,7 +115,7 @@ public function getDefinition() /** * {@inheritdoc} * - * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocScalarFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToParamTypeFixer, PhpdocToReturnTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. + * Must run before GeneralPhpdocAnnotationRemoveFixer, NoBlankLinesAfterPhpdocFixer, NoEmptyPhpdocFixer, NoSuperfluousPhpdocTagsFixer, PhpdocAddMissingParamAnnotationFixer, PhpdocAlignFixer, PhpdocAlignFixer, PhpdocInlineTagFixer, PhpdocLineSpanFixer, PhpdocNoAccessFixer, PhpdocNoAliasTagFixer, PhpdocNoEmptyReturnFixer, PhpdocNoPackageFixer, PhpdocNoUselessInheritdocFixer, PhpdocOrderByValueFixer, PhpdocOrderFixer, PhpdocReturnSelfReferenceFixer, PhpdocScalarFixer, PhpdocSeparationFixer, PhpdocSingleLineVarSpacingFixer, PhpdocSummaryFixer, PhpdocToParamTypeFixer, PhpdocToPropertyTypeFixer, PhpdocToReturnTypeFixer, PhpdocToReturnTypeFixer, PhpdocTrimConsecutiveBlankLineSeparationFixer, PhpdocTrimFixer, PhpdocTypesOrderFixer, PhpdocVarAnnotationCorrectOrderFixer, PhpdocVarWithoutNameFixer. * Must run after PhpdocAnnotationWithoutDotFixer, PhpdocIndentFixer. */ public function getPriority() diff --git a/tests/AutoReview/FixerTest.php b/tests/AutoReview/FixerTest.php index 273847c2955..08b286e749f 100644 --- a/tests/AutoReview/FixerTest.php +++ b/tests/AutoReview/FixerTest.php @@ -57,6 +57,7 @@ public function testFixerDefinitions(AbstractFixer $fixer) { static::assertInstanceOf(DefinedFixerInterface::class, $fixer); + $testIncompleteReason = null; $fixerName = $fixer->getName(); $definition = $fixer->getDefinition(); $fixerIsConfigurable = $fixer instanceof ConfigurationDefinitionFixerInterface; @@ -143,11 +144,11 @@ public function testFixerDefinitions(AbstractFixer $fixer) ]; if (\count($configSamplesProvided) < 2) { - if (\in_array($fixerName, $fixerNamesWithKnownMissingSamplesWithConfig, true)) { - static::markTestIncomplete(sprintf('[%s] Configurable fixer only provides a default configuration sample and none for its configuration options, please help and add it.', $fixerName)); + if (!\in_array($fixerName, $fixerNamesWithKnownMissingSamplesWithConfig, true)) { + static::fail(sprintf('[%s] Configurable fixer only provides a default configuration sample and none for its configuration options.', $fixerName)); } - static::fail(sprintf('[%s] Configurable fixer only provides a default configuration sample and none for its configuration options.', $fixerName)); + $testIncompleteReason = sprintf('[%s] Configurable fixer only provides a default configuration sample and none for its configuration options, please help and add it.', $fixerName); } elseif (\in_array($fixerName, $fixerNamesWithKnownMissingSamplesWithConfig, true)) { static::fail(sprintf('[%s] Invalid listed as missing code samples, please update the list.', $fixerName)); } @@ -158,6 +159,10 @@ public function testFixerDefinitions(AbstractFixer $fixer) static::assertRegExp('/^[a-z_]+[a-z]$/', $option->getName(), sprintf('[%s] Option %s is not snake_case.', $fixerName, $option->getName())); } } + + if (null !== $testIncompleteReason) { + static::markTestIncomplete($testIncompleteReason); + } } /** @@ -319,7 +324,7 @@ private static function assertCorrectCasing($needle, $haystack, $message) private static function assertValidDescription($fixerName, $descriptionType, $description) { static::assertInternalType('string', $description); - static::assertRegExp('/^[A-Z`][^"]+\.$/', $description, sprintf('[%s] The %s must start with capital letter or a ` and end with dot.', $fixerName, $descriptionType)); + static::assertRegExp('/^(\[1\] )?[A-Z`][^"]+\.$/', $description, sprintf('[%s] The %s must start with capital letter or a ` and end with dot.', $fixerName, $descriptionType)); static::assertNotContains('phpdocs', $description, sprintf('[%s] `PHPDoc` must not be in the plural in %s.', $fixerName, $descriptionType), true); static::assertCorrectCasing($description, 'PHPDoc', sprintf('[%s] `PHPDoc` must be in correct casing in %s.', $fixerName, $descriptionType)); static::assertCorrectCasing($description, 'PHPUnit', sprintf('[%s] `PHPUnit` must be in correct casing in %s.', $fixerName, $descriptionType)); diff --git a/tests/Fixer/FunctionNotation/PhpdocToPropertyTypeFixerTest.php b/tests/Fixer/FunctionNotation/PhpdocToPropertyTypeFixerTest.php new file mode 100644 index 00000000000..ff35fb94e9c --- /dev/null +++ b/tests/Fixer/FunctionNotation/PhpdocToPropertyTypeFixerTest.php @@ -0,0 +1,477 @@ + + * Dariusz Rumiński + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace PhpCsFixer\Tests\Fixer\FunctionNotation; + +use PhpCsFixer\Tests\Test\AbstractFixerTestCase; + +/** + * @internal + * + * @covers \PhpCsFixer\Fixer\FunctionNotation\PhpdocToPropertyTypeFixer + */ +final class PhpdocToPropertyTypeFixerTest extends AbstractFixerTestCase +{ + /** + * @param string $expected + * @param null|string $input + * + * @dataProvider provideFixCases + */ + public function testFix($expected, $input = null, array $config = []) + { + if (null !== $input && \PHP_VERSION_ID < 70400) { + $expected = $input; + $input = null; + } + + $this->fixer->configure($config); + + $this->doTest($expected, $input); + } + + public function provideFixCases() + { + return [ + 'no phpdoc return' => [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' false], + ], + 'array native type' => [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' */ private array $foo; }', + ' */ private $foo; }', + ], + 'array of types' => [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + ' [ + 'fixer->configure($config); + + $this->doTest($expected, $input); + } + + public function provideFixPhp70Cases() + { + return [ + 'anonymous class' => [ + '