Skip to content

Commit 9b9067b

Browse files
authored
Ignore inaccessible class child nodes (#15)
* Ignore inaccessible class child nodes * Add config flag to include inaccessible class nodes * Add test for include-inaccessible-class-nodes config
1 parent dd405ec commit 9b9067b

File tree

6 files changed

+171
-0
lines changed

6 files changed

+171
-0
lines changed

src/GenerateStubsCommand.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public function configure(): void
6262
->addOption('visitor', null, InputOption::VALUE_REQUIRED, 'Path to a PHP file which returns a `StubsGenerator\NodeVisitor` instance to replace the default node visitor.')
6363
->addOption('header', null, InputOption::VALUE_REQUIRED, 'A doc comment to prepend to the top of the generated stubs file. (Will be added below the opening `<?php` tag.)', '')
6464
->addOption('nullify-globals', null, InputOption::VALUE_NONE, 'Initialize all global variables with a value of `null`, instead of their assigned value.')
65+
->addOption('include-inaccessible-class-nodes', null, InputOption::VALUE_NONE, 'Include inaccessible class nodes like private members.')
6566
->addOption('stats', null, InputOption::VALUE_NONE, 'Whether to print stats instead of outputting stubs. Stats will always be printed if --out is provided.');
6667

6768
foreach (self::SYMBOL_OPTIONS as $opt) {
@@ -117,6 +118,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
117118
$finder = $this->parseSources($input);
118119
$generator = new StubsGenerator($this->parseSymbols($input), [
119120
'nullify_globals' => $input->getOption('nullify-globals'),
121+
'include_inaccessible_class_nodes' => $input->getOption('include-inaccessible-class-nodes')
120122
]);
121123

122124
$result = $generator->generate($finder, $visitor);

src/NodeVisitor.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use PhpParser\Node\Scalar\String_;
1212
use PhpParser\Node\Stmt;
1313
use PhpParser\Node\Stmt\Class_;
14+
use PhpParser\Node\Stmt\ClassConst;
1415
use PhpParser\Node\Stmt\ClassLike;
1516
use PhpParser\Node\Stmt\ClassMethod;
1617
use PhpParser\Node\Stmt\Const_;
@@ -19,6 +20,7 @@
1920
use PhpParser\Node\Stmt\If_;
2021
use PhpParser\Node\Stmt\Interface_;
2122
use PhpParser\Node\Stmt\Namespace_;
23+
use PhpParser\Node\Stmt\Property;
2224
use PhpParser\Node\Stmt\Trait_;
2325
use PhpParser\NodeTraverser;
2426
use PhpParser\NodeVisitorAbstract;
@@ -47,6 +49,8 @@ class NodeVisitor extends NodeVisitorAbstract
4749
private $needsConstants;
4850
/** @var bool */
4951
private $nullifyGlobals;
52+
/** @var bool */
53+
private $includeInaccessibleClassNodes;
5054

5155
/**
5256
* @psalm-suppress PropertyNotSetInConstructor
@@ -101,6 +105,7 @@ public function init(int $symbols = StubsGenerator::DEFAULT, array $config = [])
101105
$this->needsConstants = ($symbols & StubsGenerator::CONSTANTS) !== 0;
102106

103107
$this->nullifyGlobals = !empty($config['nullify_globals']);
108+
$this->includeInaccessibleClassNodes = ($config['include_inaccessible_class_nodes'] ?? false) === true;
104109

105110
$this->globalNamespace = new Namespace_();
106111
}
@@ -238,6 +243,13 @@ public function leaveNode(Node $node, bool $preserveStack = false)
238243
// Implies `$parent instanceof ClassLike`, which means $node is a
239244
// either a method, property, or constant, or its part of the
240245
// declaration itself (e.g., `extends`).
246+
247+
if (!$this->includeInaccessibleClassNodes && $parent instanceof Class_ && ($node instanceof ClassMethod || $node instanceof ClassConst || $node instanceof Property)) {
248+
if ($node->isPrivate() || ($parent->isFinal() && $node->isProtected())) {
249+
return NodeTraverser::REMOVE_NODE;
250+
}
251+
}
252+
241253
return;
242254
}
243255

test/NodeVisitorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function inputOutputProvider(): array
3636
{
3737
$cases = [
3838
'classes',
39+
['classes', 'classes-include-inaccessible-class-nodes', null, ['include_inaccessible_class_nodes' => true]],
3940
'classes-with-dependencies',
4041
'circular-dependency',
4142
'functions',
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
/** doc */
3+
abstract class A extends \B implements \C
4+
{
5+
/** doc */
6+
protected const A = 'B';
7+
8+
/** doc */
9+
private const B = 'C';
10+
11+
/** doc */
12+
public static $a = 'a';
13+
14+
private static $b = 'b';
15+
16+
/** doc */
17+
public static function b($a): void
18+
{
19+
}
20+
21+
/** doc */
22+
abstract public function c($a): string;
23+
24+
/** doc */
25+
protected function d($a) : void
26+
{
27+
}
28+
29+
/** doc */
30+
protected abstract function e($a) : string;
31+
32+
/** doc */
33+
private function f($a): void
34+
{
35+
}
36+
}
37+
38+
class D
39+
{
40+
public function a(string $a): string
41+
{
42+
}
43+
}
44+
45+
final class E
46+
{
47+
/** doc */
48+
public $a = 'a';
49+
50+
/** doc */
51+
protected $b = 'b';
52+
53+
/** doc */
54+
public function a($a) : void
55+
{
56+
}
57+
58+
/** doc */
59+
protected function b($a): void
60+
{
61+
}
62+
}
63+
64+
trait F
65+
{
66+
/** doc */
67+
private $a = 'a';
68+
69+
/** doc */
70+
private function a($a) : void
71+
{
72+
}
73+
}

test/files/classes.in.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@ abstract class A extends B implements C
55
/** doc */
66
protected const A = 'B';
77

8+
/** doc */
9+
private const B = 'C';
10+
811
/** doc */
912
public static $a = 'a';
1013

14+
private static $b = 'b';
15+
1116
/** doc */
1217
public static function b($a): void
1318
{
@@ -16,6 +21,21 @@ public static function b($a): void
1621

1722
/** doc */
1823
abstract public function c($a): string;
24+
25+
/** doc */
26+
protected function d($a): void
27+
{
28+
return;
29+
}
30+
31+
/** doc */
32+
abstract protected function e($a): string;
33+
34+
/** doc */
35+
private function f($a): void
36+
{
37+
return;
38+
}
1939
}
2040

2141
if (!class_exists('D')) {
@@ -27,3 +47,36 @@ public function a(string $a): string
2747
}
2848
}
2949
}
50+
51+
final class E
52+
{
53+
/** doc */
54+
public $a = 'a';
55+
56+
/** doc */
57+
protected $b = 'b';
58+
59+
/** doc */
60+
public function a($a): void
61+
{
62+
return;
63+
}
64+
65+
/** doc */
66+
protected function b($a): void
67+
{
68+
return;
69+
}
70+
}
71+
72+
trait F
73+
{
74+
/** doc */
75+
private $a = 'a';
76+
77+
/** doc */
78+
private function a($a): void
79+
{
80+
return;
81+
}
82+
}

test/files/classes.out.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ public static function b($a): void
1515

1616
/** doc */
1717
abstract public function c($a): string;
18+
19+
/** doc */
20+
protected function d($a) : void
21+
{
22+
}
23+
24+
/** doc */
25+
protected abstract function e($a) : string;
1826
}
1927

2028
class D
@@ -23,3 +31,25 @@ public function a(string $a): string
2331
{
2432
}
2533
}
34+
35+
final class E
36+
{
37+
/** doc */
38+
public $a = 'a';
39+
40+
/** doc */
41+
public function a($a) : void
42+
{
43+
}
44+
}
45+
46+
trait F
47+
{
48+
/** doc */
49+
private $a = 'a';
50+
51+
/** doc */
52+
private function a($a) : void
53+
{
54+
}
55+
}

0 commit comments

Comments
 (0)