Skip to content

Commit 5de0b2c

Browse files
committed
ClassNameCheck - ClassNameUsageLocation (for later usage in RestrictedUsage extensions)
1 parent e1e98fc commit 5de0b2c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+214
-56
lines changed

src/DependencyInjection/ConditionalTagsExtension.php

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use PHPStan\Rules\Constants\AlwaysUsedClassConstantsExtensionProvider;
2626
use PHPStan\Rules\LazyRegistry;
2727
use PHPStan\Rules\Properties\ReadWritePropertiesExtensionProvider;
28+
use PHPStan\Rules\RestrictedUsage\RestrictedClassNameUsageExtension;
2829
use PHPStan\Rules\RestrictedUsage\RestrictedMethodUsageExtension;
2930
use PHPStan\ShouldNotHappenException;
3031
use function array_reduce;
@@ -75,6 +76,7 @@ public function getConfigSchema(): Nette\Schema\Schema
7576
MethodDeprecationExtension::METHOD_EXTENSION_TAG => $bool,
7677
PropertyDeprecationExtension::PROPERTY_EXTENSION_TAG => $bool,
7778
RestrictedMethodUsageExtension::METHOD_EXTENSION_TAG => $bool,
79+
RestrictedClassNameUsageExtension::CLASS_NAME_EXTENSION_TAG => $bool,
7880
])->min(1));
7981
}
8082

src/Rules/AttributesCheck.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public function check(
6767
->build();
6868
}
6969

70-
foreach ($this->classCheck->checkClassNames([new ClassNameNodePair($name, $attribute)]) as $caseSensitivityError) {
70+
foreach ($this->classCheck->checkClassNames($scope, [new ClassNameNodePair($name, $attribute)], ClassNameUsageLocation::from(ClassNameUsageLocation::ATTRIBUTE)) as $caseSensitivityError) {
7171
$errors[] = $caseSensitivityError;
7272
}
7373

src/Rules/ClassNameCheck.php

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

33
namespace PHPStan\Rules;
44

5+
use PHPStan\Analyser\Scope;
6+
57
final class ClassNameCheck
68
{
79

@@ -16,7 +18,12 @@ public function __construct(
1618
* @param ClassNameNodePair[] $pairs
1719
* @return list<IdentifierRuleError>
1820
*/
19-
public function checkClassNames(array $pairs, bool $checkClassCaseSensitivity = true): array
21+
public function checkClassNames(
22+
Scope $scope,
23+
array $pairs,
24+
ClassNameUsageLocation $location,
25+
bool $checkClassCaseSensitivity = true,
26+
): array
2027
{
2128
$errors = [];
2229

src/Rules/ClassNameUsageLocation.php

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules;
4+
5+
use function array_key_exists;
6+
7+
final class ClassNameUsageLocation
8+
{
9+
10+
public const TRAIT_USE = 'traitUse';
11+
public const STATIC_PROPERTY_ACCESS = 'staticPropertyAccess';
12+
public const PHPDOC_TAG_ASSERT = 'phpDocTagAssert';
13+
public const ATTRIBUTE = 'attribute';
14+
public const EXCEPTION_CATCH = 'exceptionCatch';
15+
public const CLASS_CONSTANT_ACCESS = 'classConstantAccess';
16+
public const CLASS_IMPLEMENTS = 'classImplements';
17+
public const ENUM_IMPLEMENTS = 'enumImplements';
18+
public const INTERFACE_EXTENDS = 'interfaceExtends';
19+
public const CLASS_EXTENDS = 'classExtends';
20+
public const INSTANCEOF = 'instanceof';
21+
public const PROPERTY_TYPE = 'propertyType';
22+
public const USE_STATEMENT = 'use';
23+
public const PARAMETER_TYPE = 'parameterType';
24+
public const RETURN_TYPE = 'returnType';
25+
public const PHPDOC_TAG_SELF_OUT = 'phpDocTagSelfOut';
26+
public const PHPDOC_TAG_VAR = 'phpDocTagVar';
27+
public const INSTANTIATION = 'new';
28+
public const TYPE_ALIAS = 'typeAlias';
29+
public const PHPDOC_TAG_METHOD = 'phpDocTagMethod';
30+
public const PHPDOC_TAG_MIXIN = 'phpDocTagMixin';
31+
public const PHPDOC_TAG_PROPERTY = 'phpDocTagProperty';
32+
public const PHPDOC_TAG_REQUIRE_EXTENDS = 'phpDocTagRequireExtends';
33+
public const PHPDOC_TAG_REQUIRE_IMPLEMENTS = 'phpDocTagRequireImplements';
34+
public const STATIC_METHOD_CALL = 'staticMethodCall';
35+
public const PHPDOC_TAG_TEMPLATE_BOUND = 'phpDocTemplateBound';
36+
public const PHPDOC_TAG_TEMPLATE_DEFAULT = 'phpDocTemplateDefault';
37+
38+
/** @var array<string, self> */
39+
public static array $registry = [];
40+
41+
/**
42+
* @param self::* $value
43+
*/
44+
private function __construct(string $value) // @phpstan-ignore constructor.unusedParameter
45+
{
46+
}
47+
48+
/**
49+
* @param self::* $value
50+
*/
51+
public static function from(string $value): self
52+
{
53+
if (array_key_exists($value, self::$registry)) {
54+
return self::$registry[$value];
55+
}
56+
57+
return self::$registry[$value] = new self($value);
58+
}
59+
60+
}

src/Rules/Classes/ClassConstantRule.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use PHPStan\Reflection\ReflectionProvider;
1414
use PHPStan\Rules\ClassNameCheck;
1515
use PHPStan\Rules\ClassNameNodePair;
16+
use PHPStan\Rules\ClassNameUsageLocation;
1617
use PHPStan\Rules\IdentifierRuleError;
1718
use PHPStan\Rules\Rule;
1819
use PHPStan\Rules\RuleErrorBuilder;
@@ -150,7 +151,11 @@ private function processSingleClassConstFetch(Scope $scope, ClassConstFetch $nod
150151
}
151152
}
152153

153-
$messages = $this->classCheck->checkClassNames([new ClassNameNodePair($className, $class)]);
154+
$messages = $this->classCheck->checkClassNames(
155+
$scope,
156+
[new ClassNameNodePair($className, $class)],
157+
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_CONSTANT_ACCESS),
158+
);
154159
}
155160

156161
if (strtolower($constantName) === 'class') {

src/Rules/Classes/ExistingClassInClassExtendsRule.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPStan\Reflection\ReflectionProvider;
88
use PHPStan\Rules\ClassNameCheck;
99
use PHPStan\Rules\ClassNameNodePair;
10+
use PHPStan\Rules\ClassNameUsageLocation;
1011
use PHPStan\Rules\Rule;
1112
use PHPStan\Rules\RuleErrorBuilder;
1213
use function sprintf;
@@ -36,7 +37,11 @@ public function processNode(Node $node, Scope $scope): array
3637
return [];
3738
}
3839
$extendedClassName = (string) $node->extends;
39-
$messages = $this->classCheck->checkClassNames([new ClassNameNodePair($extendedClassName, $node->extends)]);
40+
$messages = $this->classCheck->checkClassNames(
41+
$scope,
42+
[new ClassNameNodePair($extendedClassName, $node->extends)],
43+
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_EXTENDS),
44+
);
4045
$currentClassName = null;
4146
if (isset($node->namespacedName)) {
4247
$currentClassName = (string) $node->namespacedName;

src/Rules/Classes/ExistingClassInInstanceOfRule.php

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\Reflection\ReflectionProvider;
99
use PHPStan\Rules\ClassNameCheck;
1010
use PHPStan\Rules\ClassNameNodePair;
11+
use PHPStan\Rules\ClassNameUsageLocation;
1112
use PHPStan\Rules\Rule;
1213
use PHPStan\Rules\RuleErrorBuilder;
1314
use PHPStan\Type\VerbosityLevel;
@@ -86,7 +87,9 @@ public function processNode(Node $node, Scope $scope): array
8687
$errors = array_merge(
8788
$errors,
8889
$this->classCheck->checkClassNames(
90+
$scope,
8991
[new ClassNameNodePair($name, $class)],
92+
ClassNameUsageLocation::from(ClassNameUsageLocation::INSTANCEOF),
9093
$this->checkClassCaseSensitivity,
9194
),
9295
);

src/Rules/Classes/ExistingClassInTraitUseRule.php

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPStan\Reflection\ReflectionProvider;
88
use PHPStan\Rules\ClassNameCheck;
99
use PHPStan\Rules\ClassNameNodePair;
10+
use PHPStan\Rules\ClassNameUsageLocation;
1011
use PHPStan\Rules\Rule;
1112
use PHPStan\Rules\RuleErrorBuilder;
1213
use PHPStan\ShouldNotHappenException;
@@ -35,7 +36,9 @@ public function getNodeType(): string
3536
public function processNode(Node $node, Scope $scope): array
3637
{
3738
$messages = $this->classCheck->checkClassNames(
39+
$scope,
3840
array_map(static fn (Node\Name $traitName): ClassNameNodePair => new ClassNameNodePair((string) $traitName, $traitName), $node->traits),
41+
ClassNameUsageLocation::from(ClassNameUsageLocation::TRAIT_USE),
3942
);
4043

4144
if (!$scope->isInClass()) {

src/Rules/Classes/ExistingClassesInClassImplementsRule.php

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPStan\Reflection\ReflectionProvider;
88
use PHPStan\Rules\ClassNameCheck;
99
use PHPStan\Rules\ClassNameNodePair;
10+
use PHPStan\Rules\ClassNameUsageLocation;
1011
use PHPStan\Rules\Rule;
1112
use PHPStan\Rules\RuleErrorBuilder;
1213
use function array_map;
@@ -34,7 +35,9 @@ public function getNodeType(): string
3435
public function processNode(Node $node, Scope $scope): array
3536
{
3637
$messages = $this->classCheck->checkClassNames(
38+
$scope,
3739
array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->implements),
40+
ClassNameUsageLocation::from(ClassNameUsageLocation::CLASS_IMPLEMENTS),
3841
);
3942

4043
$currentClassName = null;

src/Rules/Classes/ExistingClassesInEnumImplementsRule.php

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPStan\Reflection\ReflectionProvider;
88
use PHPStan\Rules\ClassNameCheck;
99
use PHPStan\Rules\ClassNameNodePair;
10+
use PHPStan\Rules\ClassNameUsageLocation;
1011
use PHPStan\Rules\Rule;
1112
use PHPStan\Rules\RuleErrorBuilder;
1213
use function array_map;
@@ -34,7 +35,9 @@ public function getNodeType(): string
3435
public function processNode(Node $node, Scope $scope): array
3536
{
3637
$messages = $this->classCheck->checkClassNames(
38+
$scope,
3739
array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->implements),
40+
ClassNameUsageLocation::from(ClassNameUsageLocation::ENUM_IMPLEMENTS),
3841
);
3942

4043
$currentEnumName = (string) $node->namespacedName;

src/Rules/Classes/ExistingClassesInInterfaceExtendsRule.php

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPStan\Reflection\ReflectionProvider;
88
use PHPStan\Rules\ClassNameCheck;
99
use PHPStan\Rules\ClassNameNodePair;
10+
use PHPStan\Rules\ClassNameUsageLocation;
1011
use PHPStan\Rules\Rule;
1112
use PHPStan\Rules\RuleErrorBuilder;
1213
use function array_map;
@@ -34,7 +35,9 @@ public function getNodeType(): string
3435
public function processNode(Node $node, Scope $scope): array
3536
{
3637
$messages = $this->classCheck->checkClassNames(
38+
$scope,
3739
array_map(static fn (Node\Name $interfaceName): ClassNameNodePair => new ClassNameNodePair((string) $interfaceName, $interfaceName), $node->extends),
40+
ClassNameUsageLocation::from(ClassNameUsageLocation::INTERFACE_EXTENDS),
3841
);
3942

4043
$currentInterfaceName = (string) $node->namespacedName;

src/Rules/Classes/InstantiationRule.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use PHPStan\Reflection\ReflectionProvider;
1313
use PHPStan\Rules\ClassNameCheck;
1414
use PHPStan\Rules\ClassNameNodePair;
15+
use PHPStan\Rules\ClassNameUsageLocation;
1516
use PHPStan\Rules\FunctionCallParametersCheck;
1617
use PHPStan\Rules\IdentifierRuleError;
1718
use PHPStan\Rules\Rule;
@@ -135,9 +136,9 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $
135136
];
136137
}
137138

138-
$messages = $this->classCheck->checkClassNames([
139+
$messages = $this->classCheck->checkClassNames($scope, [
139140
new ClassNameNodePair($class, $node->class),
140-
]);
141+
], ClassNameUsageLocation::from(ClassNameUsageLocation::INSTANTIATION));
141142

142143
$classReflection = $this->reflectionProvider->getClass($class);
143144
}

src/Rules/Classes/LocalTypeAliasesCheck.php

+7-4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44

55
use PhpParser\Node\Stmt\ClassLike;
66
use PHPStan\Analyser\NameScope;
7+
use PHPStan\Analyser\Scope;
78
use PHPStan\Internal\SprintfHelper;
89
use PHPStan\PhpDoc\TypeNodeResolver;
910
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
1011
use PHPStan\Reflection\ClassReflection;
1112
use PHPStan\Reflection\ReflectionProvider;
1213
use PHPStan\Rules\ClassNameCheck;
1314
use PHPStan\Rules\ClassNameNodePair;
15+
use PHPStan\Rules\ClassNameUsageLocation;
1416
use PHPStan\Rules\Generics\GenericObjectTypeCheck;
1517
use PHPStan\Rules\IdentifierRuleError;
1618
use PHPStan\Rules\MissingTypehintCheck;
@@ -51,13 +53,13 @@ public function __construct(
5153
/**
5254
* @return list<IdentifierRuleError>
5355
*/
54-
public function check(ClassReflection $reflection, ClassLike $node): array
56+
public function check(Scope $scope, ClassReflection $reflection, ClassLike $node): array
5557
{
5658
$errors = [];
5759
foreach ($this->checkInTraitDefinitionContext($reflection) as $error) {
5860
$errors[] = $error;
5961
}
60-
foreach ($this->checkInTraitUseContext($reflection, $reflection, $node) as $error) {
62+
foreach ($this->checkInTraitUseContext($scope, $reflection, $reflection, $node) as $error) {
6163
$errors[] = $error;
6264
}
6365

@@ -230,6 +232,7 @@ public function checkInTraitDefinitionContext(ClassReflection $reflection): arra
230232
* @return list<IdentifierRuleError>
231233
*/
232234
public function checkInTraitUseContext(
235+
Scope $scope,
233236
ClassReflection $reflection,
234237
ClassReflection $implementingClassReflection,
235238
ClassLike $node,
@@ -270,9 +273,9 @@ public function checkInTraitUseContext(
270273
} else {
271274
$errors = array_merge(
272275
$errors,
273-
$this->classCheck->checkClassNames([
276+
$this->classCheck->checkClassNames($scope, [
274277
new ClassNameNodePair($class, $node),
275-
], $this->checkClassCaseSensitivity),
278+
], ClassNameUsageLocation::from(ClassNameUsageLocation::TYPE_ALIAS), $this->checkClassCaseSensitivity),
276279
);
277280
}
278281
}

src/Rules/Classes/LocalTypeAliasesRule.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function getNodeType(): string
2424

2525
public function processNode(Node $node, Scope $scope): array
2626
{
27-
return $this->check->check($node->getClassReflection(), $node->getOriginalNode());
27+
return $this->check->check($scope, $node->getClassReflection(), $node->getOriginalNode());
2828
}
2929

3030
}

src/Rules/Classes/LocalTypeTraitUseAliasesRule.php

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public function getNodeType(): string
2525
public function processNode(Node $node, Scope $scope): array
2626
{
2727
return $this->check->checkInTraitUseContext(
28+
$scope,
2829
$node->getTraitReflection(),
2930
$node->getImplementingClassReflection(),
3031
$node->getOriginalNode(),

0 commit comments

Comments
 (0)