PATH:
opt
/
cpanel
/
ea-wappspector
/
vendor
/
slevomat
/
coding-standard
/
SlevomatCodingStandard
/
Sniffs
/
Commenting
<?php declare(strict_types = 1); namespace SlevomatCodingStandard\Sniffs\Commenting; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; use SlevomatCodingStandard\Helpers\AnnotationHelper; use SlevomatCodingStandard\Helpers\FixerHelper; use SlevomatCodingStandard\Helpers\NamespaceHelper; use SlevomatCodingStandard\Helpers\SniffSettingsHelper; use SlevomatCodingStandard\Helpers\TokenHelper; use function array_combine; use function array_key_exists; use function array_map; use function array_unique; use function implode; use function ltrim; use function preg_match_all; use function sprintf; use function strlen; use function strpos; use function strtolower; use function substr; use const PREG_OFFSET_CAPTURE; use const T_DOC_COMMENT_OPEN_TAG; class AnnotationNameSniff implements Sniff { public const CODE_ANNOTATION_NAME_INCORRECT = 'AnnotationNameIncorrect'; private const STANDARD_ANNOTATIONS = [ 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'inheritDoc', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'uses', 'used-by', 'var', 'version', ]; private const STATIC_ANALYSIS_ANNOTATIONS = [ 'api', 'allow-private-mutation', 'assert', 'assert-if-true', 'assert-if-false', 'consistent-constructor', 'consistent-templates', 'extends', 'external-mutation-free', 'implements', 'mixin', 'ignore-falsable-return', 'ignore-nullable-return', 'ignore-var', 'ignore-variable-method', 'ignore-variable-property', 'immutable', 'import-type', 'internal', 'method', 'mutation-free', 'no-named-arguments', 'param', 'param-out', 'property', 'property-read', 'property-write', 'psalm-check-type', 'psalm-check-type-exact', 'psalm-suppress', 'psalm-trace', 'pure', 'readonly', 'readonly-allow-private-mutation', 'require-extends', 'require-implements', 'return', 'seal-properties', 'self-out', 'template', 'template-covariant', 'template-extends', 'template-implements', 'template-use', 'this-out', 'type', 'var', 'yield', ]; private const PHPUNIT_ANNOTATIONS = [ 'author', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'doesNotPerformAssertions', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'testWith', 'ticket', 'uses', ]; /** @var list<string>|null */ public ?array $annotations = null; /** @var array<string, string>|null */ private ?array $normalizedAnnotations = null; /** * @return array<int, (int|string)> */ public function register(): array { return [ T_DOC_COMMENT_OPEN_TAG, ]; } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint * @param int $docCommentOpenPointer */ public function process(File $phpcsFile, $docCommentOpenPointer): void { $annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer); $correctAnnotationNames = $this->getNormalizedAnnotationNames(); foreach ($annotations as $annotation) { $lowerCasedAnnotationName = strtolower($annotation->getName()); if (!array_key_exists($lowerCasedAnnotationName, $correctAnnotationNames)) { continue; } $correctAnnotationName = $correctAnnotationNames[$lowerCasedAnnotationName]; if ($correctAnnotationName === $annotation->getName()) { continue; } $annotationNameWithoutAtSign = ltrim($annotation->getName(), '@'); $fullyQualifiedAnnotationName = NamespaceHelper::resolveClassName( $phpcsFile, $annotationNameWithoutAtSign, $annotation->getStartPointer(), ); if (NamespaceHelper::normalizeToCanonicalName($fullyQualifiedAnnotationName) !== $annotationNameWithoutAtSign) { continue; } $fix = $phpcsFile->addFixableError( sprintf('Annotation name is incorrect. Expected %s, found %s.', $correctAnnotationName, $annotation->getName()), $annotation->getStartPointer(), self::CODE_ANNOTATION_NAME_INCORRECT, ); if (!$fix) { continue; } $phpcsFile->fixer->beginChangeset(); FixerHelper::replace($phpcsFile, $annotation->getStartPointer(), $correctAnnotationName); $phpcsFile->fixer->endChangeset(); } $tokens = $phpcsFile->getTokens(); $docCommentContent = TokenHelper::getContent($phpcsFile, $docCommentOpenPointer, $tokens[$docCommentOpenPointer]['comment_closer']); if (preg_match_all( '~\{(' . implode('|', $correctAnnotationNames) . ')\}~i', $docCommentContent, $matches, PREG_OFFSET_CAPTURE, ) === 0) { return; } foreach ($matches[1] as $match) { $correctAnnotationName = $correctAnnotationNames[strtolower($match[0])]; if ($correctAnnotationName === $match[0]) { continue; } $fix = $phpcsFile->addFixableError( sprintf('Annotation name is incorrect. Expected %s, found %s.', $correctAnnotationName, $match[0]), $docCommentOpenPointer, self::CODE_ANNOTATION_NAME_INCORRECT, ); if (!$fix) { continue; } $phpcsFile->fixer->beginChangeset(); $fixedDocCommentContent = substr($docCommentContent, 0, $match[1]) . $correctAnnotationName . substr( $docCommentContent, $match[1] + strlen($match[0]), ); FixerHelper::change( $phpcsFile, $docCommentOpenPointer, $tokens[$docCommentOpenPointer]['comment_closer'], $fixedDocCommentContent, ); $phpcsFile->fixer->endChangeset(); } } /** * @return array<string, string> */ private function getNormalizedAnnotationNames(): array { if ($this->normalizedAnnotations !== null) { return $this->normalizedAnnotations; } if ($this->annotations !== null) { $annotationNames = array_map( static fn (string $annotationName): string => ltrim($annotationName, '@'), SniffSettingsHelper::normalizeArray($this->annotations), ); } else { $annotationNames = [...self::STANDARD_ANNOTATIONS, ...self::PHPUNIT_ANNOTATIONS, ...self::STATIC_ANALYSIS_ANNOTATIONS]; foreach (self::STATIC_ANALYSIS_ANNOTATIONS as $annotationName) { if (strpos($annotationName, 'psalm') === 0) { continue; } foreach (AnnotationHelper::STATIC_ANALYSIS_PREFIXES as $prefix) { $annotationNames[] = sprintf('%s-%s', $prefix, $annotationName); } } } $annotationNames = array_map(static fn (string $annotationName): string => '@' . $annotationName, array_unique($annotationNames)); $this->normalizedAnnotations = array_combine( array_map(static fn (string $annotationName): string => strtolower($annotationName), $annotationNames), $annotationNames, ); return $this->normalizedAnnotations; } }
[-] DocCommentSpacingSniff.php
[edit]
[-] DisallowCommentAfterCodeSniff.php
[edit]
[+]
..
[-] ForbiddenAnnotationsSniff.php
[edit]
[-] DisallowOneLinePropertyDocCommentSniff.php
[edit]
[-] ForbiddenCommentsSniff.php
[edit]
[-] UselessInheritDocCommentSniff.php
[edit]
[-] RequireOneLinePropertyDocCommentSniff.php
[edit]
[-] DeprecatedAnnotationDeclarationSniff.php
[edit]
[-] AbstractRequireOneLineDocComment.php
[edit]
[-] UselessFunctionDocCommentSniff.php
[edit]
[-] InlineDocCommentDeclarationSniff.php
[edit]
[-] RequireOneLineDocCommentSniff.php
[edit]
[-] AnnotationNameSniff.php
[edit]
[-] EmptyCommentSniff.php
[edit]