fix import of already existing param/var/return type or class annotation

This commit is contained in:
TomasVotruba 2020-07-12 18:35:56 +02:00
parent 6580260272
commit 2023d41061
11 changed files with 222 additions and 1 deletions

View File

@ -132,6 +132,7 @@ final class DocBlockNameImporter
return $identifierTypeNode;
}
// should skip because its already used
if ($this->useNodesToAddCollector->isShortImported($node, $fullyQualifiedObjectType)) {
if ($this->useNodesToAddCollector->isImportShortable($node, $fullyQualifiedObjectType)) {
$identifierTypeNode->name = $fullyQualifiedObjectType->getShortName();

View File

@ -342,3 +342,4 @@ parameters:
- '#Method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:findFirstNonAnonymousClass\(\) should return PhpParser\\Node\\Stmt\\Class_\|null but returns PhpParser\\Node\|null#'
# known value
- '#Property PhpParser\\Node\\Stmt\\Foreach_\:\:\$valueVar \(PhpParser\\Node\\Expr\) does not accept PhpParser\\Node\\Expr\|null#'
- '#Access to an undefined property PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode\:\:\$type#'

View File

@ -9,6 +9,16 @@ use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\NodeTypeResolver\FileSystem\CurrentFileInfoProvider;
use Rector\NodeTypeResolver\Node\AttributeKey;
@ -125,7 +135,9 @@ final class ShortNameResolver
$shortNames[$originalName->toString()] = $node->toString();
});
return $shortNames;
$docBlockShortNames = $this->resolveFromDocBlocks($stmts);
return array_merge($shortNames, $docBlockShortNames);
}
private function getNodeRealPath(Node $node): ?string
@ -143,4 +155,70 @@ final class ShortNameResolver
return null;
}
/**
* @param Node[] $stmts
* @return string[]
*/
private function resolveFromDocBlocks(array $stmts): array
{
$shortNames = [];
$this->callableNodeTraverser->traverseNodesWithCallable($stmts, function (Node $node) use (&$shortNames) {
/** @var PhpDocInfo|null $phpDocInfo */
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
return null;
}
foreach ($phpDocInfo->getPhpDocNode()->children as $phpDocChildNode) {
$shortTagName = $this->resolveShortTagNameFromPhpDocChildNode($phpDocChildNode);
if ($shortTagName === null) {
continue;
}
$shortNames[$shortTagName] = $shortTagName;
}
});
return $shortNames;
}
private function resolveShortTagNameFromPhpDocChildNode(PhpDocChildNode $phpDocChildNode): ?string
{
if (! $phpDocChildNode instanceof PhpDocTagNode) {
return null;
}
$tagName = ltrim($phpDocChildNode->name, '@');
// is annotation class - big letter?
if (Strings::match($tagName, '#^[A-Z]#')) {
return $tagName;
}
if (! $this->isValueNodeWithType($phpDocChildNode->value)) {
return null;
}
$typeNode = $phpDocChildNode->value->type;
if (! $typeNode instanceof IdentifierTypeNode) {
return null;
}
if (Strings::contains($typeNode->name, '\\')) {
return null;
}
return $typeNode->name;
}
private function isValueNodeWithType(PhpDocTagValueNode $phpDocTagValueNode): bool
{
return $phpDocTagValueNode instanceof PropertyTagValueNode ||
$phpDocTagValueNode instanceof ReturnTagValueNode ||
$phpDocTagValueNode instanceof ParamTagValueNode ||
$phpDocTagValueNode instanceof VarTagValueNode ||
$phpDocTagValueNode instanceof ThrowsTagValueNode;
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\FixtureImport;
use Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\View;
final class SkipConflictingAnnotationImport
{
/**
* @View()
* @return \Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\Nested\View
*/
public function countAction()
{
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\FixtureImport;
use Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\View;
class SkipConflictingDocVsPhpImport
{
/**
* @var \Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\Nested\View
*/
public $view;
public function __construct(View $view)
{
}
/**
* @return \Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\Nested\View
*/
public function getView()
{
return $this->view;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\FixtureImport;
use Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\View;
final class SkipConflictingParamDocBlockAndCreatePhp
{
/**
* @param View $variable
*/
public function process($variable)
{
}
public function countAction()
{
return new \Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\Nested\View;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\FixtureImport;
use Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\View;
final class SkipConflictingDocBlockAndCreatePhp
{
public function countAction()
{
return new \Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\Nested\View;
}
/**
* @return View
*/
public function getReturn()
{
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\FixtureImport;
use Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\View;
final class SkipConflictingReturnImport
{
/**
* @return \Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\Nested\View
*/
public function countAction()
{
}
/**
* @return View
*/
public function getReturn()
{
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\FixtureImport;
use Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\View;
final class SkipConflictingVarDocBlockAndCreatePhp
{
/**
* @var View
*/
public $variable;
public function countAction()
{
return new \Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\Nested\View;
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source\Nested;
final class View
{
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\Php55\Tests\Rector\String_\StringClassNameToClassConstantRector\Source;
final class View
{
}