Skip to content

Commit 73ee8a9

Browse files
committed
Keep @return in PHPDocs after native tentative return type is removed
1 parent 2e9a4b8 commit 73ee8a9

File tree

3 files changed

+100
-2
lines changed

3 files changed

+100
-2
lines changed

extractor/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"nikic/php-parser": "^4.10",
77
"phpstan/phpstan": "^1.5",
88
"phpstan/phpstan-php-parser": "^1.1",
9-
"phpstan/extension-installer": "^1.1"
9+
"phpstan/extension-installer": "^1.1",
10+
"phpstan/phpdoc-parser": "^1.4"
1011
},
1112
"config": {
1213
"allow-plugins": {

extractor/composer.lock

Lines changed: 45 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extractor/extract.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
#!/usr/bin/env php
22
<?php declare(strict_types = 1);
33

4+
use PhpParser\Comment;
45
use PhpParser\Node;
56
use PhpParser\ParserFactory;
7+
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
8+
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
9+
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
10+
use PHPStan\PhpDocParser\Lexer\Lexer;
11+
use PHPStan\PhpDocParser\Parser\PhpDocParser;
12+
use PHPStan\PhpDocParser\Parser\TokenIterator;
13+
use PHPStan\PhpDocParser\Parser\ConstExprParser;
14+
use PHPStan\PhpDocParser\Parser\TypeParser;
615
use Symfony\Component\Console\Application;
716
use Symfony\Component\Console\Command\Command;
817
use Symfony\Component\Console\Input\InputArgument;
@@ -26,6 +35,12 @@
2635
/** @var \PhpParser\PrettyPrinter\Standard */
2736
private $printer;
2837

38+
/** @var Lexer */
39+
private $phpDocLexer;
40+
41+
/** @var PhpDocParser */
42+
private $phpDocParser;
43+
2944
public function __construct(
3045
\PhpParser\Parser $parser,
3146
\PhpParser\PrettyPrinter\Standard $printer
@@ -34,6 +49,11 @@ public function __construct(
3449
parent::__construct();
3550
$this->parser = $parser;
3651
$this->printer = $printer;
52+
$this->phpDocLexer = new Lexer();
53+
54+
$constExprParser = new ConstExprParser();
55+
$typeParser = new TypeParser($constExprParser);
56+
$this->phpDocParser = new PhpDocParser($typeParser, $constExprParser);
3757
}
3858

3959
protected function configure(): void
@@ -363,6 +383,20 @@ private function compareFunctions(Node\FunctionLike $old, Node\FunctionLike $new
363383
if ($old->getReturnType() === null && $new->getReturnType() !== null) {
364384
if ($new->getDocComment() !== null && strpos($new->getDocComment()->getText(), '@tentative-return-type') !== 0) {
365385
$new->returnType = null; // @phpstan-ignore-line
386+
if ($old->getDocComment() !== null) {
387+
$oldPhpDocNode = $this->parseDocComment($old->getDocComment()->getText());
388+
$oldPhpDocReturn = $this->findPhpDocReturn($oldPhpDocNode);
389+
if ($oldPhpDocNode !== null) {
390+
$newPhpDocNode = $this->parseDocComment($new->getDocComment()->getText());
391+
$newPhpDocReturn = $this->findPhpDocReturn($newPhpDocNode);
392+
if ($newPhpDocReturn === null) {
393+
$children = $newPhpDocNode->children;
394+
$children[] = new PhpDocTagNode('@return', $oldPhpDocReturn);
395+
$newPhpDocNodeWithReturn = new PhpDocNode($children);
396+
$new->setDocComment(new Comment\Doc((string) $newPhpDocNodeWithReturn));
397+
}
398+
}
399+
}
366400
}
367401
}
368402
if ($this->printType($old->getReturnType()) !== $this->printType($new->getReturnType())) {
@@ -521,6 +555,25 @@ private function filterClassPhpDocs(Node\Stmt\ClassLike $class): Node\Stmt\Class
521555
return $class;
522556
}
523557

558+
private function parseDocComment(string $docComment): PhpDocNode
559+
{
560+
$tokens = new TokenIterator($this->phpDocLexer->tokenize($docComment));
561+
$phpDocNode = $this->phpDocParser->parse($tokens);
562+
$tokens->consumeTokenType(Lexer::TOKEN_END);
563+
564+
return $phpDocNode;
565+
}
566+
567+
private function findPhpDocReturn(PhpDocNode $node): ?ReturnTagValueNode
568+
{
569+
$returnTags = $node->getReturnTagValues();
570+
if (count($returnTags) !== 1) {
571+
return null;
572+
}
573+
574+
return $returnTags[0];
575+
}
576+
524577
/**
525578
* @param array<string, string> $classes
526579
* @param array<string, string> $functions

0 commit comments

Comments
 (0)