1
0

NcuExperimentalChecker.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. use PhpParser\Node\Stmt;
  8. use PhpParser\Node\Stmt\ClassConst;
  9. use PhpParser\Node\Stmt\ClassLike;
  10. use PhpParser\Node\Stmt\ClassMethod;
  11. use PhpParser\Node\Stmt\EnumCase;
  12. use Psalm\CodeLocation;
  13. use Psalm\DocComment;
  14. use Psalm\Exception\DocblockParseException;
  15. use Psalm\FileSource;
  16. use Psalm\Issue\InvalidDocblock;
  17. use Psalm\IssueBuffer;
  18. use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent;
  19. class NcuExperimentalChecker implements Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface {
  20. public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event): void {
  21. $classLike = $event->getStmt();
  22. $statementsSource = $event->getStatementsSource();
  23. self::checkClassComment($classLike, $statementsSource);
  24. foreach ($classLike->stmts as $stmt) {
  25. if ($stmt instanceof ClassConst) {
  26. self::checkStatementComment($stmt, $statementsSource, 'constant');
  27. }
  28. if ($stmt instanceof ClassMethod) {
  29. self::checkStatementComment($stmt, $statementsSource, 'method');
  30. }
  31. if ($stmt instanceof EnumCase) {
  32. self::checkStatementComment($stmt, $statementsSource, 'enum');
  33. }
  34. }
  35. }
  36. private static function checkClassComment(ClassLike $stmt, FileSource $statementsSource): void {
  37. $docblock = $stmt->getDocComment();
  38. if ($docblock === null) {
  39. IssueBuffer::maybeAdd(
  40. new InvalidDocblock(
  41. 'PHPDoc is required for classes/interfaces in NCU.',
  42. new CodeLocation($statementsSource, $stmt)
  43. )
  44. );
  45. return;
  46. }
  47. try {
  48. $parsedDocblock = DocComment::parsePreservingLength($docblock);
  49. } catch (DocblockParseException $e) {
  50. IssueBuffer::maybeAdd(
  51. new InvalidDocblock(
  52. $e->getMessage(),
  53. new CodeLocation($statementsSource, $stmt)
  54. )
  55. );
  56. return;
  57. }
  58. if (!isset($parsedDocblock->tags['experimental'])) {
  59. IssueBuffer::maybeAdd(
  60. new InvalidDocblock(
  61. '@experimental is required for classes/interfaces in NCU.',
  62. new CodeLocation($statementsSource, $stmt)
  63. )
  64. );
  65. }
  66. if (isset($parsedDocblock->tags['depreacted'])) {
  67. IssueBuffer::maybeAdd(
  68. new InvalidDocblock(
  69. 'Typo in @deprecated for classes/interfaces in NCU.',
  70. new CodeLocation($statementsSource, $stmt)
  71. )
  72. );
  73. }
  74. }
  75. private static function checkStatementComment(Stmt $stmt, FileSource $statementsSource, string $type): void {
  76. $docblock = $stmt->getDocComment();
  77. if ($docblock === null) {
  78. IssueBuffer::maybeAdd(
  79. new InvalidDocblock(
  80. 'PHPDoc is required for ' . $type . 's in NCU.',
  81. new CodeLocation($statementsSource, $stmt)
  82. ),
  83. );
  84. return;
  85. }
  86. try {
  87. $parsedDocblock = DocComment::parsePreservingLength($docblock);
  88. } catch (DocblockParseException $e) {
  89. IssueBuffer::maybeAdd(
  90. new InvalidDocblock(
  91. $e->getMessage(),
  92. new CodeLocation($statementsSource, $stmt)
  93. )
  94. );
  95. return;
  96. }
  97. if (!isset($parsedDocblock->tags['experimental'])) {
  98. IssueBuffer::maybeAdd(
  99. new InvalidDocblock(
  100. '@experimental is required for ' . $type . 's in NCU.',
  101. new CodeLocation($statementsSource, $stmt)
  102. )
  103. );
  104. }
  105. if (isset($parsedDocblock->tags['depreacted'])) {
  106. IssueBuffer::maybeAdd(
  107. new InvalidDocblock(
  108. 'Typo in @deprecated for ' . $type . ' in NCU.',
  109. new CodeLocation($statementsSource, $stmt)
  110. )
  111. );
  112. }
  113. }
  114. }