mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-07 20:00:50 +00:00
[SimplePhpDocParser] Add README + getParam*() helper methods (#4393)
This commit is contained in:
parent
a4b4b474cb
commit
01514ab9a8
4
.github/workflows/code_analysis.yaml
vendored
4
.github/workflows/code_analysis.yaml
vendored
|
@ -20,6 +20,10 @@ jobs:
|
|||
name: 'PHPStan'
|
||||
run: composer phpstan
|
||||
|
||||
-
|
||||
name: 'PHPStan for config'
|
||||
run: composer phpstan-config
|
||||
|
||||
-
|
||||
name: 'Show command'
|
||||
run: bin/rector show --config rector-ci.php --ansi
|
||||
|
|
|
@ -80,6 +80,7 @@ final class ComposerJsonManipulator
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $json
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function removeDevKeys(array $json): array
|
||||
|
@ -92,6 +93,7 @@ final class ComposerJsonManipulator
|
|||
|
||||
/**
|
||||
* Use phpstan/phpstan-src, because the phpstan.phar cannot be packed into rector.phar
|
||||
* @param mixed[] $json
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function replacePHPStanWithPHPStanSrc(array $json): array
|
||||
|
@ -118,6 +120,7 @@ final class ComposerJsonManipulator
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $json
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function addDevDependenciesFromPHPStan(array $json, string $phpstanVersion): array
|
||||
|
|
|
@ -303,13 +303,8 @@
|
|||
"vendor/bin/ecs check --fix --ansi",
|
||||
"vendor/bin/ecs check-markdown README.md docs/rector_rules_overview.md --fix --ansi"
|
||||
],
|
||||
"phpstan": [
|
||||
"vendor/bin/phpstan analyse --ansi --error-format symplify",
|
||||
"vendor/bin/phpstan analyse config --ansi --error-format symplify"
|
||||
],
|
||||
"phpstan-config": [
|
||||
"vendor/bin/phpstan analyse config --ansi --error-format symplify"
|
||||
],
|
||||
"phpstan": "vendor/bin/phpstan analyse --ansi --error-format symplify",
|
||||
"phpstan-config": "vendor/bin/phpstan analyse config --ansi --error-format symplify",
|
||||
"changelog": [
|
||||
"vendor/bin/changelog-linker dump-merges --in-categories --ansi",
|
||||
"vendor/bin/changelog-linker link --ansi",
|
||||
|
|
1
ecs.php
1
ecs.php
|
@ -98,7 +98,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
// buggy with specific markdown snippet file in docs/rules_overview.md
|
||||
ArrayListItemNewlineFixer::class => null,
|
||||
BlankLineAfterOpeningTagFixer::class => null,
|
||||
|
||||
StrictComparisonFixer::class => [__DIR__ . '/rules/polyfill/src/ConditionEvaluator.php'],
|
||||
]);
|
||||
|
||||
|
|
|
@ -5,11 +5,11 @@ declare(strict_types=1);
|
|||
namespace Rector\AttributeAwarePhpDoc\Ast\PhpDoc;
|
||||
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
||||
use Rector\BetterPhpDocParser\Attributes\Attribute\AttributeTrait;
|
||||
use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface;
|
||||
use Rector\SimplePhpDocParser\ValueObject\Ast\PhpDoc\SimplePhpDocNode;
|
||||
|
||||
final class AttributeAwarePhpDocNode extends PhpDocNode implements AttributeAwareNodeInterface
|
||||
final class AttributeAwarePhpDocNode extends SimplePhpDocNode implements AttributeAwareNodeInterface
|
||||
{
|
||||
use AttributeTrait;
|
||||
|
||||
|
|
|
@ -100,6 +100,9 @@ trait ArrayPartPhpDocTagPrinterTrait
|
|||
return ! $tagValueNodeConfiguration->getKeysByQuotedStatus()[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $item
|
||||
*/
|
||||
private function quoteKeys(array $item, string $key, string $json, string $originalContent): string
|
||||
{
|
||||
foreach (array_keys($item) as $itemKey) {
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\BetterPhpDocParser\PhpDocInfo;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Param;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
||||
|
@ -13,7 +12,6 @@ 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\PhpDoc\ThrowsTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
|
@ -22,6 +20,7 @@ use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocNode;
|
|||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocTagNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareReturnTagValueNode;
|
||||
use Rector\BetterPhpDocParser\Annotation\StaticAnnotationNaming;
|
||||
use Rector\BetterPhpDocParser\Attributes\Ast\AttributeAwareNodeFactory;
|
||||
use Rector\BetterPhpDocParser\Attributes\Ast\PhpDoc\SpacelessPhpDocTagNode;
|
||||
use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface;
|
||||
use Rector\BetterPhpDocParser\Contract\PhpDocNode\ShortNameAwareTagInterface;
|
||||
|
@ -85,6 +84,11 @@ final class PhpDocInfo
|
|||
*/
|
||||
private $phpDocRemover;
|
||||
|
||||
/**
|
||||
* @var AttributeAwareNodeFactory
|
||||
*/
|
||||
private $attributeAwareNodeFactory;
|
||||
|
||||
/**
|
||||
* @param mixed[] $tokens
|
||||
*/
|
||||
|
@ -95,7 +99,8 @@ final class PhpDocInfo
|
|||
StaticTypeMapper $staticTypeMapper,
|
||||
Node $node,
|
||||
PhpDocTypeChanger $phpDocTypeChanger,
|
||||
PhpDocRemover $phpDocRemover
|
||||
PhpDocRemover $phpDocRemover,
|
||||
AttributeAwareNodeFactory $attributeAwareNodeFactory
|
||||
) {
|
||||
$this->phpDocNode = $attributeAwarePhpDocNode;
|
||||
$this->tokens = $tokens;
|
||||
|
@ -105,6 +110,7 @@ final class PhpDocInfo
|
|||
$this->node = $node;
|
||||
$this->phpDocTypeChanger = $phpDocTypeChanger;
|
||||
$this->phpDocRemover = $phpDocRemover;
|
||||
$this->attributeAwareNodeFactory = $attributeAwareNodeFactory;
|
||||
}
|
||||
|
||||
public function getOriginalContent(): string
|
||||
|
@ -224,6 +230,9 @@ final class PhpDocInfo
|
|||
return (bool) $this->getByType($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $names
|
||||
*/
|
||||
public function hasByNames(array $names): bool
|
||||
{
|
||||
foreach ($names as $name) {
|
||||
|
@ -408,14 +417,17 @@ final class PhpDocInfo
|
|||
|
||||
public function getParamTagValueByName(string $name): ?AttributeAwareParamTagValueNode
|
||||
{
|
||||
/** @var AttributeAwareParamTagValueNode $paramTagValue */
|
||||
foreach ($this->phpDocNode->getParamTagValues() as $paramTagValue) {
|
||||
if (Strings::match($paramTagValue->parameterName, '#^(\$)?' . $name . '$#')) {
|
||||
return $paramTagValue;
|
||||
}
|
||||
$paramTagValueNode = $this->phpDocNode->getParam($name);
|
||||
if ($paramTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
$attributeAwareParamTagValueNode = $this->attributeAwareNodeFactory->createFromNode($paramTagValueNode, '');
|
||||
if (! $attributeAwareParamTagValueNode instanceof AttributeAwareParamTagValueNode) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
return $attributeAwareParamTagValueNode;
|
||||
}
|
||||
|
||||
private function getTypeOrMixed(?PhpDocTagValueNode $phpDocTagValueNode): Type
|
||||
|
@ -473,13 +485,9 @@ final class PhpDocInfo
|
|||
{
|
||||
$throwsTypes = [];
|
||||
|
||||
foreach ($this->getTagsByName('throws') as $throwsPhpDocNode) {
|
||||
if (! $throwsPhpDocNode->value instanceof ThrowsTagValueNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($this->phpDocNode->getThrowsTagValues() as $throwsPhpDocNode) {
|
||||
$throwsTypes[] = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType(
|
||||
$throwsPhpDocNode->value,
|
||||
$throwsPhpDocNode,
|
||||
$this->node
|
||||
);
|
||||
}
|
||||
|
|
|
@ -111,6 +111,9 @@ final class PhpDocInfoFactory
|
|||
return $this->createFromPhpDocNode($attributeAwarePhpDocNode, '', [], $node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[][] $tokens
|
||||
*/
|
||||
private function parseTokensToPhpDocNode(array $tokens): AttributeAwarePhpDocNode
|
||||
{
|
||||
$tokenIterator = new TokenIterator($tokens);
|
||||
|
@ -139,6 +142,9 @@ final class PhpDocInfoFactory
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $tokens
|
||||
*/
|
||||
private function createFromPhpDocNode(
|
||||
AttributeAwarePhpDocNode $attributeAwarePhpDocNode,
|
||||
string $content,
|
||||
|
@ -158,8 +164,10 @@ final class PhpDocInfoFactory
|
|||
$this->staticTypeMapper,
|
||||
$node,
|
||||
$this->phpDocTypeChanger,
|
||||
$this->phpDocRemover
|
||||
$this->phpDocRemover,
|
||||
$this->attributeAwareNodeFactory
|
||||
);
|
||||
|
||||
$node->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);
|
||||
|
||||
return $phpDocInfo;
|
||||
|
|
|
@ -80,6 +80,9 @@ abstract class AbstractTagValueNode implements AttributeAwareNodeInterface, PhpD
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $items
|
||||
*/
|
||||
protected function printItems(array $items): string
|
||||
{
|
||||
$items = $this->completeItemsQuotes($items);
|
||||
|
@ -184,6 +187,9 @@ abstract class AbstractTagValueNode implements AttributeAwareNodeInterface, PhpD
|
|||
return $this->tagValueNodeConfiguration->hasOpeningBracket() && $this->tagValueNodeConfiguration->hasClosingBracket();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $value
|
||||
*/
|
||||
private function correctArraySingleItemPrint(array $value, string $arrayItemAsString): string
|
||||
{
|
||||
if (count($value) !== 1) {
|
||||
|
|
|
@ -95,6 +95,7 @@ final class TableTagValueNode extends AbstractDoctrineTagValueNode implements Si
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $items
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function addCustomItems(array $items): array
|
||||
|
|
|
@ -10,6 +10,9 @@ use Rector\BetterPhpDocParser\PhpDocNode\AbstractTagValueNode;
|
|||
|
||||
final class SlugTagValueNode extends AbstractTagValueNode implements ShortNameAwareTagInterface, SilentKeyNodeInterface
|
||||
{
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getFields(): array
|
||||
{
|
||||
return $this->items['fields'];
|
||||
|
|
|
@ -13,6 +13,7 @@ use Rector\BetterPhpDocParser\ValueObject\TagValueNodeConfiguration;
|
|||
trait PrintTagValueNodeTrait
|
||||
{
|
||||
/**
|
||||
* @param mixed[] $items
|
||||
* @return mixed[]
|
||||
*/
|
||||
protected function makeKeysExplicit(array $items): array
|
||||
|
@ -34,6 +35,7 @@ trait PrintTagValueNodeTrait
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $items
|
||||
* @param string[] $skipKeys
|
||||
* @return mixed[]
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,9 @@ final class SymfonyRouteTagValueNode extends AbstractTagValueNode implements Sho
|
|||
return $this->printItems($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $methods
|
||||
*/
|
||||
public function changeMethods(array $methods): void
|
||||
{
|
||||
$this->tagValueNodeConfiguration->addOrderedVisibleItem('methods');
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\BetterPhpDocParser\PhpDocNodeFactory\Doctrine\Class_;
|
||||
|
||||
use Doctrine\ORM\Mapping\UniqueConstraint;
|
||||
use Nette\Utils\Strings;
|
||||
use Rector\BetterPhpDocParser\Annotation\AnnotationItemsResolver;
|
||||
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Class_\UniqueConstraintTagValueNode;
|
||||
|
@ -26,6 +27,7 @@ final class UniqueConstraintPhpDocNodeFactory
|
|||
}
|
||||
|
||||
/**
|
||||
* @param UniqueConstraint[]|null $uniqueConstraints
|
||||
* @return UniqueConstraintTagValueNode[]
|
||||
*/
|
||||
public function createUniqueConstraintTagValueNodes(?array $uniqueConstraints, string $annotationContent): array
|
||||
|
|
|
@ -29,8 +29,8 @@ final class ClassAnnotationMatcher
|
|||
|
||||
$tag = ltrim($tag, '@');
|
||||
|
||||
/** @var Use_[]|null $useNodes */
|
||||
$useNodes = $node->getAttribute(AttributeKey::USE_NODES);
|
||||
/** @var Use_[] $useNodes */
|
||||
$useNodes = (array) $node->getAttribute(AttributeKey::USE_NODES);
|
||||
|
||||
$fullyQualifiedClass = $this->resolveFullyQualifiedClass($useNodes, $node, $tag);
|
||||
$this->fullyQualifiedNameByHash[$uniqueHash] = $fullyQualifiedClass;
|
||||
|
@ -38,9 +38,12 @@ final class ClassAnnotationMatcher
|
|||
return $fullyQualifiedClass;
|
||||
}
|
||||
|
||||
private function resolveFullyQualifiedClass(?array $useNodes, Node $node, string $tag): string
|
||||
/**
|
||||
* @param Use_[] $uses
|
||||
*/
|
||||
private function resolveFullyQualifiedClass(array $uses, Node $node, string $tag): string
|
||||
{
|
||||
if ($useNodes === null) {
|
||||
if ($uses === []) {
|
||||
/** @var string|null $namespace */
|
||||
$namespace = $node->getAttribute(AttributeKey::NAMESPACE_NAME);
|
||||
if ($namespace !== null) {
|
||||
|
@ -53,7 +56,7 @@ final class ClassAnnotationMatcher
|
|||
return $tag;
|
||||
}
|
||||
|
||||
return $this->matchFullAnnotationClassWithUses($tag, $useNodes) ?? $tag;
|
||||
return $this->matchFullAnnotationClassWithUses($tag, $uses) ?? $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -92,6 +92,9 @@ final class ArrayItemStaticHelper
|
|||
return $contentItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $itemsOrder
|
||||
*/
|
||||
private static function isNotEmptyAndHasSilentKey(string $content, ?string $silentKey, array $itemsOrder): bool
|
||||
{
|
||||
if (! Strings::match($content, self::NON_EMPTY_SILENT_KEY_REGEX)) {
|
||||
|
|
|
@ -39,7 +39,7 @@ final class TagValueNodeConfiguration
|
|||
private $arrayEqualSign;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $keysByQuotedStatus = [];
|
||||
|
||||
|
@ -49,7 +49,7 @@ final class TagValueNodeConfiguration
|
|||
private $originalContent;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
* @var string[]|null
|
||||
*/
|
||||
private $orderedVisibleItems;
|
||||
|
||||
|
@ -58,6 +58,10 @@ final class TagValueNodeConfiguration
|
|||
*/
|
||||
private $silentKey;
|
||||
|
||||
/**
|
||||
* @param array<string, bool> $keysByQuotedStatus
|
||||
* @param string[] $orderedVisibleItems
|
||||
*/
|
||||
public function __construct(
|
||||
?string $originalContent = null,
|
||||
?array $orderedVisibleItems = null,
|
||||
|
@ -87,6 +91,9 @@ final class TagValueNodeConfiguration
|
|||
return $this->originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]|null
|
||||
*/
|
||||
public function getOrderedVisibleItems(): ?array
|
||||
{
|
||||
return $this->orderedVisibleItems;
|
||||
|
@ -113,7 +120,7 @@ final class TagValueNodeConfiguration
|
|||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
* @return array<string, bool>
|
||||
*/
|
||||
public function getKeysByQuotedStatus(): array
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@ final class ArrayPartPhpDocTagPrinterTest extends TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $items
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(array $items, string $key, string $expectedContent): void
|
||||
|
|
|
@ -46,6 +46,7 @@ final class ChangedFilesDetectorTest extends AbstractRectorTestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string[] $dependantFiles
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function testGetDependentFileInfos(string $filePathName, array $dependantFiles): void
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Rector\DoctrineAnnotationGenerated\DataCollector;
|
|||
final class ResolvedConstantStaticCollector
|
||||
{
|
||||
/**
|
||||
* @var mixed[]
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private static $valuesByIdentifier = [];
|
||||
|
||||
|
@ -26,7 +26,7 @@ final class ResolvedConstantStaticCollector
|
|||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function provide(): array
|
||||
{
|
||||
|
|
|
@ -75,6 +75,7 @@ final class ConstantReferenceIdentifierRestorer
|
|||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $identifierToResolvedValues
|
||||
* @param mixed $value
|
||||
* @return mixed|null
|
||||
*/
|
||||
|
@ -91,6 +92,10 @@ final class ConstantReferenceIdentifierRestorer
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $value
|
||||
* @param array<string, mixed> $identifierToResolvedValues
|
||||
*/
|
||||
private function restoreNestedValue(
|
||||
array $value,
|
||||
array $identifierToResolvedValues,
|
||||
|
|
|
@ -29,6 +29,7 @@ final class RectorsDocumentationPrinterTest extends AbstractKernelTestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string[] $rectorClasses
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(array $rectorClasses, bool $isRectorProject, string $expectedContentFilePath): void
|
||||
|
@ -55,7 +56,7 @@ final class RectorsDocumentationPrinterTest extends AbstractKernelTestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @param class-string[] $rectorClasses
|
||||
* @param string[] $rectorClasses
|
||||
* @return RectorInterface[]
|
||||
*/
|
||||
private function createRectorsFromRectorClasses(array $rectorClasses): array
|
||||
|
|
|
@ -264,6 +264,10 @@ final class NodeNameResolver
|
|||
return $this->getName($classLike->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $backtrace
|
||||
* @return mixed[]|null
|
||||
*/
|
||||
private function matchRectorBacktraceCall(array $backtrace): ?array
|
||||
{
|
||||
foreach ($backtrace as $singleTrace) {
|
||||
|
|
|
@ -156,6 +156,7 @@ final class PHPStanServicesFactory
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string[] $additionalConfigFiles
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function appendPhpstanPHPUnitExtensionIfExists(
|
||||
|
|
|
@ -236,6 +236,9 @@ final class PHPStanNodeScopeResolver
|
|||
return $classLike->name->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $dependentFiles
|
||||
*/
|
||||
private function reportCacheDebug(SmartFileInfo $smartFileInfo, array $dependentFiles): void
|
||||
{
|
||||
if (! $this->configuration->isCacheDebug()) {
|
||||
|
|
|
@ -76,6 +76,7 @@ final class PhpAttributteGroupFactory
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $items
|
||||
* @return Arg[]
|
||||
*/
|
||||
private function createArgsFromItems(array $items, ?string $silentKey = null): array
|
||||
|
@ -122,6 +123,9 @@ final class PhpAttributteGroupFactory
|
|||
return new AttributeGroup([$attribute]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $items
|
||||
*/
|
||||
private function isArrayArguments(array $items): bool
|
||||
{
|
||||
foreach (array_keys($items) as $key) {
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Rector\PostRector\Rector;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use Rector\CodingStyle\Application\UseImportsAdder;
|
||||
|
@ -119,6 +120,9 @@ final class UseAddingPostRector extends AbstractPostRector
|
|||
return new RectorDefinition('Post Rector that adds use statements');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
*/
|
||||
private function getSmartFileInfo(array $nodes): ?SmartFileInfo
|
||||
{
|
||||
foreach ($nodes as $node) {
|
||||
|
|
|
@ -94,6 +94,9 @@ final class ComposerPackageAutoloadUpdater
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $composerJson
|
||||
*/
|
||||
private function isPackageAlreadyLoaded(array $composerJson, Package $package): bool
|
||||
{
|
||||
foreach (['autoload', self::AUTOLOAD_DEV] as $autoloadSection) {
|
||||
|
|
|
@ -44,6 +44,7 @@ final class FileGenerator
|
|||
}
|
||||
|
||||
/**
|
||||
* @param SmartFileInfo[] $templateFileInfos
|
||||
* @param string[] $templateVariables
|
||||
* @return string[]
|
||||
*/
|
||||
|
@ -67,6 +68,9 @@ final class FileGenerator
|
|||
return $generatedFilePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $templateVariables
|
||||
*/
|
||||
private function generateFileInfoWithTemplateVariables(
|
||||
SmartFileInfo $smartFileInfo,
|
||||
array $templateVariables,
|
||||
|
|
|
@ -28,6 +28,7 @@ final class OverrideGuard
|
|||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $templateVariables
|
||||
* @param SmartFileInfo[] $templateFileInfos
|
||||
*/
|
||||
public function isUnwantedOverride(
|
||||
|
@ -52,6 +53,9 @@ final class OverrideGuard
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $templateVariables
|
||||
*/
|
||||
private function doesFileInfoAlreadyExist(
|
||||
array $templateVariables,
|
||||
RectorRecipe $rectorRecipe,
|
||||
|
|
|
@ -84,6 +84,9 @@ final class RectorRecipe
|
|||
*/
|
||||
private $extraFileContent;
|
||||
|
||||
/**
|
||||
* @param class-string[] $nodeTypes
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
array $nodeTypes,
|
||||
|
|
78
packages/simple-php-doc-parser/README.md
Normal file
78
packages/simple-php-doc-parser/README.md
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Simple PHP Doc Parser
|
||||
|
||||
Simple service integration of phpstan/phpdoc-parser, with few extra goodies for practical use
|
||||
|
||||
## 1. Install
|
||||
|
||||
```bash
|
||||
composer require rector/simple-php-doc-parser
|
||||
```
|
||||
|
||||
## 2. Register Bundle
|
||||
|
||||
Register bundle in your project:
|
||||
|
||||
```php
|
||||
// app/bundles.php
|
||||
return [
|
||||
Rector\SimplePhpDocParser\Bundle\SimplePhpDocParserBundle::class => [
|
||||
'all' => true,
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
or via Kernel:
|
||||
|
||||
```php
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Rector\SimplePhpDocParser\Bundle\SimplePhpDocParserBundle;
|
||||
|
||||
final class AppKernel extends Kernel
|
||||
{
|
||||
/**
|
||||
* @return BundleInterface[]
|
||||
*/
|
||||
public function registerBundles(): array
|
||||
{
|
||||
return [new SimplePhpDocParserBundle()];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Usage
|
||||
|
||||
Required services `Rector\SimplePhpDocParser\SimplePhpDocParser` in constructor, where you need it, and use it:
|
||||
|
||||
```php
|
||||
use Rector\SimplePhpDocParser\SimplePhpDocParser;
|
||||
|
||||
final class SomeClass
|
||||
{
|
||||
/**
|
||||
* @var SimplePhpDocParser
|
||||
*/
|
||||
private $simplePhpDocParser;
|
||||
|
||||
public function __construct(SimplePhpDocParser $simplePhpDocParser)
|
||||
{
|
||||
$this->simplePhpDocParser = $simplePhpDocParser;
|
||||
}
|
||||
|
||||
public function some()
|
||||
{
|
||||
$docBlock = '/** @param int $name */';
|
||||
|
||||
/** @var \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode $phpDocNode */
|
||||
$phpDocNode = $this->simplePhpDocParser->parseDocBlock($docBlock);
|
||||
|
||||
// param extras
|
||||
|
||||
/** @var \PHPStan\PhpDocParser\Ast\Type\TypeNode $nameParamType */
|
||||
$nameParamType = $phpDocNode->getParamType('name');
|
||||
|
||||
/** @var \PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode $nameParamTagValueNode */
|
||||
$nameParamTagValueNode = $phpDocNode->getParam('name');
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "rector/simple-php-doc-parser",
|
||||
"description": "Simple service integration of phpstan/phpdoc-parser",
|
||||
"description": "Simple service integration of phpstan/phpdoc-parser, with few extra goodies for practical use",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^7.2.4|^8.0",
|
||||
|
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\SimplePhpDocParser;
|
||||
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
||||
use PHPStan\PhpDocParser\Lexer\Lexer;
|
||||
use PHPStan\PhpDocParser\Parser\PhpDocParser;
|
||||
use PHPStan\PhpDocParser\Parser\TokenIterator;
|
||||
use Rector\SimplePhpDocParser\ValueObject\Ast\PhpDoc\SimplePhpDocNode;
|
||||
|
||||
/**
|
||||
* @see \Rector\SimplePhpDocParser\Tests\SimplePhpDocParser\SimplePhpDocParserTest
|
||||
|
@ -30,11 +30,12 @@ final class SimplePhpDocParser
|
|||
$this->lexer = $lexer;
|
||||
}
|
||||
|
||||
public function parseDocBlock(string $docBlock): PhpDocNode
|
||||
public function parseDocBlock(string $docBlock): SimplePhpDocNode
|
||||
{
|
||||
$tokens = $this->lexer->tokenize($docBlock);
|
||||
$tokenIterator = new TokenIterator($tokens);
|
||||
|
||||
return $this->phpDocParser->parse($tokenIterator);
|
||||
$phpDocNode = $this->phpDocParser->parse($tokenIterator);
|
||||
return new SimplePhpDocNode($phpDocNode->children);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\SimplePhpDocParser\ValueObject\Ast\PhpDoc;
|
||||
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
|
||||
/**
|
||||
* @notfinal on purpose, so it can be extended by 3rd party
|
||||
*/
|
||||
class SimplePhpDocNode extends PhpDocNode
|
||||
{
|
||||
public function getParam(string $desiredParamName): ?ParamTagValueNode
|
||||
{
|
||||
$desiredParamNameWithDollar = '$' . ltrim($desiredParamName, '$');
|
||||
|
||||
foreach ($this->getParamTagValues() as $paramTagValueNode) {
|
||||
if ($paramTagValueNode->parameterName !== $desiredParamNameWithDollar) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $paramTagValueNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getParamType(string $desiredParamName): ?TypeNode
|
||||
{
|
||||
$paramTagValueNode = $this->getParam($desiredParamName);
|
||||
if ($paramTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $paramTagValueNode->type;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
/**
|
||||
* @param string $name
|
||||
*/
|
|
@ -6,6 +6,7 @@ namespace Rector\SimplePhpDocParser\Tests\SimplePhpDocParser;
|
|||
|
||||
use Rector\Core\HttpKernel\RectorKernel;
|
||||
use Rector\SimplePhpDocParser\SimplePhpDocParser;
|
||||
use Rector\SimplePhpDocParser\ValueObject\Ast\PhpDoc\SimplePhpDocNode;
|
||||
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
|
@ -22,13 +23,28 @@ final class SimplePhpDocParserTest extends AbstractKernelTestCase
|
|||
$this->simplePhpDocParser = self::$container->get(SimplePhpDocParser::class);
|
||||
}
|
||||
|
||||
public function test(): void
|
||||
public function testVar(): void
|
||||
{
|
||||
$fileInfo = new SmartFileInfo(__DIR__ . '/Fixture/basic_doc.txt');
|
||||
$smartFileInfo = new SmartFileInfo(__DIR__ . '/Fixture/var_int.txt');
|
||||
|
||||
$phpDocNode = $this->simplePhpDocParser->parseDocBlock($fileInfo->getContents());
|
||||
$phpDocNode = $this->simplePhpDocParser->parseDocBlock($smartFileInfo->getContents());
|
||||
$this->assertInstanceOf(SimplePhpDocNode::class, $phpDocNode);
|
||||
|
||||
$varTagValues = $phpDocNode->getVarTagValues();
|
||||
$this->assertCount(1, $varTagValues);
|
||||
}
|
||||
|
||||
public function testParam(): void
|
||||
{
|
||||
$smartFileInfo = new SmartFileInfo(__DIR__ . '/Fixture/param_string_name.txt');
|
||||
|
||||
$phpDocNode = $this->simplePhpDocParser->parseDocBlock($smartFileInfo->getContents());
|
||||
$this->assertInstanceOf(SimplePhpDocNode::class, $phpDocNode);
|
||||
|
||||
// DX friendly
|
||||
$paramType = $phpDocNode->getParamType('name');
|
||||
$withDollarParamType = $phpDocNode->getParamType('$name');
|
||||
|
||||
$this->assertSame($paramType, $withDollarParamType);
|
||||
}
|
||||
}
|
||||
|
|
14
phpstan.neon
14
phpstan.neon
|
@ -123,6 +123,8 @@ parameters:
|
|||
checkGenericClassInNonGenericObjectType: false
|
||||
|
||||
excludes_analyse:
|
||||
|
||||
|
||||
# iterable types
|
||||
- '#with no value type specified in iterable type array#'
|
||||
- '#type specified in iterable type (array|iterable)#'
|
||||
|
@ -131,6 +133,9 @@ parameters:
|
|||
- utils/phpstan-extensions/src/Rule/PreventParentMethodVisibilityOverrideRule.php
|
||||
- utils/phpstan-extensions/src/Rule/KeepRectorNamespaceForRectorRule.php
|
||||
- packages/rector-generator/templates/*
|
||||
# this invalidates whole cache everytime
|
||||
- 'packages/symfony-php-config/*'
|
||||
- 'packages/simple-php-doc-parser'
|
||||
|
||||
# generated files
|
||||
- 'packages/doctrine-annotation-generated/src/ConstantPreservingDocParser.php'
|
||||
|
@ -152,8 +157,8 @@ parameters:
|
|||
ignoreErrors:
|
||||
# @todo remove
|
||||
# iterable types
|
||||
- '#with no value type specified in iterable type array#'
|
||||
- '#type specified in iterable type (array|iterable)#'
|
||||
# - '#with no value type specified in iterable type array#'
|
||||
# - '#type specified in iterable type (array|iterable)#'
|
||||
|
||||
# false positive
|
||||
- '#PHPDoc tag \@param for parameter \$node with type float is incompatible with native type PhpParser\\Node#'
|
||||
|
@ -752,11 +757,6 @@ parameters:
|
|||
- rules/symfony-code-quality/src/Rector/Class_/EventListenerToEventSubscriberRector.php # 247
|
||||
- utils/doctrine-annotation-parser-syncer/src/Rector/Namespace_/RenameAnnotationReaderClassRector.php # 41
|
||||
- utils/doctrine-annotation-parser-syncer/src/Rector/Namespace_/RenameDocParserClassRector.php # 41
|
||||
- utils/phpstan-extensions/src/Rule/ValueObjectHasNoValueObjectSuffixRule.php # 45
|
||||
- utils/phpstan-extensions/src/Rule/ValueObjectHasNoValueObjectSuffixRule.php # 59
|
||||
- utils/phpstan-extensions/src/Rule/ValueObjectHasNoValueObjectSuffixRule.php # 60
|
||||
- utils/phpstan-extensions/src/Rule/ValueObjectHasNoValueObjectSuffixRule.php # 75
|
||||
- utils/phpstan-extensions/src/Rule/ValueObjectHasNoValueObjectSuffixRule.php # 79
|
||||
|
||||
-
|
||||
message: '#Add regex101\.com link to that shows the regex in practise, so it will be easier to maintain in case of bug/extension in the future#'
|
||||
|
|
|
@ -45,6 +45,9 @@ final class UseImportsTraverser
|
|||
$this->traverseForType($stmts, $callable, Use_::TYPE_NORMAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stmt[] $stmts
|
||||
*/
|
||||
private function traverseForType(array $stmts, callable $callable, int $desiredType): void
|
||||
{
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable($stmts, function (Node $node) use (
|
||||
|
|
|
@ -78,6 +78,7 @@ final class DocAliasResolver
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string[] $possibleDocAliases
|
||||
* @return string[]
|
||||
*/
|
||||
private function appendPossibleAliases(Type $varType, array $possibleDocAliases): array
|
||||
|
|
|
@ -22,7 +22,7 @@ final class UseClassKeywordForClassNameResolutionRector extends AbstractRector
|
|||
* @var string
|
||||
* @see https://regex101.com/r/Vv41Qr/1/
|
||||
*/
|
||||
private const CLASS_BEFORE_STATIC_ACCESS_REGEX = '#([\\\\a-zA-Z0-9_\\x80-\\xff]*)::#';
|
||||
private const CLASS_BEFORE_STATIC_ACCESS_REGEX = '#(?<class_name>[\\\\a-zA-Z0-9_\\x80-\\xff]*)::#';
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
|
@ -70,18 +70,31 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
* @return string[]
|
||||
*/
|
||||
public function getExistingClasses(String_ $string): array
|
||||
{
|
||||
/** @var mixed[] $matches */
|
||||
$matches = Strings::matchAll($string->value, self::CLASS_BEFORE_STATIC_ACCESS_REGEX, PREG_PATTERN_ORDER);
|
||||
if (! isset($matches['class_name'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_filter($matches[1], function (string $className): bool {
|
||||
return class_exists($className);
|
||||
});
|
||||
$classNames = [];
|
||||
|
||||
foreach ($matches['class_name'] as $matchedClassName) {
|
||||
if (! class_exists($matchedClassName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classNames[] = $matchedClassName;
|
||||
}
|
||||
|
||||
return $classNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classNames
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getParts(String_ $string, array $classNames): array
|
||||
|
|
|
@ -34,7 +34,7 @@ use ReflectionFunction;
|
|||
final class AnnotateThrowablesRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
* @var string[]
|
||||
*/
|
||||
private $throwablesToAnnotate = [];
|
||||
|
||||
|
@ -273,6 +273,10 @@ CODE_SAMPLE
|
|||
return $callePhpDocInfo->getThrowsClassNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $foundThrownThrowables
|
||||
* @param string[] $alreadyAnnotatedThrowables
|
||||
*/
|
||||
private function diffThrowables(array $foundThrownThrowables, array $alreadyAnnotatedThrowables): int
|
||||
{
|
||||
$normalizeNamespace = static function (string $class): string {
|
||||
|
@ -296,7 +300,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string>
|
||||
* @return class-string[]
|
||||
*/
|
||||
private function extractMethodReturns(FullyQualified $fullyQualified, Identifier $identifier): array
|
||||
{
|
||||
|
@ -311,7 +315,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string>
|
||||
* @return class-string[]
|
||||
*/
|
||||
private function extractMethodThrows(FullyQualified $fullyQualified, Identifier $identifier): array
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\CodingStyle\ValueObject;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
final class ConcatStringAndPlaceholders
|
||||
{
|
||||
/**
|
||||
|
@ -12,10 +14,13 @@ final class ConcatStringAndPlaceholders
|
|||
private $content;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var Expr[]
|
||||
*/
|
||||
private $placeholderNodes = [];
|
||||
|
||||
/**
|
||||
* @param Expr[] $placeholderNodes
|
||||
*/
|
||||
public function __construct(string $content, array $placeholderNodes)
|
||||
{
|
||||
$this->content = $content;
|
||||
|
@ -28,7 +33,7 @@ final class ConcatStringAndPlaceholders
|
|||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
* @return Expr[]
|
||||
*/
|
||||
public function getPlaceholderNodes(): array
|
||||
{
|
||||
|
|
|
@ -28,6 +28,9 @@ final class DecoupledClassMethodMatcher
|
|||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, array<mixed>> $methodNamesByClass
|
||||
*/
|
||||
public function matchDecoupled(ClassMethod $classMethod, array $methodNamesByClass): ?DecoupleClassMethodMatch
|
||||
{
|
||||
$classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
|
||||
|
|
|
@ -35,7 +35,7 @@ final class DecoupleClassMethodToOwnClassRector extends AbstractRector implement
|
|||
public const METHOD_NAMES_BY_CLASS = '$methodNamesByClass';
|
||||
|
||||
/**
|
||||
* @var mixed[][]
|
||||
* @var array<string, string[]>
|
||||
*/
|
||||
private $methodNamesByClass = [];
|
||||
|
||||
|
@ -209,6 +209,9 @@ CODE_SAMPLE
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $configuration
|
||||
*/
|
||||
public function configure(array $configuration): void
|
||||
{
|
||||
$this->methodNamesByClass = $configuration[self::METHOD_NAMES_BY_CLASS] ?? [];
|
||||
|
|
|
@ -195,6 +195,9 @@ CODE_SAMPLE
|
|||
return $phpDocInfo->hasByType(TreeLevelTagValueNode::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $removedPropertyNames
|
||||
*/
|
||||
private function removeClassMethodsForProperties(Class_ $class, array $removedPropertyNames): void
|
||||
{
|
||||
foreach ($removedPropertyNames as $removedPropertyName) {
|
||||
|
|
|
@ -15,6 +15,7 @@ use PHPStan\Type\BooleanType;
|
|||
use PHPStan\Type\FloatType;
|
||||
use PHPStan\Type\IntegerType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
|
@ -106,6 +107,9 @@ CODE_SAMPLE
|
|||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Type[] $methodParameterTypes
|
||||
*/
|
||||
private function refactorArg(Arg $arg, array $methodParameterTypes, int $key): void
|
||||
{
|
||||
if (! isset($methodParameterTypes[$key])) {
|
||||
|
|
|
@ -143,6 +143,7 @@ CODE_SAMPLE
|
|||
|
||||
/**
|
||||
* Find all includes and see if any match what we want to insert
|
||||
* @param Node[] $nodes
|
||||
*/
|
||||
private function hasIncludeAlready(array $nodes): bool
|
||||
{
|
||||
|
|
|
@ -121,6 +121,9 @@ abstract class AbstractFluentChainMethodCallRector extends AbstractRector
|
|||
return new AssignAndRootExprAndNodesToAdd($assignAndRootExpr, $nodesToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MethodCall[] $chainMethodCalls
|
||||
*/
|
||||
protected function areAllClassMethodLocatedInSameClass(array $chainMethodCalls): bool
|
||||
{
|
||||
// are method calls located in the same class?
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Rector\Naming\PhpArray;
|
|||
final class ArrayFilter
|
||||
{
|
||||
/**
|
||||
* @param mixed[] $values
|
||||
* @return string[]
|
||||
*/
|
||||
public function filterWithAtLeastTwoOccurences(array $values): array
|
||||
|
|
|
@ -65,6 +65,7 @@ final class SymfonyFormAbstractTypeFactory
|
|||
}
|
||||
|
||||
/**
|
||||
* @param MethodCall[] $methodCalls
|
||||
* @return Expression[]
|
||||
*/
|
||||
private function createBuildFormMethodCalls(array $methodCalls, Variable $formBuilderVariable): array
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Rector\Nette\NodeFactory;
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
|
@ -62,6 +63,9 @@ final class ActionRenderFactory
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Expr[] $templateVariables
|
||||
*/
|
||||
private function createTemplateVariablesArray(array $templateVariables): Array_
|
||||
{
|
||||
$array = new Array_();
|
||||
|
|
|
@ -15,7 +15,7 @@ final class MagicTemplatePropertyCalls
|
|||
private $nodesToRemove = [];
|
||||
|
||||
/**
|
||||
* @var Node[]
|
||||
* @var Expr[]
|
||||
*/
|
||||
private $templateVariables = [];
|
||||
|
||||
|
@ -25,7 +25,7 @@ final class MagicTemplatePropertyCalls
|
|||
private $templateFileExpr;
|
||||
|
||||
/**
|
||||
* @param Node[] $templateVariables
|
||||
* @param Expr[] $templateVariables
|
||||
* @param Node[] $nodesToRemove
|
||||
*/
|
||||
public function __construct(?Expr $templateFileExpr, array $templateVariables, array $nodesToRemove)
|
||||
|
@ -41,7 +41,7 @@ final class MagicTemplatePropertyCalls
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Node[]
|
||||
* @return Expr[]
|
||||
*/
|
||||
public function getTemplateVariables(): array
|
||||
{
|
||||
|
|
|
@ -8,5 +8,8 @@ interface RankeableInterface
|
|||
{
|
||||
public function getName(): string;
|
||||
|
||||
/**
|
||||
* @return bool[]|int[]
|
||||
*/
|
||||
public function getRanks(): array;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ use Rector\Core\RectorDefinition\RectorDefinition;
|
|||
final class AddRemovedDefaultValuesRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var mixed[][]
|
||||
* @var array<string, array<string, array<int, mixed[]>>>
|
||||
*/
|
||||
private const METHOD_NAMES_BY_TYPE_WITH_VALUE = [
|
||||
'PHPExcel' => [
|
||||
|
@ -663,6 +663,7 @@ CODE_SAMPLE
|
|||
|
||||
/**
|
||||
* @param StaticCall|MethodCall $node
|
||||
* @param array<int, mixed> $defaultValuesByPosition
|
||||
*/
|
||||
private function refactorArgs(Node $node, array $defaultValuesByPosition): void
|
||||
{
|
||||
|
|
|
@ -189,6 +189,9 @@ final class EregToPcreTransformer
|
|||
return [implode('|', $r), $i];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $r
|
||||
*/
|
||||
private function processBracket(string $content, int $i, int $l, array &$r, int $rr): int
|
||||
{
|
||||
// special case
|
||||
|
@ -255,6 +258,9 @@ final class EregToPcreTransformer
|
|||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $r
|
||||
*/
|
||||
private function processCurlyBracket(string $s, int $i, array &$r, int $rr): int
|
||||
{
|
||||
$ii = strpos($s, '}', $i);
|
||||
|
|
|
@ -57,7 +57,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
/**
|
||||
* @param double $node
|
||||
* @param Double $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
|
|
|
@ -160,6 +160,9 @@ final class TokenManipulator
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
*/
|
||||
public function refactorTokenIsKind(array $nodes, Expr $singleTokenExpr): void
|
||||
{
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable($nodes, function (Node $node) use (
|
||||
|
|
|
@ -183,6 +183,9 @@ CODE_SAMPLE
|
|||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stmt[] $newStmtsSet
|
||||
*/
|
||||
private function refactorClassLike(
|
||||
SmartFileInfo $smartFileInfo,
|
||||
bool $shouldDeleteFile,
|
||||
|
|
|
@ -103,6 +103,8 @@ final class ClassRenamer
|
|||
/**
|
||||
* Replace types in @var/@param/@return/@throws,
|
||||
* Doctrine @ORM entity targetClass, Serialize, Assert etc.
|
||||
*
|
||||
* @param array<string, string> $oldToNewClasses
|
||||
*/
|
||||
private function refactorPhpDoc(Node $node, array $oldToNewClasses): void
|
||||
{
|
||||
|
@ -120,6 +122,9 @@ final class ClassRenamer
|
|||
$this->phpDocClassRenamer->changeTypeInAnnotationTypes($node, $oldToNewClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $oldToNewClasses
|
||||
*/
|
||||
private function refactorName(Name $name, array $oldToNewClasses): ?Name
|
||||
{
|
||||
$stringName = $this->nodeNameResolver->getName($name);
|
||||
|
@ -149,6 +154,9 @@ final class ClassRenamer
|
|||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $oldToNewClasses
|
||||
*/
|
||||
private function refactorNamespace(Namespace_ $namespace, array $oldToNewClasses): ?Node
|
||||
{
|
||||
$name = $this->nodeNameResolver->getName($namespace);
|
||||
|
@ -178,6 +186,9 @@ final class ClassRenamer
|
|||
return $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $oldToNewClasses
|
||||
*/
|
||||
private function refactorClassLike(ClassLike $classLike, array $oldToNewClasses): ?Node
|
||||
{
|
||||
// rename interfaces
|
||||
|
@ -257,6 +268,9 @@ final class ClassRenamer
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $oldToNewClasses
|
||||
*/
|
||||
private function getClassOfNamespaceToRefactor(Namespace_ $namespace, array $oldToNewClasses): ?ClassLike
|
||||
{
|
||||
$foundClass = $this->betterNodeFinder->findFirst($namespace, function (Node $node) use (
|
||||
|
|
|
@ -169,6 +169,9 @@ CODE_SAMPLE
|
|||
return $stringsToReplace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $stringsToReplace
|
||||
*/
|
||||
private function replaceStringsWithClassConstReferences(Class_ $class, array $stringsToReplace): void
|
||||
{
|
||||
$this->traverseNodesWithCallable($class, function (Node $node) use ($stringsToReplace): ?ClassConstFetch {
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Rector\SymfonyPhpConfig\Rector\ArrayItem;
|
|||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
|
@ -47,7 +48,7 @@ final class ReplaceArrayWithObjectRector extends AbstractRector implements Confi
|
|||
private $arguments = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var Expr[]
|
||||
*/
|
||||
private $nestedArguments = [];
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ final class ServiceMapProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $def
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function createTagFromXmlElement(array $def): array
|
||||
|
@ -190,6 +191,7 @@ final class ServiceMapProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function unWrapAttributes(array $data): array
|
||||
|
@ -206,6 +208,8 @@ final class ServiceMapProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $value
|
||||
* @param mixed[] $data
|
||||
* @param string|int $key
|
||||
* @return mixed[]
|
||||
*/
|
||||
|
|
|
@ -26,6 +26,9 @@ final class MethodCallToAnotherMethodCallWithArguments
|
|||
*/
|
||||
private $newArguments = [];
|
||||
|
||||
/**
|
||||
* @param mixed[] $newArguments
|
||||
*/
|
||||
public function __construct(string $type, string $oldMethod, string $newMethod, array $newArguments)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
|
|
@ -22,7 +22,7 @@ final class PropertyToMethod
|
|||
private $newGetMethod;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var mixed[]
|
||||
*/
|
||||
private $newGetArguments = [];
|
||||
|
||||
|
@ -31,6 +31,9 @@ final class PropertyToMethod
|
|||
*/
|
||||
private $newSetMethod;
|
||||
|
||||
/**
|
||||
* @param mixed[] $newGetArguments
|
||||
*/
|
||||
public function __construct(
|
||||
string $oldType,
|
||||
string $oldProperty,
|
||||
|
|
|
@ -168,6 +168,9 @@ final class TypeNormalizer
|
|||
return $this->typeFactory->createMixedPassedOrUnionType($nonNeverTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string|int, Type> $nonConstantValueTypes
|
||||
*/
|
||||
private function createArrayTypeFromNonConstantValueTypes(array $nonConstantValueTypes): ArrayType
|
||||
{
|
||||
$nonConstantValueTypes = array_values($nonConstantValueTypes);
|
||||
|
|
|
@ -12,6 +12,7 @@ final class ConfigShifter
|
|||
* Shift input config as last, so the parameters override previous rules loaded from sets
|
||||
*
|
||||
* @param SmartFileInfo[] $configFileInfos
|
||||
* @return SmartFileInfo[]
|
||||
* @noRector
|
||||
*/
|
||||
public function shiftInputConfigAsLast(array $configFileInfos, ?SmartFileInfo $inputConfigFileInfo): array
|
||||
|
|
|
@ -24,6 +24,9 @@ final class ConfigureCallValuesCollector
|
|||
$this->parametersMerger = new ParametersMerger();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getConfigureCallValues(string $rectorClass): array
|
||||
{
|
||||
return $this->configureCallValuesByRectorClass[$rectorClass] ?? [];
|
||||
|
|
|
@ -8,6 +8,9 @@ use Symfony\Component\Yaml\Yaml;
|
|||
|
||||
final class YamlPrinter
|
||||
{
|
||||
/**
|
||||
* @param mixed[] $yaml
|
||||
*/
|
||||
public function printYamlToString(array $yaml): string
|
||||
{
|
||||
return Yaml::dump($yaml, 10, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
||||
|
|
|
@ -31,6 +31,9 @@ final class StmtsManipulator
|
|||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stmt[] $stmts
|
||||
*/
|
||||
public function getUnwrappedLastStmt(array $stmts): ?Node
|
||||
{
|
||||
$lastStmtKey = array_key_last($stmts);
|
||||
|
|
|
@ -114,6 +114,11 @@ final class BetterStandardPrinter extends Standard
|
|||
$this->docBlockManipulator = $docBlockManipulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $stmts
|
||||
* @param Node[] $origStmts
|
||||
* @param mixed[] $origTokens
|
||||
*/
|
||||
public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens): string
|
||||
{
|
||||
$newStmts = $this->resolveNewStmts($stmts);
|
||||
|
@ -435,6 +440,7 @@ final class BetterStandardPrinter extends Standard
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $stmts
|
||||
* @return Node[]|mixed[]
|
||||
*/
|
||||
private function resolveNewStmts(array $stmts): array
|
||||
|
@ -495,6 +501,9 @@ final class BetterStandardPrinter extends Standard
|
|||
return Strings::replace($printerNode, self::START_DOUBLE_SLASH_COMMENT_REGEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
*/
|
||||
private function moveCommentsFromAttributeObjectToCommentsAttribute(array $nodes): void
|
||||
{
|
||||
// move phpdoc from node to "comment" attribute
|
||||
|
|
|
@ -98,6 +98,9 @@ trait NameResolverTrait
|
|||
return $this->isName($node->name, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $names
|
||||
*/
|
||||
protected function isLocalMethodCallsNamed(Node $node, array $names): bool
|
||||
{
|
||||
foreach ($names as $name) {
|
||||
|
|
|
@ -56,6 +56,7 @@ final class FunctionAnnotationResolver
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $classNames
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function expandAnnotatedClasses(ReflectionFunction $reflectionFunction, array $classNames): array
|
||||
|
|
|
@ -55,6 +55,9 @@ final class MarkdownNodeInfosPrinter
|
|||
return $this->implodeLinesWithSpace($contentLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $contentLines
|
||||
*/
|
||||
private function implodeLinesWithSpace(array $contentLines): string
|
||||
{
|
||||
return implode(PHP_EOL . PHP_EOL, $contentLines);
|
||||
|
@ -71,6 +74,9 @@ final class MarkdownNodeInfosPrinter
|
|||
return $this->implodeLinesWithSpace($contentLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $contentLines
|
||||
*/
|
||||
private function implodeLines(array $contentLines): string
|
||||
{
|
||||
return implode(PHP_EOL, $contentLines);
|
||||
|
|
|
@ -19,10 +19,6 @@ services:
|
|||
class: Rector\PHPStanExtensions\Rule\CheckGetNodeTypesReturnPhpParserNodeRule
|
||||
tags: [phpstan.rules.rule]
|
||||
|
||||
-
|
||||
class: Rector\PHPStanExtensions\Rule\ValueObjectHasNoValueObjectSuffixRule
|
||||
tags: [phpstan.rules.rule]
|
||||
|
||||
-
|
||||
class: Rector\PHPStanExtensions\Rule\RectorRuleAndValueObjectHaveSameStartsRule
|
||||
tags: [phpstan.rules.rule]
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Rule;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Rules\Rule;
|
||||
|
||||
/**
|
||||
* @see \Rector\PHPStanExtensions\Tests\Rule\ValueObjectHasNoValueObjectSuffixRule\ValueObjectHasNoValueObjectSuffixRuleTest
|
||||
*/
|
||||
final class ValueObjectHasNoValueObjectSuffixRule implements Rule
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const ERROR = 'Value Object class name "%s" is incorrect. The correct class name is "%s".';
|
||||
|
||||
/**
|
||||
* @see https://regex101.com/r/3jsBnt/1
|
||||
* @var string
|
||||
*/
|
||||
private const VALUE_OBJECT_REGEX = '#ValueObject$#';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const VALUE_OBJECT_NAMESPACE = 'ValueObject';
|
||||
|
||||
public function getNodeType(): string
|
||||
{
|
||||
return Class_::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_ $node
|
||||
* @return string[]
|
||||
*/
|
||||
public function processNode(Node $node, Scope $scope): array
|
||||
{
|
||||
if ($node->name === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (! $this->hasValueObjectNamespace($node)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (! $this->hasValueObjectSuffix($node)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [sprintf(
|
||||
self::ERROR,
|
||||
$node->name->toString(),
|
||||
Strings::replace($node->name->toString(), self::VALUE_OBJECT_REGEX, '')
|
||||
)];
|
||||
}
|
||||
|
||||
private function hasValueObjectNamespace(Class_ $class): bool
|
||||
{
|
||||
if ($class->namespacedName->parts === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array(self::VALUE_OBJECT_NAMESPACE, $class->namespacedName->parts, true);
|
||||
}
|
||||
|
||||
private function hasValueObjectSuffix(Class_ $class): bool
|
||||
{
|
||||
if ($class->name === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Strings::match($class->name->toString(), self::VALUE_OBJECT_REGEX) !== null;
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ final class CheckGetNodeTypesReturnPhpParserNodeRuleTest extends AbstractService
|
|||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
* @param array<string|string[]|int[]> $expectedErrorsWithLines
|
||||
*/
|
||||
public function testRule(string $filePath, array $expectedErrorsWithLines): void
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ final class ConfigurableRectorRuleTest extends AbstractServiceAwareRuleTestCase
|
|||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
* @param array<string|string[]|int[]> $expectedErrorsWithLines
|
||||
*/
|
||||
public function testRule(string $filePath, array $expectedErrorsWithLines): void
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ final class KeepRectorNamespaceForRectorRuleTest extends AbstractServiceAwareRul
|
|||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
* @param array<string|string[]|int[]> $expectedErrorsWithLines
|
||||
*/
|
||||
public function testRule(string $filePath, array $expectedErrorsWithLines): void
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ final class RectorRuleAndValueObjectHaveSameStartsRuleTest extends AbstractServi
|
|||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
* @param array<string|string[]|int[]> $expectedErrorsWithLines
|
||||
*/
|
||||
public function testRule(string $filePath, array $expectedErrorsWithLines): void
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ final class RequireRectorCategoryByGetNodeTypesRuleTest extends AbstractServiceA
|
|||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
* @param array<string|string[]|int[]> $expectedErrorsWithLines
|
||||
*/
|
||||
public function testRule(string $filePath, array $expectedErrorsWithLines): void
|
||||
{
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Tests\Rule\ValueObjectHasNoValueObjectSuffixRule\Fixture;
|
||||
|
||||
|
||||
class SkipNoValueObjectInNamespace
|
||||
{
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Tests\Rule\ValueObjectHasNoValueObjectSuffixRule\Fixture\ValueObject;
|
||||
|
||||
|
||||
class MoneyValueObject
|
||||
{
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Tests\Rule\ValueObjectHasNoValueObjectSuffixRule\Fixture;
|
||||
|
||||
|
||||
class SkipValueObjectWithoutValueObjectSuffix
|
||||
{
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Tests\Rule\ValueObjectHasNoValueObjectSuffixRule;
|
||||
|
||||
use Iterator;
|
||||
use PHPStan\Rules\Rule;
|
||||
use Rector\PHPStanExtensions\Rule\ValueObjectHasNoValueObjectSuffixRule;
|
||||
use Symplify\PHPStanExtensions\Testing\AbstractServiceAwareRuleTestCase;
|
||||
|
||||
final class ValueObjectHasNoValueObjectSuffixRuleTest extends AbstractServiceAwareRuleTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function testRule(string $filePath, array $expectedErrorsWithLines): void
|
||||
{
|
||||
$this->analyse([$filePath], $expectedErrorsWithLines);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
yield [__DIR__ . '/Fixture/SkipNoValueObjectInNamespace.php', []];
|
||||
yield [__DIR__ . '/Fixture/ValueObject/SkipValueObjectWithoutValueObjectSuffix.php', []];
|
||||
|
||||
$errorMessage = sprintf(ValueObjectHasNoValueObjectSuffixRule::ERROR, 'MoneyValueObject', 'Money');
|
||||
yield [__DIR__ . '/Fixture/ValueObject/MoneyValueObject.php', [[$errorMessage, 8]]];
|
||||
}
|
||||
|
||||
protected function getRule(): Rule
|
||||
{
|
||||
return new ValueObjectHasNoValueObjectSuffixRule();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user