Skip to content

Commit 68de666

Browse files
committed
More data in ClassNameUsageLocation
1 parent ff198c9 commit 68de666

15 files changed

+193
-27
lines changed

src/Rules/ClassNameUsageLocation.php

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace PHPStan\Rules;
44

5+
use PHPStan\Reflection\ClassConstantReflection;
56
use PHPStan\Reflection\ExtendedMethodReflection;
7+
use PHPStan\Reflection\ExtendedPropertyReflection;
68
use function sprintf;
79
use function ucfirst;
810

@@ -61,34 +63,123 @@ public function getMethod(): ?ExtendedMethodReflection
6163
return $this->data['method'] ?? null;
6264
}
6365

66+
public function getProperty(): ?ExtendedPropertyReflection
67+
{
68+
return $this->data['property'] ?? null;
69+
}
70+
71+
public function getPhpDocTagName(): ?string
72+
{
73+
return $this->data['phpDocTagName'] ?? null;
74+
}
75+
76+
public function getAssertedExprString(): ?string
77+
{
78+
return $this->data['assertedExprString'] ?? null;
79+
}
80+
81+
public function getClassConstant(): ?ClassConstantReflection
82+
{
83+
return $this->data['classConstant'] ?? null;
84+
}
85+
86+
public function getCurrentClassName(): ?string
87+
{
88+
return $this->data['currentClassName'] ?? null;
89+
}
90+
91+
public function getParameterName(): ?string
92+
{
93+
return $this->data['parameterName'] ?? null;
94+
}
95+
96+
public function getTypeAliasName(): ?string
97+
{
98+
return $this->data['typeAliasName'] ?? null;
99+
}
100+
101+
public function getMethodTagName(): ?string
102+
{
103+
return $this->data['methodTagName'] ?? null;
104+
}
105+
106+
public function getPropertyTagName(): ?string
107+
{
108+
return $this->data['propertyTagName'] ?? null;
109+
}
110+
111+
public function getTemplateTagName(): ?string
112+
{
113+
return $this->data['templateTagName'] ?? null;
114+
}
115+
64116
public function createMessage(string $part): string
65117
{
66118
switch ($this->value) {
67119
case self::TRAIT_USE:
68120
return sprintf('Usage of %s.', $part);
69121
case self::STATIC_PROPERTY_ACCESS:
122+
$property = $this->getProperty();
123+
if ($property !== null) {
124+
return sprintf('Access to static property $%s on %s.', $property->getName(), $part);
125+
}
126+
70127
return sprintf('Access to static property on %s.', $part);
71128
case self::PHPDOC_TAG_ASSERT:
129+
$phpDocTagName = $this->getPhpDocTagName();
130+
$assertExprString = $this->getAssertedExprString();
131+
if ($phpDocTagName !== null && $assertExprString !== null) {
132+
return sprintf('PHPDoc tag %s for %s references %s.', $phpDocTagName, $assertExprString, $part);
133+
}
134+
72135
return sprintf('Assert tag references %s.', $part);
73136
case self::ATTRIBUTE:
74137
return sprintf('Attribute references %s.', $part);
75138
case self::EXCEPTION_CATCH:
76139
return sprintf('Catching %s.', $part);
77140
case self::CLASS_CONSTANT_ACCESS:
141+
if ($this->getClassConstant() !== null) {
142+
return sprintf('Access to constant %s on %s.', $this->getClassConstant()->getName(), $part);
143+
}
78144
return sprintf('Access to constant on %s.', $part);
79145
case self::CLASS_IMPLEMENTS:
146+
if ($this->getCurrentClassName() !== null) {
147+
return sprintf('Class %s implements %s.', $this->getCurrentClassName(), $part);
148+
}
149+
80150
return sprintf('Class implements %s.', $part);
81151
case self::ENUM_IMPLEMENTS:
152+
if ($this->getCurrentClassName() !== null) {
153+
return sprintf('Enum %s implements %s.', $this->getCurrentClassName(), $part);
154+
}
155+
82156
return sprintf('Enum implements %s.', $part);
83157
case self::INTERFACE_EXTENDS:
158+
if ($this->getCurrentClassName() !== null) {
159+
return sprintf('Interface %s extends %s.', $this->getCurrentClassName(), $part);
160+
}
161+
84162
return sprintf('Interface extends %s.', $part);
85163
case self::CLASS_EXTENDS:
164+
if ($this->getCurrentClassName() !== null) {
165+
return sprintf('Class %s extends %s.', $this->getCurrentClassName(), $part);
166+
}
167+
86168
return sprintf('Class extends %s.', $part);
87169
case self::INSTANCEOF:
88170
return sprintf('Instanceof references %s.', $part);
89171
case self::PROPERTY_TYPE:
172+
$property = $this->getProperty();
173+
if ($property !== null) {
174+
return sprintf('Property $%s references %s in its type.', $property->getName(), $part);
175+
}
90176
return sprintf('Property references %s in its type.', $part);
91177
case self::PARAMETER_TYPE:
178+
$parameterName = $this->getParameterName();
179+
if ($parameterName !== null) {
180+
return sprintf('Parameter $%s references %s in its type.', $parameterName, $part);
181+
}
182+
92183
return sprintf('Parameter references %s in its type.', $part);
93184
case self::RETURN_TYPE:
94185
return sprintf('Return type references %s.', $part);
@@ -99,12 +190,22 @@ public function createMessage(string $part): string
99190
case self::INSTANTIATION:
100191
return sprintf('Instantiating %s.', $part);
101192
case self::TYPE_ALIAS:
193+
if ($this->getTypeAliasName() !== null) {
194+
return sprintf('Type alias %s references %s.', $this->getTypeAliasName(), $part);
195+
}
196+
102197
return sprintf('Type alias references %s.', $part);
103198
case self::PHPDOC_TAG_METHOD:
199+
if ($this->getMethodTagName() !== null) {
200+
return sprintf('PHPDoc tag @method for %s() references %s.', $this->getMethodTagName(), $part);
201+
}
104202
return sprintf('PHPDoc tag @method references %s.', $part);
105203
case self::PHPDOC_TAG_MIXIN:
106204
return sprintf('PHPDoc tag @mixin references %s.', $part);
107205
case self::PHPDOC_TAG_PROPERTY:
206+
if ($this->getPropertyTagName() !== null) {
207+
return sprintf('PHPDoc tag @property for $%s references %s.', $this->getPropertyTagName(), $part);
208+
}
108209
return sprintf('PHPDoc tag @property references %s.', $part);
109210
case self::PHPDOC_TAG_REQUIRE_EXTENDS:
110211
return sprintf('PHPDoc tag @phpstan-require-extends references %s.', $part);
@@ -118,8 +219,16 @@ public function createMessage(string $part): string
118219

119220
return sprintf('Call to static method on %s.', $part);
120221
case self::PHPDOC_TAG_TEMPLATE_BOUND:
222+
if ($this->getTemplateTagName() !== null) {
223+
return sprintf('PHPDoc tag @template %s bound references %s.', $this->getTemplateTagName(), $part);
224+
}
225+
121226
return sprintf('PHPDoc tag @template bound references %s.', $part);
122227
case self::PHPDOC_TAG_TEMPLATE_DEFAULT:
228+
if ($this->getTemplateTagName() !== null) {
229+
return sprintf('PHPDoc tag @template %s default references %s.', $this->getTemplateTagName(), $part);
230+
}
231+
123232
return sprintf('PHPDoc tag @template default references %s.', $part);
124233
}
125234
}

src/Rules/Classes/ClassConstantRule.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,16 @@ private function processSingleClassConstFetch(Scope $scope, ClassConstFetch $nod
151151
}
152152
}
153153

154+
$locationData = [];
155+
$locationClassReflection = $this->reflectionProvider->getClass($className);
156+
if ($locationClassReflection->hasConstant($constantName)) {
157+
$locationData['classConstant'] = $locationClassReflection->getConstant($constantName);
158+
}
159+
154160
$messages = $this->classCheck->checkClassNames(
155161
$scope,
156162
[new ClassNameNodePair($className, $class)],
157-
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_CONSTANT_ACCESS),
163+
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_CONSTANT_ACCESS, $locationData),
158164
);
159165
}
160166

src/Rules/Classes/ExistingClassInClassExtendsRule.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,18 @@ public function processNode(Node $node, Scope $scope): array
3737
return [];
3838
}
3939
$extendedClassName = (string) $node->extends;
40-
$messages = $this->classCheck->checkClassNames(
41-
$scope,
42-
[new ClassNameNodePair($extendedClassName, $node->extends)],
43-
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_EXTENDS),
44-
);
4540
$currentClassName = null;
4641
if (isset($node->namespacedName)) {
4742
$currentClassName = (string) $node->namespacedName;
4843
}
44+
$messages = $this->classCheck->checkClassNames(
45+
$scope,
46+
[new ClassNameNodePair($extendedClassName, $node->extends)],
47+
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_EXTENDS, [
48+
'currentClassName' => $currentClassName,
49+
]),
50+
);
51+
4952
if (!$this->reflectionProvider->hasClass($extendedClassName)) {
5053
if (!$scope->isInClassExists($extendedClassName)) {
5154
$errorBuilder = RuleErrorBuilder::message(sprintf(

src/Rules/Classes/ExistingClassesInClassImplementsRule.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,19 @@ public function getNodeType(): string
3434

3535
public function processNode(Node $node, Scope $scope): array
3636
{
37-
$messages = $this->classCheck->checkClassNames(
38-
$scope,
39-
array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->implements),
40-
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_IMPLEMENTS),
41-
);
42-
4337
$currentClassName = null;
4438
if (isset($node->namespacedName)) {
4539
$currentClassName = (string) $node->namespacedName;
4640
}
4741

42+
$messages = $this->classCheck->checkClassNames(
43+
$scope,
44+
array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->implements),
45+
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_IMPLEMENTS, [
46+
'currentClassName' => $currentClassName,
47+
]),
48+
);
49+
4850
foreach ($node->implements as $implements) {
4951
$implementedClassName = (string) $implements;
5052
if (!$this->reflectionProvider->hasClass($implementedClassName)) {

src/Rules/Classes/ExistingClassesInEnumImplementsRule.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@ public function getNodeType(): string
3434

3535
public function processNode(Node $node, Scope $scope): array
3636
{
37+
$currentEnumName = (string) $node->namespacedName;
3738
$messages = $this->classCheck->checkClassNames(
3839
$scope,
3940
array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->implements),
40-
ClassNameUsageLocation::from(ClassNameUsageLocation::ENUM_IMPLEMENTS),
41+
ClassNameUsageLocation::from(ClassNameUsageLocation::ENUM_IMPLEMENTS, [
42+
'currentClassName' => $currentEnumName,
43+
]),
4144
);
4245

43-
$currentEnumName = (string) $node->namespacedName;
44-
4546
foreach ($node->implements as $implements) {
4647
$implementedClassName = (string) $implements;
4748
if (!$this->reflectionProvider->hasClass($implementedClassName)) {

src/Rules/Classes/ExistingClassesInInterfaceExtendsRule.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ public function getNodeType(): string
3434

3535
public function processNode(Node $node, Scope $scope): array
3636
{
37+
$currentInterfaceName = (string) $node->namespacedName;
3738
$messages = $this->classCheck->checkClassNames(
3839
$scope,
3940
array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->extends),
40-
ClassNameUsageLocation::from(ClassNameUsageLocation::INTERFACE_EXTENDS),
41+
ClassNameUsageLocation::from(ClassNameUsageLocation::INTERFACE_EXTENDS, [
42+
'currentClassName' => $currentInterfaceName,
43+
]),
4144
);
4245

43-
$currentInterfaceName = (string) $node->namespacedName;
4446
foreach ($node->extends as $extends) {
4547
$extendedInterfaceName = (string) $extends;
4648
if (!$this->reflectionProvider->hasClass($extendedInterfaceName)) {

src/Rules/Classes/LocalTypeAliasesCheck.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,9 @@ public function checkInTraitUseContext(
275275
$errors,
276276
$this->classCheck->checkClassNames($scope, [
277277
new ClassNameNodePair($class, $node),
278-
], ClassNameUsageLocation::from(ClassNameUsageLocation::TYPE_ALIAS), $this->checkClassCaseSensitivity),
278+
], ClassNameUsageLocation::from(ClassNameUsageLocation::TYPE_ALIAS, [
279+
'typeAliasName' => $aliasName,
280+
]), $this->checkClassCaseSensitivity),
279281
);
280282
}
281283
}

src/Rules/Classes/MethodTagCheck.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,9 @@ private function checkMethodTypeInTraitUseContext(Scope $scope, ClassReflection
238238
$errors,
239239
$this->classCheck->checkClassNames($scope, [
240240
new ClassNameNodePair($class, $node),
241-
], ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_METHOD), $this->checkClassCaseSensitivity),
241+
], ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_METHOD, [
242+
'methodTagName' => $methodName,
243+
]), $this->checkClassCaseSensitivity),
242244
);
243245
}
244246
}

src/Rules/Classes/PropertyTagCheck.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ private function checkPropertyTypeInTraitUseContext(Scope $scope, ClassReflectio
219219
$errors,
220220
$this->classCheck->checkClassNames($scope, [
221221
new ClassNameNodePair($class, $node),
222-
], ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_PROPERTY), $this->checkClassCaseSensitivity),
222+
], ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_PROPERTY, [
223+
'propertyTagName' => $propertyName,
224+
]), $this->checkClassCaseSensitivity),
223225
);
224226
}
225227
}

src/Rules/FunctionDefinitionCheck.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,9 @@ public function checkAnonymousFunction(
177177
$errors,
178178
$this->classCheck->checkClassNames($scope, [
179179
new ClassNameNodePair($class, $param->type),
180-
], ClassNameUsageLocation::from(ClassNameUsageLocation::PARAMETER_TYPE), $this->checkClassCaseSensitivity),
180+
], ClassNameUsageLocation::from(ClassNameUsageLocation::PARAMETER_TYPE, [
181+
'parameterName' => $param->var->name,
182+
]), $this->checkClassCaseSensitivity),
181183
);
182184
}
183185
}
@@ -429,7 +431,9 @@ private function checkParametersAcceptor(
429431
$this->classCheck->checkClassNames(
430432
$scope,
431433
array_map(static fn (string $class): ClassNameNodePair => new ClassNameNodePair($class, $parameterNodeCallback()), $referencedClasses),
432-
ClassNameUsageLocation::from(ClassNameUsageLocation::PARAMETER_TYPE),
434+
ClassNameUsageLocation::from(ClassNameUsageLocation::PARAMETER_TYPE, [
435+
'parameterName' => $parameter->getName(),
436+
]),
433437
$this->checkClassCaseSensitivity,
434438
),
435439
);

src/Rules/Generics/TemplateTypeCheck.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ public function check(
106106
}
107107

108108
$classNameNodePairs = array_map(static fn (string $referencedClass): ClassNameNodePair => new ClassNameNodePair($referencedClass, $node), $boundType->getReferencedClasses());
109-
$messages = array_merge($messages, $this->classCheck->checkClassNames($scope, $classNameNodePairs, ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_TEMPLATE_BOUND), $this->checkClassCaseSensitivity));
109+
$messages = array_merge($messages, $this->classCheck->checkClassNames($scope, $classNameNodePairs, ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_TEMPLATE_BOUND, [
110+
'templateTagName' => $templateTagName,
111+
]), $this->checkClassCaseSensitivity));
110112

111113
$boundTypeClass = get_class($boundType);
112114
if (
@@ -183,7 +185,9 @@ public function check(
183185
}
184186

185187
$classNameNodePairs = array_map(static fn (string $referencedClass): ClassNameNodePair => new ClassNameNodePair($referencedClass, $node), $defaultType->getReferencedClasses());
186-
$messages = array_merge($messages, $this->classCheck->checkClassNames($scope, $classNameNodePairs, ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_TEMPLATE_DEFAULT), $this->checkClassCaseSensitivity));
188+
$messages = array_merge($messages, $this->classCheck->checkClassNames($scope, $classNameNodePairs, ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_TEMPLATE_DEFAULT, [
189+
'templateTagName' => $templateTagName,
190+
]), $this->checkClassCaseSensitivity));
187191

188192
$genericDefaultErrors = $this->genericObjectTypeCheck->check(
189193
$defaultType,

src/Rules/InternalTag/RestrictedInternalClassNameUsageExtension.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,24 @@ public function isRestrictedClassNameUsage(
4242
}
4343
}
4444

45+
if ($location->value === ClassNameUsageLocation::STATIC_PROPERTY_ACCESS) {
46+
$property = $location->getProperty();
47+
if ($property !== null) {
48+
if ($property->isInternal()->yes() || $property->getDeclaringClass()->isInternal()) {
49+
return null;
50+
}
51+
}
52+
}
53+
54+
if ($location->value === ClassNameUsageLocation::CLASS_CONSTANT_ACCESS) {
55+
$constant = $location->getClassConstant();
56+
if ($constant !== null) {
57+
if ($constant->isInternal()->yes() || $constant->getDeclaringClass()->isInternal()) {
58+
return null;
59+
}
60+
}
61+
}
62+
4563
return RestrictedUsage::create(
4664
$location->createMessage(sprintf('internal %s %s', strtolower($classReflection->getClassTypeDescription()), $classReflection->getDisplayName())),
4765
$location->createIdentifier(sprintf('internal%s', $classReflection->getClassTypeDescription())),

src/Rules/PhpDoc/AssertRuleHelper.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ public function check(
154154
$errors,
155155
$this->classCheck->checkClassNames($scope, [
156156
new ClassNameNodePair($class, $node),
157-
], ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_ASSERT), $this->checkClassCaseSensitivity),
157+
], ClassNameUsageLocation::from(ClassNameUsageLocation::PHPDOC_TAG_ASSERT, [
158+
'phpDocTagName' => $tagName,
159+
'assertedExprString' => $assertedExprString,
160+
]), $this->checkClassCaseSensitivity),
158161
);
159162
}
160163

0 commit comments

Comments
 (0)