Skip to content

Commit ba8678f

Browse files
authored
Add DeprecationHelper DeprecatedScopeResolver (#714)
* Add DeprecationHelper DeprecatedScopeResolver * test with phpstan 1.10.x-dev * call stack released in 1.10.55 * fix linting and tests on d9 * Use getFunctionCallStackWithParameters * require phpstan ^1.10.56
1 parent a5a001a commit ba8678f

File tree

5 files changed

+161
-2
lines changed

5 files changed

+161
-2
lines changed

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
],
1212
"require": {
1313
"php": "^7.4 || ^8.0",
14-
"symfony/finder": "^4.2 || ^5.0 || ^6.0 || ^7.0",
15-
"phpstan/phpstan": "^1.10.1",
14+
"phpstan/phpstan": "^1.10.56",
1615
"phpstan/phpstan-deprecation-rules": "^1.1.4",
16+
"symfony/finder": "^4.2 || ^5.0 || ^6.0 || ^7.0",
1717
"symfony/yaml": "^4.2|| ^5.0 || ^6.0 || ^7.0",
1818
"webflo/drupal-finder": "^1.2"
1919
},

extension.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,8 @@ services:
307307
class: mglaman\PHPStanDrupal\DeprecatedScope\GroupLegacyScope
308308
tags:
309309
- phpstan.deprecations.deprecatedScopeResolver
310+
311+
-
312+
class: mglaman\PHPStanDrupal\DeprecatedScope\DeprecationHelperScope
313+
tags:
314+
- phpstan.deprecations.deprecatedScopeResolver
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace mglaman\PHPStanDrupal\DeprecatedScope;
6+
7+
use Drupal\Component\Utility\DeprecationHelper;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Reflection\MethodReflection;
10+
use PHPStan\Rules\Deprecations\DeprecatedScopeResolver;
11+
12+
final class DeprecationHelperScope implements DeprecatedScopeResolver
13+
{
14+
public function isScopeDeprecated(Scope $scope): bool
15+
{
16+
if (!class_exists(DeprecationHelper::class)) {
17+
return false;
18+
}
19+
$callStack = $scope->getFunctionCallStackWithParameters();
20+
if (count($callStack) === 0) {
21+
return false;
22+
}
23+
[$function, $parameter] = $callStack[0];
24+
if (!$function instanceof MethodReflection) {
25+
return false;
26+
}
27+
if ($function->getName() !== 'backwardsCompatibleCall'
28+
|| $function->getDeclaringClass()->getName() !== DeprecationHelper::class
29+
) {
30+
return false;
31+
}
32+
return $parameter !== null && $parameter->getName() === 'deprecatedCallable';
33+
}
34+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace mglaman\PHPStanDrupal\Tests\DeprecatedScope;
6+
7+
use mglaman\PHPStanDrupal\Tests\DrupalRuleTestCase;
8+
use PHPStan\Rules\Deprecations\CallToDeprecatedFunctionRule;
9+
use PHPStan\Rules\Deprecations\DeprecatedScopeHelper;
10+
use PHPStan\Rules\Rule;
11+
12+
final class DeprecationHelperScopeTest extends DrupalRuleTestCase {
13+
14+
protected function getRule(): Rule
15+
{
16+
// @phpstan-ignore-next-line
17+
return new CallToDeprecatedFunctionRule(
18+
self::createReflectionProvider(),
19+
self::getContainer()->getByType(DeprecatedScopeHelper::class)
20+
);
21+
}
22+
23+
public function testCustomScope(): void
24+
{
25+
[$version] = explode('.', \Drupal::VERSION, 2);
26+
if ($version < '10') {
27+
self::markTestSkipped('Not tested on < Drupal 10');
28+
}
29+
require_once __DIR__ . '/data/deprecated-data-definition.php';
30+
$this->analyse(
31+
[__DIR__ . '/data/deprecation-helper-test.php'],
32+
[
33+
[
34+
'Call to deprecated function Deprecated\deprecated_function().',
35+
26,
36+
],
37+
[
38+
'Call to deprecated function Deprecated\deprecated_function().',
39+
42,
40+
],
41+
]
42+
);
43+
}
44+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace GroupLegacy;
4+
5+
use Drupal\Component\Utility\DeprecationHelper;
6+
use function Deprecated\deprecated_function;
7+
8+
final class FooTest {
9+
10+
public function methodCallingThings(): void {
11+
12+
\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(
13+
\Drupal::VERSION,
14+
'10.1.0',
15+
fn() => count([]),
16+
fn() => deprecated_function()
17+
);
18+
19+
DeprecationHelper::backwardsCompatibleCall(
20+
\Drupal::VERSION,
21+
'10.1.0',
22+
fn() => count([]),
23+
fn() => deprecated_function()
24+
);
25+
26+
deprecated_function();
27+
28+
DeprecationHelper::backwardsCompatibleCall(
29+
\Drupal::VERSION,
30+
'10.1.0',
31+
function() {
32+
count([]);
33+
},
34+
function() {
35+
deprecated_function();
36+
}
37+
);
38+
39+
DeprecationHelper::backwardsCompatibleCall(
40+
\Drupal::VERSION,
41+
'10.1.0',
42+
fn() => deprecated_function(),
43+
fn() => count([])
44+
);
45+
46+
DeprecationHelper::backwardsCompatibleCall(
47+
\Drupal::VERSION,
48+
'10.1.0',
49+
$this->currentCallable(...),
50+
$this->deprecatedCallable(...)
51+
);
52+
53+
DeprecationHelper::backwardsCompatibleCall(
54+
\Drupal::VERSION,
55+
'10.1.0',
56+
// @todo somehow this should trigger an error as well.
57+
$this->deprecatedCallable(...),
58+
$this->currentCallable(...)
59+
);
60+
}
61+
62+
/**
63+
* @deprecated
64+
*
65+
* @note if using reference callables they must be tagged as deprecated.
66+
*/
67+
public function deprecatedCallable()
68+
{
69+
deprecated_function();
70+
}
71+
72+
public function currentCallable()
73+
{
74+
count([]);
75+
}
76+
}

0 commit comments

Comments
 (0)