Skip to content

Commit 3447391

Browse files
committed
Fix resolving class constant type using self:: in a class attribute argument
1 parent fd6a0f2 commit 3447391

File tree

3 files changed

+54
-4
lines changed

3 files changed

+54
-4
lines changed

src/Rules/Classes/ClassAttributesRule.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
use Attribute;
66
use PhpParser\Node;
77
use PHPStan\Analyser\Scope;
8+
use PHPStan\Node\InClassNode;
89
use PHPStan\Rules\AttributesCheck;
910
use PHPStan\Rules\Rule;
1011

1112
/**
12-
* @implements Rule<Node\Stmt\ClassLike>
13+
* @implements Rule<InClassNode>
1314
*/
1415
final class ClassAttributesRule implements Rule
1516
{
@@ -20,14 +21,16 @@ public function __construct(private AttributesCheck $attributesCheck)
2021

2122
public function getNodeType(): string
2223
{
23-
return Node\Stmt\ClassLike::class;
24+
return InClassNode::class;
2425
}
2526

2627
public function processNode(Node $node, Scope $scope): array
2728
{
29+
$classLikeNode = $node->getOriginalNode();
30+
2831
return $this->attributesCheck->check(
2932
$scope,
30-
$node->attrGroups,
33+
$classLikeNode->attrGroups,
3134
Attribute::TARGET_CLASS,
3235
'class',
3336
);

tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php

+21-1
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@
2222
class ClassAttributesRuleTest extends RuleTestCase
2323
{
2424

25+
private bool $checkExplicitMixed = false;
26+
27+
private bool $checkImplicitMixed = false;
28+
2529
protected function getRule(): Rule
2630
{
2731
$reflectionProvider = $this->createReflectionProvider();
2832
return new ClassAttributesRule(
2933
new AttributesCheck(
3034
$reflectionProvider,
3135
new FunctionCallParametersCheck(
32-
new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false),
36+
new RuleLevelHelper($reflectionProvider, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false),
3337
new NullsafeCheck(),
3438
new PhpVersion(80000),
3539
new UnresolvableTypeHelper(),
@@ -148,4 +152,20 @@ public function testAllowDynamicPropertiesAttribute(): void
148152
$this->analyse([__DIR__ . '/data/allow-dynamic-properties-attribute.php'], []);
149153
}
150154

155+
public function testBug12011(): void
156+
{
157+
if (PHP_VERSION_ID < 80300) {
158+
$this->markTestSkipped('Test requires PHP 8.3.');
159+
}
160+
161+
$this->checkExplicitMixed = true;
162+
$this->checkImplicitMixed = true;
163+
$this->analyse([__DIR__ . '/data/bug-12011.php'], [
164+
[
165+
'Parameter #1 $name of attribute class Bug12011\Table constructor expects string|null, int given.',
166+
23,
167+
],
168+
]);
169+
}
170+
151171
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Bug12011;
4+
5+
use Attribute;
6+
7+
#[Table(self::TABLE_NAME)]
8+
class HelloWorld
9+
{
10+
private const string TABLE_NAME = 'table';
11+
}
12+
13+
#[Attribute(Attribute::TARGET_CLASS)]
14+
final class Table
15+
{
16+
public function __construct(
17+
public readonly string|null $name = null,
18+
public readonly string|null $schema = null,
19+
) {
20+
}
21+
}
22+
23+
#[Table(self::TABLE_NAME)]
24+
class HelloWorld2
25+
{
26+
private const int TABLE_NAME = 1;
27+
}

0 commit comments

Comments
 (0)