mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-07 20:00:50 +00:00
use PhpDocInfo by default
This commit is contained in:
parent
650279493e
commit
71332ebd41
|
@ -6,21 +6,26 @@ namespace Rector\BetterPhpDocParser\PhpDocInfo;
|
|||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareParamTagValueNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocTagNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareReturnTagValueNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareVarTagValueNode;
|
||||
use Rector\BetterPhpDocParser\Annotation\AnnotationNaming;
|
||||
use Rector\BetterPhpDocParser\Attributes\Ast\PhpDoc\SpacelessPhpDocTagNode;
|
||||
use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface;
|
||||
use Rector\BetterPhpDocParser\PhpDocNode\AbstractTagValueNode;
|
||||
use Rector\Exception\NotImplementedException;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\PHPStan\TypeComparator;
|
||||
use Rector\NodeTypeResolver\StaticTypeMapper;
|
||||
|
||||
/**
|
||||
|
@ -58,6 +63,11 @@ final class PhpDocInfo
|
|||
*/
|
||||
private $node;
|
||||
|
||||
/**
|
||||
* @var TypeComparator
|
||||
*/
|
||||
private $typeComparator;
|
||||
|
||||
/**
|
||||
* @param mixed[] $tokens
|
||||
*/
|
||||
|
@ -66,7 +76,8 @@ final class PhpDocInfo
|
|||
array $tokens,
|
||||
string $originalContent,
|
||||
StaticTypeMapper $staticTypeMapper,
|
||||
Node $node
|
||||
Node $node,
|
||||
TypeComparator $typeComparator
|
||||
) {
|
||||
$this->phpDocNode = $attributeAwarePhpDocNode;
|
||||
$this->tokens = $tokens;
|
||||
|
@ -74,6 +85,7 @@ final class PhpDocInfo
|
|||
$this->originalContent = $originalContent;
|
||||
$this->staticTypeMapper = $staticTypeMapper;
|
||||
$this->node = $node;
|
||||
$this->typeComparator = $typeComparator;
|
||||
}
|
||||
|
||||
public function getOriginalContent(): string
|
||||
|
@ -296,6 +308,56 @@ final class PhpDocInfo
|
|||
return $paramTypesByName;
|
||||
}
|
||||
|
||||
public function changeReturnType(Type $newType): void
|
||||
{
|
||||
// make sure the tags are not identical, e.g imported class vs FQN class
|
||||
if ($this->typeComparator->areTypesEquals($this->getReturnType(), $newType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// overide existing type
|
||||
$newPHPStanPhpDocType = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType);
|
||||
|
||||
$currentReturnTagValueNode = $this->getReturnTagValue();
|
||||
if ($currentReturnTagValueNode !== null) {
|
||||
// only change type
|
||||
$currentReturnTagValueNode->type = $newPHPStanPhpDocType;
|
||||
} else {
|
||||
// add completely new one
|
||||
$returnTagValueNode = new AttributeAwareReturnTagValueNode($newPHPStanPhpDocType, '');
|
||||
$this->addTagValueNode($returnTagValueNode);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOpeningTokenValue(): ?string
|
||||
{
|
||||
if (! isset($this->tokens[0])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$openingToken = $this->tokens[0];
|
||||
|
||||
return $openingToken[0];
|
||||
}
|
||||
|
||||
public function changeOpeningTokenValue(string $value): void
|
||||
{
|
||||
$this->tokens[0][0] = $value;
|
||||
}
|
||||
|
||||
public function addBareTag(string $tag): void
|
||||
{
|
||||
$tag = '@' . ltrim($tag, '@');
|
||||
|
||||
$phpDocTagNode = new AttributeAwarePhpDocTagNode($tag, new GenericTagValueNode(''));
|
||||
$this->addPhpDocTagNode($phpDocTagNode);
|
||||
}
|
||||
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return $this->phpDocNode->children === [];
|
||||
}
|
||||
|
||||
private function getParamTagValueByName(string $name): ?AttributeAwareParamTagValueNode
|
||||
{
|
||||
$phpDocNode = $this->getPhpDocNode();
|
||||
|
@ -331,4 +393,16 @@ final class PhpDocInfo
|
|||
|
||||
return $firstAnnotationName === $secondAnnotationName;
|
||||
}
|
||||
|
||||
private function addTagValueNode(PhpDocTagValueNode $phpDocTagValueNode): void
|
||||
{
|
||||
if ($phpDocTagValueNode instanceof ReturnTagValueNode) {
|
||||
$name = '@return';
|
||||
} else {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
$phpDocTagNode = new AttributeAwarePhpDocTagNode($name, $phpDocTagValueNode);
|
||||
$this->addPhpDocTagNode($phpDocTagNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace Rector\BetterPhpDocParser\PhpDocInfo;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
||||
use PHPStan\PhpDocParser\Lexer\Lexer;
|
||||
use PHPStan\PhpDocParser\Parser\PhpDocParser;
|
||||
use PHPStan\PhpDocParser\Parser\TokenIterator;
|
||||
|
@ -16,6 +15,7 @@ use Rector\BetterPhpDocParser\Contract\PhpDocNodeFactoryInterface;
|
|||
use Rector\BetterPhpDocParser\ValueObject\StartEndValueObject;
|
||||
use Rector\Configuration\CurrentNodeProvider;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\PHPStan\TypeComparator;
|
||||
use Rector\NodeTypeResolver\StaticTypeMapper;
|
||||
|
||||
final class PhpDocInfoFactory
|
||||
|
@ -40,16 +40,42 @@ final class PhpDocInfoFactory
|
|||
*/
|
||||
private $staticTypeMapper;
|
||||
|
||||
/**
|
||||
* @var TypeComparator
|
||||
*/
|
||||
private $typeComparator;
|
||||
|
||||
public function __construct(
|
||||
PhpDocParser $phpDocParser,
|
||||
Lexer $lexer,
|
||||
CurrentNodeProvider $currentNodeProvider,
|
||||
StaticTypeMapper $staticTypeMapper
|
||||
StaticTypeMapper $staticTypeMapper,
|
||||
TypeComparator $typeComparator
|
||||
) {
|
||||
$this->phpDocParser = $phpDocParser;
|
||||
$this->lexer = $lexer;
|
||||
$this->currentNodeProvider = $currentNodeProvider;
|
||||
$this->staticTypeMapper = $staticTypeMapper;
|
||||
$this->typeComparator = $typeComparator;
|
||||
}
|
||||
|
||||
public function createFromString(Node $node, string $content): PhpDocInfo
|
||||
{
|
||||
$tokens = $this->lexer->tokenize($content);
|
||||
$phpDocNode = $this->parseTokensToPhpDocNode($tokens);
|
||||
|
||||
$phpDocInfo = new PhpDocInfo(
|
||||
$phpDocNode,
|
||||
$tokens,
|
||||
$content,
|
||||
$this->staticTypeMapper,
|
||||
$node,
|
||||
$this->typeComparator
|
||||
);
|
||||
|
||||
$node->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);
|
||||
|
||||
return $phpDocInfo;
|
||||
}
|
||||
|
||||
public function createFromNode(Node $node): PhpDocInfo
|
||||
|
@ -58,21 +84,30 @@ final class PhpDocInfoFactory
|
|||
$this->currentNodeProvider->setNode($node);
|
||||
|
||||
if ($node->getDocComment() === null) {
|
||||
$content = '';
|
||||
$tokens = [];
|
||||
$phpDocNode = new AttributeAwarePhpDocNode([]);
|
||||
if ($node->getComments() !== []) {
|
||||
$content = $this->createCommentsString($node);
|
||||
$tokens = $this->lexer->tokenize($content);
|
||||
$phpDocNode = $this->parseTokensToPhpDocNode($tokens);
|
||||
} else {
|
||||
$content = '';
|
||||
$tokens = [];
|
||||
$phpDocNode = new AttributeAwarePhpDocNode([]);
|
||||
}
|
||||
} else {
|
||||
$content = $node->getDocComment()->getText();
|
||||
|
||||
$tokens = $this->lexer->tokenize($content);
|
||||
$tokenIterator = new TokenIterator($tokens);
|
||||
|
||||
/** @var AttributeAwarePhpDocNode $phpDocNode */
|
||||
$phpDocNode = $this->phpDocParser->parse($tokenIterator);
|
||||
$phpDocNode = $this->setPositionOfLastToken($phpDocNode);
|
||||
$phpDocNode = $this->parseTokensToPhpDocNode($tokens);
|
||||
$this->setPositionOfLastToken($phpDocNode);
|
||||
}
|
||||
|
||||
$phpDocInfo = new PhpDocInfo($phpDocNode, $tokens, $content, $this->staticTypeMapper, $node);
|
||||
$phpDocInfo = new PhpDocInfo(
|
||||
$phpDocNode,
|
||||
$tokens,
|
||||
$content,
|
||||
$this->staticTypeMapper,
|
||||
$node,
|
||||
$this->typeComparator
|
||||
);
|
||||
$node->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);
|
||||
|
||||
return $phpDocInfo;
|
||||
|
@ -81,11 +116,10 @@ final class PhpDocInfoFactory
|
|||
/**
|
||||
* Needed for printing
|
||||
*/
|
||||
private function setPositionOfLastToken(
|
||||
AttributeAwarePhpDocNode $attributeAwarePhpDocNode
|
||||
): AttributeAwarePhpDocNode {
|
||||
private function setPositionOfLastToken(AttributeAwarePhpDocNode $attributeAwarePhpDocNode): void
|
||||
{
|
||||
if ($attributeAwarePhpDocNode->children === []) {
|
||||
return $attributeAwarePhpDocNode;
|
||||
return;
|
||||
}
|
||||
|
||||
$phpDocChildNodes = $attributeAwarePhpDocNode->children;
|
||||
|
@ -98,7 +132,17 @@ final class PhpDocInfoFactory
|
|||
if ($startEndValueObject !== null) {
|
||||
$attributeAwarePhpDocNode->setAttribute(Attribute::LAST_TOKEN_POSITION, $startEndValueObject->getEnd());
|
||||
}
|
||||
}
|
||||
|
||||
return $attributeAwarePhpDocNode;
|
||||
private function createCommentsString(Node $node): string
|
||||
{
|
||||
return implode('', $node->getComments());
|
||||
}
|
||||
|
||||
private function parseTokensToPhpDocNode(array $tokens): AttributeAwarePhpDocNode
|
||||
{
|
||||
$tokenIterator = new TokenIterator($tokens);
|
||||
|
||||
return $this->phpDocParser->parse($tokenIterator);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ final class PhpDocInfoPrinter
|
|||
* - Print(subnode2)
|
||||
* - Tokens[subnode2.endPos .. node.endPos]
|
||||
*/
|
||||
public function printFormatPreserving(PhpDocInfo $phpDocInfo, bool $shouldSkipEmptyLinesAbove = false): string
|
||||
public function printFormatPreserving(PhpDocInfo $phpDocInfo): string
|
||||
{
|
||||
if ($phpDocInfo->getTokens() === []) {
|
||||
// completely new noe, just print string version of it
|
||||
|
@ -99,13 +99,11 @@ final class PhpDocInfoPrinter
|
|||
$this->currentTokenPosition = 0;
|
||||
$this->removedNodePositions = [];
|
||||
|
||||
return $this->printPhpDocNode($this->attributeAwarePhpDocNode, $shouldSkipEmptyLinesAbove);
|
||||
return $this->printPhpDocNode($this->attributeAwarePhpDocNode);
|
||||
}
|
||||
|
||||
private function printPhpDocNode(
|
||||
AttributeAwarePhpDocNode $attributeAwarePhpDocNode,
|
||||
bool $shouldSkipEmptyLinesAbove = false
|
||||
): string {
|
||||
private function printPhpDocNode(AttributeAwarePhpDocNode $attributeAwarePhpDocNode): string
|
||||
{
|
||||
// no nodes were, so empty doc
|
||||
if ($this->isPhpDocNodeEmpty($attributeAwarePhpDocNode)) {
|
||||
return '';
|
||||
|
@ -119,14 +117,14 @@ final class PhpDocInfoPrinter
|
|||
$nodeCount = count($attributeAwarePhpDocNode->children);
|
||||
|
||||
foreach ($attributeAwarePhpDocNode->children as $i => $phpDocChildNode) {
|
||||
$output .= $this->printNode($phpDocChildNode, null, $i + 1, $nodeCount, $shouldSkipEmptyLinesAbove);
|
||||
$output .= $this->printNode($phpDocChildNode, null, $i + 1, $nodeCount);
|
||||
}
|
||||
|
||||
$output = $this->printEnd($output);
|
||||
|
||||
// @see
|
||||
// fix missing start
|
||||
if (! Strings::match($output, '#^(\/\/|\/\*\*|\/\*)#') && $output) {
|
||||
if (! Strings::match($output, '#^(\/\/|\/\*\*|\/\*|\#)#') && $output) {
|
||||
$output = '/**' . $output;
|
||||
}
|
||||
|
||||
|
@ -156,8 +154,7 @@ final class PhpDocInfoPrinter
|
|||
AttributeAwareNodeInterface $attributeAwareNode,
|
||||
?StartEndValueObject $startEndValueObject = null,
|
||||
int $i = 0,
|
||||
int $nodeCount = 0,
|
||||
bool $shouldSkipEmptyLinesAbove = false
|
||||
int $nodeCount = 0
|
||||
): string {
|
||||
$output = '';
|
||||
|
||||
|
@ -171,7 +168,7 @@ final class PhpDocInfoPrinter
|
|||
$output,
|
||||
$this->currentTokenPosition,
|
||||
$startEndValueObject->getStart(),
|
||||
! $shouldSkipEmptyLinesAbove && $isLastToken
|
||||
$isLastToken
|
||||
);
|
||||
|
||||
$this->currentTokenPosition = $startEndValueObject->getEnd();
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\CakePHPToSymfony\Rector\Class_;
|
||||
|
||||
use Nette\Utils\FileSystem;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\CakePHPToSymfony\NodeFactory\EventSubscriberClassFactory;
|
||||
|
@ -88,9 +87,7 @@ PHP
|
|||
);
|
||||
$eventSubscriberFilePath = $this->eventSubscriberClassFactory->resolveEventSubscriberFilePath($node);
|
||||
|
||||
// @todo make temporary
|
||||
$content = '<?php' . PHP_EOL . $this->print($eventSubscriberClass) . PHP_EOL;
|
||||
FileSystem::write($eventSubscriberFilePath, $content);
|
||||
$this->printToFile($eventSubscriberClass, $eventSubscriberFilePath);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPBeforeFilterToRequestEventSubscriberRector\Fixture;
|
||||
|
||||
final class SuperadminControllerEventSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\CodeQuality\Rector\If_;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
|
@ -112,13 +113,21 @@ PHP
|
|||
|
||||
private function combineComments(Node $firstNode, Node $secondNode): void
|
||||
{
|
||||
$firstNode->setAttribute('comments', array_merge($firstNode->getComments(), $secondNode->getComments()));
|
||||
|
||||
if ($firstNode->getDocComment() === null) {
|
||||
$comments = array_merge($firstNode->getComments(), $secondNode->getComments());
|
||||
if ($comments === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = '';
|
||||
foreach ($comments as $comment) {
|
||||
if (Strings::startsWith($comment->getText(), '/*')) {
|
||||
$content .= $comment->getText() . PHP_EOL;
|
||||
} else {
|
||||
$content .= $comment->getText();
|
||||
}
|
||||
}
|
||||
|
||||
// update original node php doc info object
|
||||
$this->phpDocInfoFactory->createFromNode($firstNode);
|
||||
$this->phpDocInfoFactory->createFromString($firstNode, $content);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ declare(strict_types=1);
|
|||
namespace Rector\CodingStyle\Rector\ClassMethod;
|
||||
|
||||
use Iterator;
|
||||
use PhpParser\Comment;
|
||||
use PhpParser\Comment\Doc;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
|
@ -33,20 +31,15 @@ final class ReturnArrayClassMethodToYieldRector extends AbstractRector
|
|||
*/
|
||||
private $methodsByType = [];
|
||||
|
||||
/**
|
||||
* @var Comment[]
|
||||
*/
|
||||
private $returnComments = [];
|
||||
|
||||
/**
|
||||
* @var NodeTransformer
|
||||
*/
|
||||
private $nodeTransformer;
|
||||
|
||||
/**
|
||||
* @var Doc|null
|
||||
* @var PhpDocInfo|null
|
||||
*/
|
||||
private $returnDocComment;
|
||||
private $returnPhpDocInfo;
|
||||
|
||||
/**
|
||||
* @param string[][] $methodsByType
|
||||
|
@ -137,7 +130,7 @@ PHP
|
|||
continue;
|
||||
}
|
||||
|
||||
$this->collectComments($statement);
|
||||
$this->returnPhpDocInfo = $statement->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
|
||||
return $statement->expr;
|
||||
}
|
||||
|
@ -170,18 +163,12 @@ PHP
|
|||
$classMethod->stmts = array_merge((array) $classMethod->stmts, $yieldNodes);
|
||||
}
|
||||
|
||||
private function completeComments(Node $node): void
|
||||
private function completeComments(ClassMethod $classMethod): void
|
||||
{
|
||||
if ($this->returnDocComment !== null) {
|
||||
$node->setDocComment($this->returnDocComment);
|
||||
} elseif ($this->returnComments !== []) {
|
||||
$node->setAttribute('comments', $this->returnComments);
|
||||
if ($this->returnPhpDocInfo === null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectComments(Node $node): void
|
||||
{
|
||||
$this->returnDocComment = $node->getDocComment();
|
||||
$this->returnComments = $node->getComments();
|
||||
$classMethod->setAttribute(AttributeKey::PHP_DOC_INFO, $this->returnPhpDocInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ namespace Rector\DeadCode\Rector\Stmt;
|
|||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Nop;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
@ -16,6 +19,16 @@ use Rector\RectorDefinition\RectorDefinition;
|
|||
*/
|
||||
final class RemoveDeadStmtRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var PhpDocInfoFactory
|
||||
*/
|
||||
private $phpDocInfoFactory;
|
||||
|
||||
public function __construct(PhpDocInfoFactory $phpDocInfoFactory)
|
||||
{
|
||||
$this->phpDocInfoFactory = $phpDocInfoFactory;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Removes dead code statements', [
|
||||
|
@ -40,29 +53,38 @@ PHP
|
|||
return [Expression::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Expression $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$livingCode = $this->keepLivingCodeFromExpr($node->expr);
|
||||
|
||||
if ($livingCode === []) {
|
||||
return $this->savelyRemoveNode($node);
|
||||
return $this->removeNodeAndKeepComments($node);
|
||||
}
|
||||
|
||||
$firstExpr = array_shift($livingCode);
|
||||
$node->expr = $firstExpr;
|
||||
|
||||
foreach ($livingCode as $expr) {
|
||||
$this->addNodeAfterNode(new Expression($expr), $node);
|
||||
$newNode = new Expression($expr);
|
||||
$this->addNodeAfterNode($newNode, $node);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function savelyRemoveNode(Node $node): ?Node
|
||||
private function removeNodeAndKeepComments(Node $node): ?Node
|
||||
{
|
||||
/** @var PhpDocInfo $phpDocInfo */
|
||||
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
|
||||
if ($node->getComments() !== []) {
|
||||
$nop = new Nop();
|
||||
$nop->setAttribute('comments', $node->getComments());
|
||||
$nop->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);
|
||||
|
||||
$this->phpDocInfoFactory->createFromNode($nop);
|
||||
|
||||
return $nop;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodeQuality\Tests\Rector\Stmt\DeadCodeRemovingRector\Fixture\ArrayDimFetch;
|
||||
|
||||
function commentUnwrapKeep()
|
||||
{
|
||||
//comment
|
||||
$var[methodCall()];
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodeQuality\Tests\Rector\Stmt\DeadCodeRemovingRector\Fixture\ArrayDimFetch;
|
||||
|
||||
function commentUnwrapKeep()
|
||||
{
|
||||
//comment
|
||||
methodCall();
|
||||
}
|
||||
|
||||
?>
|
|
@ -23,6 +23,20 @@ final class RemoveDeadStmtRectorTest extends AbstractRectorTestCase
|
|||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideDataForTestKeepComments()
|
||||
*/
|
||||
public function testKeepComments(string $file): void
|
||||
{
|
||||
$this->markTestSkipped('Temporary skip removed docs');
|
||||
$this->doTestFile($file);
|
||||
}
|
||||
|
||||
public function provideDataForTestKeepComments(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureRemovedComments');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return RemoveDeadStmtRector::class;
|
||||
|
|
|
@ -12,6 +12,7 @@ use PhpParser\Node\Stmt\Return_;
|
|||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\StringType;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
||||
use Rector\BetterPhpDocParser\PhpDocNode\Gedmo\SlugTagValueNode;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PhpParser\Node\Manipulator\ClassManipulator;
|
||||
|
@ -32,9 +33,15 @@ final class SluggableBehaviorRector extends AbstractRector
|
|||
*/
|
||||
private $classManipulator;
|
||||
|
||||
public function __construct(ClassManipulator $classManipulator)
|
||||
/**
|
||||
* @var PhpDocInfoFactory
|
||||
*/
|
||||
private $phpDocInfoFactory;
|
||||
|
||||
public function __construct(ClassManipulator $classManipulator, PhpDocInfoFactory $phpDocInfoFactory)
|
||||
{
|
||||
$this->classManipulator = $classManipulator;
|
||||
$this->phpDocInfoFactory = $phpDocInfoFactory;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
|
@ -153,7 +160,10 @@ PHP
|
|||
$classMethod->returnType = new Identifier('array');
|
||||
$classMethod->stmts[] = new Return_($this->createArray($slugFields));
|
||||
|
||||
$this->docBlockManipulator->addReturnTag($classMethod, new ArrayType(new MixedType(), new StringType()));
|
||||
$returnType = new ArrayType(new MixedType(), new StringType());
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod);
|
||||
$phpDocInfo->changeReturnType($returnType);
|
||||
// $this->docBlockManipulator->addReturnTag($classMethod, new ArrayType(new MixedType(), new StringType()));
|
||||
|
||||
$this->classManipulator->addAsFirstMethod($class, $classMethod);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\DoctrineGedmoToKnplabs\Rector\Class_;
|
||||
|
||||
use Nette\Utils\FileSystem;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
|
@ -268,9 +267,6 @@ PHP
|
|||
|
||||
$namespace->stmts[] = $class;
|
||||
|
||||
// @todo make temporary
|
||||
$content = '<?php' . PHP_EOL . $this->print($namespace) . PHP_EOL;
|
||||
|
||||
FileSystem::write($filePath, $content);
|
||||
$this->printToFile($namespace, $filePath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DoctrineGedmoToKnplabs\Tests\Rector\Class_\TranslationBehaviorRector\Fixture;
|
||||
|
||||
/**
|
|
@ -4,26 +4,15 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\DoctrineGedmoToKnplabs\Tests\Rector\Class_\TranslationBehaviorRector;
|
||||
|
||||
use Nette\Utils\FileSystem;
|
||||
use Rector\DoctrineGedmoToKnplabs\Rector\Class_\TranslationBehaviorRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class TranslationBehaviorRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
protected function tearDown(): void
|
||||
{
|
||||
// remove generated file
|
||||
FileSystem::delete(__DIR__ . '/Fixture/SomeClassTranslation.php');
|
||||
}
|
||||
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFile(__DIR__ . '/Fixture/fixture.php.inc');
|
||||
|
||||
$generatedFile = sys_get_temp_dir() . '/rector_temp_tests/SomeClassTranslation.php';
|
||||
$this->assertFileExists($generatedFile);
|
||||
|
||||
$this->assertFileEquals(__DIR__ . '/Source/ExpectedSomeClassTranslation.php', $generatedFile);
|
||||
$this->doTestExtraFile('SomeClassTranslation.php', __DIR__ . '/Source/SomeClassTranslation.php');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace Rector\NetteToSymfony\Rector\Assign;
|
||||
|
||||
use Nette\Application\UI\Control;
|
||||
use Nette\Utils\FileSystem;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
|
@ -207,9 +206,7 @@ PHP
|
|||
|
||||
$filePath = dirname($fileInfo->getRealPath()) . DIRECTORY_SEPARATOR . 'SomeFormController.php';
|
||||
|
||||
// @todo make temporary
|
||||
$content = '<?php' . PHP_EOL . $this->print([$namespace]) . PHP_EOL;
|
||||
FileSystem::write($filePath, $content);
|
||||
$this->printToFile($namespace, $filePath);
|
||||
}
|
||||
|
||||
private function createBuildFormClassMethod(Variable $formBuilderVariable): ClassMethod
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\NetteToSymfony\Tests\Rector\Assign\FormControlToControllerAndFormTypeRector\Fixture;
|
||||
|
||||
class SomeFormController extends \Symfony\Bundle\FrameworkBundle\Controller\AbstractController
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace Rector\NodeTypeResolver\NodeVisitor;
|
|||
use PhpParser\Node;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class PhpDocInfoNodeVisitor extends NodeVisitorAbstract
|
||||
{
|
||||
|
@ -26,13 +25,8 @@ final class PhpDocInfoNodeVisitor extends NodeVisitorAbstract
|
|||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node->getDocComment() === null) {
|
||||
$node->setAttribute(AttributeKey::PHP_DOC_INFO, null);
|
||||
return;
|
||||
}
|
||||
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($node);
|
||||
$node->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);
|
||||
// also binds to the node
|
||||
$this->phpDocInfoFactory->createFromNode($node);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ use PHPStan\PhpDocParser\Ast\Node as PhpDocParserNode;
|
|||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use PHPStan\Type\Constant\ConstantArrayType;
|
||||
use PHPStan\Type\MixedType;
|
||||
|
@ -200,37 +199,6 @@ final class DocBlockManipulator
|
|||
$node->setAttribute(AttributeKey::ORIGINAL_NODE, null);
|
||||
}
|
||||
|
||||
public function addReturnTag(Node $node, Type $newType): void
|
||||
{
|
||||
/** @var PhpDocInfo|null $phpDocInfo */
|
||||
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
|
||||
$currentReturnType = $phpDocInfo !== null ? $phpDocInfo->getReturnType() : new MixedType();
|
||||
|
||||
// make sure the tags are not identical, e.g imported class vs FQN class
|
||||
if ($this->typeComparator->areTypesEquals($currentReturnType, $newType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var PhpDocInfo|null $phpDocInfo */
|
||||
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
|
||||
if ($phpDocInfo === null) {
|
||||
$this->addTypeSpecificTag($node, 'return', $newType);
|
||||
return;
|
||||
}
|
||||
|
||||
$returnTagValueNode = $phpDocInfo->getByType(ReturnTagValueNode::class);
|
||||
|
||||
// overide existing type
|
||||
if ($returnTagValueNode === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$newPHPStanPhpDocType = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType);
|
||||
$returnTagValueNode->type = $newPHPStanPhpDocType;
|
||||
}
|
||||
|
||||
public function replaceTagByAnother(PhpDocNode $phpDocNode, string $oldTag, string $newTag): void
|
||||
{
|
||||
$oldTag = AnnotationNaming::normalizeName($oldTag);
|
||||
|
@ -333,7 +301,7 @@ final class DocBlockManipulator
|
|||
return false;
|
||||
}
|
||||
|
||||
public function updateNodeWithPhpDocInfo(Node $node, bool $shouldSkipEmptyLinesAbove = false): void
|
||||
public function updateNodeWithPhpDocInfo(Node $node): void
|
||||
{
|
||||
// nothing to change
|
||||
/** @var PhpDocInfo|null $phpDocInfo */
|
||||
|
@ -342,8 +310,7 @@ final class DocBlockManipulator
|
|||
return;
|
||||
}
|
||||
|
||||
$phpDoc = $this->printPhpDocInfoToString($shouldSkipEmptyLinesAbove, $phpDocInfo);
|
||||
|
||||
$phpDoc = $this->printPhpDocInfoToString($phpDocInfo);
|
||||
if ($phpDoc === '') {
|
||||
// no comments, null
|
||||
$node->setAttribute('comments', null);
|
||||
|
@ -352,11 +319,12 @@ final class DocBlockManipulator
|
|||
|
||||
// no change, don't save it
|
||||
// this is needed to prevent short classes override with FQN with same value → people don't like that for some reason
|
||||
|
||||
if ($node->getDocComment() && $node->getDocComment()->getText() === $phpDoc) {
|
||||
if (! $this->haveDocCommentOrCommentsChanged($node, $phpDoc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this is needed to remove duplicated // comments
|
||||
$node->setAttribute('comments', null);
|
||||
$node->setDocComment(new Doc($phpDoc));
|
||||
}
|
||||
|
||||
|
@ -408,13 +376,32 @@ final class DocBlockManipulator
|
|||
}
|
||||
}
|
||||
|
||||
private function printPhpDocInfoToString(bool $shouldSkipEmptyLinesAbove, PhpDocInfo $phpDocInfo): string
|
||||
private function printPhpDocInfoToString(PhpDocInfo $phpDocInfo): string
|
||||
{
|
||||
// new node, needs to be reparsed
|
||||
if ($phpDocInfo->getPhpDocNode()->children !== [] && $phpDocInfo->getTokens() === []) {
|
||||
return (string) $phpDocInfo->getPhpDocNode();
|
||||
}
|
||||
|
||||
return $this->phpDocInfoPrinter->printFormatPreserving($phpDocInfo, $shouldSkipEmptyLinesAbove);
|
||||
return $this->phpDocInfoPrinter->printFormatPreserving($phpDocInfo);
|
||||
}
|
||||
|
||||
private function haveDocCommentOrCommentsChanged(Node $node, string $phpDoc): bool
|
||||
{
|
||||
// has it changed?
|
||||
$docComment = $node->getDocComment();
|
||||
if ($docComment !== null && $docComment->getText() === $phpDoc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// nothing to change
|
||||
if ($node->getComments() !== []) {
|
||||
$commentsContent = implode('', $node->getComments());
|
||||
if ($commentsContent === $phpDoc) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ final class UnionTypeAnalyzer
|
|||
{
|
||||
$isNullableType = false;
|
||||
$hasIterable = false;
|
||||
$hasArray = false;
|
||||
|
||||
foreach ($unionType->getTypes() as $unionedType) {
|
||||
if ($unionedType instanceof IterableType) {
|
||||
|
@ -26,6 +27,7 @@ final class UnionTypeAnalyzer
|
|||
}
|
||||
|
||||
if ($unionedType instanceof ArrayType) {
|
||||
$hasArray = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -42,6 +44,6 @@ final class UnionTypeAnalyzer
|
|||
return null;
|
||||
}
|
||||
|
||||
return new UnionTypeAnalysis($isNullableType, $hasIterable);
|
||||
return new UnionTypeAnalysis($isNullableType, $hasIterable, $hasArray);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use PhpParser\Node\Name\FullyQualified;
|
|||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\UnionType as PhpParserUnionType;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Type\IterableType;
|
||||
use PHPStan\Type\NullType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
|
@ -65,8 +66,13 @@ final class UnionTypeMapper implements TypeMapperInterface
|
|||
public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode
|
||||
{
|
||||
$unionTypesNodes = [];
|
||||
$skipIterable = $this->shouldSkipIterable($type);
|
||||
|
||||
foreach ($type->getTypes() as $unionedType) {
|
||||
if ($unionedType instanceof IterableType && $skipIterable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$unionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType);
|
||||
}
|
||||
|
||||
|
@ -233,4 +239,14 @@ final class UnionTypeMapper implements TypeMapperInterface
|
|||
|
||||
return is_a($secondType->getClassName(), $firstType->getClassName(), true);
|
||||
}
|
||||
|
||||
private function shouldSkipIterable(UnionType $unionType): bool
|
||||
{
|
||||
$unionTypeAnalysis = $this->unionTypeAnalyzer->analyseForNullableAndIterable($unionType);
|
||||
if ($unionTypeAnalysis === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $unionTypeAnalysis->hasIterable() && $unionTypeAnalysis->hasArray();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,16 @@ final class UnionTypeAnalysis
|
|||
*/
|
||||
private $hasIterable = false;
|
||||
|
||||
public function __construct(bool $isNullableType, bool $hasIterable)
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $hasArray = false;
|
||||
|
||||
public function __construct(bool $isNullableType, bool $hasIterable, bool $hasArray)
|
||||
{
|
||||
$this->isNullableType = $isNullableType;
|
||||
$this->hasIterable = $hasIterable;
|
||||
$this->hasArray = $hasArray;
|
||||
}
|
||||
|
||||
public function isNullableType(): bool
|
||||
|
@ -31,4 +37,9 @@ final class UnionTypeAnalysis
|
|||
{
|
||||
return $this->hasIterable;
|
||||
}
|
||||
|
||||
public function hasArray(): bool
|
||||
{
|
||||
return $this->hasArray;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,10 @@ declare(strict_types=1);
|
|||
namespace Rector\PHPUnit\Rector\ClassMethod;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Comment\Doc;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocTagNode;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\FileSystemRector\Parser\FileInfoParser;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -133,21 +130,9 @@ PHP
|
|||
|
||||
private function addDoesNotPerformAssertion(ClassMethod $classMethod): void
|
||||
{
|
||||
// A. create new doc
|
||||
$doc = $classMethod->getDocComment();
|
||||
if ($doc === null) {
|
||||
$text = sprintf('/**%s * @doesNotPerformAssertion%s */', PHP_EOL, PHP_EOL);
|
||||
$classMethod->setDocComment(new Doc($text));
|
||||
return;
|
||||
}
|
||||
|
||||
// B. extend current doc
|
||||
/** @var PhpDocInfo $phpDocInfo */
|
||||
$phpDocInfo = $classMethod->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
$phpDocNode = $phpDocInfo->getPhpDocNode();
|
||||
$phpDocNode->children[] = new AttributeAwarePhpDocTagNode('@doesNotPerformAssertion', new GenericTagValueNode(
|
||||
''
|
||||
));
|
||||
$phpDocInfo->addBareTag('@doesNotPerformAssertion');
|
||||
}
|
||||
|
||||
private function containsAssertCall(ClassMethod $classMethod): bool
|
||||
|
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\PHPUnit\Rector\ClassMethod;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Comment\Doc;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Rector\AbstractPHPUnitRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
@ -19,6 +19,11 @@ use Rector\RectorDefinition\RectorDefinition;
|
|||
*/
|
||||
final class EnsureDataProviderInDocBlockRector extends AbstractPHPUnitRector
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const DOC_BLOCK_OPENING = '/**';
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Data provider annotation must be in doc block', [
|
||||
|
@ -70,33 +75,18 @@ PHP
|
|||
return null;
|
||||
}
|
||||
|
||||
if (! $this->hasDataProviderComment($node)) {
|
||||
/** @var PhpDocInfo $phpDocInfo */
|
||||
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
if (! $phpDocInfo->hasByName('@dataProvider')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$doc = $node->getComments()[0]->getText();
|
||||
$doc = Strings::replace($doc, '#^/\*(\s)#', '/**$1');
|
||||
if ($phpDocInfo->getOpeningTokenValue() === self::DOC_BLOCK_OPENING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->setAttribute('comments', null);
|
||||
$node->setDocComment(new Doc($doc));
|
||||
$phpDocInfo->changeOpeningTokenValue(self::DOC_BLOCK_OPENING);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function hasDataProviderComment(Node $node): bool
|
||||
{
|
||||
$docComment = $node->getDocComment();
|
||||
if ($docComment !== null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$comments = $node->getComments();
|
||||
foreach ($comments as $comment) {
|
||||
if (Strings::match($comment->getText(), '#@dataProvider\s+\w#')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class SkipProphecyAssertions extends \PHPUnit\Framework\TestCase
|
|||
$denormalizer = $this->prophesize(DenormalizerInterface::class);
|
||||
$denormalizer
|
||||
->denormalize($fixedData, $type)
|
||||
->shouldBeCalled(); // this is an assertion here
|
||||
->shouldBeCalled();
|
||||
|
||||
(new Denormalizer($denormalizer))->handle($badData, $type);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use PhpParser\Node\Stmt\ClassMethod;
|
|||
use PhpParser\Node\Stmt\Return_;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
@ -82,9 +83,15 @@ final class EventListenerToEventSubscriberRector extends AbstractRector
|
|||
*/
|
||||
private $applicationServiceMapProvider;
|
||||
|
||||
public function __construct(ServiceMapProvider $applicationServiceMapProvider)
|
||||
/**
|
||||
* @var PhpDocInfoFactory
|
||||
*/
|
||||
private $phpDocInfoFactory;
|
||||
|
||||
public function __construct(ServiceMapProvider $applicationServiceMapProvider, PhpDocInfoFactory $phpDocInfoFactory)
|
||||
{
|
||||
$this->applicationServiceMapProvider = $applicationServiceMapProvider;
|
||||
$this->phpDocInfoFactory = $phpDocInfoFactory;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
|
@ -348,8 +355,9 @@ PHP
|
|||
$classMethod->returnType = new Identifier('array');
|
||||
}
|
||||
|
||||
$arrayMixedType = new ArrayType(new MixedType(), new MixedType(true));
|
||||
$this->docBlockManipulator->addReturnTag($classMethod, $arrayMixedType);
|
||||
$returnType = new ArrayType(new MixedType(), new MixedType(true));
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod);
|
||||
$phpDocInfo->changeReturnType($returnType);
|
||||
}
|
||||
|
||||
private function createEventItem(EventListenerTag $eventListenerTag): ArrayItem
|
||||
|
|
|
@ -12,6 +12,8 @@ use PHPStan\Type\IterableType;
|
|||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
use PHPStan\Type\VoidType;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
|
@ -107,7 +109,9 @@ PHP
|
|||
return null;
|
||||
}
|
||||
|
||||
$this->docBlockManipulator->addReturnTag($node, $inferedType);
|
||||
/** @var PhpDocInfo $phpDocInfo */
|
||||
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
$phpDocInfo->changeReturnType($inferedType);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
@ -149,6 +153,12 @@ PHP
|
|||
if ($newType instanceof UnionType && $this->shouldSkipUnionType($newType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// not an array type
|
||||
if ($newType instanceof VoidType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $newType instanceof ConstantArrayType && count($newType->getValueTypes()) > self::MAX_NUMBER_OF_TYPES;
|
||||
}
|
||||
|
||||
|
@ -196,8 +206,6 @@ PHP
|
|||
return false;
|
||||
}
|
||||
|
||||
$currentReturnType = $currentPhpDocInfo->getReturnType();
|
||||
|
||||
return $currentReturnType instanceof ArrayType;
|
||||
return $currentPhpDocInfo->getReturnType() instanceof ArrayType;
|
||||
}
|
||||
}
|
||||
|
|
13
phpstan.neon
13
phpstan.neon
|
@ -50,7 +50,6 @@ parameters:
|
|||
|
||||
# false positive - type is set by annotation above
|
||||
- '#Array \(array<PhpParser\\Node\\Stmt>\) does not accept PhpParser\\Node#'
|
||||
- '#Method Rector\\NodeTypeResolver\\PhpDoc\\NodeAnalyzer\\DocBlockManipulator::getTagByName\(\) should return PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode but returns PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode\|null#'
|
||||
- '#Parameter \#1 \$node of method Rector\\PhpParser\\Node\\Commander\\NodeAddingCommander::wrapToExpression\(\) expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Stmt, PhpParser\\Node given#'
|
||||
|
||||
# irrelevant
|
||||
|
@ -63,8 +62,6 @@ parameters:
|
|||
- '#Access to an undefined property PhpParser\\Node\\Expr\\MethodCall\|PhpParser\\Node\\Stmt\\ClassMethod::\$params#'
|
||||
- '#Cannot call method getName\(\) on PHPStan\\Reflection\\ClassReflection\|null#'
|
||||
|
||||
- '#Cannot call method getText\(\) on PhpParser\\Comment\\Doc\|null#'
|
||||
|
||||
# false positive, has annotation type above
|
||||
- '#Method Rector\\CodeQuality\\Rector\\Foreach_\\SimplifyForeachToCoalescingRector\:\:matchReturnOrAssignNode\(\) should return PhpParser\\Node\\Expr\\Assign\|PhpParser\\Node\\Stmt\\Return_\|null but returns PhpParser\\Node\|null#'
|
||||
- '#Access to an undefined property PhpParser\\Node::\$(\w+)#'
|
||||
|
@ -113,7 +110,6 @@ parameters:
|
|||
|
||||
# known types
|
||||
- '#Method Rector\\NodeContainer\\ParsedNodesByType\:\:(.*?)\(\) should return PhpParser\\Node\\Stmt\\(.*?)\|null but returns PhpParser\\Node\|null#'
|
||||
- '#Method Rector\\NodeContainer\\ParsedNodesByType\:\:findImplementersOfInterface\(\) should return array<PhpParser\\Node\\Stmt\\Interface_\> but returns array<int, PhpParser\\Node\>#'
|
||||
- '#Access to an undefined property PhpParser\\Node\\Expr\\Error\|PhpParser\\Node\\Expr\\Variable\:\:\$name#'
|
||||
- '#Strict comparison using \=\=\= between PhpParser\\Node\\Expr\\ArrayItem and null will always evaluate to false#'
|
||||
- '#Parameter \#2 \.\.\.\$args of function array_merge expects array, array<int, string\>\|false given#'
|
||||
|
@ -143,14 +139,11 @@ parameters:
|
|||
- '#Property Rector\\TypeDeclaration\\TypeInferer\\(.*?)\:\:\$(.*?)TypeInferers \(array<Rector\\TypeDeclaration\\Contract\\TypeInferer\\(.*?)TypeInfererInterface\>\) does not accept array<Rector\\TypeDeclaration\\Contract\\TypeInferer\\PriorityAwareTypeInfererInterface\>#'
|
||||
# sense-less errors
|
||||
|
||||
- '#Parameter \#1 \$functionLike of method Rector\\NodeTypeResolver\\PhpDoc\\NodeAnalyzer\\DocBlockManipulator\:\:getParamTypesByName\(\) expects PhpParser\\Node\\Expr\\Closure\|PhpParser\\Node\\Stmt\\ClassMethod\|PhpParser\\Node\\Stmt\\Function_, PhpParser\\Node\\FunctionLike given#'
|
||||
|
||||
# PHP 7.4 1_000 support
|
||||
- '#Property PhpParser\\Node\\Scalar\\DNumber\:\:\$value \(float\) does not accept string#'
|
||||
- '#Call to function is_string\(\) with float will always evaluate to false#'
|
||||
|
||||
- '#Parameter \#1 \$obj of function spl_object_hash expects object, PhpParser\\Comment\\Doc\|null given#'
|
||||
|
||||
- '#Method Rector\\Doctrine\\Rector\\MethodCall\\ChangeSetIdToUuidValueRector\:\:getSetUuidMethodCallOnSameVariable\(\) should return PhpParser\\Node\\Expr\\MethodCall\|null but returns PhpParser\\Node\|null#'
|
||||
|
||||
# bugs
|
||||
|
@ -228,12 +221,12 @@ parameters:
|
|||
|
||||
# known value
|
||||
- '#Access to undefined constant Rector\\BetterPhpDocParser\\PhpDocNode\\AbstractTagValueNode\:\:SHORT_NAME#'
|
||||
- '#Parameter \#1 \$name of method Rector\\Rector\\AbstractRector\:\:getShortName\(\) expects PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|string, PhpParser\\Node\\Identifier\|null given#'
|
||||
- '#Parameter \#1 \$entityClass of method Rector\\CakePHPToSymfony\\Rector\\NodeFactory\\DoctrineNodeFactory\:\:createConstructorWithGetRepositoryAssign\(\) expects string, string\|null given#'
|
||||
- '#Parameter \#1 \$node of method PHPStan\\Analyser\\Scope\:\:getType\(\) expects PhpParser\\Node\\Expr, PhpParser\\Node given#'
|
||||
|
||||
- '#Parameter \#2 \$name of class PhpParser\\Node\\Expr\\MethodCall constructor expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Identifier\|string, string\|null given#'
|
||||
- '#Ternary operator condition is always false#'
|
||||
|
||||
- '#Parameter \#1 \$tagValueNode of method Rector\\BetterPhpDocParser\\PhpDocInfo\\PhpDocInfo\:\:addTagValueNodeWithShortName\(\) expects Rector\\BetterPhpDocParser\\PhpDocNode\\AbstractTagValueNode, PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode\|Rector\\BetterPhpDocParser\\PhpDocNode\\Doctrine\\Property_\\JoinColumnTagValueNode given#'
|
||||
- '#Parameter \#1 \$eventListenerTag of method Rector\\SymfonyCodeQuality\\Rector\\Class_\\EventListenerToEventSubscriberRector\:\:createEventItem\(\) expects Rector\\Symfony\\ValueObject\\Tag\\EventListenerTag, Rector\\Symfony\\Contract\\Tag\\TagInterface given#'
|
||||
- '#Method Rector\\BetterPhpDocParser\\PhpDocInfo\\PhpDocInfoFactory\:\:parseTokensToPhpDocNode\(\) should return Rector\\AttributeAwarePhpDoc\\Ast\\PhpDoc\\AttributeAwarePhpDocNode but returns PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode#'
|
||||
|
||||
- '#Property PhpParser\\Node\\Stmt\\Expression\:\:\$expr \(PhpParser\\Node\\Expr\) does not accept PhpParser\\Node\\Expr\|null#'
|
||||
|
|
|
@ -261,8 +261,8 @@ final class BetterStandardPrinter extends Standard
|
|||
*/
|
||||
protected function pExpr_Array(Array_ $node): string
|
||||
{
|
||||
if (! $node->hasAttribute('kind')) {
|
||||
$node->setAttribute('kind', Array_::KIND_SHORT);
|
||||
if (! $node->hasAttribute(AttributeKey::KIND)) {
|
||||
$node->setAttribute(AttributeKey::KIND, Array_::KIND_SHORT);
|
||||
}
|
||||
|
||||
return parent::pExpr_Array($node);
|
||||
|
|
|
@ -348,7 +348,7 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
|||
foreach ($stmts as $key => $ifStmt) {
|
||||
if ($key === 0) {
|
||||
// move comment from if to first element to keep it
|
||||
$ifStmt->setAttribute('comments', $node->getComments());
|
||||
$ifStmt->setAttribute(AttributeKey::PHP_DOC_INFO, $node->getAttribute(AttributeKey::PHP_DOC_INFO));
|
||||
}
|
||||
|
||||
$this->addNodeAfterNode($ifStmt, $node);
|
||||
|
|
Loading…
Reference in New Issue
Block a user