OcpSinceChecker.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright 2023 Daniel Kesselberg <mail@danielkesselberg.de>
  5. *
  6. * @author 2023 Daniel Kesselberg <mail@danielkesselberg.de>
  7. *
  8. * This code is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License, version 3,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License, version 3,
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>
  19. *
  20. */
  21. use PhpParser\Node\Stmt;
  22. use PhpParser\Node\Stmt\ClassLike;
  23. use Psalm\CodeLocation;
  24. use Psalm\DocComment;
  25. use Psalm\Exception\DocblockParseException;
  26. use Psalm\FileSource;
  27. use Psalm\Issue\InvalidDocblock;
  28. use Psalm\IssueBuffer;
  29. use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent;
  30. class OcpSinceChecker implements Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface {
  31. public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event): void {
  32. $stmt = $event->getStmt();
  33. $statementsSource = $event->getStatementsSource();
  34. self::checkClassComment($stmt, $statementsSource);
  35. foreach ($stmt->getMethods() as $method) {
  36. self::checkMethodComment($method, $statementsSource);
  37. }
  38. }
  39. private static function checkClassComment(ClassLike $stmt, FileSource $statementsSource): void {
  40. $docblock = $stmt->getDocComment();
  41. if ($docblock === null) {
  42. IssueBuffer::maybeAdd(
  43. new InvalidDocblock(
  44. 'PHPDoc is required for classes/interfaces in OCP.',
  45. new CodeLocation($statementsSource, $stmt)
  46. )
  47. );
  48. return;
  49. }
  50. try {
  51. $parsedDocblock = DocComment::parsePreservingLength($docblock);
  52. } catch (DocblockParseException $e) {
  53. IssueBuffer::maybeAdd(
  54. new InvalidDocblock(
  55. $e->getMessage(),
  56. new CodeLocation($statementsSource, $stmt)
  57. )
  58. );
  59. return;
  60. }
  61. if (!isset($parsedDocblock->tags['since'])) {
  62. IssueBuffer::maybeAdd(
  63. new InvalidDocblock(
  64. '@since is required for classes/interfaces in OCP.',
  65. new CodeLocation($statementsSource, $stmt)
  66. )
  67. );
  68. }
  69. }
  70. private static function checkMethodComment(Stmt $stmt, FileSource $statementsSource): void {
  71. $docblock = $stmt->getDocComment();
  72. if ($docblock === null) {
  73. IssueBuffer::maybeAdd(
  74. new InvalidDocblock(
  75. 'PHPDoc is required for methods in OCP.',
  76. new CodeLocation($statementsSource, $stmt)
  77. ),
  78. );
  79. return;
  80. }
  81. try {
  82. $parsedDocblock = DocComment::parsePreservingLength($docblock);
  83. } catch (DocblockParseException $e) {
  84. IssueBuffer::maybeAdd(
  85. new InvalidDocblock(
  86. $e->getMessage(),
  87. new CodeLocation($statementsSource, $stmt)
  88. )
  89. );
  90. return;
  91. }
  92. if (!isset($parsedDocblock->tags['since'])) {
  93. IssueBuffer::maybeAdd(
  94. new InvalidDocblock(
  95. '@since is required for methods in OCP.',
  96. new CodeLocation($statementsSource, $stmt)
  97. )
  98. );
  99. }
  100. }
  101. }