Skip to content

Commit 323ffba

Browse files
committed
Updated Rector to commit 80f067637a6cc61f11791798dc4832949c97747a
rectorphp/rector-src@80f0676 [DeadCode] Skip constant compare from vendor/ on NarrowWideUnionReturnTypeRector (#8056)
1 parent 3f9080e commit 323ffba

5 files changed

Lines changed: 175 additions & 4 deletions

File tree

rules/DeadCode/Rector/FunctionLike/NarrowWideUnionReturnTypeRector.php

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
use PhpParser\Node;
77
use PhpParser\Node\Expr;
88
use PhpParser\Node\Expr\ArrowFunction;
9+
use PhpParser\Node\Expr\ClassConstFetch;
910
use PhpParser\Node\Expr\Closure;
1011
use PhpParser\Node\Expr\ConstFetch;
12+
use PhpParser\Node\Expr\Ternary;
1113
use PhpParser\Node\FunctionLike;
1214
use PhpParser\Node\Name;
1315
use PhpParser\Node\NullableType;
@@ -18,12 +20,14 @@
1820
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
1921
use PHPStan\Reflection\ClassReflection;
2022
use PHPStan\Type\NullType;
23+
use PHPStan\Type\ObjectType;
2124
use PHPStan\Type\Type;
2225
use PHPStan\Type\TypeCombinator;
2326
use PHPStan\Type\UnionType as PHPStanUnionType;
2427
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
2528
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
2629
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
30+
use Rector\Composer\ComposerJsonPackageVersionResolver;
2731
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
2832
use Rector\PhpParser\Node\BetterNodeFinder;
2933
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
@@ -68,7 +72,11 @@ final class NarrowWideUnionReturnTypeRector extends AbstractRector implements Mi
6872
* @readonly
6973
*/
7074
private TypeFactory $typeFactory;
71-
public function __construct(BetterNodeFinder $betterNodeFinder, StaticTypeMapper $staticTypeMapper, ReflectionResolver $reflectionResolver, SilentVoidResolver $silentVoidResolver, PhpDocTypeChanger $phpDocTypeChanger, PhpDocInfoFactory $phpDocInfoFactory, TypeFactory $typeFactory)
75+
/**
76+
* @readonly
77+
*/
78+
private ComposerJsonPackageVersionResolver $composerJsonPackageVersionResolver;
79+
public function __construct(BetterNodeFinder $betterNodeFinder, StaticTypeMapper $staticTypeMapper, ReflectionResolver $reflectionResolver, SilentVoidResolver $silentVoidResolver, PhpDocTypeChanger $phpDocTypeChanger, PhpDocInfoFactory $phpDocInfoFactory, TypeFactory $typeFactory, ComposerJsonPackageVersionResolver $composerJsonPackageVersionResolver)
7280
{
7381
$this->betterNodeFinder = $betterNodeFinder;
7482
$this->staticTypeMapper = $staticTypeMapper;
@@ -77,6 +85,7 @@ public function __construct(BetterNodeFinder $betterNodeFinder, StaticTypeMapper
7785
$this->phpDocTypeChanger = $phpDocTypeChanger;
7886
$this->phpDocInfoFactory = $phpDocInfoFactory;
7987
$this->typeFactory = $typeFactory;
88+
$this->composerJsonPackageVersionResolver = $composerJsonPackageVersionResolver;
8089
}
8190
public function getRuleDefinition(): RuleDefinition
8291
{
@@ -239,10 +248,43 @@ private function collectActualReturnTypes(array $returnStatements): array
239248
if ($returnStatement->expr === null) {
240249
continue;
241250
}
242-
$returnTypes[] = $this->nodeTypeResolver->getNativeType($returnStatement->expr);
251+
$returnTypes = array_merge($returnTypes, $this->resolveNativeReturnTypes($returnStatement->expr));
243252
}
244253
return $returnTypes;
245254
}
255+
/**
256+
* @return Type[]
257+
*/
258+
private function resolveNativeReturnTypes(Expr $expr): array
259+
{
260+
if (!$expr instanceof Ternary || !$this->hasVendorClassConstFetch($expr->cond)) {
261+
return [$this->nodeTypeResolver->getNativeType($expr)];
262+
}
263+
$ifExpr = $expr->if instanceof Expr ? $expr->if : $expr->cond;
264+
return array_merge($this->resolveNativeReturnTypes($ifExpr), $this->resolveNativeReturnTypes($expr->else));
265+
}
266+
private function hasVendorClassConstFetch(Expr $expr): bool
267+
{
268+
$classConstFetches = $this->betterNodeFinder->findInstanceOf($expr, ClassConstFetch::class);
269+
foreach ($classConstFetches as $classConstFetch) {
270+
$classType = $this->nodeTypeResolver->getType($classConstFetch->class);
271+
if (!$classType instanceof ObjectType) {
272+
continue;
273+
}
274+
$classReflection = $classType->getClassReflection();
275+
if (!$classReflection instanceof ClassReflection) {
276+
continue;
277+
}
278+
$fileName = $classReflection->getFileName();
279+
if ($fileName === null) {
280+
continue;
281+
}
282+
if ($this->composerJsonPackageVersionResolver->hasPackageMultiMajorVersions($fileName)) {
283+
return \true;
284+
}
285+
}
286+
return \false;
287+
}
246288
/**
247289
* @param Type[] $actualReturnTypes
248290
* @return Type[]

src/Application/VersionResolver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ final class VersionResolver
1919
* @api
2020
* @var string
2121
*/
22-
public const PACKAGE_VERSION = 'dfa70694d2cdbb5342ab784176ede1f8e27f18b4';
22+
public const PACKAGE_VERSION = '80f067637a6cc61f11791798dc4832949c97747a';
2323
/**
2424
* @api
2525
* @var string
2626
*/
27-
public const RELEASE_DATE = '2026-06-27 14:40:46';
27+
public const RELEASE_DATE = '2026-06-27 14:42:30';
2828
/**
2929
* @var int
3030
*/
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
declare (strict_types=1);
4+
namespace Rector\Composer;
5+
6+
use RectorPrefix202606\Composer\Semver\VersionParser;
7+
use Rector\FileSystem\JsonFileSystem;
8+
use Rector\Skipper\FileSystem\PathNormalizer;
9+
use UnexpectedValueException;
10+
/**
11+
* @see \Rector\Tests\Composer\ComposerJsonPackageVersionResolverTest
12+
*/
13+
final class ComposerJsonPackageVersionResolver
14+
{
15+
/**
16+
* @var null|array<string, string>
17+
*/
18+
private ?array $packageVersionConstraints = null;
19+
/**
20+
* @var array<string, bool>
21+
*/
22+
private array $packageMultiMajorVersions = [];
23+
/**
24+
* @var array<string, null|string>
25+
*/
26+
private array $packageNamesByFilePath = [];
27+
/**
28+
* @readonly
29+
*/
30+
private string $composerJsonFilePath;
31+
public function __construct(?string $composerJsonFilePath = null)
32+
{
33+
$this->composerJsonFilePath = $composerJsonFilePath ?? getcwd() . '/composer.json';
34+
}
35+
public function hasPackageMultiMajorVersions(string $filePath): bool
36+
{
37+
$packageName = $this->resolvePackageName($filePath);
38+
if ($packageName === null) {
39+
return \false;
40+
}
41+
return $this->packageMultiMajorVersions[$packageName] ??= $this->resolveHasPackageMultiMajorVersions($packageName);
42+
}
43+
private function resolveHasPackageMultiMajorVersions(string $packageName): bool
44+
{
45+
$versionConstraint = $this->resolvePackageVersionConstraints()[$packageName] ?? null;
46+
if ($versionConstraint === null) {
47+
return \false;
48+
}
49+
$versionConstraintParts = preg_split('#\s*\|\|?\s*#', $versionConstraint);
50+
if ($versionConstraintParts === \false || count($versionConstraintParts) < 2) {
51+
return \false;
52+
}
53+
$majorVersions = [];
54+
$versionParser = new VersionParser();
55+
foreach ($versionConstraintParts as $versionConstraintPart) {
56+
if (preg_match('#\d+#', $versionConstraintPart) !== 1) {
57+
continue;
58+
}
59+
try {
60+
$constraint = $versionParser->parseConstraints($versionConstraintPart);
61+
} catch (UnexpectedValueException $exception) {
62+
continue;
63+
}
64+
$lowerMajorVersion = $this->resolveMajorVersion($constraint->getLowerBound()->getVersion());
65+
if ($lowerMajorVersion === null) {
66+
continue;
67+
}
68+
$majorVersions[$lowerMajorVersion] = \true;
69+
}
70+
return count($majorVersions) > 1;
71+
}
72+
private function resolvePackageName(string $filePath): ?string
73+
{
74+
if (array_key_exists($filePath, $this->packageNamesByFilePath)) {
75+
return $this->packageNamesByFilePath[$filePath];
76+
}
77+
$normalizedFilePath = PathNormalizer::normalize($filePath);
78+
$vendorPosition = strpos($normalizedFilePath, '/vendor/');
79+
if ($vendorPosition === \false) {
80+
return $this->packageNamesByFilePath[$filePath] = null;
81+
}
82+
$vendorRelativePath = (string) substr($normalizedFilePath, $vendorPosition + strlen('/vendor/'));
83+
$pathParts = explode('/', $vendorRelativePath);
84+
if (count($pathParts) < 2) {
85+
return $this->packageNamesByFilePath[$filePath] = null;
86+
}
87+
return $this->packageNamesByFilePath[$filePath] = $pathParts[0] . '/' . $pathParts[1];
88+
}
89+
/**
90+
* @return array<string, string>
91+
*/
92+
private function resolvePackageVersionConstraints(): array
93+
{
94+
if ($this->packageVersionConstraints !== null) {
95+
return $this->packageVersionConstraints;
96+
}
97+
if (!file_exists($this->composerJsonFilePath)) {
98+
return $this->packageVersionConstraints = [];
99+
}
100+
$composerJson = JsonFileSystem::readFilePath($this->composerJsonFilePath);
101+
$packageVersionConstraints = [];
102+
foreach (['require', 'require-dev'] as $requireKey) {
103+
$requires = $composerJson[$requireKey] ?? [];
104+
if (!is_array($requires)) {
105+
continue;
106+
}
107+
foreach ($requires as $packageName => $versionConstraint) {
108+
if (!is_string($packageName)) {
109+
continue;
110+
}
111+
if (!is_string($versionConstraint)) {
112+
continue;
113+
}
114+
$packageVersionConstraints[$packageName] = $versionConstraint;
115+
}
116+
}
117+
return $this->packageVersionConstraints = $packageVersionConstraints;
118+
}
119+
private function resolveMajorVersion(string $version): ?int
120+
{
121+
$match = preg_match('#^(\d+)\.#', $version, $matches);
122+
if ($match !== 1) {
123+
return null;
124+
}
125+
return (int) $matches[1];
126+
}
127+
}

vendor/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,7 @@
13511351
'Rector\\Comments\\NodeDocBlock\\DocBlockUpdater' => $baseDir . '/src/Comments/NodeDocBlock/DocBlockUpdater.php',
13521352
'Rector\\Comments\\NodeTraverser\\CommentRemovingNodeTraverser' => $baseDir . '/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php',
13531353
'Rector\\Comments\\NodeVisitor\\CommentRemovingNodeVisitor' => $baseDir . '/src/Comments/NodeVisitor/CommentRemovingNodeVisitor.php',
1354+
'Rector\\Composer\\ComposerJsonPackageVersionResolver' => $baseDir . '/src/Composer/ComposerJsonPackageVersionResolver.php',
13541355
'Rector\\Composer\\InstalledPackageResolver' => $baseDir . '/src/Composer/InstalledPackageResolver.php',
13551356
'Rector\\Composer\\ValueObject\\InstalledPackage' => $baseDir . '/src/Composer/ValueObject/InstalledPackage.php',
13561357
'Rector\\Config\\Level\\CodeQualityLevel' => $baseDir . '/src/Config/Level/CodeQualityLevel.php',

vendor/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,7 @@ class ComposerStaticInite7732782e781a0db6ef2f014a417d492
16161616
'Rector\\Comments\\NodeDocBlock\\DocBlockUpdater' => __DIR__ . '/../..' . '/src/Comments/NodeDocBlock/DocBlockUpdater.php',
16171617
'Rector\\Comments\\NodeTraverser\\CommentRemovingNodeTraverser' => __DIR__ . '/../..' . '/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php',
16181618
'Rector\\Comments\\NodeVisitor\\CommentRemovingNodeVisitor' => __DIR__ . '/../..' . '/src/Comments/NodeVisitor/CommentRemovingNodeVisitor.php',
1619+
'Rector\\Composer\\ComposerJsonPackageVersionResolver' => __DIR__ . '/../..' . '/src/Composer/ComposerJsonPackageVersionResolver.php',
16191620
'Rector\\Composer\\InstalledPackageResolver' => __DIR__ . '/../..' . '/src/Composer/InstalledPackageResolver.php',
16201621
'Rector\\Composer\\ValueObject\\InstalledPackage' => __DIR__ . '/../..' . '/src/Composer/ValueObject/InstalledPackage.php',
16211622
'Rector\\Config\\Level\\CodeQualityLevel' => __DIR__ . '/../..' . '/src/Config/Level/CodeQualityLevel.php',

0 commit comments

Comments
 (0)