Skip to content

Commit a19934c

Browse files
Boegiemglaman
andauthored
Detect public static $modules when it should be protected static $modules in tests (#597)
* First stab. * strict types * adjust message --------- Co-authored-by: Matt Glaman <[email protected]>
1 parent d721420 commit a19934c

File tree

4 files changed

+205
-20
lines changed

4 files changed

+205
-20
lines changed

rules.neon

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
rules:
2-
- mglaman\PHPStanDrupal\Rules\Drupal\Coder\DiscouragedFunctionsRule
3-
- mglaman\PHPStanDrupal\Rules\Drupal\GlobalDrupalDependencyInjectionRule
4-
- mglaman\PHPStanDrupal\Rules\Drupal\PluginManager\PluginManagerSetsCacheBackendRule
5-
- mglaman\PHPStanDrupal\Rules\Deprecations\AccessDeprecatedConstant
6-
- mglaman\PHPStanDrupal\Rules\Classes\ClassExtendsInternalClassRule
7-
- mglaman\PHPStanDrupal\Rules\Classes\PluginManagerInspectionRule
8-
- mglaman\PHPStanDrupal\Rules\Deprecations\ConditionManagerCreateInstanceContextConfigurationRule
9-
- mglaman\PHPStanDrupal\Rules\Drupal\RenderCallbackRule
10-
- mglaman\PHPStanDrupal\Rules\Deprecations\StaticServiceDeprecatedServiceRule
11-
- mglaman\PHPStanDrupal\Rules\Deprecations\GetDeprecatedServiceRule
12-
- mglaman\PHPStanDrupal\Rules\Drupal\Tests\BrowserTestBaseDefaultThemeRule
13-
- mglaman\PHPStanDrupal\Rules\Deprecations\ConfigEntityConfigExportRule
14-
- mglaman\PHPStanDrupal\Rules\Deprecations\PluginAnnotationContextDefinitionsRule
15-
- mglaman\PHPStanDrupal\Rules\Drupal\ModuleLoadInclude
16-
- mglaman\PHPStanDrupal\Rules\Drupal\LoadIncludes
17-
- mglaman\PHPStanDrupal\Rules\Drupal\EntityQuery\EntityQueryHasAccessCheckRule
18-
- mglaman\PHPStanDrupal\Rules\Deprecations\SymfonyCmfRouteObjectInterfaceConstantsRule
19-
- mglaman\PHPStanDrupal\Rules\Deprecations\SymfonyCmfRoutingInClassMethodSignatureRule
20-
- mglaman\PHPStanDrupal\Rules\Drupal\RequestStackGetMainRequestRule
1+
rules:
2+
- mglaman\PHPStanDrupal\Rules\Drupal\Coder\DiscouragedFunctionsRule
3+
- mglaman\PHPStanDrupal\Rules\Drupal\GlobalDrupalDependencyInjectionRule
4+
- mglaman\PHPStanDrupal\Rules\Drupal\PluginManager\PluginManagerSetsCacheBackendRule
5+
- mglaman\PHPStanDrupal\Rules\Deprecations\AccessDeprecatedConstant
6+
- mglaman\PHPStanDrupal\Rules\Classes\ClassExtendsInternalClassRule
7+
- mglaman\PHPStanDrupal\Rules\Classes\PluginManagerInspectionRule
8+
- mglaman\PHPStanDrupal\Rules\Deprecations\ConditionManagerCreateInstanceContextConfigurationRule
9+
- mglaman\PHPStanDrupal\Rules\Drupal\RenderCallbackRule
10+
- mglaman\PHPStanDrupal\Rules\Deprecations\StaticServiceDeprecatedServiceRule
11+
- mglaman\PHPStanDrupal\Rules\Deprecations\GetDeprecatedServiceRule
12+
- mglaman\PHPStanDrupal\Rules\Drupal\Tests\BrowserTestBaseDefaultThemeRule
13+
- mglaman\PHPStanDrupal\Rules\Deprecations\ConfigEntityConfigExportRule
14+
- mglaman\PHPStanDrupal\Rules\Deprecations\PluginAnnotationContextDefinitionsRule
15+
- mglaman\PHPStanDrupal\Rules\Drupal\ModuleLoadInclude
16+
- mglaman\PHPStanDrupal\Rules\Drupal\LoadIncludes
17+
- mglaman\PHPStanDrupal\Rules\Drupal\EntityQuery\EntityQueryHasAccessCheckRule
18+
- mglaman\PHPStanDrupal\Rules\Deprecations\SymfonyCmfRouteObjectInterfaceConstantsRule
19+
- mglaman\PHPStanDrupal\Rules\Deprecations\SymfonyCmfRoutingInClassMethodSignatureRule
20+
- mglaman\PHPStanDrupal\Rules\Drupal\RequestStackGetMainRequestRule
21+
- mglaman\PHPStanDrupal\Rules\Drupal\TestClassesProtectedPropertyModulesRule
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace mglaman\PHPStanDrupal\Rules\Drupal;
6+
7+
use PhpParser\Node;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Node\ClassPropertyNode;
10+
use PHPStan\Rules\Rule;
11+
use PHPStan\Rules\RuleErrorBuilder;
12+
use PHPStan\ShouldNotHappenException;
13+
use PHPUnit\Framework\TestCase;
14+
15+
class TestClassesProtectedPropertyModulesRule implements Rule
16+
{
17+
18+
public function getNodeType(): string
19+
{
20+
return ClassPropertyNode::class;
21+
}
22+
23+
/**
24+
* @throws \PHPStan\ShouldNotHappenException
25+
*/
26+
public function processNode(Node $node, Scope $scope): array
27+
{
28+
assert($node instanceof ClassPropertyNode);
29+
30+
if (!$scope->isInClass()) {
31+
throw new ShouldNotHappenException();
32+
}
33+
34+
if ($node->getName() !== 'modules') {
35+
return [];
36+
}
37+
38+
$scopeClassReflection = $scope->getClassReflection();
39+
if ($scopeClassReflection->isAnonymous()) {
40+
return [];
41+
}
42+
43+
if (!in_array(TestCase::class, $scopeClassReflection->getParentClassesNames(), true)) {
44+
return [];
45+
}
46+
47+
if ($node->isPublic()) {
48+
return [
49+
RuleErrorBuilder::message(
50+
sprintf('Property %s::$modules property must be protected.', $scopeClassReflection->getDisplayName())
51+
)->tip('Change record: https://www.drupal.org/node/2909426')->build(),
52+
];
53+
}
54+
55+
return [];
56+
}
57+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace mglaman\PHPStanDrupal\Tests\Rules;
6+
7+
use mglaman\PHPStanDrupal\Rules\Drupal\TestClassesProtectedPropertyModulesRule;
8+
use mglaman\PHPStanDrupal\Tests\DrupalRuleTestCase;
9+
use PHPStan\Rules\Rule;
10+
11+
class TestClassesProtectedPropertyModulesRuleTest extends DrupalRuleTestCase
12+
{
13+
14+
protected function getRule(): Rule
15+
{
16+
return new TestClassesProtectedPropertyModulesRule();
17+
}
18+
19+
/**
20+
* @dataProvider cases
21+
*/
22+
public function test(array $files, array $errors): void
23+
{
24+
$this->analyse($files, $errors);
25+
}
26+
27+
public function cases(): \Generator
28+
{
29+
yield [
30+
[__DIR__ . '/data/test-cases-test-classes-protected-property-modules-rule.php'],
31+
[
32+
[
33+
'Property TestCasesTestClassesProtectedPropertyModulesRule\PublicStaticPropertyModulesClass::$modules property must be protected.',
34+
25,
35+
'Change record: https://www.drupal.org/node/2909426',
36+
],
37+
],
38+
];
39+
}
40+
41+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace TestCasesTestClassesProtectedPropertyModulesRule;
4+
5+
use Drupal\node\Entity\Node;
6+
use Drupal\Tests\node\Functional\NodeAccessFieldTest;
7+
8+
class ProtectedStaticPropertyModulesClass extends NodeAccessFieldTest {
9+
10+
/**
11+
* Modules to install.
12+
*
13+
* @var array
14+
*/
15+
protected static $modules = ['action', 'user'];
16+
}
17+
18+
class PublicStaticPropertyModulesClass extends NodeAccessFieldTest {
19+
20+
/**
21+
* Modules to install.
22+
*
23+
* @var array
24+
*/
25+
public static $modules = ['action', 'user'];
26+
}
27+
28+
class ProtectedStaticPropertyNotModulesClass extends NodeAccessFieldTest {
29+
30+
/**
31+
* Modules to install.
32+
*
33+
* @var array
34+
*/
35+
protected static $not_modules = ['action', 'user'];
36+
}
37+
38+
class PublicStaticPropertyNotModulesClass extends NodeAccessFieldTest {
39+
40+
/**
41+
* Modules to install.
42+
*
43+
* @var array
44+
*/
45+
public static $not_modules = ['action', 'user'];
46+
}
47+
48+
class NonExtendingProtectedStaticPropertyModulesClass {
49+
50+
/**
51+
* Modules to install.
52+
*
53+
* @var array
54+
*/
55+
protected static $modules = ['action', 'user'];
56+
}
57+
58+
class NonExtendingPublicStaticPropertyModulesClass {
59+
60+
/**
61+
* Modules to install.
62+
*
63+
* @var array
64+
*/
65+
public static $modules = ['action', 'user'];
66+
}
67+
68+
class NonExtendingPHPUnitFrameworkTestCaseProtectedStaticPropertyModulesClass extends Node {
69+
70+
/**
71+
* Modules to install.
72+
*
73+
* @var array
74+
*/
75+
protected static $modules = ['action', 'user'];
76+
}
77+
78+
class NonExtendingPHPUnitFrameworkTestCasePublicStaticPropertyModulesClass extends Node {
79+
80+
/**
81+
* Modules to install.
82+
*
83+
* @var array
84+
*/
85+
public static $modules = ['action', 'user'];
86+
}

0 commit comments

Comments
 (0)