Skip to content

Commit

Permalink
Add assert syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
rvanvelzen authored and ondrejmirtes committed May 4, 2022
1 parent 129a63b commit 8f703ba
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
36 changes: 36 additions & 0 deletions src/Ast/PhpDoc/AssertTagValueNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace PHPStan\PhpDocParser\Ast\PhpDoc;

use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;

class AssertTagValueNode implements PhpDocTagValueNode
{

use NodeAttributes;

/** @var TypeNode */
public $type;

/** @var string */
public $parameter;

/** @var string (may be empty) */
public $description;

public function __construct(TypeNode $type, string $parameter, string $description)
{
$this->type = $type;
$this->parameter = $parameter;
$this->description = $description;
}


public function __toString(): string
{
return trim("{$this->type} {$this->parameter} {$this->description}");
}

}
13 changes: 13 additions & 0 deletions src/Parser/PhpDocParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,11 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
$tagValue = $this->parseTypeAliasImportTagValue($tokens);
break;

case '@phpstan-assert':
case '@psalm-assert':
$tagValue = $this->parseAssertTagValue($tokens);
break;

default:
$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens));
break;
Expand Down Expand Up @@ -420,6 +425,14 @@ private function parseTypeAliasImportTagValue(TokenIterator $tokens): Ast\PhpDoc
return new Ast\PhpDoc\TypeAliasImportTagValueNode($importedAlias, new IdentifierTypeNode($importedFrom), $importedAs);
}

private function parseAssertTagValue(TokenIterator $tokens): Ast\PhpDoc\AssertTagValueNode
{
$type = $this->typeParser->parse($tokens);
$parameter = $this->parseRequiredVariableName($tokens);
$description = $this->parseOptionalDescription($tokens);
return new Ast\PhpDoc\AssertTagValueNode($type, $parameter, $description);
}

private function parseOptionalVariableName(TokenIterator $tokens): string
{
if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {
Expand Down
87 changes: 87 additions & 0 deletions tests/PHPStan/Parser/PhpDocParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\DeprecatedTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
Expand Down Expand Up @@ -75,6 +76,7 @@ protected function setUp(): void
* @dataProvider provideExtendsTagsData
* @dataProvider provideTypeAliasTagsData
* @dataProvider provideTypeAliasImportTagsData
* @dataProvider provideAssertTagsData
* @dataProvider provideRealWorldExampleData
* @dataProvider provideDescriptionWithOrWithoutHtml
*/
Expand Down Expand Up @@ -3480,6 +3482,91 @@ public function provideTypeAliasImportTagsData(): Iterator
];
}

public function provideAssertTagsData(): Iterator
{
yield [
'OK',
'/** @phpstan-assert Type $var */',
new PhpDocNode([
new PhpDocTagNode(
'@phpstan-assert',
new AssertTagValueNode(
new IdentifierTypeNode('Type'),
'$var',
''
)
),
]),
];

yield [
'OK with psalm syntax',
'/** @psalm-assert Type $var */',
new PhpDocNode([
new PhpDocTagNode(
'@psalm-assert',
new AssertTagValueNode(
new IdentifierTypeNode('Type'),
'$var',
''
)
),
]),
];

yield [
'OK with description',
'/** @phpstan-assert Type $var assert Type to $var */',
new PhpDocNode([
new PhpDocTagNode(
'@phpstan-assert',
new AssertTagValueNode(
new IdentifierTypeNode('Type'),
'$var',
'assert Type to $var'
)
),
]),
];

yield [
'OK with union type',
'/** @phpstan-assert Type|Other $var */',
new PhpDocNode([
new PhpDocTagNode(
'@phpstan-assert',
new AssertTagValueNode(
new UnionTypeNode([
new IdentifierTypeNode('Type'),
new IdentifierTypeNode('Other'),
]),
'$var',
''
)
),
]),
];

yield [
'invalid $this->method()',
'/** @phpstan-assert Type $this->method() */',
new PhpDocNode([
new PhpDocTagNode(
'@phpstan-assert',
new InvalidTagValueNode(
'Type $this->method()',
new ParserException(
'$this',
Lexer::TOKEN_THIS_VARIABLE,
25,
Lexer::TOKEN_VARIABLE
)
)
),
]),
];
}

public function providerDebug(): Iterator
{
$sample = '/**
Expand Down

0 comments on commit 8f703ba

Please sign in to comment.