class AnnotationNameSniff
Hierarchy
- class \SlevomatCodingStandard\Sniffs\Commenting\AnnotationNameSniff implements \PHP_CodeSniffer\Sniffs\Sniff
Expanded class hierarchy of AnnotationNameSniff
File
-
vendor/
slevomat/ coding-standard/ SlevomatCodingStandard/ Sniffs/ Commenting/ AnnotationNameSniff.php, line 28
Namespace
SlevomatCodingStandard\Sniffs\CommentingView source
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 $annotations;
/** @var array<string, string>|null */
private $normalizedAnnotations;
/**
* @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();
$phpcsFile->fixer
->replaceToken($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 function (string $annotationName) : string {
return ltrim($annotationName, '@');
}, SniffSettingsHelper::normalizeArray($this->annotations));
}
else {
$annotationNames = array_merge(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 function (string $annotationName) : string {
return '@' . $annotationName;
}, array_unique($annotationNames));
$this->normalizedAnnotations = array_combine(array_map(static function (string $annotationName) : string {
return strtolower($annotationName);
}, $annotationNames), $annotationNames);
return $this->normalizedAnnotations;
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title |
---|---|---|---|---|
AnnotationNameSniff::$annotations | public | property | @var list<string>|null | |
AnnotationNameSniff::$normalizedAnnotations | private | property | @var array<string, string>|null | |
AnnotationNameSniff::CODE_ANNOTATION_NAME_INCORRECT | public | constant | ||
AnnotationNameSniff::getNormalizedAnnotationNames | private | function | * | |
AnnotationNameSniff::PHPUNIT_ANNOTATIONS | private | constant | ||
AnnotationNameSniff::process | public | function | * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint * |
Overrides Sniff::process |
AnnotationNameSniff::register | public | function | * | Overrides Sniff::register |
AnnotationNameSniff::STANDARD_ANNOTATIONS | private | constant | ||
AnnotationNameSniff::STATIC_ANALYSIS_ANNOTATIONS | private | constant |