Skip to content

Commit

Permalink
Merge pull request #2775 from rectorphp/php-doc-object-attribute
Browse files Browse the repository at this point in the history
[DX] Reducing technical debt of DocBlockManipulator with 705 lines
  • Loading branch information
TomasVotruba committed Jan 31, 2020
2 parents 9f7030c + f0de672 commit d1757f2
Show file tree
Hide file tree
Showing 89 changed files with 954 additions and 617 deletions.
2 changes: 2 additions & 0 deletions .phpstorm.meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
\Rector\NodeTypeResolver\Node\AttributeKey::START_TOKEN_POSITION,
\Rector\NodeTypeResolver\Node\AttributeKey::ORIGINAL_NODE,
\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE,
\Rector\NodeTypeResolver\Node\AttributeKey::PHP_DOC_INFO,
);

expectedArguments(
Expand All @@ -61,4 +62,5 @@
\Rector\NodeTypeResolver\Node\AttributeKey::START_TOKEN_POSITION,
\Rector\NodeTypeResolver\Node\AttributeKey::ORIGINAL_NODE,
\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE,
\Rector\NodeTypeResolver\Node\AttributeKey::PHP_DOC_INFO,
);
1 change: 1 addition & 0 deletions ecs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ parameters:

Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff:
- 'packages/MinimalScope/src/Rector/Class_/ChangeLocalPropertyToVariableRector.php'
- 'packages/CodingStyle/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php'
# solve later
- 'src/Console/Command/ScreenFileCommand.php'
- 'packages/Doctrine/src/Rector/ClassMethod/AddMethodCallBasedParamTypeRector.php'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Rector\Autodiscovery\FileMover\FileMover;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Class_\EntityTagValueNode;
use Rector\FileSystemRector\Rector\AbstractFileSystemRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Symplify\SmartFileSystem\SmartFileInfo;
Expand Down Expand Up @@ -102,7 +103,7 @@ private function areDoctrineEntityNodes(array $nodes): bool
return false;
}

$phpDocInfo = $this->getPhpDocInfo($class);
$phpDocInfo = $class->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Rector\BetterPhpDocParser\Attributes\Attribute;

use Rector\BetterPhpDocParser\ValueObject\StartEndValueObject;

final class Attribute
{
/**
Expand All @@ -12,9 +14,10 @@ final class Attribute
public const HAS_DESCRIPTION_WITH_ORIGINAL_SPACES = 'has_description_with_restored_spaces';

/**
* @experiment
* @var string
*/
public const PHP_DOC_NODE_INFO = 'php_doc_node_info';
public const START_END = StartEndValueObject::class;

/**
* @var string
Expand Down
14 changes: 14 additions & 0 deletions packages/BetterPhpDocParser/src/PhpDocInfo/PhpDocInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Nette\Utils\Strings;
use PhpParser\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
Expand All @@ -16,7 +17,9 @@
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\ShouldNotHappenException;
use Rector\NodeTypeResolver\StaticTypeMapper;

Expand Down Expand Up @@ -78,6 +81,17 @@ public function getOriginalContent(): string
return $this->originalContent;
}

public function addPhpDocTagNode(PhpDocChildNode $phpDocChildNode): void
{
$this->phpDocNode->children[] = $phpDocChildNode;
}

public function addTagValueNodeWithShortName(AbstractTagValueNode $tagValueNode): void
{
$spacelessPhpDocTagNode = new SpacelessPhpDocTagNode($tagValueNode::SHORT_NAME, $tagValueNode);
$this->addPhpDocTagNode($spacelessPhpDocTagNode);
}

public function getPhpDocNode(): AttributeAwarePhpDocNode
{
return $this->phpDocNode;
Expand Down
63 changes: 21 additions & 42 deletions packages/BetterPhpDocParser/src/PhpDocInfo/PhpDocInfoFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
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;
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocNode;
use Rector\BetterPhpDocParser\Attributes\Attribute\Attribute;
use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface;
use Rector\BetterPhpDocParser\Contract\PhpDocNodeFactoryInterface;
use Rector\BetterPhpDocParser\ValueObject\StartEndValueObject;
use Rector\Configuration\CurrentNodeProvider;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\StaticTypeMapper;

final class PhpDocInfoFactory
Expand All @@ -38,11 +40,6 @@ final class PhpDocInfoFactory
*/
private $staticTypeMapper;

/**
* @var PhpDocInfo[]
*/
private $phpDocInfoByObjectHash = [];

public function __construct(
PhpDocParser $phpDocParser,
Lexer $lexer,
Expand All @@ -57,41 +54,30 @@ public function __construct(

public function createFromNode(Node $node): PhpDocInfo
{
$hash = $this->createUniqueDocNodeHash($node);

if (isset($this->phpDocInfoByObjectHash[$hash])) {
return $this->phpDocInfoByObjectHash[$hash];
}

/** needed for @see PhpDocNodeFactoryInterface */
$this->currentNodeProvider->setNode($node);

$content = $node->getDocComment()->getText();
$tokens = $this->lexer->tokenize($content);
if ($node->getDocComment() === null) {
$content = '';
$tokens = [];
$phpDocNode = new AttributeAwarePhpDocNode([]);
} else {
$content = $node->getDocComment()->getText();

$tokenIterator = new TokenIterator($tokens);
$tokens = $this->lexer->tokenize($content);
$tokenIterator = new TokenIterator($tokens);

/** @var AttributeAwarePhpDocNode $phpDocNode */
$phpDocNode = $this->phpDocParser->parse($tokenIterator);
$phpDocNode = $this->setPositionOfLastToken($phpDocNode);
/** @var AttributeAwarePhpDocNode $phpDocNode */
$phpDocNode = $this->phpDocParser->parse($tokenIterator);
$phpDocNode = $this->setPositionOfLastToken($phpDocNode);
}

$phpDocInfo = new PhpDocInfo($phpDocNode, $tokens, $content, $this->staticTypeMapper, $node);
$this->phpDocInfoByObjectHash[$hash] = $phpDocInfo;
$node->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);

return $phpDocInfo;
}

private function createUniqueDocNodeHash(Node $node): string
{
$this->ensureNodeHasDocComment($node);

$objectHash = spl_object_hash($node);
$docCommentHash = spl_object_hash($node->getDocComment());
$docCommentContentHash = sha1($node->getDocComment()->getText());

return $objectHash . $docCommentHash . $docCommentContentHash;
}

/**
* Needed for printing
*/
Expand All @@ -106,20 +92,13 @@ private function setPositionOfLastToken(
/** @var AttributeAwareNodeInterface $lastChildNode */
$lastChildNode = array_pop($phpDocChildNodes);

$phpDocNodeInfo = $lastChildNode->getAttribute(Attribute::PHP_DOC_NODE_INFO);
if ($phpDocNodeInfo !== null) {
$attributeAwarePhpDocNode->setAttribute(Attribute::LAST_TOKEN_POSITION, $phpDocNodeInfo->getEnd());
}
/** @var StartEndValueObject $startEndValueObject */
$startEndValueObject = $lastChildNode->getAttribute(Attribute::START_END);

return $attributeAwarePhpDocNode;
}

private function ensureNodeHasDocComment(Node $node): void
{
if ($node->getDocComment() !== null) {
return;
if ($startEndValueObject !== null) {
$attributeAwarePhpDocNode->setAttribute(Attribute::LAST_TOKEN_POSITION, $startEndValueObject->getEnd());
}

throw new ShouldNotHappenException(sprintf('"%s" is missing a DocComment node', get_class($node)));
return $attributeAwarePhpDocNode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ abstract class AbstractTagValueNode implements AttributeAwareNodeInterface, PhpD
*/
protected $hasNewlineAfterOpening = false;

/**
* @var string|null
*/
protected $originalContent;

/**
* @param mixed[] $item
*/
Expand Down Expand Up @@ -60,6 +65,10 @@ protected function printContentItems(array $contentItems): string
}

if ($contentItems === []) {
if ($this->originalContent !== null && Strings::endsWith($this->originalContent, '()')) {
return '()';
}

return '';
}

Expand Down Expand Up @@ -131,6 +140,7 @@ protected function resolveOriginalContentSpacingAndOrder(?string $originalConten
return;
}

$this->originalContent = $originalContent;
$this->orderedVisibleItems = ArrayItemStaticHelper::resolveAnnotationItemsOrder($originalContent);
$this->hasNewlineAfterOpening = (bool) Strings::match($originalContent, '#^\(\s+#m');
$this->hasNewlineBeforeClosing = (bool) Strings::match($originalContent, '#\s+\)$#m');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ final class InheritanceTypeTagValueNode extends AbstractDoctrineTagValueNode
*/
private $value;

public function __construct(?string $value)
public function __construct(?string $value, ?string $originalContent)
{
$this->value = $value;
$this->resolveOriginalContentSpacingAndOrder($originalContent);
}

public function __toString(): string
Expand All @@ -29,6 +30,10 @@ public function __toString(): string
return '';
}

return '("' . $this->value . '")';
if ($this->originalContent && ! in_array('value', (array) $this->orderedVisibleItems, true)) {
return '("' . $this->value . '")';
}

return '(value="' . $this->value . '")';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ public function __toString(): string
$contentItems = [];

if ($this->name !== null) {
$contentItems['name'] = sprintf('name="%s"', $this->name);
if ($this->originalContent !== null && ! in_array('name', (array) $this->orderedVisibleItems, true)) {
$contentItems[] = '"' . $this->name . '"';
} else {
$contentItems['name'] = sprintf('name="%s"', $this->name);
}
}

if ($this->schema !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,6 @@ public function __toString(): string
{
$contentItems = [];

if ($this->nullable !== null) {
$contentItems['nullable'] = sprintf('nullable=%s', $this->nullable ? 'true' : 'false');
}

if ($this->name) {
$contentItems['name'] = sprintf('name="%s"', $this->name);
}
Expand All @@ -95,7 +91,12 @@ public function __toString(): string
$contentItems['referencedColumnName'] = sprintf('referencedColumnName="%s"', $this->referencedColumnName);
}

if ($this->unique !== null) {
if ($this->nullable !== null) {
$contentItems['nullable'] = sprintf('nullable=%s', $this->nullable ? 'true' : 'false');
}

// skip default value
if ($this->unique !== null && $this->unique) {
$contentItems['unique'] = sprintf('unique=%s', $this->unique ? 'true' : 'false');
}

Expand Down Expand Up @@ -134,13 +135,13 @@ public function isNullable(): ?bool
return $this->nullable;
}

public function changeName(string $newName): void
public function getTag(): ?string
{
$this->name = $newName;
return $this->tag ?: self::SHORT_NAME;
}

public function getTag(): ?string
public function getUnique(): ?bool
{
return $this->tag ?: self::SHORT_NAME;
return $this->unique;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,23 @@ public function __toString(): string
$itemContents = [];

if ($this->serviceName) {
$itemContents[] = $this->serviceName;
$itemContents[] = '"' . $this->serviceName . '"';
}

if ($this->required !== null) {
$itemContents[] = sprintf('required=%s', $this->required ? 'true' : 'false');
}

if ($this->strict !== null) {
// skip default
if (! $this->strict) {
$itemContents[] = sprintf('strict=%s', $this->strict ? 'true' : 'false');
}

if ($itemContents === []) {
return '';
}

$stringContent = implode(', ', $itemContents);

return '(' . $stringContent . ')';
return $this->printContentItems($itemContents);
}

public function getServiceName(): ?string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public function createFromNodeAndTokens(Node $node, TokenIterator $tokenIterator
return null;
}

return new InheritanceTypeTagValueNode($inheritanceType->value);
$annotationContent = $this->resolveContentFromTokenIterator($tokenIterator);

return new InheritanceTypeTagValueNode($inheritanceType->value, $annotationContent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ private function parseChildAndStoreItsPositions(TokenIterator $tokenIterator): N
$startEndValueObject = new StartEndValueObject($tokenStart, $tokenEnd);

$attributeAwareNode = $this->attributeAwareNodeFactory->createFromNode($phpDocNode);
$attributeAwareNode->setAttribute(Attribute::PHP_DOC_NODE_INFO, $startEndValueObject);
$attributeAwareNode->setAttribute(Attribute::START_END, $startEndValueObject);

$possibleMultilineText = $this->multilineSpaceFormatPreserver->resolveCurrentPhpDocNodeText(
$attributeAwareNode
Expand Down

0 comments on commit d1757f2

Please sign in to comment.