Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Rector\AttributeAwarePhpDoc\Ast\Type;

use Nette\Utils\Strings;
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
Expand All @@ -17,28 +18,7 @@ final class AttributeAwareCallableTypeNode extends CallableTypeNode implements A
public function __toString(): string
{
// keep original (Psalm?) format, see https://github.com/rectorphp/rector/issues/2841
if ($this->isExplicitCallable()) {
return $this->createExplicitCallable();
}

return 'callable';
}

private function isExplicitCallable(): bool
{
if ($this->returnType instanceof GenericTypeNode) {
return true;
}

if (! $this->returnType instanceof IdentifierTypeNode) {
return false;
}

if (! $this->returnType instanceof IdentifierTypeNode) {
return false;
}

return $this->returnType->name !== 'mixed';
return $this->createExplicitCallable();
}

private function createExplicitCallable(): string
Expand All @@ -48,18 +28,48 @@ private function createExplicitCallable(): string

$parameterTypeString = $this->createParameterTypeString();

return sprintf('%s(%s):%s', $this->identifier->name, $parameterTypeString, (string) $returnType);
$returnTypeAsString = (string) $returnType;
if (Strings::contains($returnTypeAsString, '|')) {
$returnTypeAsString = '(' . $returnTypeAsString . ')';
}

$parameterTypeString = $this->normalizeParameterType($parameterTypeString, $returnTypeAsString);
$returnTypeAsString = $this->normalizeReturnType($returnTypeAsString);

return sprintf('%s%s%s', $this->identifier->name, $parameterTypeString, $returnTypeAsString);
}

private function createParameterTypeString(): string
{
$parameterTypeStrings = [];
foreach ($this->parameters as $parameter) {
$parameterTypeStrings[] = (string) $parameter;
$parameterTypeStrings[] = trim((string) $parameter);
}

$parameterTypeString = implode(',', $parameterTypeStrings);
$parameterTypeString = implode(', ', $parameterTypeStrings);

return trim($parameterTypeString);
}

private function normalizeReturnType(string $returnTypeAsString): string
{
if ($returnTypeAsString === 'mixed') {
return '';
}

return ':' . $returnTypeAsString;
}

private function normalizeParameterType(string $parameterTypeString, string $returnTypeAsString): string
{
if ($parameterTypeString !== '') {
return '(' . $parameterTypeString . ')';
}

if ($returnTypeAsString !== 'mixed' && $returnTypeAsString !== '') {
return '()';
}

return $parameterTypeString;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,4 @@
final class AttributeAwareNullableTypeNode extends NullableTypeNode implements AttributeAwareNodeInterface
{
use AttributeTrait;

public function __toString(): string
{
return $this->type . '|null';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareCallableTypeNode;
use Rector\AttributeAwarePhpDoc\Contract\AttributeNodeAwareFactory\AttributeAwareNodeFactoryAwareInterface;
use Rector\AttributeAwarePhpDoc\Contract\AttributeNodeAwareFactory\AttributeNodeAwareFactoryInterface;
use Rector\BetterPhpDocParser\Attributes\Ast\AttributeAwareNodeFactory;
use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface;

final class AttributeAwareCallableTypeNodeFactory implements AttributeNodeAwareFactoryInterface
final class AttributeAwareCallableTypeNodeFactory implements AttributeNodeAwareFactoryInterface, AttributeAwareNodeFactoryAwareInterface
{
/**
* @var AttributeAwareNodeFactory
*/
private $attributeAwareNodeFactory;

public function getOriginalNodeClass(): string
{
return CallableTypeNode::class;
Expand All @@ -27,6 +34,19 @@ public function isMatch(Node $node): bool
*/
public function create(Node $node): AttributeAwareNodeInterface
{
return new AttributeAwareCallableTypeNode($node->identifier, $node->parameters, $node->returnType);
$identifier = $this->attributeAwareNodeFactory->createFromNode($node->identifier);

foreach ($node->parameters as $key => $parameter) {
$node->parameters[$key] = $this->attributeAwareNodeFactory->createFromNode($parameter);
}

$returnType = $this->attributeAwareNodeFactory->createFromNode($node->returnType);

return new AttributeAwareCallableTypeNode($identifier, $node->parameters, $returnType);
}

public function setAttributeAwareNodeFactory(AttributeAwareNodeFactory $attributeAwareNodeFactory): void
{
$this->attributeAwareNodeFactory = $attributeAwareNodeFactory;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocNode;
use Rector\BetterPhpDocParser\Attributes\Ast\AttributeAwareNodeFactory;
use Rector\BetterPhpDocParser\Attributes\Attribute\Attribute;
use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface;
use Rector\BetterPhpDocParser\Contract\PhpDocNodeFactoryInterface;
Expand Down Expand Up @@ -45,25 +46,34 @@ final class PhpDocInfoFactory
*/
private $typeComparator;

/**
* @var AttributeAwareNodeFactory
*/
private $attributeAwareNodeFactory;

public function __construct(
PhpDocParser $phpDocParser,
Lexer $lexer,
CurrentNodeProvider $currentNodeProvider,
StaticTypeMapper $staticTypeMapper,
TypeComparator $typeComparator
TypeComparator $typeComparator,
AttributeAwareNodeFactory $attributeAwareNodeFactory
) {
$this->phpDocParser = $phpDocParser;
$this->lexer = $lexer;
$this->currentNodeProvider = $currentNodeProvider;
$this->staticTypeMapper = $staticTypeMapper;
$this->typeComparator = $typeComparator;
$this->attributeAwareNodeFactory = $attributeAwareNodeFactory;
}

public function createFromString(Node $node, string $content): PhpDocInfo
{
$tokens = $this->lexer->tokenize($content);
$phpDocNode = $this->parseTokensToPhpDocNode($tokens);

$phpDocNode = $this->attributeAwareNodeFactory->createFromNode($phpDocNode);

$phpDocInfo = new PhpDocInfo(
$phpDocNode,
$tokens,
Expand Down Expand Up @@ -99,6 +109,8 @@ public function createFromNode(Node $node): ?PhpDocInfo
$this->setPositionOfLastToken($phpDocNode);
}

$phpDocNode = $this->attributeAwareNodeFactory->createFromNode($phpDocNode);

$phpDocInfo = new PhpDocInfo(
$phpDocNode,
$tokens,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ public function printFormatPreserving(PhpDocInfo $phpDocInfo): string
$this->currentTokenPosition = 0;
$this->removedNodePositions = [];

return $this->printPhpDocNode($this->attributeAwarePhpDocNode);
$phpDocString = $this->printPhpDocNode($this->attributeAwarePhpDocNode);

// hotfix of extra space with callable ()
return Strings::replace($phpDocString, '#callable(\s+)\(#', 'callable(');
}

private function printPhpDocNode(AttributeAwarePhpDocNode $attributeAwarePhpDocNode): string
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** @var callable(array<mixed>) */
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** @param callable(array<mixed>) $hitCallback */
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ final class PhpDocInfoPrinterTest extends AbstractPhpDocInfoPrinterTest
{
/**
* @dataProvider provideData()
* @dataProvider provideDataCallable()
*/
public function test(string $docFilePath): void
{
Expand All @@ -26,6 +27,11 @@ public function provideData(): Iterator
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureBasic', '*.txt');
}

public function provideDataCallable(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureCallable', '*.txt');
}

/**
* @dataProvider provideDataEmpty()
*/
Expand Down