LineCountingVisitor.php 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of sebastian/lines-of-code.
  4. *
  5. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace SebastianBergmann\LinesOfCode;
  11. use function array_merge;
  12. use function array_unique;
  13. use function assert;
  14. use function count;
  15. use PhpParser\Comment;
  16. use PhpParser\Node;
  17. use PhpParser\Node\Expr;
  18. use PhpParser\NodeVisitorAbstract;
  19. final class LineCountingVisitor extends NodeVisitorAbstract
  20. {
  21. /**
  22. * @psalm-var non-negative-int
  23. */
  24. private readonly int $linesOfCode;
  25. /**
  26. * @var Comment[]
  27. */
  28. private array $comments = [];
  29. /**
  30. * @var int[]
  31. */
  32. private array $linesWithStatements = [];
  33. /**
  34. * @psalm-param non-negative-int $linesOfCode
  35. */
  36. public function __construct(int $linesOfCode)
  37. {
  38. $this->linesOfCode = $linesOfCode;
  39. }
  40. public function enterNode(Node $node): void
  41. {
  42. $this->comments = array_merge($this->comments, $node->getComments());
  43. if (!$node instanceof Expr) {
  44. return;
  45. }
  46. $this->linesWithStatements[] = $node->getStartLine();
  47. }
  48. public function result(): LinesOfCode
  49. {
  50. $commentLinesOfCode = 0;
  51. foreach ($this->comments() as $comment) {
  52. $commentLinesOfCode += ($comment->getEndLine() - $comment->getStartLine() + 1);
  53. }
  54. $nonCommentLinesOfCode = $this->linesOfCode - $commentLinesOfCode;
  55. $logicalLinesOfCode = count(array_unique($this->linesWithStatements));
  56. assert($commentLinesOfCode >= 0);
  57. assert($nonCommentLinesOfCode >= 0);
  58. assert($logicalLinesOfCode >= 0);
  59. return new LinesOfCode(
  60. $this->linesOfCode,
  61. $commentLinesOfCode,
  62. $nonCommentLinesOfCode,
  63. $logicalLinesOfCode,
  64. );
  65. }
  66. /**
  67. * @return Comment[]
  68. */
  69. private function comments(): array
  70. {
  71. $comments = [];
  72. foreach ($this->comments as $comment) {
  73. $comments[$comment->getStartLine() . '_' . $comment->getStartTokenPos() . '_' . $comment->getEndLine() . '_' . $comment->getEndTokenPos()] = $comment;
  74. }
  75. return $comments;
  76. }
  77. }