Skip to content

Commit 927d442

Browse files
authored
Add AlwaysUsedClassConstantsExtension interface
1 parent 4159444 commit 927d442

8 files changed

+133
-2
lines changed

conf/config.neon

+3
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,9 @@ services:
773773
-
774774
class: PHPStan\Rules\NullsafeCheck
775775

776+
-
777+
class: PHPStan\Rules\Constants\LazyAlwaysUsedClassConstantsExtensionProvider
778+
776779
-
777780
class: PHPStan\Rules\Properties\LazyReadWritePropertiesExtensionProvider
778781

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Constants;
4+
5+
use PHPStan\Reflection\ConstantReflection;
6+
7+
interface AlwaysUsedClassConstantsExtension
8+
{
9+
10+
public function isAlwaysUsed(ConstantReflection $constant): bool;
11+
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Constants;
4+
5+
interface AlwaysUsedClassConstantsExtensionProvider
6+
{
7+
8+
public const EXTENSION_TAG = 'phpstan.constants.alwaysUsedClassConstantsExtension';
9+
10+
/**
11+
* @return AlwaysUsedClassConstantsExtension[]
12+
*/
13+
public function getExtensions(): array;
14+
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Constants;
4+
5+
use PHPStan\DependencyInjection\Container;
6+
7+
class LazyAlwaysUsedClassConstantsExtensionProvider implements AlwaysUsedClassConstantsExtensionProvider
8+
{
9+
10+
private Container $container;
11+
12+
/** @var AlwaysUsedClassConstantsExtension[]|null */
13+
private ?array $extensions = null;
14+
15+
public function __construct(Container $container)
16+
{
17+
$this->container = $container;
18+
}
19+
20+
public function getExtensions(): array
21+
{
22+
if ($this->extensions === null) {
23+
$this->extensions = $this->container->getServicesByTag(AlwaysUsedClassConstantsExtensionProvider::EXTENSION_TAG);
24+
}
25+
26+
return $this->extensions;
27+
}
28+
29+
}

src/Rules/DeadCode/UnusedPrivateConstantRule.php

+19-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpParser\Node;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Node\ClassConstantsNode;
8+
use PHPStan\Rules\Constants\AlwaysUsedClassConstantsExtensionProvider;
89
use PHPStan\Rules\Rule;
910
use PHPStan\Rules\RuleErrorBuilder;
1011

@@ -14,6 +15,13 @@
1415
class UnusedPrivateConstantRule implements Rule
1516
{
1617

18+
private AlwaysUsedClassConstantsExtensionProvider $extensionProvider;
19+
20+
public function __construct(AlwaysUsedClassConstantsExtensionProvider $extensionProvider)
21+
{
22+
$this->extensionProvider = $extensionProvider;
23+
}
24+
1725
public function getNodeType(): string
1826
{
1927
return ClassConstantsNode::class;
@@ -35,8 +43,18 @@ public function processNode(Node $node, Scope $scope): array
3543
if (!$constant->isPrivate()) {
3644
continue;
3745
}
46+
3847
foreach ($constant->consts as $const) {
39-
$constants[$const->name->toString()] = $const;
48+
$constantName = $const->name->toString();
49+
50+
$constantReflection = $classReflection->getConstant($constantName);
51+
foreach ($this->extensionProvider->getExtensions() as $extension) {
52+
if ($extension->isAlwaysUsed($constantReflection)) {
53+
continue 2;
54+
}
55+
}
56+
57+
$constants[$constantName] = $const;
4058
}
4159
}
4260

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Constants;
4+
5+
class DirectAlwaysUsedClassConstantsExtensionProvider implements AlwaysUsedClassConstantsExtensionProvider
6+
{
7+
8+
/** @var AlwaysUsedClassConstantsExtension[] */
9+
private $extensions;
10+
11+
/**
12+
* @param AlwaysUsedClassConstantsExtension[] $extensions
13+
*/
14+
public function __construct(array $extensions)
15+
{
16+
$this->extensions = $extensions;
17+
}
18+
19+
/**
20+
* @return AlwaysUsedClassConstantsExtension[]
21+
*/
22+
public function getExtensions(): array
23+
{
24+
return $this->extensions;
25+
}
26+
27+
}

tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php

+21-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
namespace PHPStan\Rules\DeadCode;
44

5+
use PHPStan\Reflection\ConstantReflection;
6+
use PHPStan\Rules\Constants\AlwaysUsedClassConstantsExtension;
7+
use PHPStan\Rules\Constants\DirectAlwaysUsedClassConstantsExtensionProvider;
58
use PHPStan\Rules\Rule;
69
use PHPStan\Testing\RuleTestCase;
10+
use UnusedPrivateConstant\TestExtension;
711

812
/**
913
* @extends RuleTestCase<UnusedPrivateConstantRule>
@@ -13,7 +17,19 @@ class UnusedPrivateConstantRuleTest extends RuleTestCase
1317

1418
protected function getRule(): Rule
1519
{
16-
return new UnusedPrivateConstantRule();
20+
return new UnusedPrivateConstantRule(
21+
new DirectAlwaysUsedClassConstantsExtensionProvider([
22+
new class() implements AlwaysUsedClassConstantsExtension {
23+
24+
public function isAlwaysUsed(ConstantReflection $constant): bool
25+
{
26+
return $constant->getDeclaringClass()->getName() === TestExtension::class
27+
&& $constant->getName() === 'USED';
28+
}
29+
30+
},
31+
])
32+
);
1733
}
1834

1935
public function testRule(): void
@@ -23,6 +39,10 @@ public function testRule(): void
2339
'Constant UnusedPrivateConstant\Foo::BAR_CONST is unused.',
2440
10,
2541
],
42+
[
43+
'Constant UnusedPrivateConstant\TestExtension::UNUSED is unused.',
44+
23,
45+
],
2646
]);
2747
}
2848

tests/PHPStan/Rules/DeadCode/data/unused-private-constant.php

+7
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ public function doFoo()
1515
}
1616

1717
}
18+
19+
class TestExtension
20+
{
21+
private const USED = 1;
22+
23+
private const UNUSED = 2;
24+
}

0 commit comments

Comments
 (0)