Skip to content

Commit

Permalink
use PhpDocInfo by default
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Feb 3, 2020
1 parent 6502794 commit 71332eb
Show file tree
Hide file tree
Showing 32 changed files with 351 additions and 195 deletions.
76 changes: 75 additions & 1 deletion packages/BetterPhpDocParser/src/PhpDocInfo/PhpDocInfo.php
Expand Up @@ -6,21 +6,26 @@

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;

/**
Expand Down Expand Up @@ -58,6 +63,11 @@ final class PhpDocInfo
*/
private $node;

/**
* @var TypeComparator
*/
private $typeComparator;

/**
* @param mixed[] $tokens
*/
Expand All @@ -66,14 +76,16 @@ public function __construct(
array $tokens,
string $originalContent,
StaticTypeMapper $staticTypeMapper,
Node $node
Node $node,
TypeComparator $typeComparator
) {
$this->phpDocNode = $attributeAwarePhpDocNode;
$this->tokens = $tokens;
$this->originalPhpDocNode = clone $attributeAwarePhpDocNode;
$this->originalContent = $originalContent;
$this->staticTypeMapper = $staticTypeMapper;
$this->node = $node;
$this->typeComparator = $typeComparator;
}

public function getOriginalContent(): string
Expand Down Expand Up @@ -296,6 +308,56 @@ public function getParamTypesByName(): array
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();
Expand Down Expand Up @@ -331,4 +393,16 @@ private function areAnnotationNamesEqual(string $firstAnnotationName, string $se

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);
}
}
78 changes: 61 additions & 17 deletions packages/BetterPhpDocParser/src/PhpDocInfo/PhpDocInfoFactory.php
Expand Up @@ -5,7 +5,6 @@
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;
Expand All @@ -16,6 +15,7 @@
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
Expand All @@ -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
Expand All @@ -58,21 +84,30 @@ public function createFromNode(Node $node): PhpDocInfo
$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;
Expand All @@ -81,11 +116,10 @@ public function createFromNode(Node $node): PhpDocInfo
/**
* Needed for printing
*/
private function setPositionOfLastToken(
AttributeAwarePhpDocNode $attributeAwarePhpDocNode
): AttributeAwarePhpDocNode {
private function setPositionOfLastToken(AttributeAwarePhpDocNode $attributeAwarePhpDocNode): void
{
if ($attributeAwarePhpDocNode->children === []) {
return $attributeAwarePhpDocNode;
return;
}

$phpDocChildNodes = $attributeAwarePhpDocNode->children;
Expand All @@ -98,7 +132,17 @@ private function setPositionOfLastToken(
if ($startEndValueObject !== null) {
$attributeAwarePhpDocNode->setAttribute(Attribute::LAST_TOKEN_POSITION, $startEndValueObject->getEnd());
}
}

private function createCommentsString(Node $node): string
{
return implode('', $node->getComments());
}

private function parseTokensToPhpDocNode(array $tokens): AttributeAwarePhpDocNode
{
$tokenIterator = new TokenIterator($tokens);

return $attributeAwarePhpDocNode;
return $this->phpDocParser->parse($tokenIterator);
}
}
19 changes: 8 additions & 11 deletions packages/BetterPhpDocParser/src/Printer/PhpDocInfoPrinter.php
Expand Up @@ -79,7 +79,7 @@ public function __construct(
* - 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
Expand All @@ -99,13 +99,11 @@ public function printFormatPreserving(PhpDocInfo $phpDocInfo, bool $shouldSkipEm
$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 '';
Expand All @@ -119,14 +117,14 @@ private function printPhpDocNode(
$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;
}

Expand Down Expand Up @@ -156,8 +154,7 @@ private function printNode(
AttributeAwareNodeInterface $attributeAwareNode,
?StartEndValueObject $startEndValueObject = null,
int $i = 0,
int $nodeCount = 0,
bool $shouldSkipEmptyLinesAbove = false
int $nodeCount = 0
): string {
$output = '';

Expand All @@ -171,7 +168,7 @@ private function printNode(
$output,
$this->currentTokenPosition,
$startEndValueObject->getStart(),
! $shouldSkipEmptyLinesAbove && $isLastToken
$isLastToken
);

$this->currentTokenPosition = $startEndValueObject->getEnd();
Expand Down
Expand Up @@ -4,7 +4,6 @@

namespace Rector\CakePHPToSymfony\Rector\Class_;

use Nette\Utils\FileSystem;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\CakePHPToSymfony\NodeFactory\EventSubscriberClassFactory;
Expand Down Expand Up @@ -88,9 +87,7 @@ public function refactor(Node $node): ?Node
);
$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;
}
Expand Down
@@ -1,4 +1,5 @@
<?php

namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPBeforeFilterToRequestEventSubscriberRector\Fixture;

final class SuperadminControllerEventSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
Expand Down
17 changes: 13 additions & 4 deletions packages/CodeQuality/src/Rector/If_/CombineIfRector.php
Expand Up @@ -4,6 +4,7 @@

namespace Rector\CodeQuality\Rector\If_;

use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
use PhpParser\Node\Stmt\If_;
Expand Down Expand Up @@ -112,13 +113,21 @@ private function shouldSkip(If_ $node): bool

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

0 comments on commit 71332eb

Please sign in to comment.