Skip to content

Commit

Permalink
Allow omitting @param type
Browse files Browse the repository at this point in the history
  • Loading branch information
rvanvelzen committed Jun 8, 2022
1 parent d579798 commit 9d45205
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 5 deletions.
2 changes: 1 addition & 1 deletion doc/grammars/phpdoc-param.peg
@@ -1,5 +1,5 @@
PhpDocParam
= AnnotationName Type IsReference? IsVariadic? ParameterName Description?
= AnnotationName Type? IsReference? IsVariadic? ParameterName Description?

AnnotationName
= '@param'
Expand Down
14 changes: 14 additions & 0 deletions src/Ast/PhpDoc/PhpDocNode.php
Expand Up @@ -76,6 +76,20 @@ static function (PhpDocTagValueNode $value): bool {
}


/**
* @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[]
*/
Expand Down
41 changes: 41 additions & 0 deletions src/Ast/PhpDoc/TypelessParamTagValueNode.php
@@ -0,0 +1,41 @@
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use 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}");
}

}
24 changes: 20 additions & 4 deletions src/Parser/PhpDocParser.php
Expand Up @@ -230,14 +230,31 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
}


private function parseParamTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamTagValueNode
/**
* @return Ast\PhpDoc\ParamTagValueNode|Ast\PhpDoc\TypelessParamTagValueNode
*/
private function parseParamTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode
{
$type = $this->typeParser->parse($tokens);
if (
$tokens->isCurrentTokenType(Lexer::TOKEN_REFERENCE)
|| $tokens->isCurrentTokenType(Lexer::TOKEN_VARIADIC)
|| $tokens->isCurrentTokenType(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);
return new Ast\PhpDoc\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference);

if ($type !== null) {
return new Ast\PhpDoc\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference);
}

return new Ast\PhpDoc\TypelessParamTagValueNode($isVariadic, $parameterName, $description, $isReference);
}


Expand Down Expand Up @@ -463,7 +480,6 @@ private function parseRequiredVariableName(TokenIterator $tokens): string
return $parameterName;
}


private function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken = false): string
{
if ($limitStartToken) {
Expand Down
82 changes: 82 additions & 0 deletions tests/PHPStan/Parser/PhpDocParserTest.php
Expand Up @@ -27,6 +27,7 @@
use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasImportTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TypelessParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\UsesTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
Expand Down Expand Up @@ -64,6 +65,7 @@ protected function setUp(): void
/**
* @dataProvider provideTagsWithNumbers
* @dataProvider provideParamTagsData
* @dataProvider provideTypelessParamTagsData
* @dataProvider provideVarTagsData
* @dataProvider provideReturnTagsData
* @dataProvider provideThrowsTagsData
Expand Down Expand Up @@ -395,6 +397,86 @@ public function provideParamTagsData(): Iterator
];
}

public function provideTypelessParamTagsData(): Iterator
{
yield [
'OK',
'/** @param $foo description */',
new PhpDocNode([
new PhpDocTagNode(
'@param',
new TypelessParamTagValueNode(
false,
'$foo',
'description'
)
),
]),
];

yield [
'OK reference',
'/** @param &$foo description */',
new PhpDocNode([
new PhpDocTagNode(
'@param',
new TypelessParamTagValueNode(
false,
'$foo',
'description',
true
)
),
]),
];

yield [
'OK variadic',
'/** @param ...$foo description */',
new PhpDocNode([
new PhpDocTagNode(
'@param',
new TypelessParamTagValueNode(
true,
'$foo',
'description'
)
),
]),
];

yield [
'OK reference variadic',
'/** @param &...$foo description */',
new PhpDocNode([
new PhpDocTagNode(
'@param',
new TypelessParamTagValueNode(
true,
'$foo',
'description',
true
)
),
]),
];

yield [
'OK without type and description',
'/** @param $foo */',
new PhpDocNode([
new PhpDocTagNode(
'@param',
new TypelessParamTagValueNode(
false,
'$foo',
'',
false
)
),
]),
];
}

public function provideVarTagsData(): Iterator
{
Expand Down

0 comments on commit 9d45205

Please sign in to comment.