Skip to content

Commit

Permalink
SlevomatCodingStandard.TypeHints.ParameterTypeHintSniff: "MissingTrav…
Browse files Browse the repository at this point in the history
…ersableTypeHintSpecification" is not reported when promoted property has @var annotation
  • Loading branch information
kukulich committed Jul 8, 2022
1 parent 1cd31e0 commit 0cec515
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 11 deletions.
42 changes: 40 additions & 2 deletions SlevomatCodingStandard/Helpers/FunctionHelper.php
Expand Up @@ -7,6 +7,7 @@
use PHP_CodeSniffer\Util\Tokens;
use SlevomatCodingStandard\Helpers\Annotation\ParameterAnnotation;
use SlevomatCodingStandard\Helpers\Annotation\ReturnAnnotation;
use SlevomatCodingStandard\Helpers\Annotation\VariableAnnotation;
use function array_filter;
use function array_map;
use function array_merge;
Expand Down Expand Up @@ -324,11 +325,30 @@ public static function getParametersAnnotations(File $phpcsFile, int $functionPo
}

/**
* @return array<string, ParameterAnnotation>
* @return array<string, ParameterAnnotation|VariableAnnotation>
*/
public static function getValidParametersAnnotations(File $phpcsFile, int $functionPointer): array
{
$tokens = $phpcsFile->getTokens();

$parametersAnnotations = [];

if (self::getName($phpcsFile, $functionPointer) === '__construct') {
for ($i = $tokens[$functionPointer]['parenthesis_opener'] + 1; $i < $tokens[$functionPointer]['parenthesis_closer']; $i++) {
if ($tokens[$i]['code'] !== T_VARIABLE) {
continue;
}

/** @var VariableAnnotation[] $varAnnotations */
$varAnnotations = AnnotationHelper::getAnnotationsByName($phpcsFile, $i, '@var');
if ($varAnnotations === []) {
continue;
}

$parametersAnnotations[$tokens[$i]['content']] = $varAnnotations[0];
}
}

foreach (self::getParametersAnnotations($phpcsFile, $functionPointer) as $parameterAnnotation) {
if ($parameterAnnotation->getContent() === null) {
continue;
Expand All @@ -345,12 +365,30 @@ public static function getValidParametersAnnotations(File $phpcsFile, int $funct
}

/**
* @return array<string, ParameterAnnotation>
* @return array<string, ParameterAnnotation|VariableAnnotation>
*/
public static function getValidPrefixedParametersAnnotations(File $phpcsFile, int $functionPointer): array
{
$tokens = $phpcsFile->getTokens();

$parametersAnnotations = [];
foreach (AnnotationHelper::PREFIXES as $prefix) {
if (self::getName($phpcsFile, $functionPointer) === '__construct') {
for ($i = $tokens[$functionPointer]['parenthesis_opener'] + 1; $i < $tokens[$functionPointer]['parenthesis_closer']; $i++) {
if ($tokens[$i]['code'] !== T_VARIABLE) {
continue;
}

/** @var VariableAnnotation[] $varAnnotations */
$varAnnotations = AnnotationHelper::getAnnotationsByName($phpcsFile, $i, sprintf('@%s-var', $prefix));
if ($varAnnotations === []) {
continue;
}

$parametersAnnotations[$tokens[$i]['content']] = $varAnnotations[0];
}
}

/** @var ParameterAnnotation[] $annotations */
$annotations = AnnotationHelper::getAnnotationsByName($phpcsFile, $functionPointer, sprintf('@%s-param', $prefix));
foreach ($annotations as $parameterAnnotation) {
Expand Down
6 changes: 5 additions & 1 deletion SlevomatCodingStandard/Helpers/TypeHintHelper.php
Expand Up @@ -102,8 +102,12 @@ public static function convertUnofficialUnionTypeHintToOfficialTypeHints(string

public static function isTypeDefinedInAnnotation(File $phpcsFile, int $pointer, string $typeHint): bool
{
/** @var int $docCommentOpenPointer */
$docCommentOpenPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $pointer);

if ($docCommentOpenPointer === null) {
return false;
}

return self::isTemplate($phpcsFile, $docCommentOpenPointer, $typeHint)
|| self::isAlias($phpcsFile, $docCommentOpenPointer, $typeHint);
}
Expand Down
17 changes: 11 additions & 6 deletions SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSniff.php
Expand Up @@ -15,6 +15,7 @@
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
use SlevomatCodingStandard\Helpers\Annotation\ParameterAnnotation;
use SlevomatCodingStandard\Helpers\Annotation\VariableAnnotation;
use SlevomatCodingStandard\Helpers\AnnotationHelper;
use SlevomatCodingStandard\Helpers\AnnotationTypeHelper;
use SlevomatCodingStandard\Helpers\DocCommentHelper;
Expand All @@ -40,6 +41,7 @@
use function strtolower;
use const T_BITWISE_AND;
use const T_DOC_COMMENT_CLOSE_TAG;
use const T_DOC_COMMENT_OPEN_TAG;
use const T_DOC_COMMENT_STAR;
use const T_ELLIPSIS;
use const T_FUNCTION;
Expand Down Expand Up @@ -124,8 +126,8 @@ public function process(File $phpcsFile, $functionPointer): void

/**
* @param (TypeHint|null)[] $parametersTypeHints
* @param ParameterAnnotation[] $parametersAnnotations
* @param ParameterAnnotation[] $prefixedParametersAnnotations
* @param array<string, ParameterAnnotation|VariableAnnotation> $parametersAnnotations
* @param array<string, ParameterAnnotation|VariableAnnotation> $prefixedParametersAnnotations
*/
private function checkTypeHints(
File $phpcsFile,
Expand Down Expand Up @@ -384,8 +386,8 @@ private function checkTypeHints(

/**
* @param (TypeHint|null)[] $parametersTypeHints
* @param ParameterAnnotation[] $parametersAnnotations
* @param ParameterAnnotation[] $prefixedParametersAnnotations
* @param array<string, ParameterAnnotation|VariableAnnotation> $parametersAnnotations
* @param array<string, ParameterAnnotation|VariableAnnotation> $prefixedParametersAnnotations
*/
private function checkTraversableTypeHintSpecification(
File $phpcsFile,
Expand Down Expand Up @@ -499,7 +501,7 @@ private function checkTraversableTypeHintSpecification(

/**
* @param (TypeHint|null)[] $parametersTypeHints
* @param ParameterAnnotation[] $parametersAnnotations
* @param array<string, ParameterAnnotation|VariableAnnotation> $parametersAnnotations
*/
private function checkUselessAnnotations(
File $phpcsFile,
Expand Down Expand Up @@ -554,7 +556,10 @@ private function checkUselessAnnotations(
continue;
}

$docCommentOpenPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $functionPointer);
$docCommentOpenPointer = $parameterAnnotation instanceof VariableAnnotation
? TokenHelper::findPrevious($phpcsFile, T_DOC_COMMENT_OPEN_TAG, $parameterAnnotation->getStartPointer() - 1)
: DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $functionPointer);

$starPointer = TokenHelper::findPrevious(
$phpcsFile,
T_DOC_COMMENT_STAR,
Expand Down
6 changes: 5 additions & 1 deletion tests/Sniffs/TypeHints/ParameterTypeHintSniffTest.php
Expand Up @@ -28,7 +28,7 @@ public function testErrors(): void
'traversableTypeHints' => ['Traversable', '\ArrayIterator'],
]);

self::assertSame(47, $report->getErrorCount());
self::assertSame(50, $report->getErrorCount());

self::assertSniffError($report, 6, ParameterTypeHintSniff::CODE_MISSING_ANY_TYPE_HINT);
self::assertSniffError($report, 14, ParameterTypeHintSniff::CODE_MISSING_NATIVE_TYPE_HINT);
Expand Down Expand Up @@ -81,6 +81,10 @@ public function testErrors(): void
self::assertSniffError($report, 285, ParameterTypeHintSniff::CODE_USELESS_ANNOTATION);
self::assertSniffError($report, 292, ParameterTypeHintSniff::CODE_MISSING_ANY_TYPE_HINT);

self::assertSniffError($report, 301, ParameterTypeHintSniff::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION);
self::assertSniffError($report, 303, ParameterTypeHintSniff::CODE_USELESS_ANNOTATION);
self::assertSniffError($report, 304, ParameterTypeHintSniff::CODE_USELESS_ANNOTATION);

self::assertAllFixedInFile($report);
}

Expand Down
14 changes: 14 additions & 0 deletions tests/Sniffs/TypeHints/data/parameterTypeHintErrors.fixed.php
Expand Up @@ -282,3 +282,17 @@ private function noTypeHintNoAnnotationWithPhpdoc($a)
}

}

class Promoted
{

public function __construct(
public array $promoted,
/***/
public int $promoted2, /***/ private string $promoted3
)
{

}

}
14 changes: 14 additions & 0 deletions tests/Sniffs/TypeHints/data/parameterTypeHintErrors.php
Expand Up @@ -294,3 +294,17 @@ private function noTypeHintNoAnnotationWithPhpdoc($a)
}

}

class Promoted
{

public function __construct(
public array $promoted,
/** @var int */
public int $promoted2, /** @var string */ private string $promoted3
)
{

}

}
17 changes: 16 additions & 1 deletion tests/Sniffs/TypeHints/data/parameterTypeHintNoErrors.php
@@ -1,4 +1,4 @@
<?php
<?php // lint >= 8.0

use Doctrine\Common\Collections\ArrayCollection;

Expand Down Expand Up @@ -315,3 +315,18 @@ public function withNullableArrayAlias(?array $array)
}

}

class Promoted
{

public function __construct(
/** @var array<int, string> */
public array $promoted,
/** @phpstan-var array<int, string> */
public array $promoted2
)
{

}

}

0 comments on commit 0cec515

Please sign in to comment.