Skip to content

Commit c96332e

Browse files
authored
Merge branch refs/heads/1.8.x into 1.9.x
2 parents 07e0fc9 + 32b3c67 commit c96332e

File tree

3 files changed

+38
-11
lines changed

3 files changed

+38
-11
lines changed

src/PhpDoc/StubValidator.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private function getRuleRegistry(Container $container): RuleRegistry
171171
$genericObjectTypeCheck,
172172
$unresolvableTypeHelper,
173173
),
174-
new IncompatiblePropertyPhpDocTypeRule($genericObjectTypeCheck, $unresolvableTypeHelper),
174+
new IncompatiblePropertyPhpDocTypeRule($genericObjectTypeCheck, $unresolvableTypeHelper, $fileTypeMapper),
175175
new InvalidPhpDocTagValueRule(
176176
$container->getByType(Lexer::class),
177177
$container->getByType(PhpDocParser::class),

src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php

+31-9
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
use PHPStan\Rules\Rule;
1111
use PHPStan\Rules\RuleErrorBuilder;
1212
use PHPStan\ShouldNotHappenException;
13+
use PHPStan\Type\FileTypeMapper;
1314
use PHPStan\Type\Generic\TemplateType;
15+
use PHPStan\Type\ParserNodeTypeToPHPStanType;
1416
use PHPStan\Type\VerbosityLevel;
1517
use function array_merge;
18+
use function count;
1619
use function sprintf;
1720

1821
/**
@@ -24,6 +27,7 @@ class IncompatiblePropertyPhpDocTypeRule implements Rule
2427
public function __construct(
2528
private GenericObjectTypeCheck $genericObjectTypeCheck,
2629
private UnresolvableTypeHelper $unresolvableTypeHelper,
30+
private FileTypeMapper $fileTypeMapper,
2731
)
2832
{
2933
}
@@ -40,15 +44,33 @@ public function processNode(Node $node, Scope $scope): array
4044
}
4145

4246
$propertyName = $node->getName();
43-
$propertyReflection = $scope->getClassReflection()->getNativeProperty($propertyName);
47+
$phpDoc = $node->getPhpDoc();
48+
if ($phpDoc === null) {
49+
return [];
50+
}
51+
52+
$resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc(
53+
$scope->getFile(),
54+
$scope->isInClass() ? $scope->getClassReflection()->getName() : null,
55+
$scope->isInTrait() ? $scope->getTraitReflection()->getName() : null,
56+
null,
57+
$phpDoc,
58+
);
59+
60+
$varTags = $resolvedPhpDoc->getVarTags();
61+
$phpDocType = null;
62+
if (isset($varTags[0]) && count($varTags) === 1) {
63+
$phpDocType = $varTags[0]->getType();
64+
} elseif (isset($varTags[$propertyName])) {
65+
$phpDocType = $varTags[$propertyName]->getType();
66+
}
4467

45-
if (!$propertyReflection->hasPhpDocType()) {
68+
if ($phpDocType === null) {
4669
return [];
4770
}
4871

49-
$phpDocType = $propertyReflection->getPhpDocType();
5072
$description = 'PHPDoc tag @var';
51-
if ($propertyReflection->isPromoted()) {
73+
if ($node->isPromoted()) {
5274
$description = 'PHPDoc type';
5375
}
5476

@@ -59,18 +81,18 @@ public function processNode(Node $node, Scope $scope): array
5981
$messages[] = RuleErrorBuilder::message(sprintf(
6082
'%s for property %s::$%s contains unresolvable type.',
6183
$description,
62-
$propertyReflection->getDeclaringClass()->getName(),
84+
$scope->getClassReflection()->getDisplayName(),
6385
$propertyName,
6486
))->build();
6587
}
6688

67-
$nativeType = $propertyReflection->getNativeType();
89+
$nativeType = ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $scope->getClassReflection());
6890
$isSuperType = $nativeType->isSuperTypeOf($phpDocType);
6991
if ($isSuperType->no()) {
7092
$messages[] = RuleErrorBuilder::message(sprintf(
7193
'%s for property %s::$%s with type %s is incompatible with native type %s.',
7294
$description,
73-
$propertyReflection->getDeclaringClass()->getDisplayName(),
95+
$scope->getClassReflection()->getDisplayName(),
7496
$propertyName,
7597
$phpDocType->describe(VerbosityLevel::typeOnly()),
7698
$nativeType->describe(VerbosityLevel::typeOnly()),
@@ -80,7 +102,7 @@ public function processNode(Node $node, Scope $scope): array
80102
$errorBuilder = RuleErrorBuilder::message(sprintf(
81103
'%s for property %s::$%s with type %s is not subtype of native type %s.',
82104
$description,
83-
$propertyReflection->getDeclaringClass()->getDisplayName(),
105+
$scope->getClassReflection()->getDisplayName(),
84106
$propertyName,
85107
$phpDocType->describe(VerbosityLevel::typeOnly()),
86108
$nativeType->describe(VerbosityLevel::typeOnly()),
@@ -93,7 +115,7 @@ public function processNode(Node $node, Scope $scope): array
93115
$messages[] = $errorBuilder->build();
94116
}
95117

96-
$className = SprintfHelper::escapeFormatString($propertyReflection->getDeclaringClass()->getDisplayName());
118+
$className = SprintfHelper::escapeFormatString($scope->getClassReflection()->getDisplayName());
97119
$escapedPropertyName = SprintfHelper::escapeFormatString($propertyName);
98120

99121
$messages = array_merge($messages, $this->genericObjectTypeCheck->check(

tests/PHPStan/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRuleTest.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHPStan\Rules\Generics\GenericObjectTypeCheck;
66
use PHPStan\Rules\Rule;
77
use PHPStan\Testing\RuleTestCase;
8+
use PHPStan\Type\FileTypeMapper;
89

910
/**
1011
* @extends RuleTestCase<IncompatiblePropertyPhpDocTypeRule>
@@ -14,7 +15,11 @@ class IncompatiblePropertyPhpDocTypeRuleTest extends RuleTestCase
1415

1516
protected function getRule(): Rule
1617
{
17-
return new IncompatiblePropertyPhpDocTypeRule(new GenericObjectTypeCheck(), new UnresolvableTypeHelper());
18+
return new IncompatiblePropertyPhpDocTypeRule(
19+
new GenericObjectTypeCheck(),
20+
new UnresolvableTypeHelper(),
21+
self::getContainer()->getByType(FileTypeMapper::class),
22+
);
1823
}
1924

2025
public function testRule(): void

0 commit comments

Comments
 (0)