From 9b9067b2fc92394e4b6aee242f34440fe9d02d9c Mon Sep 17 00:00:00 2001 From: Martin Herndl Date: Wed, 8 Feb 2023 21:40:27 +0100 Subject: [PATCH] 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 --- src/GenerateStubsCommand.php | 2 + src/NodeVisitor.php | 12 +++ test/NodeVisitorTest.php | 1 + ...s-include-inaccessible-class-nodes.out.php | 73 +++++++++++++++++++ test/files/classes.in.php | 53 ++++++++++++++ test/files/classes.out.php | 30 ++++++++ 6 files changed, 171 insertions(+) create mode 100644 test/files/classes-include-inaccessible-class-nodes.out.php diff --git a/src/GenerateStubsCommand.php b/src/GenerateStubsCommand.php index 03433ff..11f0423 100644 --- a/src/GenerateStubsCommand.php +++ b/src/GenerateStubsCommand.php @@ -62,6 +62,7 @@ public function configure(): void ->addOption('visitor', null, InputOption::VALUE_REQUIRED, 'Path to a PHP file which returns a `StubsGenerator\NodeVisitor` instance to replace the default node visitor.') ->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 `addOption('nullify-globals', null, InputOption::VALUE_NONE, 'Initialize all global variables with a value of `null`, instead of their assigned value.') + ->addOption('include-inaccessible-class-nodes', null, InputOption::VALUE_NONE, 'Include inaccessible class nodes like private members.') ->addOption('stats', null, InputOption::VALUE_NONE, 'Whether to print stats instead of outputting stubs. Stats will always be printed if --out is provided.'); foreach (self::SYMBOL_OPTIONS as $opt) { @@ -117,6 +118,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $finder = $this->parseSources($input); $generator = new StubsGenerator($this->parseSymbols($input), [ 'nullify_globals' => $input->getOption('nullify-globals'), + 'include_inaccessible_class_nodes' => $input->getOption('include-inaccessible-class-nodes') ]); $result = $generator->generate($finder, $visitor); diff --git a/src/NodeVisitor.php b/src/NodeVisitor.php index 57b4ce0..b74a97c 100644 --- a/src/NodeVisitor.php +++ b/src/NodeVisitor.php @@ -11,6 +11,7 @@ use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassConst; use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Const_; @@ -19,6 +20,7 @@ use PhpParser\Node\Stmt\If_; use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Namespace_; +use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Trait_; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; @@ -47,6 +49,8 @@ class NodeVisitor extends NodeVisitorAbstract private $needsConstants; /** @var bool */ private $nullifyGlobals; + /** @var bool */ + private $includeInaccessibleClassNodes; /** * @psalm-suppress PropertyNotSetInConstructor @@ -101,6 +105,7 @@ public function init(int $symbols = StubsGenerator::DEFAULT, array $config = []) $this->needsConstants = ($symbols & StubsGenerator::CONSTANTS) !== 0; $this->nullifyGlobals = !empty($config['nullify_globals']); + $this->includeInaccessibleClassNodes = ($config['include_inaccessible_class_nodes'] ?? false) === true; $this->globalNamespace = new Namespace_(); } @@ -238,6 +243,13 @@ public function leaveNode(Node $node, bool $preserveStack = false) // Implies `$parent instanceof ClassLike`, which means $node is a // either a method, property, or constant, or its part of the // declaration itself (e.g., `extends`). + + if (!$this->includeInaccessibleClassNodes && $parent instanceof Class_ && ($node instanceof ClassMethod || $node instanceof ClassConst || $node instanceof Property)) { + if ($node->isPrivate() || ($parent->isFinal() && $node->isProtected())) { + return NodeTraverser::REMOVE_NODE; + } + } + return; } diff --git a/test/NodeVisitorTest.php b/test/NodeVisitorTest.php index 35c151e..7af26e4 100644 --- a/test/NodeVisitorTest.php +++ b/test/NodeVisitorTest.php @@ -36,6 +36,7 @@ public function inputOutputProvider(): array { $cases = [ 'classes', + ['classes', 'classes-include-inaccessible-class-nodes', null, ['include_inaccessible_class_nodes' => true]], 'classes-with-dependencies', 'circular-dependency', 'functions', diff --git a/test/files/classes-include-inaccessible-class-nodes.out.php b/test/files/classes-include-inaccessible-class-nodes.out.php new file mode 100644 index 0000000..f246623 --- /dev/null +++ b/test/files/classes-include-inaccessible-class-nodes.out.php @@ -0,0 +1,73 @@ +