Skip to content

Commit

Permalink
Add DeprecationHelper DeprecatedScopeResolver (#714)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
mglaman authored Jan 16, 2024
1 parent a5a001a commit ba8678f
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 2 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
],
"require": {
"php": "^7.4 || ^8.0",
"symfony/finder": "^4.2 || ^5.0 || ^6.0 || ^7.0",
"phpstan/phpstan": "^1.10.1",
"phpstan/phpstan": "^1.10.56",
"phpstan/phpstan-deprecation-rules": "^1.1.4",
"symfony/finder": "^4.2 || ^5.0 || ^6.0 || ^7.0",
"symfony/yaml": "^4.2|| ^5.0 || ^6.0 || ^7.0",
"webflo/drupal-finder": "^1.2"
},
Expand Down
5 changes: 5 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,8 @@ services:
class: mglaman\PHPStanDrupal\DeprecatedScope\GroupLegacyScope
tags:
- phpstan.deprecations.deprecatedScopeResolver

-
class: mglaman\PHPStanDrupal\DeprecatedScope\DeprecationHelperScope
tags:
- phpstan.deprecations.deprecatedScopeResolver
34 changes: 34 additions & 0 deletions src/DeprecatedScope/DeprecationHelperScope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace mglaman\PHPStanDrupal\DeprecatedScope;

use Drupal\Component\Utility\DeprecationHelper;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Rules\Deprecations\DeprecatedScopeResolver;

final class DeprecationHelperScope implements DeprecatedScopeResolver
{
public function isScopeDeprecated(Scope $scope): bool
{
if (!class_exists(DeprecationHelper::class)) {
return false;
}
$callStack = $scope->getFunctionCallStackWithParameters();
if (count($callStack) === 0) {
return false;
}
[$function, $parameter] = $callStack[0];
if (!$function instanceof MethodReflection) {
return false;
}
if ($function->getName() !== 'backwardsCompatibleCall'
|| $function->getDeclaringClass()->getName() !== DeprecationHelper::class
) {
return false;
}
return $parameter !== null && $parameter->getName() === 'deprecatedCallable';
}
}
44 changes: 44 additions & 0 deletions tests/src/DeprecatedScope/DeprecationHelperScopeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace mglaman\PHPStanDrupal\Tests\DeprecatedScope;

use mglaman\PHPStanDrupal\Tests\DrupalRuleTestCase;
use PHPStan\Rules\Deprecations\CallToDeprecatedFunctionRule;
use PHPStan\Rules\Deprecations\DeprecatedScopeHelper;
use PHPStan\Rules\Rule;

final class DeprecationHelperScopeTest extends DrupalRuleTestCase {

protected function getRule(): Rule
{
// @phpstan-ignore-next-line
return new CallToDeprecatedFunctionRule(
self::createReflectionProvider(),
self::getContainer()->getByType(DeprecatedScopeHelper::class)
);
}

public function testCustomScope(): void
{
[$version] = explode('.', \Drupal::VERSION, 2);
if ($version < '10') {
self::markTestSkipped('Not tested on < Drupal 10');
}
require_once __DIR__ . '/data/deprecated-data-definition.php';
$this->analyse(
[__DIR__ . '/data/deprecation-helper-test.php'],
[
[
'Call to deprecated function Deprecated\deprecated_function().',
26,
],
[
'Call to deprecated function Deprecated\deprecated_function().',
42,
],
]
);
}
}
76 changes: 76 additions & 0 deletions tests/src/DeprecatedScope/data/deprecation-helper-test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace GroupLegacy;

use Drupal\Component\Utility\DeprecationHelper;
use function Deprecated\deprecated_function;

final class FooTest {

public function methodCallingThings(): void {

\Drupal\Component\Utility\DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'10.1.0',
fn() => count([]),
fn() => deprecated_function()
);

DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'10.1.0',
fn() => count([]),
fn() => deprecated_function()
);

deprecated_function();

DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'10.1.0',
function() {
count([]);
},
function() {
deprecated_function();
}
);

DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'10.1.0',
fn() => deprecated_function(),
fn() => count([])
);

DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'10.1.0',
$this->currentCallable(...),
$this->deprecatedCallable(...)
);

DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'10.1.0',
// @todo somehow this should trigger an error as well.
$this->deprecatedCallable(...),
$this->currentCallable(...)
);
}

/**
* @deprecated
*
* @note if using reference callables they must be tagged as deprecated.
*/
public function deprecatedCallable()
{
deprecated_function();
}

public function currentCallable()
{
count([]);
}
}

0 comments on commit ba8678f

Please sign in to comment.