Skip to content

Commit

Permalink
Debugging function - PHPStan\debugScope()
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Sep 3, 2024
1 parent c50b71f commit 5909fb2
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 2 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
"src/"
]
},
"files": ["src/dumpType.php", "src/autoloadFunctions.php", "src/Testing/functions.php"]
"files": ["src/debugScope.php", "src/dumpType.php", "src/autoloadFunctions.php", "src/Testing/functions.php"]
},
"autoload-dev": {
"psr-4": {
Expand Down
1 change: 1 addition & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ extensions:
validateExcludePaths: PHPStan\DependencyInjection\ValidateExcludePathsExtension

rules:
- PHPStan\Rules\Debug\DebugScopeRule
- PHPStan\Rules\Debug\DumpTypeRule
- PHPStan\Rules\Debug\FileAssertRule

Expand Down
2 changes: 1 addition & 1 deletion src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -5400,7 +5400,7 @@ public function debug(): array
$descriptions[$key] = $variableTypeHolder->getType()->describe(VerbosityLevel::precise());
}
foreach ($this->nativeExpressionTypes as $exprString => $nativeTypeHolder) {
$key = sprintf('native %s', $exprString);
$key = sprintf('native %s (%s)', $exprString, $nativeTypeHolder->getCertainty()->describe());
$descriptions[$key] = $nativeTypeHolder->getType()->describe(VerbosityLevel::precise());
}

Expand Down
66 changes: 66 additions & 0 deletions src/Rules/Debug/DebugScopeRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Debug;

use PhpParser\Node;
use PHPStan\Analyser\MutatingScope;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function count;
use function implode;
use function sprintf;
use function strtolower;

/**
* @implements Rule<Node\Expr\FuncCall>
*/
final class DebugScopeRule implements Rule
{

public function __construct(private ReflectionProvider $reflectionProvider)
{
}

public function getNodeType(): string
{
return Node\Expr\FuncCall::class;
}

public function processNode(Node $node, Scope $scope): array
{
if (!$node->name instanceof Node\Name) {
return [];
}

$functionName = $this->reflectionProvider->resolveFunctionName($node->name, $scope);
if ($functionName === null) {
return [];
}

if (strtolower($functionName) !== 'phpstan\debugscope') {
return [];
}

if (!$scope instanceof MutatingScope) {
return [];
}

$parts = [];
foreach ($scope->debug() as $key => $row) {
$parts[] = sprintf('%s: %s', $key, $row);
}

if (count($parts) === 0) {
$parts[] = 'Scope is empty';
}

return [
RuleErrorBuilder::message(
implode("\n", $parts),
)->nonIgnorable()->identifier('phpstan.debugScope')->build(),
];
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ final class CallToFunctionStatementWithoutSideEffectsRule implements Rule

public const PHPSTAN_TESTING_FUNCTIONS = [
'PHPStan\\dumpType',
'PHPStan\\debugScope',
'PHPStan\\Testing\\assertType',
'PHPStan\\Testing\\assertNativeType',
'PHPStan\\Testing\\assertVariableCertainty',
Expand Down
14 changes: 14 additions & 0 deletions src/debugScope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php declare(strict_types = 1);

namespace PHPStan;

/**
* @phpstan-pure
* @return mixed
*
* @throws void
*/
function debugScope() // phpcs:ignore Squiz.Functions.GlobalFunction.Found
{
return null;
}
56 changes: 56 additions & 0 deletions tests/PHPStan/Rules/Debug/DebugScopeRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Debug;

use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use function implode;

/**
* @extends RuleTestCase<DebugScopeRule>
*/
class DebugScopeRuleTest extends RuleTestCase
{

protected function getRule(): Rule
{
return new DebugScopeRule($this->createReflectionProvider());
}

public function testRuleInPhpStanNamespace(): void
{
$this->analyse([__DIR__ . '/data/debug-scope.php'], [
[
'Scope is empty',
7,
],
[
implode("\n", [
'$a (Yes): int',
'$b (Yes): int',
'$debug (Yes): bool',
'native $a (Yes): int',
'native $b (Yes): int',
'native $debug (Yes): bool',
]),
10,
],
[
implode("\n", [
'$a (Yes): int',
'$b (Yes): int',
'$debug (Yes): bool',
'$c (Maybe): 1',
'native $a (Yes): int',
'native $b (Yes): int',
'native $debug (Yes): bool',
'native $c (Maybe): 1',
'condition about $c #1: if $debug=false then $c is *ERROR* (No)',
'condition about $c #2: if $debug=true then $c is 1 (Yes)',
]),
16,
],
]);
}

}
17 changes: 17 additions & 0 deletions tests/PHPStan/Rules/Debug/data/debug-scope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace DebugScope;

use function PHPStan\debugScope;

debugScope();

function (int $a, int $b, bool $debug): void {
debugScope();

if ($debug) {
$c = 1;
}

debugScope();
};

0 comments on commit 5909fb2

Please sign in to comment.