�ɲɾ�����ӯ�����һ��ˣ��������С���˴��ͣ�������P���ҹ��ñ˽��ά�Բ��������˸߸ԣ�������ơ��ҹ��ñ�����ά�Բ���ˡ���˳^�ӣ������ӡ�
���ͯj�ӣ��ƺ���ӣ�
? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!PK 41] Q coding-standard/composer.jsonnu [ {
"name": "slevomat/coding-standard",
"description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.",
"license": "MIT",
"type": "phpcodesniffer-standard",
"keywords": [ "phpcs", "dev" ],
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"bin-dir": "bin",
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"require": {
"php": "^7.4 || ^8.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2",
"phpstan/phpdoc-parser": "^2.3.0",
"squizlabs/php_codesniffer": "^3.13.4"
},
"require-dev": {
"phing/phing": "3.0.1|3.1.0",
"php-parallel-lint/php-parallel-lint": "1.4.0",
"phpstan/phpstan": "2.1.24",
"phpstan/phpstan-deprecation-rules": "2.0.3",
"phpstan/phpstan-phpunit": "2.0.7",
"phpstan/phpstan-strict-rules": "2.0.6",
"phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.36|12.3.10"
},
"autoload": {
"psr-4": {
"SlevomatCodingStandard\\": "SlevomatCodingStandard/"
}
},
"autoload-dev": {
"psr-4": {
"SlevomatCodingStandard\\PHPStan\\": "build/PHPStan/",
"SlevomatCodingStandard\\": "tests/"
}
},
"extra": {
"branch-alias": {
"dev-master": "8.x-dev"
}
}
}
PK 41]Ӓl 2 coding-standard/SlevomatCodingStandard/ruleset.xmlnu [
./../autoload-bootstrap.php
PK 41]^ˏ c coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowMultipleAttributesPerLineSniff.phpnu [
*/
public function register(): array
{
return [T_ATTRIBUTE];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $attributeOpenerPointer
*/
public function process(File $phpcsFile, $attributeOpenerPointer): void
{
if (!AttributeHelper::isValidAttribute($phpcsFile, $attributeOpenerPointer)) {
return;
}
$tokens = $phpcsFile->getTokens();
$attributeCloserPointer = $tokens[$attributeOpenerPointer]['attribute_closer'];
$nextAttributeOpenerPointer = TokenHelper::findNext($phpcsFile, T_ATTRIBUTE, $attributeCloserPointer + 1);
if ($nextAttributeOpenerPointer === null) {
return;
}
if ($tokens[$attributeCloserPointer]['line'] !== $tokens[$nextAttributeOpenerPointer]['line']) {
return;
}
$attributeTargetPointer = AttributeHelper::getAttributeTarget($phpcsFile, $attributeOpenerPointer);
$nextAttributeTargetPointer = AttributeHelper::getAttributeTarget($phpcsFile, $nextAttributeOpenerPointer);
if ($attributeTargetPointer !== $nextAttributeTargetPointer) {
return;
}
$fix = $phpcsFile->addFixableError(
'Multiple attributes per line are disallowed.',
$nextAttributeOpenerPointer,
self::CODE_DISALLOWED_MULTIPLE_ATTRIBUTES_PER_LINE,
);
if (!$fix) {
return;
}
$nonWhitespacePointerBefore = TokenHelper::findPreviousNonWhitespace($phpcsFile, $nextAttributeOpenerPointer - 1);
$indentation = IndentationHelper::getIndentation(
$phpcsFile,
TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $attributeOpenerPointer),
);
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $nonWhitespacePointerBefore, $nextAttributeOpenerPointer);
FixerHelper::addBefore($phpcsFile, $nextAttributeOpenerPointer, $phpcsFile->eolChar . $indentation);
$phpcsFile->fixer->endChangeset();
}
}
PK 41]Ѝ> Q coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributesOrderSniff.phpnu [ */
public array $order = [];
public bool $orderAlphabetically = false;
/**
* @return array
*/
public function register(): array
{
return [T_ATTRIBUTE];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $attributeOpenerPointer
*/
public function process(File $phpcsFile, $attributeOpenerPointer): void
{
if (!AttributeHelper::isValidAttribute($phpcsFile, $attributeOpenerPointer)) {
return;
}
if ($this->order === [] && !$this->orderAlphabetically) {
throw new UnexpectedValueException('Neither manual or alphabetical order is set.');
}
if ($this->order !== [] && $this->orderAlphabetically) {
throw new UnexpectedValueException('Only one order can be set.');
}
$this->order = $this->normalizeOrder($this->order);
$tokens = $phpcsFile->getTokens();
$pointerBefore = TokenHelper::findPreviousNonWhitespace($phpcsFile, $attributeOpenerPointer - 1);
if ($tokens[$pointerBefore]['code'] === T_ATTRIBUTE_END) {
return;
}
$attributesGroups = [AttributeHelper::getAttributes($phpcsFile, $attributeOpenerPointer)];
$lastAttributeCloserPointer = $tokens[$attributeOpenerPointer]['attribute_closer'];
do {
$nextPointer = TokenHelper::findNextNonWhitespace($phpcsFile, $lastAttributeCloserPointer + 1);
if ($tokens[$nextPointer]['code'] !== T_ATTRIBUTE) {
break;
}
$attributesGroups[] = AttributeHelper::getAttributes($phpcsFile, $nextPointer);
$lastAttributeCloserPointer = $tokens[$nextPointer]['attribute_closer'];
} while (true);
if ($this->orderAlphabetically) {
$actualOrder = $attributesGroups;
$expectedOrder = $actualOrder;
uasort(
$expectedOrder,
static fn (array $attributesGroup1, array $attributesGroup2): int => strnatcmp(
$attributesGroup1[0]->getName(),
$attributesGroup2[0]->getName(),
),
);
} else {
$actualOrder = [];
foreach ($attributesGroups as $attributesGroupNo => $attributesGroup) {
$attributeName = $this->normalizeAttributeName($attributesGroup[0]->getFullyQualifiedName());
foreach ($this->order as $orderPosition => $attributeNameOnPosition) {
if (
$attributeName === $attributeNameOnPosition
|| (
substr($attributeNameOnPosition, -1) === '\\'
&& strpos($attributeName, $attributeNameOnPosition) === 0
)
|| (
substr($attributeNameOnPosition, -1) === '*'
&& strpos($attributeName, substr($attributeNameOnPosition, 0, -1)) === 0
)
) {
$actualOrder[$attributesGroupNo] = $orderPosition;
continue 2;
}
}
// Unknown order - add to the end
$actualOrder[$attributesGroupNo] = 999;
}
$expectedOrder = $actualOrder;
asort($expectedOrder);
}
if ($expectedOrder === $actualOrder) {
return;
}
$fix = $phpcsFile->addFixableError('Incorrect order of attributes.', $attributeOpenerPointer, self::CODE_INCORRECT_ORDER);
if (!$fix) {
return;
}
$attributesGroupsContent = [];
foreach ($attributesGroups as $attributesGroupNo => $attributesGroup) {
$attributesGroupsContent[$attributesGroupNo] = TokenHelper::getContent(
$phpcsFile,
$attributesGroup[0]->getAttributePointer(),
$tokens[$attributesGroup[0]->getAttributePointer()]['attribute_closer'],
);
}
$areOnSameLine = $tokens[$attributeOpenerPointer]['line'] === $tokens[$lastAttributeCloserPointer]['line'];
$attributesStartPointer = $attributeOpenerPointer;
$attributesEndPointer = $lastAttributeCloserPointer;
$indentation = IndentationHelper::getIndentation($phpcsFile, $attributeOpenerPointer);
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetweenIncluding($phpcsFile, $attributesStartPointer, $attributesEndPointer);
foreach (array_keys($expectedOrder) as $position => $attributesGroupNo) {
if ($areOnSameLine) {
if ($position !== 0) {
FixerHelper::add($phpcsFile, $attributesStartPointer, ' ');
}
FixerHelper::add($phpcsFile, $attributesStartPointer, $attributesGroupsContent[$attributesGroupNo]);
} else {
if ($position !== 0) {
FixerHelper::add($phpcsFile, $attributesStartPointer, $indentation);
}
FixerHelper::add($phpcsFile, $attributesStartPointer, $attributesGroupsContent[$attributesGroupNo]);
if ($position !== count($attributesGroups) - 1) {
$phpcsFile->fixer->addNewline($attributesStartPointer);
}
}
}
$phpcsFile->fixer->endChangeset();
}
/**
* @param list $order
* @return list
*/
private function normalizeOrder(array $order): array
{
return array_map(fn (string $item): string => $this->normalizeAttributeName(trim($item)), $order);
}
private function normalizeAttributeName(string $name): string
{
return ltrim($name, '\\');
}
}
PK 41]`7 7 [ coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowAttributesJoiningSniff.phpnu [
*/
public function register(): array
{
return [T_ATTRIBUTE];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $attributeOpenerPointer
*/
public function process(File $phpcsFile, $attributeOpenerPointer): void
{
if (!AttributeHelper::isValidAttribute($phpcsFile, $attributeOpenerPointer)) {
return;
}
$attributes = AttributeHelper::getAttributes($phpcsFile, $attributeOpenerPointer);
$attributeCount = count($attributes);
if ($attributeCount === 1) {
return;
}
$fix = $phpcsFile->addFixableError(
sprintf('%d attributes are joined.', $attributeCount),
$attributeOpenerPointer,
self::CODE_DISALLOWED_ATTRIBUTES_JOINING,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
for ($i = 1; $i < count($attributes); $i++) {
$previousAttribute = $attributes[$i - 1];
$attribute = $attributes[$i];
FixerHelper::add($phpcsFile, $previousAttribute->getEndPointer(), ']');
for ($j = $previousAttribute->getEndPointer() + 1; $j < $attribute->getStartPointer(); $j++) {
if ($phpcsFile->fixer->getTokenContent($j) === ',') {
FixerHelper::replace($phpcsFile, $j, '');
}
}
FixerHelper::addBefore($phpcsFile, $attribute->getStartPointer(), '#[');
}
$phpcsFile->fixer->endChangeset();
}
}
PK 41]ra&< [ coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributeAndTargetSpacingSniff.phpnu [
*/
public function register(): array
{
return [T_ATTRIBUTE];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $attributeOpenerPointer
*/
public function process(File $phpcsFile, $attributeOpenerPointer): void
{
$this->linesCount = SniffSettingsHelper::normalizeInteger($this->linesCount);
if (!AttributeHelper::isValidAttribute($phpcsFile, $attributeOpenerPointer)) {
return;
}
$tokens = $phpcsFile->getTokens();
$attributeCloserPointer = $tokens[$attributeOpenerPointer]['attribute_closer'];
$pointerAfter = TokenHelper::findNextNonWhitespace($phpcsFile, $attributeCloserPointer + 1);
while ($tokens[$pointerAfter]['code'] === T_COMMENT) {
$pointerAfter = TokenHelper::findNextNonWhitespace($phpcsFile, $pointerAfter + 1);
}
if ($tokens[$pointerAfter]['code'] === T_ATTRIBUTE) {
return;
}
$areOnSameLine = $tokens[$pointerAfter]['line'] === $tokens[$attributeCloserPointer]['line'];
if ($areOnSameLine) {
if ($this->allowOnSameLine) {
return;
}
$errorMessage = $this->linesCount === 1
? 'Expected 1 blank line between attribute and its target, both are on same line.'
: sprintf('Expected %1$d blank lines between attribute and its target, both are on same line.', $this->linesCount);
} else {
$actualLinesCount = $tokens[$pointerAfter]['line'] - $tokens[$attributeCloserPointer]['line'] - 1;
if ($this->linesCount === $actualLinesCount) {
return;
}
$errorMessage = $this->linesCount === 1
? sprintf('Expected 1 blank line between attribute and its target, found %1$d.', $actualLinesCount)
: sprintf('Expected %1$d blank lines between attribute and its target, found %2$d.', $this->linesCount, $actualLinesCount);
}
$fix = $phpcsFile->addFixableError(
$errorMessage,
$attributeOpenerPointer,
self::CODE_INCORRECT_LINES_COUNT_BETWEEN_ATTRIBUTE_AND_TARGET,
);
if (!$fix) {
return;
}
if ($areOnSameLine) {
$indentation = IndentationHelper::getIndentation(
$phpcsFile,
TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $pointerAfter),
);
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeWhitespaceAfter($phpcsFile, $attributeCloserPointer);
FixerHelper::addBefore($phpcsFile, $pointerAfter, str_repeat($phpcsFile->eolChar, $this->linesCount + 1) . $indentation);
$phpcsFile->fixer->endChangeset();
return;
}
$firstTokenOnLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $pointerAfter);
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $attributeCloserPointer, $firstTokenOnLine);
FixerHelper::addBefore($phpcsFile, $firstTokenOnLine, str_repeat($phpcsFile->eolChar, $this->linesCount + 1));
$phpcsFile->fixer->endChangeset();
}
}
PK 41]<
a coding-standard/SlevomatCodingStandard/Sniffs/Attributes/RequireAttributeAfterDocCommentSniff.phpnu [
*/
public function register(): array
{
return [T_ATTRIBUTE];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $attributeOpenerPointer
*/
public function process(File $phpcsFile, $attributeOpenerPointer): void
{
if (!AttributeHelper::isValidAttribute($phpcsFile, $attributeOpenerPointer)) {
return;
}
$tokens = $phpcsFile->getTokens();
$docCommentOpenerPointer = TokenHelper::findNextExcluding(
$phpcsFile,
T_WHITESPACE,
$tokens[$attributeOpenerPointer]['attribute_closer'] + 1,
);
if ($tokens[$docCommentOpenerPointer]['code'] !== T_DOC_COMMENT_OPEN_TAG) {
return;
}
$docCommentStartPointer = TokenHelper::findFirstTokenOnLine($phpcsFile, $docCommentOpenerPointer);
$docCommentEndPointer = TokenHelper::findLastTokenOnLine($phpcsFile, $tokens[$docCommentOpenerPointer]['comment_closer']);
$docComment = TokenHelper::getContent($phpcsFile, $docCommentStartPointer, $docCommentEndPointer);
$firstAttributeOpenerPointer = $attributeOpenerPointer;
do {
$nonWhitespacePointerBefore = TokenHelper::findPreviousNonWhitespace($phpcsFile, $firstAttributeOpenerPointer - 1);
if ($tokens[$nonWhitespacePointerBefore]['code'] !== T_ATTRIBUTE_END) {
break;
}
$firstAttributeOpenerPointer = $tokens[$nonWhitespacePointerBefore]['attribute_opener'];
} while (true);
$attributeStartPointer = TokenHelper::findFirstTokenOnLine($phpcsFile, $firstAttributeOpenerPointer);
$fix = $phpcsFile->addFixableError(
'Attribute should be placed after documentation comment.',
$attributeOpenerPointer,
self::CODE_ATTRIBUTE_BEFORE_DOC_COMMENT,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::addBefore($phpcsFile, $attributeStartPointer, $docComment);
FixerHelper::removeBetweenIncluding($phpcsFile, $docCommentStartPointer, $docCommentEndPointer);
$phpcsFile->fixer->endChangeset();
}
}
PK 41][XbPa a W coding-standard/SlevomatCodingStandard/Sniffs/Operators/DisallowEqualOperatorsSniff.phpnu [
*/
public function register(): array
{
return [
T_IS_EQUAL,
T_IS_NOT_EQUAL,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $operatorPointer
*/
public function process(File $phpcsFile, $operatorPointer): void
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$operatorPointer]['code'] === T_IS_EQUAL) {
$fix = $phpcsFile->addFixableError(
'Operator == is disallowed, use === instead.',
$operatorPointer,
self::CODE_DISALLOWED_EQUAL_OPERATOR,
);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $operatorPointer, '===');
$phpcsFile->fixer->endChangeset();
}
} else {
$fix = $phpcsFile->addFixableError(sprintf(
'Operator %s is disallowed, use !== instead.',
$tokens[$operatorPointer]['content'],
), $operatorPointer, self::CODE_DISALLOWED_NOT_EQUAL_OPERATOR);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $operatorPointer, '!==');
$phpcsFile->fixer->endChangeset();
}
}
}
}
PK 41]gC) t coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireOnlyStandaloneIncrementAndDecrementOperatorsSniff.phpnu [
*/
public function register(): array
{
return [
T_DEC,
T_INC,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $operatorPointer
*/
public function process(File $phpcsFile, $operatorPointer): void
{
$tokens = $phpcsFile->getTokens();
/** @var int $nextPointer */
$nextPointer = TokenHelper::findNextEffective($phpcsFile, $operatorPointer + 1);
$afterVariableEndPointer = IdentificatorHelper::findEndPointer($phpcsFile, $nextPointer);
$isPostOperator = $afterVariableEndPointer === null;
if ($isPostOperator) {
/** @var int $beforeVariableEndPointer */
$beforeVariableEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $operatorPointer - 1);
/** @var int $instructionStartPointer */
$instructionStartPointer = IdentificatorHelper::findStartPointer($phpcsFile, $beforeVariableEndPointer);
$instructionEndPointer = $operatorPointer;
} else {
$instructionStartPointer = $operatorPointer;
/** @var int $instructionEndPointer */
$instructionEndPointer = $afterVariableEndPointer;
}
if ($this->isStandalone($phpcsFile, $instructionStartPointer, $instructionEndPointer)) {
return;
}
if ($tokens[$operatorPointer]['code'] === T_INC) {
if ($isPostOperator) {
$code = self::CODE_POST_INCREMENT_OPERATOR_NOT_USED_STANDALONE;
$message = 'Post-increment operator should be used only as single instruction.';
} else {
$code = self::CODE_PRE_INCREMENT_OPERATOR_NOT_USED_STANDALONE;
$message = 'Pre-increment operator should be used only as single instruction.';
}
} else {
if ($isPostOperator) {
$code = self::CODE_POST_DECREMENT_OPERATOR_NOT_USED_STANDALONE;
$message = 'Post-decrement operator should be used only as single instruction.';
} else {
$code = self::CODE_PRE_DECREMENT_OPERATOR_NOT_USED_STANDALONE;
$message = 'Pre-decrement operator should be used only as single instruction.';
}
}
$phpcsFile->addError($message, $operatorPointer, $code);
}
private function isStandalone(File $phpcsFile, int $instructionStartPointer, int $instructionEndPointer): bool
{
$tokens = $phpcsFile->getTokens();
$pointerBeforeInstructionStart = TokenHelper::findPreviousEffective($phpcsFile, $instructionStartPointer - 1);
if (!in_array(
$tokens[$pointerBeforeInstructionStart]['code'],
[T_SEMICOLON, T_COLON, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_OPEN_TAG],
true,
)) {
return false;
}
$pointerAfterInstructionEnd = TokenHelper::findNextEffective($phpcsFile, $instructionEndPointer + 1);
if ($tokens[$pointerAfterInstructionEnd]['code'] === T_SEMICOLON) {
return true;
}
if ($tokens[$pointerAfterInstructionEnd]['code'] === T_CLOSE_PARENTHESIS) {
return array_key_exists('parenthesis_owner', $tokens[$pointerAfterInstructionEnd])
&& in_array($tokens[$tokens[$pointerAfterInstructionEnd]['parenthesis_owner']]['code'], [T_FOR, T_WHILE], true);
}
return false;
}
}
PK 41],=/ / b coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireCombinedAssignmentOperatorSniff.phpnu [
*/
public function register(): array
{
return [
T_EQUAL,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $equalPointer
*/
public function process(File $phpcsFile, $equalPointer): void
{
$tokens = $phpcsFile->getTokens();
/** @var int $variableStartPointer */
$variableStartPointer = TokenHelper::findNextEffective($phpcsFile, $equalPointer + 1);
$variableEndPointer = IdentificatorHelper::findEndPointer($phpcsFile, $variableStartPointer);
if ($variableEndPointer === null) {
return;
}
$operatorPointer = TokenHelper::findNextEffective($phpcsFile, $variableEndPointer + 1);
$operators = [
T_BITWISE_AND => '&=',
T_BITWISE_OR => '|=',
T_STRING_CONCAT => '.=',
T_DIVIDE => '/=',
T_MINUS => '-=',
T_POW => '**=',
T_MODULUS => '%=',
T_MULTIPLY => '*=',
T_PLUS => '+=',
T_SL => '<<=',
T_SR => '>>=',
T_BITWISE_XOR => '^=',
];
if (!array_key_exists($tokens[$operatorPointer]['code'], $operators)) {
return;
}
$isFixable = true;
if ($tokens[$variableEndPointer]['code'] === T_CLOSE_SQUARE_BRACKET) {
$pointerAfterOperator = TokenHelper::findNextEffective($phpcsFile, $operatorPointer + 1);
if (in_array(
$tokens[$pointerAfterOperator]['code'],
[T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_QUOTED_STRING, T_START_HEREDOC, T_START_NOWDOC],
true,
)) {
return;
}
$isFixable = in_array($tokens[$pointerAfterOperator]['code'], [T_LNUMBER, T_DNUMBER], true);
}
$variableContent = IdentificatorHelper::getContent($phpcsFile, $variableStartPointer, $variableEndPointer);
/** @var int $beforeEqualEndPointer */
$beforeEqualEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $equalPointer - 1);
$beforeEqualStartPointer = IdentificatorHelper::findStartPointer($phpcsFile, $beforeEqualEndPointer);
if ($beforeEqualStartPointer === null) {
return;
}
$beforeEqualVariableContent = IdentificatorHelper::getContent($phpcsFile, $beforeEqualStartPointer, $beforeEqualEndPointer);
if ($beforeEqualVariableContent !== $variableContent) {
return;
}
$semicolonPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $equalPointer + 1);
if (TokenHelper::findNext($phpcsFile, Tokens::$operators, $operatorPointer + 1, $semicolonPointer) !== null) {
return;
}
$errorMessage = sprintf(
'Use "%s" operator instead of "=" and "%s".',
$operators[$tokens[$operatorPointer]['code']],
$tokens[$operatorPointer]['content'],
);
if (!$isFixable) {
$phpcsFile->addError($errorMessage, $equalPointer, self::CODE_REQUIRED_COMBINED_ASSIGNMENT_OPERATOR);
return;
}
$fix = $phpcsFile->addFixableError($errorMessage, $equalPointer, self::CODE_REQUIRED_COMBINED_ASSIGNMENT_OPERATOR);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::change($phpcsFile, $equalPointer, $operatorPointer, $operators[$tokens[$operatorPointer]['code']]);
$phpcsFile->fixer->endChangeset();
}
}
PK 41]1
V coding-standard/SlevomatCodingStandard/Sniffs/Operators/SpreadOperatorSpacingSniff.phpnu [
*/
public function register(): array
{
return [
T_ELLIPSIS,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $spreadOperatorPointer
*/
public function process(File $phpcsFile, $spreadOperatorPointer): void
{
$this->spacesCountAfterOperator = SniffSettingsHelper::normalizeInteger($this->spacesCountAfterOperator);
$pointerAfterWhitespace = TokenHelper::findNextNonWhitespace($phpcsFile, $spreadOperatorPointer + 1);
$whitespace = TokenHelper::getContent($phpcsFile, $spreadOperatorPointer + 1, $pointerAfterWhitespace - 1);
if ($this->spacesCountAfterOperator === strlen($whitespace)) {
return;
}
$errorMessage = $this->spacesCountAfterOperator === 0
? 'There must be no whitespace after spread operator.'
: sprintf(
'There must be exactly %d whitespace%s after spread operator.',
$this->spacesCountAfterOperator,
$this->spacesCountAfterOperator !== 1 ? 's' : '',
);
$fix = $phpcsFile->addFixableError($errorMessage, $spreadOperatorPointer, self::CODE_INCORRECT_SPACES_AFTER_OPERATOR);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::add(
$phpcsFile,
$spreadOperatorPointer,
str_repeat(' ', $this->spacesCountAfterOperator),
);
FixerHelper::removeBetween($phpcsFile, $spreadOperatorPointer, $pointerAfterWhitespace);
$phpcsFile->fixer->endChangeset();
}
}
PK 41]V8: : X coding-standard/SlevomatCodingStandard/Sniffs/Operators/NegationOperatorSpacingSniff.phpnu [
*/
public function register(): array
{
return [T_MINUS];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): void
{
$this->spacesCount = SniffSettingsHelper::normalizeInteger($this->spacesCount);
$tokens = $phpcsFile->getTokens();
$previousEffective = TokenHelper::findPreviousEffective($phpcsFile, $pointer - 1);
$possibleOperandTypes = [
...TokenHelper::ONLY_NAME_TOKEN_CODES,
T_CONSTANT_ENCAPSED_STRING,
T_CLASS_C,
T_CLOSE_PARENTHESIS,
T_CLOSE_SHORT_ARRAY,
T_CLOSE_SQUARE_BRACKET,
T_DIR,
T_DNUMBER,
T_ENCAPSED_AND_WHITESPACE,
T_FILE,
T_FUNC_C,
T_LINE,
T_LNUMBER,
T_METHOD_C,
T_NS_C,
T_NUM_STRING,
T_TRAIT_C,
T_VARIABLE,
];
if (in_array($tokens[$previousEffective]['code'], $possibleOperandTypes, true)) {
return;
}
$possibleVariableStartPointer = IdentificatorHelper::findStartPointer($phpcsFile, $previousEffective);
if ($possibleVariableStartPointer !== null) {
return;
}
$whitespacePointer = $pointer + 1;
$numberOfSpaces = $tokens[$whitespacePointer]['code'] !== T_WHITESPACE ? 0 : strlen($tokens[$whitespacePointer]['content']);
if ($numberOfSpaces === $this->spacesCount) {
return;
}
$fix = $phpcsFile->addFixableError(
sprintf(
'Expected exactly %d space after "%s", %d found.',
$this->spacesCount,
$tokens[$pointer]['content'],
$numberOfSpaces,
),
$pointer,
self::CODE_INVALID_SPACE_AFTER_MINUS,
);
if (!$fix) {
return;
}
if ($this->spacesCount > $numberOfSpaces) {
FixerHelper::add($phpcsFile, $pointer, ' ');
return;
}
FixerHelper::replace($phpcsFile, $whitespacePointer, '');
}
}
PK 41]o2
g coding-standard/SlevomatCodingStandard/Sniffs/Operators/DisallowIncrementAndDecrementOperatorsSniff.phpnu [
*/
public function register(): array
{
return [
T_DEC,
T_INC,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $operatorPointer
*/
public function process(File $phpcsFile, $operatorPointer): void
{
$tokens = $phpcsFile->getTokens();
/** @var int $nextPointer */
$nextPointer = TokenHelper::findNextEffective($phpcsFile, $operatorPointer + 1);
$afterVariableEndPointer = IdentificatorHelper::findEndPointer($phpcsFile, $nextPointer);
$isPostOperator = $afterVariableEndPointer === null;
if ($tokens[$operatorPointer]['code'] === T_INC) {
if ($isPostOperator) {
$code = self::CODE_DISALLOWED_POST_INCREMENT_OPERATOR;
$message = 'Use of post-increment operator is disallowed.';
} else {
$code = self::CODE_DISALLOWED_PRE_INCREMENT_OPERATOR;
$message = 'Use of pre-increment operator is disallowed.';
}
} else {
if ($isPostOperator) {
$code = self::CODE_DISALLOWED_POST_DECREMENT_OPERATOR;
$message = 'Use of post-decrement operator is disallowed.';
} else {
$code = self::CODE_DISALLOWED_PRE_DECREMENT_OPERATOR;
$message = 'Use of pre-decrement operator is disallowed.';
}
}
$phpcsFile->addError($message, $operatorPointer, $code);
}
}
PK 41]#Rg g R coding-standard/SlevomatCodingStandard/Sniffs/Whitespaces/DuplicateSpacesSniff.phpnu [
*/
public function register(): array
{
return [
T_WHITESPACE,
T_DOC_COMMENT_WHITESPACE,
T_DOC_COMMENT_STRING,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $whitespacePointer
*/
public function process(File $phpcsFile, $whitespacePointer): void
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$whitespacePointer]['column'] === 1) {
return;
}
$content = $tokens[$whitespacePointer]['content'];
if ($content === $phpcsFile->eolChar) {
return;
}
if ($tokens[$whitespacePointer]['code'] === T_WHITESPACE) {
if ($this->ignoreSpacesBeforeAssignment) {
$pointerAfter = TokenHelper::findNextNonWhitespace($phpcsFile, $whitespacePointer + 1);
if (
$pointerAfter !== null
&& in_array($tokens[$pointerAfter]['code'], Tokens::$assignmentTokens, true)
) {
return;
}
}
if ($this->ignoreSpacesInParameters) {
$pointerAfter = TokenHelper::findNextNonWhitespace($phpcsFile, $whitespacePointer + 1);
if (
$pointerAfter !== null
&& $tokens[$pointerAfter]['code'] === T_VARIABLE
&& ParameterHelper::isParameter($phpcsFile, $pointerAfter)
) {
return;
}
}
if ($this->ignoreSpacesInMatch) {
$pointerAfter = TokenHelper::findNextNonWhitespace($phpcsFile, $whitespacePointer + 1);
if (
$pointerAfter !== null
&& $tokens[$pointerAfter]['code'] === T_MATCH_ARROW
) {
return;
}
}
} else {
if ($this->ignoreSpacesInComment) {
return;
}
if (
$tokens[$whitespacePointer - 1]['code'] === T_DOC_COMMENT_STAR
&& $tokens[$whitespacePointer + 1]['code'] === T_DOC_COMMENT_STRING
) {
return;
}
if ($this->ignoreSpacesInAnnotation) {
$pointerBefore = TokenHelper::findPrevious($phpcsFile, [T_DOC_COMMENT_OPEN_TAG, T_DOC_COMMENT_TAG], $whitespacePointer - 1);
if (
$pointerBefore !== null
&& $tokens[$pointerBefore]['code'] === T_DOC_COMMENT_TAG
&& $tokens[$whitespacePointer + 1]['code'] !== T_DOC_COMMENT_CLOSE_TAG
) {
return;
}
}
}
$matchResult = preg_match_all('~ {2,}~', $content, $matches, PREG_OFFSET_CAPTURE);
if ($matchResult === false || $matchResult === 0) {
return;
}
$fix = false;
foreach ($matches[0] as [$match, $offset]) {
$position = $tokens[$whitespacePointer]['column'] + $offset;
$fixable = $phpcsFile->addFixableError(
sprintf('Duplicate spaces at position %d.', $position),
$whitespacePointer,
self::CODE_DUPLICATE_SPACES,
);
if ($fixable) {
$fix = true;
}
}
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $whitespacePointer, preg_replace('~ {2,}~', ' ', $content));
$phpcsFile->fixer->endChangeset();
}
}
PK 41]Rg R coding-standard/SlevomatCodingStandard/Sniffs/Files/FilepathNamespaceExtractor.phpnu [ */
private array $rootNamespaces;
/** @var array dir(string) => true(bool) */
private array $skipDirs;
/** @var list */
private array $extensions;
/**
* @param array $rootNamespaces directory(string) => namespace
* @param list $skipDirs
* @param list $extensions index(integer) => extension
*/
public function __construct(array $rootNamespaces, array $skipDirs, array $extensions)
{
$this->rootNamespaces = $rootNamespaces;
$this->skipDirs = array_fill_keys($skipDirs, true);
$this->extensions = array_map(static fn (string $extension): string => strtolower($extension), $extensions);
}
public function getTypeNameFromProjectPath(string $path): ?string
{
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
if (!in_array($extension, $this->extensions, true)) {
return null;
}
/** @var list $pathParts */
$pathParts = preg_split('~[/\\\]~', $path);
$rootNamespace = null;
while (count($pathParts) > 0) {
array_shift($pathParts);
foreach ($this->rootNamespaces as $directory => $namespace) {
if (!StringHelper::startsWith(implode('/', $pathParts) . '/', $directory . '/')) {
continue;
}
$directoryPartsCount = count(explode('/', $directory));
for ($i = 0; $i < $directoryPartsCount; $i++) {
array_shift($pathParts);
}
$rootNamespace = $namespace;
break 2;
}
}
if ($rootNamespace === null) {
return null;
}
array_unshift($pathParts, $rootNamespace);
$typeName = implode('\\', array_filter($pathParts, fn (string $pathPart): bool => !isset($this->skipDirs[$pathPart])));
return substr($typeName, 0, -strlen('.' . $extension));
}
}
PK 41]: : G coding-standard/SlevomatCodingStandard/Sniffs/Files/FileLengthSniff.phpnu [
*/
public function register(): array
{
return [T_OPEN_TAG];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): void
{
$this->maxLinesLength = SniffSettingsHelper::normalizeInteger($this->maxLinesLength);
$flags = array_keys(array_filter([
FunctionHelper::LINE_INCLUDE_COMMENT => $this->includeComments,
FunctionHelper::LINE_INCLUDE_WHITESPACE => $this->includeWhitespace,
]));
$flags = array_reduce($flags, static fn ($carry, $flag): int => $carry | $flag, 0);
$length = FunctionHelper::getLineCount($phpcsFile, $pointer, $flags);
if ($length <= $this->maxLinesLength) {
return;
}
$errorMessage = sprintf('Your file is too long. Currently using %d lines. Can be up to %d lines.', $length, $this->maxLinesLength);
$phpcsFile->addError($errorMessage, $pointer, self::CODE_FILE_TOO_LONG);
}
}
PK 41]pY T coding-standard/SlevomatCodingStandard/Sniffs/Files/TypeNameMatchesFileNameSniff.phpnu [ */
public array $rootNamespaces = [];
/** @var list */
public array $skipDirs = [];
/** @var list */
public array $ignoredNamespaces = [];
/** @var list */
public array $extensions = ['php'];
/** @var array|null */
private ?array $normalizedRootNamespaces = null;
/** @var list|null */
private ?array $normalizedSkipDirs = null;
/** @var list|null */
private ?array $normalizedIgnoredNamespaces = null;
/** @var list|null */
private ?array $normalizedExtensions = null;
private ?FilepathNamespaceExtractor $namespaceExtractor = null;
/**
* @return array
*/
public function register(): array
{
return TokenHelper::CLASS_TYPE_TOKEN_CODES;
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $typePointer
*/
public function process(File $phpcsFile, $typePointer): void
{
$tokens = $phpcsFile->getTokens();
/** @var int $namePointer */
$namePointer = TokenHelper::findNext($phpcsFile, T_STRING, $typePointer + 1);
$typeName = NamespaceHelper::normalizeToCanonicalName(ClassHelper::getFullyQualifiedName($phpcsFile, $typePointer));
foreach ($this->getIgnoredNamespaces() as $ignoredNamespace) {
if (!StringHelper::startsWith($typeName, $ignoredNamespace . '\\')) {
continue;
}
return;
}
$filename = str_replace('/', DIRECTORY_SEPARATOR, $phpcsFile->getFilename());
$basePath = str_replace('/', DIRECTORY_SEPARATOR, $phpcsFile->config->basepath ?? '');
if ($basePath !== '' && StringHelper::startsWith($filename, $basePath)) {
$filename = substr($filename, strlen($basePath));
}
$expectedTypeName = $this->getNamespaceExtractor()->getTypeNameFromProjectPath($filename);
if ($typeName === $expectedTypeName) {
return;
}
$phpcsFile->addError(
sprintf(
'%s name %s does not match filepath %s.',
ucfirst($tokens[$typePointer]['content']),
$typeName,
$phpcsFile->getFilename(),
),
$namePointer,
self::CODE_NO_MATCH_BETWEEN_TYPE_NAME_AND_FILE_NAME,
);
}
/**
* @return array path(string) => namespace
*/
private function getRootNamespaces(): array
{
if ($this->normalizedRootNamespaces === null) {
/** @var array $normalizedRootNamespaces */
$normalizedRootNamespaces = SniffSettingsHelper::normalizeAssociativeArray($this->rootNamespaces);
$this->normalizedRootNamespaces = $normalizedRootNamespaces;
uksort($this->normalizedRootNamespaces, static function (string $a, string $b): int {
$aParts = explode('/', str_replace('\\', '/', $a));
$bParts = explode('/', str_replace('\\', '/', $b));
$minPartsCount = min(count($aParts), count($bParts));
for ($i = 0; $i < $minPartsCount; $i++) {
$comparison = strcasecmp($bParts[$i], $aParts[$i]);
if ($comparison === 0) {
continue;
}
return $comparison;
}
return count($bParts) <=> count($aParts);
});
}
return $this->normalizedRootNamespaces;
}
/**
* @return list
*/
private function getSkipDirs(): array
{
$this->normalizedSkipDirs ??= SniffSettingsHelper::normalizeArray($this->skipDirs);
return $this->normalizedSkipDirs;
}
/**
* @return list
*/
private function getIgnoredNamespaces(): array
{
$this->normalizedIgnoredNamespaces ??= SniffSettingsHelper::normalizeArray($this->ignoredNamespaces);
return $this->normalizedIgnoredNamespaces;
}
/**
* @return list
*/
private function getExtensions(): array
{
$this->normalizedExtensions ??= SniffSettingsHelper::normalizeArray($this->extensions);
return $this->normalizedExtensions;
}
private function getNamespaceExtractor(): FilepathNamespaceExtractor
{
$this->namespaceExtractor ??= new FilepathNamespaceExtractor(
$this->getRootNamespaces(),
$this->getSkipDirs(),
$this->getExtensions(),
);
return $this->namespaceExtractor;
}
}
PK 41]=
G coding-standard/SlevomatCodingStandard/Sniffs/Files/LineLengthSniff.phpnu [
*/
public function register(): array
{
return [T_OPEN_TAG];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): int
{
$tokens = $phpcsFile->getTokens();
for ($i = 0; $i < $phpcsFile->numTokens; $i++) {
if ($tokens[$i]['column'] !== 1) {
continue;
}
$this->checkLineLength($phpcsFile, $i);
}
return $phpcsFile->numTokens + 1;
}
private function checkLineLength(File $phpcsFile, int $pointer): void
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$pointer]['column'] === 1 && $tokens[$pointer]['length'] === 0) {
// Blank line.
return;
}
$line = $tokens[$pointer]['line'];
$nextLineStartPtr = $pointer;
while (isset($tokens[$nextLineStartPtr]) && $line === $tokens[$nextLineStartPtr]['line']) {
$pointer = $nextLineStartPtr;
$nextLineStartPtr++;
}
if ($tokens[$pointer]['content'] === $phpcsFile->eolChar) {
$pointer--;
}
$lineLength = $tokens[$pointer]['column'] + $tokens[$pointer]['length'] - 1;
if ($lineLength <= $this->lineLengthLimit) {
return;
}
if (in_array($tokens[$pointer]['code'], [T_COMMENT, T_DOC_COMMENT_STRING], true)) {
if ($this->ignoreComments === true) {
return;
}
// If this is a long comment, check if it can be broken up onto multiple lines.
// Some comments contain unbreakable strings like URLs and so it makes sense
// to ignore the line length in these cases if the URL would be longer than the max
// line length once you indent it to the correct level.
if ($lineLength > $this->lineLengthLimit) {
$oldLength = strlen($tokens[$pointer]['content']);
$newLength = strlen(ltrim($tokens[$pointer]['content'], "/#\t "));
$indent = $tokens[$pointer]['column'] - 1 + $oldLength - $newLength;
$nonBreakingLength = $tokens[$pointer]['length'];
$space = strrpos($tokens[$pointer]['content'], ' ');
if ($space !== false) {
$nonBreakingLength -= $space + 1;
}
if ($nonBreakingLength + $indent > $this->lineLengthLimit) {
return;
}
}
}
if ($this->ignoreImports) {
$usePointer = UseStatementHelper::getUseStatementPointer($phpcsFile, $pointer - 1);
if (
is_int($usePointer)
&& $tokens[$usePointer]['line'] === $tokens[$pointer]['line']
&& UseStatementHelper::isImportUse($phpcsFile, $usePointer)
) {
return;
}
}
$error = sprintf('Line exceeds maximum limit of %s characters, contains %s characters.', $this->lineLengthLimit, $lineLength);
$phpcsFile->addError($error, $pointer, self::CODE_LINE_TOO_LONG);
}
}
PK 41]JL? ? b coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AbstractFullyQualifiedGlobalReference.phpnu [ */
public array $exclude = [];
/** @var list */
public array $include = [];
/** @var list|null */
private ?array $normalizedExclude = null;
/** @var list|null */
private ?array $normalizedInclude = null;
abstract protected function getNotFullyQualifiedMessage(): string;
abstract protected function isCaseSensitive(): bool;
abstract protected function isValidType(ReferencedName $name): bool;
/**
* @return array
*/
public function register(): array
{
return [
T_OPEN_TAG,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $openTagPointer
*/
public function process(File $phpcsFile, $openTagPointer): void
{
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
if (TokenHelper::findNext($phpcsFile, T_OPEN_USE_GROUP, $openTagPointer) !== null) {
return;
}
$tokens = $phpcsFile->getTokens();
$namespacePointers = NamespaceHelper::getAllNamespacesPointers($phpcsFile);
$referencedNames = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer);
$include = array_flip($this->getNormalizedInclude());
$exclude = array_flip($this->getNormalizedExclude());
foreach ($referencedNames as $referencedName) {
$name = $referencedName->getNameAsReferencedInFile();
$namePointer = $referencedName->getStartPointer();
if (!$this->isValidType($referencedName)) {
continue;
}
if (NamespaceHelper::isFullyQualifiedName($name)) {
continue;
}
if (NamespaceHelper::hasNamespace($name)) {
continue;
}
if ($namespacePointers === []) {
continue;
}
$canonicalName = $this->isCaseSensitive() ? $name : strtolower($name);
$useStatements = UseStatementHelper::getUseStatementsForPointer($phpcsFile, $namePointer);
if (array_key_exists(UseStatement::getUniqueId($referencedName->getType(), $canonicalName), $useStatements)) {
$fullyQualifiedName = NamespaceHelper::resolveName($phpcsFile, $name, $referencedName->getType(), $namePointer);
if (NamespaceHelper::hasNamespace($fullyQualifiedName)) {
continue;
}
}
if ($include !== [] && !array_key_exists($canonicalName, $include)) {
continue;
}
if (array_key_exists($canonicalName, $exclude)) {
continue;
}
$fix = $phpcsFile->addFixableError(
sprintf($this->getNotFullyQualifiedMessage(), $tokens[$namePointer]['content']),
$namePointer,
self::CODE_NON_FULLY_QUALIFIED,
);
if (!$fix) {
continue;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::addBefore($phpcsFile, $namePointer, NamespaceHelper::NAMESPACE_SEPARATOR);
$phpcsFile->fixer->endChangeset();
}
}
/**
* @return list
*/
protected function getNormalizedInclude(): array
{
$this->normalizedInclude ??= $this->normalizeNames($this->include);
return $this->normalizedInclude;
}
/**
* @return list
*/
private function getNormalizedExclude(): array
{
$this->normalizedExclude ??= $this->normalizeNames($this->exclude);
return $this->normalizedExclude;
}
/**
* @param list $names
* @return list
*/
private function normalizeNames(array $names): array
{
$names = SniffSettingsHelper::normalizeArray($names);
if (!$this->isCaseSensitive()) {
$names = array_map(static fn (string $name): string => strtolower($name), $names);
}
return $names;
}
}
PK 41]wJB+ B+ L coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseSpacingSniff.phpnu [
*/
public function register(): array
{
return [
T_OPEN_TAG,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $openTagPointer
*/
public function process(File $phpcsFile, $openTagPointer): void
{
$this->linesCountBeforeFirstUse = SniffSettingsHelper::normalizeInteger($this->linesCountBeforeFirstUse);
$this->linesCountBetweenUseTypes = SniffSettingsHelper::normalizeInteger($this->linesCountBetweenUseTypes);
$this->linesCountAfterLastUse = SniffSettingsHelper::normalizeInteger($this->linesCountAfterLastUse);
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
$fileUseStatements = UseStatementHelper::getFileUseStatements($phpcsFile);
if (count($fileUseStatements) === 0) {
return;
}
foreach ($fileUseStatements as $useStatementsByName) {
$useStatements = array_values($useStatementsByName);
$this->checkLinesBeforeFirstUse($phpcsFile, $useStatements[0]);
$this->checkLinesAfterLastUse($phpcsFile, $useStatements[count($useStatements) - 1]);
$this->checkLinesBetweenSameTypesOfUse($phpcsFile, $useStatements);
$this->checkLinesBetweenDifferentTypesOfUse($phpcsFile, $useStatements);
}
}
private function checkLinesBeforeFirstUse(File $phpcsFile, UseStatement $firstUse): void
{
$tokens = $phpcsFile->getTokens();
/** @var int $pointerBeforeFirstUse */
$pointerBeforeFirstUse = TokenHelper::findPreviousNonWhitespace($phpcsFile, $firstUse->getPointer() - 1);
$useStartPointer = $firstUse->getPointer();
if (
in_array($tokens[$pointerBeforeFirstUse]['code'], Tokens::$commentTokens, true)
&& $tokens[$pointerBeforeFirstUse]['line'] + 1 === $tokens[$useStartPointer]['line']
) {
$useStartPointer = array_key_exists('comment_opener', $tokens[$pointerBeforeFirstUse])
? $tokens[$pointerBeforeFirstUse]['comment_opener']
: CommentHelper::getMultilineCommentStartPointer($phpcsFile, $pointerBeforeFirstUse);
/** @var int $pointerBeforeFirstUse */
$pointerBeforeFirstUse = TokenHelper::findPreviousNonWhitespace($phpcsFile, $useStartPointer - 1);
}
$actualLinesCountBeforeFirstUse = $tokens[$useStartPointer]['line'] - $tokens[$pointerBeforeFirstUse]['line'] - 1;
if ($actualLinesCountBeforeFirstUse === $this->linesCountBeforeFirstUse) {
return;
}
$fix = $phpcsFile->addFixableError(
sprintf(
'Expected %d line%s before first use statement, found %d.',
$this->linesCountBeforeFirstUse,
$this->linesCountBeforeFirstUse === 1 ? '' : 's',
$actualLinesCountBeforeFirstUse,
),
$firstUse->getPointer(),
self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
if ($tokens[$pointerBeforeFirstUse]['code'] === T_OPEN_TAG) {
FixerHelper::replace($phpcsFile, $pointerBeforeFirstUse, 'linesCountBeforeFirstUse; $i++) {
$phpcsFile->fixer->addNewline($pointerBeforeFirstUse);
}
$phpcsFile->fixer->endChangeset();
}
private function checkLinesAfterLastUse(File $phpcsFile, UseStatement $lastUse): void
{
$tokens = $phpcsFile->getTokens();
/** @var int $useEndPointer */
$useEndPointer = TokenHelper::findNextLocal($phpcsFile, T_SEMICOLON, $lastUse->getPointer() + 1);
$pointerAfterWhitespaceEnd = TokenHelper::findNextNonWhitespace($phpcsFile, $useEndPointer + 1);
if ($pointerAfterWhitespaceEnd === null) {
return;
}
if (
in_array($tokens[$pointerAfterWhitespaceEnd]['code'], Tokens::$commentTokens, true)
&& $tokens[$pointerAfterWhitespaceEnd]['code'] !== T_DOC_COMMENT_OPEN_TAG
&& (
$tokens[$useEndPointer]['line'] === $tokens[$pointerAfterWhitespaceEnd]['line']
|| $tokens[$useEndPointer]['line'] + 1 === $tokens[$pointerAfterWhitespaceEnd]['line']
)
) {
$useEndPointer = CommentHelper::getMultilineCommentEndPointer($phpcsFile, $pointerAfterWhitespaceEnd);
/** @var int $pointerAfterWhitespaceEnd */
$pointerAfterWhitespaceEnd = TokenHelper::findNextNonWhitespace($phpcsFile, $useEndPointer + 1);
}
$actualLinesCountAfterLastUse = $tokens[$pointerAfterWhitespaceEnd]['line'] - $tokens[$useEndPointer]['line'] - 1;
if ($actualLinesCountAfterLastUse === $this->linesCountAfterLastUse) {
return;
}
$fix = $phpcsFile->addFixableError(
sprintf(
'Expected %d line%s after last use statement, found %d.',
$this->linesCountAfterLastUse,
$this->linesCountAfterLastUse === 1 ? '' : 's',
$actualLinesCountAfterLastUse,
),
$lastUse->getPointer(),
self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $useEndPointer, $pointerAfterWhitespaceEnd);
$linesToAdd = $this->linesCountAfterLastUse;
if (CommentHelper::isLineComment($phpcsFile, $useEndPointer)) {
$linesToAdd--;
}
for ($i = 0; $i <= $linesToAdd; $i++) {
$phpcsFile->fixer->addNewline($useEndPointer);
}
$phpcsFile->fixer->endChangeset();
}
/**
* @param list $useStatements
*/
private function checkLinesBetweenSameTypesOfUse(File $phpcsFile, array $useStatements): void
{
if (count($useStatements) === 1) {
return;
}
$tokens = $phpcsFile->getTokens();
$requiredLinesCountBetweenUses = 0;
$previousUse = null;
foreach ($useStatements as $use) {
if ($previousUse === null) {
$previousUse = $use;
continue;
}
if (!$use->hasSameType($previousUse)) {
$previousUse = null;
continue;
}
/** @var int $pointerBeforeUse */
$pointerBeforeUse = TokenHelper::findPreviousNonWhitespace($phpcsFile, $use->getPointer() - 1);
$useStartPointer = $use->getPointer();
if (
in_array($tokens[$pointerBeforeUse]['code'], Tokens::$commentTokens, true)
&& TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $pointerBeforeUse) === $pointerBeforeUse
&& $tokens[$pointerBeforeUse]['line'] + 1 === $tokens[$useStartPointer]['line']
) {
$useStartPointer = array_key_exists('comment_opener', $tokens[$pointerBeforeUse])
? $tokens[$pointerBeforeUse]['comment_opener']
: CommentHelper::getMultilineCommentStartPointer($phpcsFile, $pointerBeforeUse);
}
$actualLinesCountAfterPreviousUse = $tokens[$useStartPointer]['line'] - $tokens[$previousUse->getPointer()]['line'] - 1;
if ($actualLinesCountAfterPreviousUse === $requiredLinesCountBetweenUses) {
$previousUse = $use;
continue;
}
$fix = $phpcsFile->addFixableError(
sprintf(
'Expected 0 lines between same types of use statement, found %d.',
$actualLinesCountAfterPreviousUse,
),
$use->getPointer(),
self::CODE_INCORRECT_LINES_COUNT_BETWEEN_SAME_TYPES_OF_USE,
);
if (!$fix) {
$previousUse = $use;
continue;
}
/** @var int $previousUseSemicolonPointer */
$previousUseSemicolonPointer = TokenHelper::findNextLocal($phpcsFile, T_SEMICOLON, $previousUse->getPointer() + 1);
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $previousUseSemicolonPointer, $useStartPointer);
$phpcsFile->fixer->addNewline($previousUseSemicolonPointer);
$phpcsFile->fixer->endChangeset();
$previousUse = $use;
}
}
/**
* @param list $useStatements
*/
private function checkLinesBetweenDifferentTypesOfUse(File $phpcsFile, array $useStatements): void
{
if (count($useStatements) === 1) {
return;
}
$tokens = $phpcsFile->getTokens();
$previousUse = null;
foreach ($useStatements as $use) {
if ($previousUse === null) {
$previousUse = $use;
continue;
}
if ($use->hasSameType($previousUse)) {
$previousUse = $use;
continue;
}
/** @var int $pointerBeforeUse */
$pointerBeforeUse = TokenHelper::findPreviousNonWhitespace($phpcsFile, $use->getPointer() - 1);
$useStartPointer = $use->getPointer();
if (
in_array($tokens[$pointerBeforeUse]['code'], Tokens::$commentTokens, true)
&& TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $pointerBeforeUse) === $pointerBeforeUse
&& $tokens[$pointerBeforeUse]['line'] + 1 === $tokens[$useStartPointer]['line']
) {
$useStartPointer = array_key_exists('comment_opener', $tokens[$pointerBeforeUse])
? $tokens[$pointerBeforeUse]['comment_opener']
: CommentHelper::getMultilineCommentStartPointer($phpcsFile, $pointerBeforeUse);
}
$actualLinesCountAfterPreviousUse = $tokens[$useStartPointer]['line'] - $tokens[$previousUse->getPointer()]['line'] - 1;
if ($actualLinesCountAfterPreviousUse === $this->linesCountBetweenUseTypes) {
$previousUse = $use;
continue;
}
$fix = $phpcsFile->addFixableError(
sprintf(
'Expected %d line%s between different types of use statement, found %d.',
$this->linesCountBetweenUseTypes,
$this->linesCountBetweenUseTypes === 1 ? '' : 's',
$actualLinesCountAfterPreviousUse,
),
$use->getPointer(),
self::CODE_INCORRECT_LINES_COUNT_BETWEEN_DIFFERENT_TYPES_OF_USE,
);
if (!$fix) {
$previousUse = $use;
continue;
}
/** @var int $previousUseSemicolonPointer */
$previousUseSemicolonPointer = TokenHelper::findNextLocal($phpcsFile, T_SEMICOLON, $previousUse->getPointer() + 1);
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $previousUseSemicolonPointer, $useStartPointer);
for ($i = 0; $i <= $this->linesCountBetweenUseTypes; $i++) {
$phpcsFile->fixer->addNewline($previousUseSemicolonPointer);
}
$phpcsFile->fixer->endChangeset();
$previousUse = $use;
}
}
}
PK 41])*$ $ L coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UnusedUsesSniff.phpnu [ */
public array $ignoredAnnotationNames = [];
/** @var list */
public array $ignoredAnnotations = [];
/** @var list|null */
private ?array $normalizedIgnoredAnnotationNames = null;
/** @var list|null */
private ?array $normalizedIgnoredAnnotations = null;
/**
* @return array
*/
public function register(): array
{
return [
T_OPEN_TAG,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $openTagPointer
*/
public function process(File $phpcsFile, $openTagPointer): void
{
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
$startPointer = TokenHelper::findPrevious($phpcsFile, T_NAMESPACE, $openTagPointer - 1) ?? $openTagPointer;
$fileUnusedNames = UseStatementHelper::getFileUseStatements($phpcsFile);
$referencedNamesInCode = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $startPointer);
$referencedNamesInAttributes = ReferencedNameHelper::getAllReferencedNamesInAttributes($phpcsFile, $startPointer);
$pointersBeforeUseStatements = array_reverse(NamespaceHelper::getAllNamespacesPointers($phpcsFile));
$allUsedNames = [];
foreach ([$referencedNamesInCode, $referencedNamesInAttributes] as $referencedNames) {
foreach ($referencedNames as $referencedName) {
$pointer = $referencedName->getStartPointer();
$pointerBeforeUseStatements = $this->firstPointerBefore($pointer, $pointersBeforeUseStatements, $startPointer);
$name = $referencedName->getNameAsReferencedInFile();
$nameParts = NamespaceHelper::getNameParts($name);
$nameAsReferencedInFile = $nameParts[0];
$nameReferencedWithoutSubNamespace = count($nameParts) === 1;
$uniqueId = $nameReferencedWithoutSubNamespace
? UseStatement::getUniqueId($referencedName->getType(), $nameAsReferencedInFile)
: UseStatement::getUniqueId(ReferencedName::TYPE_CLASS, $nameAsReferencedInFile);
if (
NamespaceHelper::isFullyQualifiedName($name)
|| !array_key_exists($pointerBeforeUseStatements, $fileUnusedNames)
|| !array_key_exists($uniqueId, $fileUnusedNames[$pointerBeforeUseStatements])
) {
continue;
}
$allUsedNames[$pointerBeforeUseStatements][$uniqueId] = true;
}
}
if ($this->searchAnnotations) {
$tokens = $phpcsFile->getTokens();
$searchAnnotationsPointer = $startPointer + 1;
while (true) {
$docCommentOpenPointer = TokenHelper::findNext($phpcsFile, T_DOC_COMMENT_OPEN_TAG, $searchAnnotationsPointer);
if ($docCommentOpenPointer === null) {
break;
}
$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
if ($annotations === []) {
$searchAnnotationsPointer = $tokens[$docCommentOpenPointer]['comment_closer'] + 1;
continue;
}
$pointerBeforeUseStatements = $this->firstPointerBefore(
$docCommentOpenPointer - 1,
$pointersBeforeUseStatements,
$startPointer,
);
if (!array_key_exists($pointerBeforeUseStatements, $fileUnusedNames)) {
$searchAnnotationsPointer = $tokens[$docCommentOpenPointer]['comment_closer'] + 1;
continue;
}
foreach ($fileUnusedNames[$pointerBeforeUseStatements] as $useStatement) {
if (!$useStatement->isClass()) {
continue;
}
$nameAsReferencedInFile = $useStatement->getNameAsReferencedInFile();
$uniqueId = UseStatement::getUniqueId($useStatement->getType(), $nameAsReferencedInFile);
foreach ($annotations as $annotation) {
if (in_array($annotation->getName(), $this->getIgnoredAnnotations(), true)) {
continue;
}
if ($annotation->isInvalid()) {
continue;
}
$contentsToCheck = [];
if ($annotation->getValue() instanceof GenericTagValueNode) {
$contentsToCheck[] = $annotation->getName();
$contentsToCheck[] = $annotation->getValue()->value;
} else {
$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType(
$annotation->getNode(),
IdentifierTypeNode::class,
);
$doctrineAnnotations = AnnotationHelper::getAnnotationNodesByType(
$annotation->getNode(),
DoctrineAnnotation::class,
);
$constFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
$contentsToCheck = array_filter(array_merge(
$contentsToCheck,
array_map(static function (IdentifierTypeNode $identifierTypeNode): ?string {
if (
TypeHintHelper::isSimpleTypeHint($identifierTypeNode->name)
|| TypeHintHelper::isSimpleUnofficialTypeHints($identifierTypeNode->name)
|| !TypeHelper::isTypeName($identifierTypeNode->name)
) {
return null;
}
return $identifierTypeNode->name;
}, $identifierTypeNodes),
array_map(function (DoctrineAnnotation $doctrineAnnotation): ?string {
if (in_array($doctrineAnnotation->name, $this->getIgnoredAnnotationNames(), true)) {
return null;
}
return $doctrineAnnotation->name;
}, $doctrineAnnotations),
array_map(
static fn (ConstFetchNode $constFetchNode): string => $constFetchNode->className,
$constFetchNodes,
),
), static fn (?string $content): bool => $content !== null);
}
foreach ($contentsToCheck as $contentToCheck) {
if (preg_match(
'~(?<=^|[^a-z\\\\])(' . preg_quote($nameAsReferencedInFile, '~') . ')(?=\\s|::|\\\\|\||\[|$)~im',
$contentToCheck,
) === 0) {
continue;
}
$allUsedNames[$pointerBeforeUseStatements][$uniqueId] = true;
}
}
}
$searchAnnotationsPointer = $tokens[$docCommentOpenPointer]['comment_closer'] + 1;
}
}
foreach ($fileUnusedNames as $pointerBeforeUnusedNames => $unusedNames) {
$usedNames = $allUsedNames[$pointerBeforeUnusedNames] ?? [];
foreach (array_diff_key($unusedNames, $usedNames) as $unusedUse) {
$fullName = $unusedUse->getFullyQualifiedTypeName();
if (
$unusedUse->getNameAsReferencedInFile() !== $fullName
&& $unusedUse->getNameAsReferencedInFile() !== NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($fullName)
) {
$fullName .= sprintf(' (as %s)', $unusedUse->getNameAsReferencedInFile());
}
$fix = $phpcsFile->addFixableError(sprintf(
'Type %s is not used in this file.',
$fullName,
), $unusedUse->getPointer(), self::CODE_UNUSED_USE);
if (!$fix) {
continue;
}
$endPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $unusedUse->getPointer()) + 1;
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetweenIncluding($phpcsFile, $unusedUse->getPointer(), $endPointer);
$phpcsFile->fixer->endChangeset();
}
}
}
/**
* @return list
*/
private function getIgnoredAnnotationNames(): array
{
$this->normalizedIgnoredAnnotationNames ??= array_merge(
SniffSettingsHelper::normalizeArray($this->ignoredAnnotationNames),
[
'@param',
'@throws',
'@property',
'@method',
],
);
return $this->normalizedIgnoredAnnotationNames;
}
/**
* @return list
*/
private function getIgnoredAnnotations(): array
{
$this->normalizedIgnoredAnnotations ??= SniffSettingsHelper::normalizeArray($this->ignoredAnnotations);
return $this->normalizedIgnoredAnnotations;
}
/**
* @param list $pointersBeforeUseStatements
*/
private function firstPointerBefore(int $pointer, array $pointersBeforeUseStatements, int $startPointer): int
{
foreach ($pointersBeforeUseStatements as $pointerBeforeUseStatements) {
if ($pointerBeforeUseStatements < $pointer) {
return $pointerBeforeUseStatements;
}
}
return $startPointer;
}
}
PK 41]V2 2 Z coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedExceptionsSniff.phpnu [ */
public array $specialExceptionNames = [];
/** @var list */
public array $ignoredNames = [];
/** @var list|null */
private ?array $normalizedSpecialExceptionNames = null;
/** @var list|null */
private ?array $normalizedIgnoredNames = null;
/**
* @return array
*/
public function register(): array
{
return [
T_OPEN_TAG,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $openTagPointer
*/
public function process(File $phpcsFile, $openTagPointer): void
{
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
$namespacePointers = array_reverse(NamespaceHelper::getAllNamespacesPointers($phpcsFile));
$referencedNames = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer);
foreach ($referencedNames as $referencedName) {
$pointer = $referencedName->getStartPointer();
$name = $referencedName->getNameAsReferencedInFile();
$uniqueId = UseStatement::getUniqueId($referencedName->getType(), $name);
$useStatements = UseStatementHelper::getUseStatementsForPointer($phpcsFile, $pointer);
if (
isset($useStatements[$uniqueId])
&& $referencedName->hasSameUseStatementType($useStatements[$uniqueId])
) {
$useStatement = $useStatements[$uniqueId];
if (
in_array($useStatement->getFullyQualifiedTypeName(), $this->getIgnoredNames(), true)
|| (
!StringHelper::endsWith($useStatement->getFullyQualifiedTypeName(), 'Exception')
&& $useStatement->getFullyQualifiedTypeName() !== Throwable::class
&& (!StringHelper::endsWith($useStatement->getFullyQualifiedTypeName(), 'Error') || NamespaceHelper::hasNamespace(
$useStatement->getFullyQualifiedTypeName(),
))
&& !in_array($useStatement->getFullyQualifiedTypeName(), $this->getSpecialExceptionNames(), true)
)
) {
continue;
}
} else {
$fileNamespacePointer = null;
if ($namespacePointers !== []) {
foreach ($namespacePointers as $namespacePointer) {
if ($namespacePointer < $pointer) {
$fileNamespacePointer = $namespacePointer;
break;
}
}
}
$fileNamespace = $fileNamespacePointer !== null
? NamespaceHelper::getName($phpcsFile, $fileNamespacePointer)
: null;
$canonicalName = $name;
if (!NamespaceHelper::isFullyQualifiedName($name) && $fileNamespace !== null) {
$canonicalName = sprintf('%s%s%s', $fileNamespace, NamespaceHelper::NAMESPACE_SEPARATOR, $name);
}
if (
in_array($canonicalName, $this->getIgnoredNames(), true)
|| (
!StringHelper::endsWith($name, 'Exception')
&& $name !== Throwable::class
&& (!StringHelper::endsWith($canonicalName, 'Error') || NamespaceHelper::hasNamespace($canonicalName))
&& !in_array($canonicalName, $this->getSpecialExceptionNames(), true)
)
) {
continue;
}
}
if (NamespaceHelper::isFullyQualifiedName($name)) {
continue;
}
$fix = $phpcsFile->addFixableError(sprintf(
'Exception %s should be referenced via a fully qualified name.',
$name,
), $pointer, self::CODE_NON_FULLY_QUALIFIED_EXCEPTION);
if (!$fix) {
continue;
}
$fullyQualifiedName = NamespaceHelper::resolveClassName($phpcsFile, $name, $pointer);
$phpcsFile->fixer->beginChangeset();
FixerHelper::change($phpcsFile, $referencedName->getStartPointer(), $referencedName->getEndPointer(), $fullyQualifiedName);
$phpcsFile->fixer->endChangeset();
}
}
/**
* @return list
*/
private function getSpecialExceptionNames(): array
{
$this->normalizedSpecialExceptionNames ??= SniffSettingsHelper::normalizeArray($this->specialExceptionNames);
return $this->normalizedSpecialExceptionNames;
}
/**
* @return list
*/
private function getIgnoredNames(): array
{
$this->normalizedIgnoredNames ??= SniffSettingsHelper::normalizeArray($this->ignoredNames);
return $this->normalizedIgnoredNames;
}
}
PK 41] V coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseFromSameNamespaceSniff.phpnu [
*/
public function register(): array
{
return [
T_USE,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $usePointer
*/
public function process(File $phpcsFile, $usePointer): void
{
if (!UseStatementHelper::isImportUse($phpcsFile, $usePointer)) {
return;
}
$namespaceName = NamespaceHelper::findCurrentNamespaceName($phpcsFile, $usePointer);
$namespaceName ??= '';
$usedTypeName = UseStatementHelper::getFullyQualifiedTypeNameFromUse($phpcsFile, $usePointer);
if (!StringHelper::startsWith($usedTypeName, $namespaceName)) {
return;
}
$asPointer = $this->findAsPointer($phpcsFile, $usePointer);
if ($asPointer !== null) {
return;
}
$usedTypeNameRest = substr($usedTypeName, strlen($namespaceName));
if (!NamespaceHelper::isFullyQualifiedName($usedTypeNameRest) && $namespaceName !== '') {
return;
}
if (NamespaceHelper::hasNamespace($usedTypeNameRest)) {
return;
}
$fix = $phpcsFile->addFixableError(sprintf(
'Use %s is from the same namespace – that is prohibited.',
$usedTypeName,
), $usePointer, self::CODE_USE_FROM_SAME_NAMESPACE);
if (!$fix) {
return;
}
$endPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $usePointer) + 1;
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetweenIncluding($phpcsFile, $usePointer, $endPointer);
$phpcsFile->fixer->endChangeset();
}
private function findAsPointer(File $phpcsFile, int $startPointer): ?int
{
return TokenHelper::findNextLocal($phpcsFile, T_AS, $startPointer);
}
}
PK 41]!M N coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UselessAliasSniff.phpnu [
*/
public function register(): array
{
return [
T_OPEN_TAG,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $openTagPointer
*/
public function process(File $phpcsFile, $openTagPointer): void
{
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
$fileUseStatements = UseStatementHelper::getFileUseStatements($phpcsFile);
if (count($fileUseStatements) === 0) {
return;
}
foreach ($fileUseStatements as $useStatements) {
foreach ($useStatements as $useStatement) {
if ($useStatement->getAlias() === null) {
continue;
}
$unqualifiedName = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($useStatement->getFullyQualifiedTypeName());
if ($unqualifiedName !== $useStatement->getAlias()) {
continue;
}
$fix = $phpcsFile->addFixableError(
sprintf('Useless alias "%s" for use of "%s".', $useStatement->getAlias(), $useStatement->getFullyQualifiedTypeName()),
$useStatement->getPointer(),
self::CODE_USELESS_ALIAS,
);
if (!$fix) {
continue;
}
$asPointer = TokenHelper::findNext($phpcsFile, T_AS, $useStatement->getPointer() + 1);
$nameEndPointer = TokenHelper::findPrevious($phpcsFile, TokenHelper::ONLY_NAME_TOKEN_CODES, $asPointer - 1);
$useSemicolonPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $asPointer + 1);
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $nameEndPointer, $useSemicolonPointer);
$phpcsFile->fixer->endChangeset();
}
}
}
}
PK 41] _ coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedGlobalFunctionsSniff.phpnu [
*/
protected function getNormalizedInclude(): array
{
$include = parent::getNormalizedInclude();
if ($this->includeSpecialFunctions) {
array_push($include, ...FunctionHelper::SPECIAL_FUNCTIONS);
}
return $include;
}
protected function getNotFullyQualifiedMessage(): string
{
return 'Function %s() should be referenced via a fully qualified name.';
}
protected function isCaseSensitive(): bool
{
return false;
}
protected function isValidType(ReferencedName $name): bool
{
return $name->isFunction();
}
}
PK 41]\T [ coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/RequireOneNamespaceInFileSniff.phpnu [
*/
public function register(): array
{
return [
T_NAMESPACE,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $namespacePointer
*/
public function process(File $phpcsFile, $namespacePointer): void
{
$tokens = $phpcsFile->getTokens();
$pointerAfterNamespace = TokenHelper::findNextEffective($phpcsFile, $namespacePointer + 1);
if ($tokens[$pointerAfterNamespace]['code'] === T_NS_SEPARATOR) {
return;
}
$previousNamespacePointer = $namespacePointer;
do {
$previousNamespacePointer = TokenHelper::findPrevious($phpcsFile, T_NAMESPACE, $previousNamespacePointer - 1);
if ($previousNamespacePointer === null) {
return;
}
$pointerAfterPreviousNamespace = TokenHelper::findNextEffective($phpcsFile, $previousNamespacePointer + 1);
if ($tokens[$pointerAfterPreviousNamespace]['code'] === T_NS_SEPARATOR) {
continue;
}
break;
} while (true);
$phpcsFile->addError('Only one namespace in a file is allowed.', $namespacePointer, self::CODE_MORE_NAMESPACES_IN_FILE);
}
}
PK 41]4 R coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/DisallowGroupUseSniff.phpnu [
*/
public function register(): array
{
return [
T_OPEN_USE_GROUP,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $usePointer
*/
public function process(File $phpcsFile, $usePointer): void
{
$phpcsFile->addError(
'Group use declaration is disallowed, use single use for every import.',
$usePointer,
self::CODE_DISALLOWED_GROUP_USE,
);
}
}
PK 41]=g Z coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AlphabeticallySortedUsesSniff.phpnu [
*/
public function register(): array
{
return [
T_OPEN_TAG,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $openTagPointer
*/
public function process(File $phpcsFile, $openTagPointer): void
{
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
// If there are any 'use group' statements then we cannot sort and fix the file.
$groupUsePointer = TokenHelper::findNext($phpcsFile, T_OPEN_USE_GROUP, $openTagPointer);
if ($groupUsePointer !== null) {
return;
}
$fileUseStatements = UseStatementHelper::getFileUseStatements($phpcsFile);
foreach ($fileUseStatements as $useStatements) {
$lastUse = null;
foreach ($useStatements as $useStatement) {
if ($lastUse === null) {
$lastUse = $useStatement;
} else {
$order = $this->compareUseStatements($useStatement, $lastUse);
if ($order < 0) {
// The use statements are not ordered correctly. Go through all statements and if any are multi-part then
// we report the problem but cannot fix it, because this would lose the secondary parts of the statement.
$fixable = true;
$tokens = $phpcsFile->getTokens();
foreach ($useStatements as $statement) {
$nextBreaker = TokenHelper::findNext($phpcsFile, [T_SEMICOLON, T_COMMA], $statement->getPointer());
if ($tokens[$nextBreaker]['code'] === T_COMMA) {
$fixable = false;
break;
}
}
$errorParameters = [
sprintf(
'Use statements should be sorted alphabetically. The first wrong one is %s.',
$useStatement->getFullyQualifiedTypeName(),
),
$useStatement->getPointer(),
self::CODE_INCORRECT_ORDER,
];
if (!$fixable) {
$phpcsFile->addError(...$errorParameters);
return;
}
$fix = $phpcsFile->addFixableError(...$errorParameters);
if ($fix) {
$this->fixAlphabeticalOrder($phpcsFile, $useStatements);
}
return;
}
$lastUse = $useStatement;
}
}
}
}
/**
* @param array $useStatements
*/
private function fixAlphabeticalOrder(File $phpcsFile, array $useStatements): void
{
/** @var UseStatement $firstUseStatement */
$firstUseStatement = reset($useStatements);
/** @var UseStatement $lastUseStatement */
$lastUseStatement = end($useStatements);
$lastSemicolonPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $lastUseStatement->getPointer());
$firstPointer = $firstUseStatement->getPointer();
$tokens = $phpcsFile->getTokens();
$commentsBefore = [];
foreach ($useStatements as $useStatement) {
$pointerBeforeUseStatement = TokenHelper::findPreviousNonWhitespace($phpcsFile, $useStatement->getPointer() - 1);
if (!in_array($tokens[$pointerBeforeUseStatement]['code'], Tokens::$commentTokens, true)) {
continue;
}
$commentAndWhitespace = TokenHelper::getContent($phpcsFile, $pointerBeforeUseStatement, $useStatement->getPointer() - 1);
if (StringHelper::endsWith($commentAndWhitespace, $phpcsFile->eolChar . $phpcsFile->eolChar)) {
continue;
}
$commentStartPointer = in_array($tokens[$pointerBeforeUseStatement]['code'], TokenHelper::INLINE_COMMENT_TOKEN_CODES, true)
? CommentHelper::getMultilineCommentStartPointer($phpcsFile, $pointerBeforeUseStatement)
: $tokens[$pointerBeforeUseStatement]['comment_opener'];
$commentsBefore[$useStatement->getPointer()] = TokenHelper::getContent(
$phpcsFile,
$commentStartPointer,
$pointerBeforeUseStatement,
);
if ($firstPointer === $useStatement->getPointer()) {
$firstPointer = $commentStartPointer;
}
}
uasort($useStatements, fn (UseStatement $a, UseStatement $b): int => $this->compareUseStatements($a, $b));
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetweenIncluding($phpcsFile, $firstPointer, $lastSemicolonPointer);
FixerHelper::add(
$phpcsFile,
$firstPointer,
implode($phpcsFile->eolChar, array_map(static function (UseStatement $useStatement) use ($phpcsFile, $commentsBefore): string {
$unqualifiedName = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($useStatement->getFullyQualifiedTypeName());
$useTypeName = UseStatement::getTypeName($useStatement->getType());
$useTypeFormatted = $useTypeName !== null ? sprintf('%s ', $useTypeName) : '';
$commentBefore = '';
if (array_key_exists($useStatement->getPointer(), $commentsBefore)) {
$commentBefore = $commentsBefore[$useStatement->getPointer()];
if (!StringHelper::endsWith($commentBefore, $phpcsFile->eolChar)) {
$commentBefore .= $phpcsFile->eolChar;
}
}
if ($unqualifiedName === $useStatement->getNameAsReferencedInFile()) {
return sprintf('%suse %s%s;', $commentBefore, $useTypeFormatted, $useStatement->getFullyQualifiedTypeName());
}
return sprintf(
'%suse %s%s as %s;',
$commentBefore,
$useTypeFormatted,
$useStatement->getFullyQualifiedTypeName(),
$useStatement->getNameAsReferencedInFile(),
);
}, $useStatements)),
);
$phpcsFile->fixer->endChangeset();
}
private function compareUseStatements(UseStatement $a, UseStatement $b): int
{
if (!$a->hasSameType($b)) {
$order = [
UseStatement::TYPE_CLASS => 1,
UseStatement::TYPE_FUNCTION => $this->psr12Compatible ? 2 : 3,
UseStatement::TYPE_CONSTANT => $this->psr12Compatible ? 3 : 2,
];
return $order[$a->getType()] <=> $order[$b->getType()];
}
$aNameParts = explode(NamespaceHelper::NAMESPACE_SEPARATOR, $a->getFullyQualifiedTypeName());
$bNameParts = explode(NamespaceHelper::NAMESPACE_SEPARATOR, $b->getFullyQualifiedTypeName());
$minPartsCount = min(count($aNameParts), count($bNameParts));
for ($i = 0; $i < $minPartsCount; $i++) {
$comparison = $this->compare($aNameParts[$i], $bNameParts[$i]);
if ($comparison === 0) {
continue;
}
return $comparison;
}
return count($aNameParts) <=> count($bNameParts);
}
private function compare(string $a, string $b): int
{
if ($this->caseSensitive) {
return strcmp($a, $b);
}
return strcasecmp($a, $b);
}
}
PK 41]H?2 R coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceSpacingSniff.phpnu [
*/
public function register(): array
{
return [
T_NAMESPACE,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $namespacePointer
*/
public function process(File $phpcsFile, $namespacePointer): void
{
$this->linesCountBeforeNamespace = SniffSettingsHelper::normalizeInteger($this->linesCountBeforeNamespace);
$this->linesCountAfterNamespace = SniffSettingsHelper::normalizeInteger($this->linesCountAfterNamespace);
$this->checkLinesBeforeNamespace($phpcsFile, $namespacePointer);
$this->checkLinesAfterNamespace($phpcsFile, $namespacePointer);
}
private function checkLinesBeforeNamespace(File $phpcsFile, int $namespacePointer): void
{
$tokens = $phpcsFile->getTokens();
/** @var int $pointerBeforeNamespace */
$pointerBeforeNamespace = TokenHelper::findPreviousNonWhitespace($phpcsFile, $namespacePointer - 1);
$whitespaceBeforeNamespace = '';
$isInlineCommentBefore = (bool) preg_match('~^(?://|#)(.*)~', $tokens[$pointerBeforeNamespace]['content']);
if ($tokens[$pointerBeforeNamespace]['code'] === T_OPEN_TAG) {
$whitespaceBeforeNamespace .= substr($tokens[$pointerBeforeNamespace]['content'], strlen('eolChar;
}
if ($pointerBeforeNamespace + 1 !== $namespacePointer) {
$whitespaceBeforeNamespace .= TokenHelper::getContent($phpcsFile, $pointerBeforeNamespace + 1, $namespacePointer - 1);
}
$actualLinesCountBeforeNamespace = substr_count($whitespaceBeforeNamespace, $phpcsFile->eolChar) - 1;
if ($actualLinesCountBeforeNamespace === $this->linesCountBeforeNamespace) {
return;
}
$fix = $phpcsFile->addFixableError(
sprintf(
'Expected %d line%s before namespace statement, found %d.',
$this->linesCountBeforeNamespace,
$this->linesCountBeforeNamespace === 1 ? '' : 's',
$actualLinesCountBeforeNamespace,
),
$namespacePointer,
self::CODE_INCORRECT_LINES_COUNT_BEFORE_NAMESPACE,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
if ($tokens[$pointerBeforeNamespace]['code'] === T_OPEN_TAG) {
FixerHelper::replace($phpcsFile, $pointerBeforeNamespace, 'eolChar),
);
}
FixerHelper::removeBetween($phpcsFile, $pointerBeforeNamespace, $namespacePointer);
for ($i = 0; $i <= $this->linesCountBeforeNamespace; $i++) {
$phpcsFile->fixer->addNewline($pointerBeforeNamespace);
}
$phpcsFile->fixer->endChangeset();
}
private function checkLinesAfterNamespace(File $phpcsFile, int $namespacePointer): void
{
if (array_key_exists('scope_opener', $phpcsFile->getTokens()[$namespacePointer])) {
return;
}
/** @var int $namespaceSemicolonPointer */
$namespaceSemicolonPointer = TokenHelper::findNextLocal($phpcsFile, T_SEMICOLON, $namespacePointer + 1);
$pointerAfterWhitespaceEnd = TokenHelper::findNextNonWhitespace($phpcsFile, $namespaceSemicolonPointer + 1);
if ($pointerAfterWhitespaceEnd === null) {
return;
}
$whitespaceAfterNamespace = TokenHelper::getContent($phpcsFile, $namespaceSemicolonPointer + 1, $pointerAfterWhitespaceEnd - 1);
$actualLinesCountAfterNamespace = substr_count($whitespaceAfterNamespace, $phpcsFile->eolChar) - 1;
if ($actualLinesCountAfterNamespace === $this->linesCountAfterNamespace) {
return;
}
$fix = $phpcsFile->addFixableError(
sprintf(
'Expected %d line%s after namespace statement, found %d.',
$this->linesCountAfterNamespace,
$this->linesCountAfterNamespace === 1 ? '' : 's',
$actualLinesCountAfterNamespace,
),
$namespacePointer,
self::CODE_INCORRECT_LINES_COUNT_AFTER_NAMESPACE,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $namespaceSemicolonPointer, $pointerAfterWhitespaceEnd);
for ($i = 0; $i <= $this->linesCountAfterNamespace; $i++) {
$phpcsFile->fixer->addNewline($namespaceSemicolonPointer);
}
$phpcsFile->fixer->endChangeset();
}
}
PK 41]6CKf f X coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.phpnu [ */
public array $specialExceptionNames = [];
/** @var list */
public array $ignoredNames = [];
public bool $allowPartialUses = true;
/**
* If empty, all namespaces are required to be used
*
* @var list
*/
public array $namespacesRequiredToUse = [];
public bool $allowFullyQualifiedNameForCollidingClasses = false;
public bool $allowFullyQualifiedNameForCollidingFunctions = false;
public bool $allowFullyQualifiedNameForCollidingConstants = false;
/** @var list|null */
private ?array $normalizedSpecialExceptionNames = null;
/** @var list|null */
private ?array $normalizedIgnoredNames = null;
/** @var list|null */
private ?array $normalizedNamespacesRequiredToUse = null;
/**
* @return array
*/
public function register(): array
{
return [
T_OPEN_TAG,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $openTagPointer
*/
public function process(File $phpcsFile, $openTagPointer): void
{
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
$namespacePointers = NamespaceHelper::getAllNamespacesPointers($phpcsFile);
if ($namespacePointers === [] && !$this->allowWhenNoNamespace) {
return;
}
$tokens = $phpcsFile->getTokens();
$references = $this->getReferences($phpcsFile, $openTagPointer);
$definedClassesIndex = [];
foreach (ClassHelper::getAllNames($phpcsFile) as $definedClassPointer => $definedClassName) {
$definedClassesIndex[strtolower($definedClassName)] = NamespaceHelper::resolveClassName(
$phpcsFile,
$definedClassName,
$definedClassPointer,
);
}
$definedFunctionsIndex = array_flip(
array_map(
static fn (string $functionName): string => strtolower($functionName),
FunctionHelper::getAllFunctionNames($phpcsFile),
),
);
$definedConstantsIndex = array_flip(ConstantHelper::getAllNames($phpcsFile));
$classReferencesIndex = [];
$classReferences = array_filter(
$references,
static fn (stdClass $reference): bool => $reference->source === self::SOURCE_CODE && $reference->isClass,
);
foreach ($classReferences as $classReference) {
$classReferencesIndex[strtolower($classReference->name)] = NamespaceHelper::resolveName(
$phpcsFile,
$classReference->name,
$classReference->type,
$classReference->startPointer,
);
}
$referenceErrors = [];
foreach ($references as $reference) {
$useStatements = UseStatementHelper::getUseStatementsForPointer($phpcsFile, $reference->startPointer);
$name = $reference->name;
/** @var int $startPointer */
$startPointer = $reference->startPointer;
$canonicalName = NamespaceHelper::normalizeToCanonicalName($name);
$unqualifiedName = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($name);
if (in_array(strtolower($unqualifiedName), ['true', 'false', 'null'], true)) {
continue;
}
$collidingUseStatementUniqueId = UseStatement::getUniqueId($reference->type, $unqualifiedName);
$isPartialUse = false;
foreach ($useStatements as $useStatement) {
$useStatementName = $useStatement->getAlias() ?? $useStatement->getNameAsReferencedInFile();
if (strpos($name, $useStatementName . '\\') === 0) {
$isPartialUse = true;
break;
}
}
$isFullyQualified = NamespaceHelper::isFullyQualifiedName($name)
|| ($namespacePointers === [] && NamespaceHelper::hasNamespace($name) && !$isPartialUse);
$isGlobalFallback = !$isFullyQualified
&& !NamespaceHelper::hasNamespace($name)
&& $namespacePointers !== []
&& !array_key_exists(UseStatement::getUniqueId($reference->type, $name), $useStatements);
$isGlobalFunctionFallback = false;
if ($reference->isFunction && $isGlobalFallback) {
$isGlobalFunctionFallback = !array_key_exists(strtolower($reference->name), $definedFunctionsIndex) && function_exists(
$reference->name,
);
}
$isGlobalConstantFallback = false;
if ($reference->isConstant && $isGlobalFallback) {
$isGlobalConstantFallback = !array_key_exists($reference->name, $definedConstantsIndex) && defined($reference->name);
}
if ($isFullyQualified) {
if ($reference->isClass && $this->allowFullyQualifiedNameForCollidingClasses) {
$lowerCasedUnqualifiedClassName = strtolower($unqualifiedName);
if (
array_key_exists($lowerCasedUnqualifiedClassName, $definedClassesIndex)
&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName(
$definedClassesIndex[$lowerCasedUnqualifiedClassName],
)
) {
continue;
}
if (
array_key_exists($lowerCasedUnqualifiedClassName, $classReferencesIndex)
&& $name !== $classReferencesIndex[$lowerCasedUnqualifiedClassName]
) {
continue;
}
if (
array_key_exists($collidingUseStatementUniqueId, $useStatements)
&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName(
$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName(),
)
) {
continue;
}
} elseif ($reference->isFunction && $this->allowFullyQualifiedNameForCollidingFunctions) {
$lowerCasedUnqualifiedFunctionName = strtolower($unqualifiedName);
if (array_key_exists($lowerCasedUnqualifiedFunctionName, $definedFunctionsIndex)) {
continue;
}
if (
array_key_exists($collidingUseStatementUniqueId, $useStatements)
&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName(
$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName(),
)
) {
continue;
}
} elseif ($reference->isConstant && $this->allowFullyQualifiedNameForCollidingConstants) {
if (array_key_exists($unqualifiedName, $definedConstantsIndex)) {
continue;
}
if (
array_key_exists($collidingUseStatementUniqueId, $useStatements)
&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName(
$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName(),
)
) {
continue;
}
}
}
if ($isFullyQualified || $isGlobalFunctionFallback || $isGlobalConstantFallback) {
if ($isFullyQualified && !$this->isRequiredToBeUsed($name)) {
continue;
}
$isExceptionByName = StringHelper::endsWith($name, 'Exception')
|| $name === '\Throwable'
|| (StringHelper::endsWith($name, 'Error') && !NamespaceHelper::hasNamespace($name))
|| in_array($canonicalName, $this->getSpecialExceptionNames(), true);
$inIgnoredNames = in_array($canonicalName, $this->getIgnoredNames(), true);
if ($isExceptionByName && !$inIgnoredNames && $this->allowFullyQualifiedExceptions) {
continue;
}
if (
$isFullyQualified
&& !NamespaceHelper::hasNamespace($name)
&& $namespacePointers === []
) {
$label = sprintf(
$reference->isConstant ? 'Constant %s' : ($reference->isFunction ? 'Function %s()' : 'Class %s'),
$name,
);
$fix = $phpcsFile->addFixableError(sprintf(
'%s should not be referenced via a fully qualified name, but via an unqualified name without the leading \\, because the file does not have a namespace and the type cannot be put in a use statement.',
$label,
), $startPointer, self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME_WITHOUT_NAMESPACE);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
if ($reference->source === self::SOURCE_ANNOTATION) {
$fixedDocComment = AnnotationHelper::fixAnnotation(
$reference->parsedDocComment,
$reference->annotation,
$reference->nameNode,
new IdentifierTypeNode(substr($reference->name, 1)),
);
FixerHelper::change(
$phpcsFile,
$reference->parsedDocComment->getOpenPointer(),
$reference->parsedDocComment->getClosePointer(),
$fixedDocComment,
);
} elseif ($reference->source === self::SOURCE_ANNOTATION_CONSTANT_FETCH) {
$fixedDocComment = AnnotationHelper::fixAnnotation(
$reference->parsedDocComment,
$reference->annotation,
$reference->constantFetchNode,
new ConstFetchNode(substr($reference->name, 1), $reference->constantFetchNode->name),
);
FixerHelper::change(
$phpcsFile,
$reference->parsedDocComment->getOpenPointer(),
$reference->parsedDocComment->getClosePointer(),
$fixedDocComment,
);
} else {
FixerHelper::replace(
$phpcsFile,
$startPointer,
substr($tokens[$startPointer]['content'], 1),
);
}
$phpcsFile->fixer->endChangeset();
}
} else {
$shouldBeUsed = NamespaceHelper::hasNamespace($name);
if (!$shouldBeUsed) {
if ($reference->isFunction) {
$shouldBeUsed = $isFullyQualified
? !$this->allowFullyQualifiedGlobalFunctions
: !$this->allowFallbackGlobalFunctions;
} elseif ($reference->isConstant) {
$shouldBeUsed = $isFullyQualified
? !$this->allowFullyQualifiedGlobalConstants
: !$this->allowFallbackGlobalConstants;
} else {
$shouldBeUsed = !$this->allowFullyQualifiedGlobalClasses;
}
}
if (!$shouldBeUsed) {
continue;
}
$referenceErrors[] = (object) [
'reference' => $reference,
'canonicalName' => $canonicalName,
'isGlobalConstantFallback' => $isGlobalConstantFallback,
'isGlobalFunctionFallback' => $isGlobalFunctionFallback,
];
}
} elseif (!$this->allowPartialUses) {
if (NamespaceHelper::isQualifiedName($name)) {
$phpcsFile->addError(sprintf(
'Partial use statements are not allowed, but referencing %s found.',
$name,
), $startPointer, self::CODE_PARTIAL_USE);
}
}
}
if (count($referenceErrors) === 0) {
return;
}
$alreadyAddedUses = [
UseStatement::TYPE_CLASS => [],
UseStatement::TYPE_FUNCTION => [],
UseStatement::TYPE_CONSTANT => [],
];
$phpcsFile->fixer->beginChangeset();
foreach ($referenceErrors as $referenceData) {
$reference = $referenceData->reference;
/** @var int $startPointer */
$startPointer = $reference->startPointer;
$canonicalName = $referenceData->canonicalName;
$nameToReference = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($reference->name);
$canonicalNameToReference = $reference->isConstant ? $nameToReference : strtolower($nameToReference);
$isGlobalConstantFallback = $referenceData->isGlobalConstantFallback;
$isGlobalFunctionFallback = $referenceData->isGlobalFunctionFallback;
$useStatements = UseStatementHelper::getUseStatementsForPointer($phpcsFile, $reference->startPointer);
$canBeFixed = array_reduce(
$alreadyAddedUses[$reference->type],
static function (bool $carry, string $use) use ($canonicalName): bool {
$useLastName = strtolower(NamespaceHelper::getLastNamePart($use));
$canonicalLastName = strtolower(NamespaceHelper::getLastNamePart($canonicalName));
return $useLastName === $canonicalLastName ? false : $carry;
},
true,
);
if (
(
$reference->isClass
&& array_key_exists($canonicalNameToReference, $definedClassesIndex)
&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName($definedClassesIndex[$canonicalNameToReference])
)
|| (
$reference->isClass
&& array_key_exists($canonicalNameToReference, $classReferencesIndex)
&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName($classReferencesIndex[$canonicalNameToReference])
)
|| ($reference->isFunction && array_key_exists($canonicalNameToReference, $definedFunctionsIndex))
|| ($reference->isConstant && array_key_exists($canonicalNameToReference, $definedConstantsIndex))
) {
$canBeFixed = false;
}
foreach ($useStatements as $useStatement) {
if ($useStatement->getType() !== $reference->type) {
continue;
}
if ($useStatement->getFullyQualifiedTypeName() === $canonicalName) {
continue;
}
if ($useStatement->getCanonicalNameAsReferencedInFile() !== $canonicalNameToReference) {
continue;
}
$canBeFixed = false;
break;
}
$label = sprintf(
$reference->isConstant
? 'Constant %s'
: ($reference->isFunction ? 'Function %s()' : 'Class %s'),
$reference->name,
);
$errorCode = $isGlobalConstantFallback || $isGlobalFunctionFallback
? self::CODE_REFERENCE_VIA_FALLBACK_GLOBAL_NAME
: self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME;
$errorMessage = $isGlobalConstantFallback || $isGlobalFunctionFallback
? sprintf('%s should not be referenced via a fallback global name, but via a use statement.', $label)
: sprintf('%s should not be referenced via a fully qualified name, but via a use statement.', $label);
if (!$canBeFixed) {
$phpcsFile->addError($errorMessage, $startPointer, $errorCode);
continue;
}
$fix = $phpcsFile->addFixableError($errorMessage, $startPointer, $errorCode);
if (!$fix) {
continue;
}
$addUse = !in_array($canonicalName, $alreadyAddedUses[$reference->type], true);
if (
$reference->isClass
&& array_key_exists($canonicalNameToReference, $definedClassesIndex)
) {
$addUse = false;
}
foreach ($useStatements as $useStatement) {
if (
$useStatement->getType() !== $reference->type
|| $useStatement->getFullyQualifiedTypeName() !== $canonicalName
) {
continue;
}
$nameToReference = $useStatement->getNameAsReferencedInFile();
$addUse = false;
// Lock the use statement, so it is not modified by other sniffs
FixerHelper::replace(
$phpcsFile,
$useStatement->getPointer(),
$phpcsFile->fixer->getTokenContent($useStatement->getPointer()),
);
break;
}
if ($addUse) {
$useStatementPlacePointer = $this->getUseStatementPlacePointer($phpcsFile, $openTagPointer, $useStatements);
$useTypeName = UseStatement::getTypeName($reference->type);
$useTypeFormatted = $useTypeName !== null ? sprintf('%s ', $useTypeName) : '';
$phpcsFile->fixer->addNewline($useStatementPlacePointer);
FixerHelper::add(
$phpcsFile,
$useStatementPlacePointer,
sprintf('use %s%s;', $useTypeFormatted, $canonicalName),
);
$alreadyAddedUses[$reference->type][] = $canonicalName;
}
if ($reference->source === self::SOURCE_ANNOTATION) {
$fixedDocComment = AnnotationHelper::fixAnnotation(
$reference->parsedDocComment,
$reference->annotation,
$reference->nameNode,
new IdentifierTypeNode($nameToReference),
);
FixerHelper::change(
$phpcsFile,
$reference->parsedDocComment->getOpenPointer(),
$reference->parsedDocComment->getClosePointer(),
$fixedDocComment,
);
} elseif ($reference->source === self::SOURCE_ANNOTATION_CONSTANT_FETCH) {
$fixedDocComment = AnnotationHelper::fixAnnotation(
$reference->parsedDocComment,
$reference->annotation,
$reference->constantFetchNode,
new ConstFetchNode($nameToReference, $reference->constantFetchNode->name),
);
FixerHelper::change(
$phpcsFile,
$reference->parsedDocComment->getOpenPointer(),
$reference->parsedDocComment->getClosePointer(),
$fixedDocComment,
);
} elseif ($reference->source === self::SOURCE_ATTRIBUTE) {
$attributeContent = TokenHelper::getContent($phpcsFile, $startPointer, $reference->endPointer);
$fixedAttributeContent = preg_replace(
'~(?<=\W)' . preg_quote($reference->name, '~') . '(?=\W)~',
$nameToReference,
$attributeContent,
);
FixerHelper::change($phpcsFile, $startPointer, $reference->endPointer, $fixedAttributeContent);
} else {
FixerHelper::change($phpcsFile, $startPointer, $reference->endPointer, $nameToReference);
}
}
$phpcsFile->fixer->endChangeset();
}
/**
* @return list
*/
private function getSpecialExceptionNames(): array
{
$this->normalizedSpecialExceptionNames ??= SniffSettingsHelper::normalizeArray($this->specialExceptionNames);
return $this->normalizedSpecialExceptionNames;
}
/**
* @return list
*/
private function getIgnoredNames(): array
{
$this->normalizedIgnoredNames ??= SniffSettingsHelper::normalizeArray($this->ignoredNames);
return $this->normalizedIgnoredNames;
}
/**
* @return list
*/
private function getNamespacesRequiredToUse(): array
{
$this->normalizedNamespacesRequiredToUse ??= SniffSettingsHelper::normalizeArray($this->namespacesRequiredToUse);
return $this->normalizedNamespacesRequiredToUse;
}
/**
* @param array $useStatements
*/
private function getUseStatementPlacePointer(File $phpcsFile, int $openTagPointer, array $useStatements): int
{
if (count($useStatements) !== 0) {
$lastUseStatement = array_values($useStatements)[count($useStatements) - 1];
/** @var int $useStatementPlacePointer */
$useStatementPlacePointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $lastUseStatement->getPointer() + 1);
return $useStatementPlacePointer;
}
$namespacePointer = TokenHelper::findNext($phpcsFile, T_NAMESPACE, $openTagPointer + 1);
if ($namespacePointer !== null) {
/** @var int $useStatementPlacePointer */
$useStatementPlacePointer = TokenHelper::findNext($phpcsFile, [T_SEMICOLON, T_OPEN_CURLY_BRACKET], $namespacePointer + 1);
return $useStatementPlacePointer;
}
$tokens = $phpcsFile->getTokens();
$useStatementPlacePointer = $openTagPointer;
if (
substr($tokens[$openTagPointer]['content'], -1) !== $phpcsFile->eolChar
&& $tokens[$openTagPointer + 1]['content'] === $phpcsFile->eolChar
) {
// @codeCoverageIgnoreStart
$useStatementPlacePointer++;
// @codeCoverageIgnoreEnd
}
$nonWhitespacePointerAfterOpenTag = TokenHelper::findNextNonWhitespace($phpcsFile, $openTagPointer + 1);
if (in_array($tokens[$nonWhitespacePointerAfterOpenTag]['code'], Tokens::$commentTokens, true)) {
$commentEndPointer = CommentHelper::getCommentEndPointer($phpcsFile, $nonWhitespacePointerAfterOpenTag);
if (StringHelper::endsWith($tokens[$commentEndPointer]['content'], $phpcsFile->eolChar)) {
$useStatementPlacePointer = $commentEndPointer;
} else {
$newLineAfterComment = $commentEndPointer + 1;
if (array_key_exists($newLineAfterComment, $tokens) && $tokens[$newLineAfterComment]['content'] === $phpcsFile->eolChar) {
$pointerAfterCommentEnd = TokenHelper::findNextNonWhitespace($phpcsFile, $newLineAfterComment + 1);
if (TokenHelper::findNextContent(
$phpcsFile,
T_WHITESPACE,
$phpcsFile->eolChar,
$newLineAfterComment + 1,
$pointerAfterCommentEnd,
) !== null) {
$useStatementPlacePointer = $commentEndPointer;
}
}
}
}
$pointerAfter = TokenHelper::findNextEffective($phpcsFile, $useStatementPlacePointer + 1);
if ($tokens[$pointerAfter]['code'] === T_DECLARE) {
return TokenHelper::findNext($phpcsFile, T_SEMICOLON, $pointerAfter + 1);
}
return $useStatementPlacePointer;
}
private function isRequiredToBeUsed(string $name): bool
{
if ($this->namespacesRequiredToUse === []) {
return true;
}
foreach ($this->getNamespacesRequiredToUse() as $namespace) {
if (!NamespaceHelper::isTypeInNamespace($name, $namespace)) {
continue;
}
return true;
}
return false;
}
/**
* @return list
*/
private function getReferences(File $phpcsFile, int $openTagPointer): array
{
$tokens = $phpcsFile->getTokens();
$references = [];
foreach (ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer) as $referencedName) {
$reference = new stdClass();
$reference->source = self::SOURCE_CODE;
$reference->name = $referencedName->getNameAsReferencedInFile();
$reference->type = $referencedName->getType();
$reference->startPointer = $referencedName->getStartPointer();
$reference->endPointer = $referencedName->getEndPointer();
$reference->isClass = $referencedName->isClass();
$reference->isConstant = $referencedName->isConstant();
$reference->isFunction = $referencedName->isFunction();
$references[] = $reference;
}
foreach (ReferencedNameHelper::getAllReferencedNamesInAttributes($phpcsFile, $openTagPointer) as $referencedName) {
$reference = new stdClass();
$reference->source = self::SOURCE_ATTRIBUTE;
$reference->name = $referencedName->getNameAsReferencedInFile();
$reference->type = $referencedName->getType();
$reference->startPointer = $referencedName->getStartPointer();
$reference->endPointer = $referencedName->getEndPointer();
$reference->isClass = $referencedName->isClass();
$reference->isConstant = $referencedName->isConstant();
$reference->isFunction = $referencedName->isFunction();
$references[] = $reference;
}
if (!$this->searchAnnotations) {
return $references;
}
$searchAnnotationsPointer = $openTagPointer + 1;
while (true) {
$docCommentOpenPointer = TokenHelper::findNext($phpcsFile, T_DOC_COMMENT_OPEN_TAG, $searchAnnotationsPointer);
if ($docCommentOpenPointer === null) {
break;
}
$parsedDocComment = DocCommentHelper::parseDocComment($phpcsFile, $docCommentOpenPointer);
if ($parsedDocComment !== null) {
$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
foreach ($annotations as $annotation) {
$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
foreach ($identifierTypeNodes as $typeHintNode) {
$typeHint = $typeHintNode->name;
$lowercasedTypeHint = strtolower($typeHint);
if (
TypeHintHelper::isSimpleTypeHint($lowercasedTypeHint)
|| TypeHintHelper::isSimpleUnofficialTypeHints($lowercasedTypeHint)
|| !TypeHelper::isTypeName($typeHint)
) {
continue;
}
$reference = new stdClass();
$reference->source = self::SOURCE_ANNOTATION;
$reference->parsedDocComment = $parsedDocComment;
$reference->annotation = $annotation;
$reference->nameNode = $typeHintNode;
$reference->name = $typeHint;
$reference->type = ReferencedName::TYPE_CLASS;
$reference->startPointer = $annotation->getStartPointer();
$reference->endPointer = null;
$reference->isClass = true;
$reference->isConstant = false;
$reference->isFunction = false;
$references[] = $reference;
}
$constantFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
foreach ($constantFetchNodes as $constantFetchNode) {
$reference = new stdClass();
$reference->source = self::SOURCE_ANNOTATION_CONSTANT_FETCH;
$reference->parsedDocComment = $parsedDocComment;
$reference->annotation = $annotation;
$reference->constantFetchNode = $constantFetchNode;
$reference->name = $constantFetchNode->className;
$reference->type = ReferencedName::TYPE_CLASS;
$reference->startPointer = $annotation->getStartPointer();
$reference->endPointer = null;
$reference->isClass = true;
$reference->isConstant = false;
$reference->isFunction = false;
$references[] = $reference;
}
}
}
$searchAnnotationsPointer = $tokens[$docCommentOpenPointer]['comment_closer'] + 1;
}
return $references;
}
}
PK 41]\ _ coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedGlobalConstantsSniff.phpnu [ isConstant();
}
}
PK 41]5M ^ coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseDoesNotStartWithBackslashSniff.phpnu [
*/
public function register(): array
{
return [
T_USE,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $usePointer
*/
public function process(File $phpcsFile, $usePointer): void
{
if (!UseStatementHelper::isImportUse($phpcsFile, $usePointer)) {
return;
}
$tokens = $phpcsFile->getTokens();
/** @var int $nextTokenPointer */
$nextTokenPointer = TokenHelper::findNextEffective($phpcsFile, $usePointer + 1);
if (
in_array($tokens[$nextTokenPointer]['code'], TokenHelper::ONLY_NAME_TOKEN_CODES, true)
&& (
$tokens[$nextTokenPointer]['content'] === 'function'
|| $tokens[$nextTokenPointer]['content'] === 'const'
)
) {
/** @var int $nextTokenPointer */
$nextTokenPointer = TokenHelper::findNextEffective($phpcsFile, $nextTokenPointer + 1);
}
if (!NamespaceHelper::isFullyQualifiedPointer($phpcsFile, $nextTokenPointer)) {
return;
}
$fix = $phpcsFile->addFixableError(
'Use statement cannot start with a backslash.',
$nextTokenPointer,
self::CODE_STARTS_WITH_BACKSLASH,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace(
$phpcsFile,
$nextTokenPointer,
ltrim($tokens[$nextTokenPointer]['content'], '\\'),
);
$phpcsFile->fixer->endChangeset();
}
}
PK 41]M V coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceDeclarationSniff.phpnu [
*/
public function register(): array
{
return [
T_NAMESPACE,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $namespacePointer
*/
public function process(File $phpcsFile, $namespacePointer): void
{
$tokens = $phpcsFile->getTokens();
$pointerAfterNamespace = TokenHelper::findNextEffective($phpcsFile, $namespacePointer + 1);
if ($tokens[$pointerAfterNamespace]['code'] === T_NS_SEPARATOR) {
return;
}
$this->checkWhitespaceAfterNamespace($phpcsFile, $namespacePointer);
$this->checkDisallowedContentBetweenNamespaceNameAndSemicolon($phpcsFile, $namespacePointer);
$this->checkDisallowedBracketedSyntax($phpcsFile, $namespacePointer);
}
private function checkWhitespaceAfterNamespace(File $phpcsFile, int $namespacePointer): void
{
$tokens = $phpcsFile->getTokens();
$whitespacePointer = $namespacePointer + 1;
if ($tokens[$whitespacePointer]['code'] !== T_WHITESPACE) {
$phpcsFile->addError(
'Expected one space after namespace statement.',
$namespacePointer,
self::CODE_INVALID_WHITESPACE_AFTER_NAMESPACE,
);
return;
}
if ($tokens[$whitespacePointer]['content'] === ' ') {
return;
}
$errorMessage = sprintf('Expected one space after namespace statement, found %d.', strlen($tokens[$whitespacePointer]['content']));
$fix = $phpcsFile->addFixableError($errorMessage, $namespacePointer, self::CODE_INVALID_WHITESPACE_AFTER_NAMESPACE);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $whitespacePointer, ' ');
$phpcsFile->fixer->endChangeset();
}
private function checkDisallowedContentBetweenNamespaceNameAndSemicolon(File $phpcsFile, int $namespacePointer): void
{
if (array_key_exists('scope_opener', $phpcsFile->getTokens()[$namespacePointer])) {
return;
}
$namespaceNameStartPointer = TokenHelper::findNextEffective($phpcsFile, $namespacePointer + 1);
$namespaceNameEndPointer = TokenHelper::findNextExcluding(
$phpcsFile,
TokenHelper::NAME_TOKEN_CODES,
$namespaceNameStartPointer + 1,
) - 1;
/** @var int $namespaceSemicolonPointer */
$namespaceSemicolonPointer = TokenHelper::findNextLocal($phpcsFile, T_SEMICOLON, $namespaceNameEndPointer + 1);
if ($namespaceNameEndPointer + 1 === $namespaceSemicolonPointer) {
return;
}
$fix = $phpcsFile->addFixableError(
'Disallowed content between namespace name and semicolon.',
$namespacePointer,
self::CODE_DISALLOWED_CONTENT_BETWEEN_NAMESPACE_NAME_AND_SEMICOLON,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $namespaceNameEndPointer, $namespaceSemicolonPointer);
$phpcsFile->fixer->endChangeset();
}
private function checkDisallowedBracketedSyntax(File $phpcsFile, int $namespacePointer): void
{
$tokens = $phpcsFile->getTokens();
if (!array_key_exists('scope_opener', $tokens[$namespacePointer])) {
return;
}
$fix = $phpcsFile->addFixableError(
'Bracketed syntax for namespaces is disallowed.',
$namespacePointer,
self::CODE_DISALLOWED_BRACKETED_SYNTAX,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $tokens[$namespacePointer]['scope_opener'], ';');
FixerHelper::replace($phpcsFile, $tokens[$namespacePointer]['scope_closer'], '');
$phpcsFile->fixer->endChangeset();
}
}
PK 41]<܈E E e coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedClassNameInAnnotationSniff.phpnu [ */
public array $ignoredAnnotationNames = [];
/**
* @return array
*/
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);
$this->ignoredAnnotationNames = SniffSettingsHelper::normalizeArray($this->ignoredAnnotationNames);
foreach ($annotations as $annotation) {
$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
$annotationName = $annotation->getName();
foreach ($identifierTypeNodes as $typeHintNode) {
$typeHint = $typeHintNode->name;
$lowercasedTypeHint = strtolower($typeHint);
if (
TypeHintHelper::isSimpleTypeHint($lowercasedTypeHint)
|| TypeHintHelper::isSimpleUnofficialTypeHints($lowercasedTypeHint)
|| !TypeHelper::isTypeName($typeHint)
|| TypeHintHelper::isTypeDefinedInAnnotation($phpcsFile, $docCommentOpenPointer, $typeHint)
) {
continue;
}
if (in_array($annotationName, $this->ignoredAnnotationNames, true)) {
continue;
}
$fullyQualifiedTypeHint = TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $docCommentOpenPointer, $typeHint);
if ($fullyQualifiedTypeHint === $typeHint) {
continue;
}
$fix = $phpcsFile->addFixableError(sprintf(
'Class name %s in %s should be referenced via a fully qualified name.',
$fullyQualifiedTypeHint,
$annotationName,
), $annotation->getStartPointer(), self::CODE_NON_FULLY_QUALIFIED_CLASS_NAME);
if (!$fix) {
continue;
}
$parsedDocComment = DocCommentHelper::parseDocComment($phpcsFile, $docCommentOpenPointer);
$fixedDocComment = AnnotationHelper::fixAnnotation(
$parsedDocComment,
$annotation,
$typeHintNode,
new IdentifierTypeNode($fullyQualifiedTypeHint),
);
$phpcsFile->fixer->beginChangeset();
FixerHelper::change(
$phpcsFile,
$parsedDocComment->getOpenPointer(),
$parsedDocComment->getClosePointer(),
$fixedDocComment,
);
$phpcsFile->fixer->endChangeset();
}
$constantFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
foreach ($constantFetchNodes as $constantFetchNode) {
$isClassConstant = $constantFetchNode->className !== '';
$typeHint = $isClassConstant
? $constantFetchNode->className
: $constantFetchNode->name;
if ($typeHint === 'self') {
continue;
}
$fullyQualifiedTypeHint = $isClassConstant
? NamespaceHelper::resolveClassName($phpcsFile, $typeHint, $docCommentOpenPointer)
: NamespaceHelper::resolveName($phpcsFile, $typeHint, ReferencedName::TYPE_CONSTANT, $docCommentOpenPointer);
if ($fullyQualifiedTypeHint === $typeHint) {
continue;
}
$fix = $phpcsFile->addFixableError(sprintf(
'%s name %s in %s should be referenced via a fully qualified name.',
$isClassConstant ? 'Class' : 'Constant',
$fullyQualifiedTypeHint,
$annotationName,
), $annotation->getStartPointer(), self::CODE_NON_FULLY_QUALIFIED_CLASS_NAME);
if (!$fix) {
continue;
}
$fixedConstantFetchNode = PhpDocParserHelper::cloneNode($constantFetchNode);
if ($isClassConstant) {
$fixedConstantFetchNode->className = $fullyQualifiedTypeHint;
} else {
$fixedConstantFetchNode->name = $fullyQualifiedTypeHint;
}
$parsedDocComment = DocCommentHelper::parseDocComment($phpcsFile, $docCommentOpenPointer);
$fixedDocComment = AnnotationHelper::fixAnnotation(
$parsedDocComment,
$annotation,
$constantFetchNode,
$fixedConstantFetchNode,
);
$phpcsFile->fixer->beginChangeset();
FixerHelper::change(
$phpcsFile,
$parsedDocComment->getOpenPointer(),
$parsedDocComment->getClosePointer(),
$fixedDocComment,
);
$phpcsFile->fixer->endChangeset();
}
}
}
}
PK 41]5
tk k ^ coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseOnlyWhitelistedNamespacesSniff.phpnu [ */
public array $namespacesRequiredToUse = [];
/** @var list|null */
private ?array $normalizedNamespacesRequiredToUse = null;
/**
* @return array
*/
public function register(): array
{
return [
T_USE,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $usePointer
*/
public function process(File $phpcsFile, $usePointer): void
{
if (!UseStatementHelper::isImportUse($phpcsFile, $usePointer)) {
return;
}
$className = UseStatementHelper::getFullyQualifiedTypeNameFromUse($phpcsFile, $usePointer);
if ($this->allowUseFromRootNamespace && !NamespaceHelper::isQualifiedName($className)) {
return;
}
foreach ($this->getNamespacesRequiredToUse() as $namespace) {
if (!NamespaceHelper::isTypeInNamespace($className, $namespace)) {
continue;
}
return;
}
$phpcsFile->addError(sprintf(
'Type %s should not be used, but referenced via a fully qualified name.',
$className,
), $usePointer, self::CODE_NON_FULLY_QUALIFIED);
}
/**
* @return list
*/
private function getNamespacesRequiredToUse(): array
{
$this->normalizedNamespacesRequiredToUse ??= SniffSettingsHelper::normalizeArray($this->namespacesRequiredToUse);
return $this->normalizedNamespacesRequiredToUse;
}
}
PK 41] U coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/MultipleUsesPerLineSniff.phpnu [
*/
public function register(): array
{
return [
T_USE,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $usePointer
*/
public function process(File $phpcsFile, $usePointer): void
{
if (!UseStatementHelper::isImportUse($phpcsFile, $usePointer)) {
return;
}
$endPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $usePointer + 1);
$commaPointer = TokenHelper::findNext($phpcsFile, T_COMMA, $usePointer + 1, $endPointer);
if ($commaPointer === null) {
return;
}
$phpcsFile->addError('Multiple used types per use statement are forbidden.', $commaPointer, self::CODE_MULTIPLE_USES_PER_LINE);
}
}
PK 41]7Ҙ : coding-standard/SlevomatCodingStandard/Sniffs/TestCase.phpnu [ > $sniffProperties
* @param list $codesToCheck
* @param list $cliArgs
*/
protected static function checkFile(string $filePath, array $sniffProperties = [], array $codesToCheck = [], array $cliArgs = []): File
{
if (defined('PHP_CODESNIFFER_CBF') === false) {
define('PHP_CODESNIFFER_CBF', false);
}
$codeSniffer = new Runner();
$codeSniffer->config = new Config(array_merge(['-s'], $cliArgs));
$codeSniffer->init();
if (count($sniffProperties) > 0) {
foreach ($sniffProperties as $name => $value) {
$sniffProperties[$name] = [
'value' => $value,
'scope' => 'sniff',
];
}
$codeSniffer->ruleset->ruleset[self::getSniffName()]['properties'] = $sniffProperties;
}
$sniffClassName = static::getSniffClassName();
/** @var Sniff $sniff */
$sniff = new $sniffClassName();
$codeSniffer->ruleset->sniffs = [$sniffClassName => $sniff];
if (count($codesToCheck) > 0) {
foreach (self::getSniffClassReflection()->getConstants() as $constantName => $constantValue) {
if (strpos($constantName, 'CODE_') !== 0 || in_array($constantValue, $codesToCheck, true)) {
continue;
}
$codeSniffer->ruleset->ruleset[sprintf('%s.%s', self::getSniffName(), $constantValue)]['severity'] = 0;
}
}
$codeSniffer->ruleset->populateTokenListeners();
$codeSniffer->config->tabWidth = self::TAB_WIDTH;
$file = new LocalFile($filePath, $codeSniffer->ruleset, $codeSniffer->config);
$file->process();
return $file;
}
protected static function assertNoSniffErrorInFile(File $phpcsFile): void
{
$errors = $phpcsFile->getErrors();
$text = sprintf('No errors expected, but %d errors found:', count($errors));
foreach ($errors as $line => $error) {
$text .= sprintf(
'%sLine %d:%s%s',
PHP_EOL,
$line,
PHP_EOL,
self::getFormattedErrors($error),
);
}
self::assertEmpty($errors, $text);
}
protected static function assertNoSniffWarningInFile(File $phpcsFile): void
{
$warnings = $phpcsFile->getWarnings();
$text = sprintf('No warnings expected, but %d warnings found:', count($warnings));
foreach ($warnings as $line => $warning) {
$text .= sprintf(
'%sLine %d:%s%s',
PHP_EOL,
$line,
PHP_EOL,
self::getFormattedErrors($warning),
);
}
self::assertEmpty($warnings, $text);
}
protected static function assertSniffError(File $phpcsFile, int $line, string $code, ?string $message = null): void
{
$errors = $phpcsFile->getErrors();
self::assertTrue(isset($errors[$line]), sprintf('Expected error on line %s, but none found.', $line));
$sniffCode = sprintf('%s.%s', self::getSniffName(), $code);
self::assertTrue(
self::hasError($errors[$line], $sniffCode, $message),
sprintf(
'Expected error %s%s, but none found on line %d.%sErrors found on line %d:%s%s%s',
$sniffCode,
$message !== null
? sprintf(' with message "%s"', $message)
: '',
$line,
PHP_EOL . PHP_EOL,
$line,
PHP_EOL,
self::getFormattedErrors($errors[$line]),
PHP_EOL,
),
);
}
protected static function assertSniffWarning(File $phpcsFile, int $line, string $code, ?string $message = null): void
{
$errors = $phpcsFile->getWarnings();
self::assertTrue(isset($errors[$line]), sprintf('Expected warning on line %s, but none found.', $line));
$sniffCode = sprintf('%s.%s', self::getSniffName(), $code);
self::assertTrue(
self::hasError($errors[$line], $sniffCode, $message),
sprintf(
'Expected warning %s%s, but none found on line %d.%sWarnings found on line %d:%s%s%s',
$sniffCode,
$message !== null
? sprintf(' with message "%s"', $message)
: '',
$line,
PHP_EOL . PHP_EOL,
$line,
PHP_EOL,
self::getFormattedErrors($errors[$line]),
PHP_EOL,
),
);
}
protected static function assertNoSniffError(File $phpcsFile, int $line): void
{
$errors = $phpcsFile->getErrors();
self::assertFalse(
isset($errors[$line]),
sprintf(
'Expected no error on line %s, but found:%s%s%s',
$line,
PHP_EOL . PHP_EOL,
isset($errors[$line]) ? self::getFormattedErrors($errors[$line]) : '',
PHP_EOL,
),
);
}
protected static function assertAllFixedInFile(File $phpcsFile): void
{
$phpcsFile->disableCaching();
$phpcsFile->fixer->fixFile();
self::assertStringEqualsFile(preg_replace('~(\\.php)$~', '.fixed\\1', $phpcsFile->getFilename()), $phpcsFile->fixer->getContents());
}
/**
* @return class-string
*/
protected static function getSniffClassName(): string
{
/** @var class-string $sniffClassName */
$sniffClassName = substr(static::class, 0, -strlen('Test'));
return $sniffClassName;
}
protected static function getSniffName(): string
{
return Common::getSniffCode(static::getSniffClassName());
}
private static function getSniffClassReflection(): ReflectionClass
{
static $reflections = [];
$className = static::getSniffClassName();
return $reflections[$className] ?? $reflections[$className] = new ReflectionClass($className);
}
/**
* @param list> $errorsOnLine
*/
private static function hasError(array $errorsOnLine, string $sniffCode, ?string $message): bool
{
$hasError = false;
foreach ($errorsOnLine as $errorsOnPosition) {
foreach ($errorsOnPosition as $error) {
/** @var string $errorSource */
$errorSource = $error['source'];
/** @var string $errorMessage */
$errorMessage = $error['message'];
if (
$errorSource === $sniffCode
&& (
$message === null
|| strpos($errorMessage, $message) !== false
)
) {
$hasError = true;
break;
}
}
}
return $hasError;
}
/**
* @param list> $errors
*/
private static function getFormattedErrors(array $errors): string
{
return implode(
PHP_EOL,
array_map(
static fn (array $errors): string => implode(
PHP_EOL,
array_map(static fn (array $error): string => sprintf("\t%s: %s", $error['source'], $error['message']), $errors),
),
$errors,
),
);
}
}
PK 41]U[3 [3 R coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertyDeclarationSniff.phpnu [ |null */
public ?array $modifiersOrder = [];
public bool $checkPromoted = false;
public bool $enableMultipleSpacesBetweenModifiersCheck = false;
/** @var array>|null */
private ?array $normalizedModifiersOrder = null;
/**
* @return array
*/
public function register(): array
{
return TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES;
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $modifierPointer
*/
public function process(File $phpcsFile, $modifierPointer): void
{
$tokens = $phpcsFile->getTokens();
$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $modifierPointer - 1);
if ($tokens[$asPointer]['code'] === T_AS) {
return;
}
$nextPointer = TokenHelper::findNextEffective($phpcsFile, $modifierPointer + 1);
if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
// We don't want to report the same property multiple times
return;
}
if ($tokens[$modifierPointer]['code'] === T_STATIC) {
if ($tokens[$nextPointer]['code'] === T_DOUBLE_COLON) {
// Ignore static::
return;
}
if ($tokens[$nextPointer]['code'] === T_OPEN_PARENTHESIS) {
// Ignore static()
return;
}
if (in_array($tokens[$nextPointer]['code'], [T_OPEN_CURLY_BRACKET, T_SEMICOLON, T_TYPE_UNION], true)) {
// Ignore "static" as return type hint of method
return;
}
}
// Ignore other class members with same mofidiers
$propertyPointer = TokenHelper::findNext($phpcsFile, [T_CLASS, T_FUNCTION, T_CONST, T_VARIABLE], $modifierPointer + 1);
if ($propertyPointer === null || $tokens[$propertyPointer]['code'] !== T_VARIABLE) {
return;
}
if (!PropertyHelper::isProperty($phpcsFile, $propertyPointer, $this->checkPromoted)) {
return;
}
$firstModifierPointer = PropertyHelper::getStartPointer($phpcsFile, $propertyPointer);
$this->checkModifiersOrder($phpcsFile, $propertyPointer, $firstModifierPointer, $modifierPointer);
$this->checkSpacesBetweenModifiers($phpcsFile, $propertyPointer, $firstModifierPointer, $modifierPointer);
$this->checkTypeHintSpacing($phpcsFile, $propertyPointer, $modifierPointer);
}
private function checkModifiersOrder(File $phpcsFile, int $propertyPointer, int $firstModifierPointer, int $lastModifierPointer): void
{
$modifiersPointers = TokenHelper::findNextAll(
$phpcsFile,
TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
$firstModifierPointer,
$lastModifierPointer + 1,
);
if (count($modifiersPointers) < 2) {
return;
}
$tokens = $phpcsFile->getTokens();
$modifiersGroups = $this->getNormalizedModifiersOrder();
$expectedModifiersPositions = [];
foreach ($modifiersPointers as $modifierPointer) {
$position = 0;
for ($i = 0; $i < count($modifiersGroups); $i++) {
$modifierPositionInGroup = array_search($tokens[$modifierPointer]['code'], $modifiersGroups[$i], true);
if ($modifierPositionInGroup !== false) {
$expectedModifiersPositions[$modifierPointer] = $position + $modifierPositionInGroup;
continue 2;
}
$position += count($modifiersGroups[$i]);
}
// Modifier position is not defined so add it to the end
$expectedModifiersPositions[$modifierPointer] = $position;
}
$error = false;
for ($i = 1; $i < count($modifiersPointers); $i++) {
for ($j = 0; $j < $i; $j++) {
if ($expectedModifiersPositions[$modifiersPointers[$i]] < $expectedModifiersPositions[$modifiersPointers[$j]]) {
$error = true;
break;
}
}
}
if (!$error) {
return;
}
$actualModifiers = array_map(static fn (int $modifierPointer): string => $tokens[$modifierPointer]['content'], $modifiersPointers);
$actualModifiersFormatted = implode(' ', $actualModifiers);
asort($expectedModifiersPositions);
$expectedModifiers = array_map(
static fn (int $modifierPointer): string => $tokens[$modifierPointer]['content'],
array_keys($expectedModifiersPositions),
);
$expectedModifiersFormatted = implode(' ', $expectedModifiers);
$fix = $phpcsFile->addFixableError(
sprintf(
'Incorrect order of modifiers "%s" of property %s, expected "%s".',
$actualModifiersFormatted,
$tokens[$propertyPointer]['content'],
$expectedModifiersFormatted,
),
$firstModifierPointer,
self::CODE_INCORRECT_ORDER_OF_MODIFIERS,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::change($phpcsFile, $firstModifierPointer, $lastModifierPointer, $expectedModifiersFormatted);
$phpcsFile->fixer->endChangeset();
}
private function checkSpacesBetweenModifiers(
File $phpcsFile,
int $propertyPointer,
int $firstModifierPointer,
int $lastModifierPointer
): void
{
if (!$this->enableMultipleSpacesBetweenModifiersCheck) {
return;
}
$modifiersPointers = TokenHelper::findNextAll(
$phpcsFile,
TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
$firstModifierPointer,
$lastModifierPointer + 1,
);
if (count($modifiersPointers) < 2) {
return;
}
$tokens = $phpcsFile->getTokens();
$error = false;
for ($i = 0; $i < count($modifiersPointers) - 1; $i++) {
$whitespace = TokenHelper::getContent($phpcsFile, $modifiersPointers[$i] + 1, $modifiersPointers[$i + 1] - 1);
if ($whitespace !== ' ') {
$error = true;
break;
}
}
if (!$error) {
return;
}
$fix = $phpcsFile->addFixableError(
sprintf('There must be exactly one space between modifiers of property %s.', $tokens[$propertyPointer]['content']),
$firstModifierPointer,
self::CODE_MULTIPLE_SPACES_BETWEEN_MODIFIERS,
);
if (!$fix) {
return;
}
$expectedModifiers = array_map(
static fn (int $modifierPointer): string => $tokens[$modifierPointer]['content'],
$modifiersPointers,
);
$expectedModifiersFormatted = implode(' ', $expectedModifiers);
$phpcsFile->fixer->beginChangeset();
FixerHelper::change($phpcsFile, $firstModifierPointer, $lastModifierPointer, $expectedModifiersFormatted);
$phpcsFile->fixer->endChangeset();
}
private function checkTypeHintSpacing(File $phpcsFile, int $propertyPointer, int $lastModifierPointer): void
{
$typeHintEndPointer = TokenHelper::findPrevious(
$phpcsFile,
TokenHelper::TYPE_HINT_TOKEN_CODES,
$propertyPointer - 1,
$lastModifierPointer,
);
if ($typeHintEndPointer === null) {
return;
}
$tokens = $phpcsFile->getTokens();
$typeHintStartPointer = TypeHintHelper::getStartPointer($phpcsFile, $typeHintEndPointer);
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $typeHintStartPointer - 1, $lastModifierPointer);
$nullabilitySymbolPointer = $previousPointer !== null && $tokens[$previousPointer]['code'] === T_NULLABLE ? $previousPointer : null;
$propertyName = $tokens[$propertyPointer]['content'];
if ($tokens[$lastModifierPointer + 1]['code'] !== T_WHITESPACE) {
$errorMessage = sprintf('There must be exactly one space before type hint nullability symbol of property %s.', $propertyName);
$errorCode = self::CODE_NO_SPACE_BEFORE_NULLABILITY_SYMBOL;
$fix = $phpcsFile->addFixableError($errorMessage, $typeHintEndPointer, $errorCode);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
FixerHelper::add($phpcsFile, $lastModifierPointer, ' ');
$phpcsFile->fixer->endChangeset();
}
} elseif ($tokens[$lastModifierPointer + 1]['content'] !== ' ') {
if ($nullabilitySymbolPointer !== null) {
$errorMessage = sprintf(
'There must be exactly one space before type hint nullability symbol of property %s.',
$propertyName,
);
$errorCode = self::CODE_MULTIPLE_SPACES_BEFORE_NULLABILITY_SYMBOL;
} else {
$errorMessage = sprintf('There must be exactly one space before type hint of property %s.', $propertyName);
$errorCode = self::CODE_MULTIPLE_SPACES_BEFORE_TYPE_HINT;
}
$fix = $phpcsFile->addFixableError($errorMessage, $lastModifierPointer, $errorCode);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $lastModifierPointer + 1, ' ');
$phpcsFile->fixer->endChangeset();
}
}
if ($tokens[$typeHintEndPointer + 1]['code'] !== T_WHITESPACE) {
$fix = $phpcsFile->addFixableError(
sprintf('There must be exactly one space between type hint and property %s.', $propertyName),
$typeHintEndPointer,
self::CODE_NO_SPACE_BETWEEN_TYPE_HINT_AND_PROPERTY,
);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
FixerHelper::add($phpcsFile, $typeHintEndPointer, ' ');
$phpcsFile->fixer->endChangeset();
}
} elseif ($tokens[$typeHintEndPointer + 1]['content'] !== ' ') {
$fix = $phpcsFile->addFixableError(
sprintf('There must be exactly one space between type hint and property %s.', $propertyName),
$typeHintEndPointer,
self::CODE_MULTIPLE_SPACES_BETWEEN_TYPE_HINT_AND_PROPERTY,
);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $typeHintEndPointer + 1, ' ');
$phpcsFile->fixer->endChangeset();
}
}
if ($nullabilitySymbolPointer === null) {
return;
}
if ($nullabilitySymbolPointer + 1 === $typeHintStartPointer) {
return;
}
$fix = $phpcsFile->addFixableError(
sprintf('There must be no whitespace between type hint nullability symbol and type hint of property %s.', $propertyName),
$typeHintStartPointer,
self::CODE_WHITESPACE_AFTER_NULLABILITY_SYMBOL,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $nullabilitySymbolPointer + 1, '');
$phpcsFile->fixer->endChangeset();
}
/**
* @return array>
*/
private function getNormalizedModifiersOrder(): array
{
if ($this->normalizedModifiersOrder === null) {
$modifiersGroups = SniffSettingsHelper::normalizeArray($this->modifiersOrder);
if ($modifiersGroups === []) {
$modifiersGroups = [
'final, abstract',
'var, public, public(set), protected, protected(set), private, private(set)',
'static, readonly',
];
}
$this->normalizedModifiersOrder = [];
$mapping = [
'final' => T_FINAL,
'abstract' => T_ABSTRACT,
'var' => T_VAR,
'public' => T_PUBLIC,
'public(set)' => T_PUBLIC_SET,
'protected' => T_PROTECTED,
'protected(set)' => T_PROTECTED_SET,
'private' => T_PRIVATE,
'private(set)' => T_PRIVATE_SET,
'static' => T_STATIC,
'readonly' => T_READONLY,
];
foreach ($modifiersGroups as $modifiersGroupNo => $modifiersGroup) {
$this->normalizedModifiersOrder[$modifiersGroupNo] = [];
/** @var list $modifiers */
$modifiers = preg_split('~\\s*,\\s*~', strtolower($modifiersGroup));
foreach ($modifiers as $modifier) {
if (!array_key_exists($modifier, $mapping)) {
throw new UnexpectedValueException(sprintf('Unknown property modifier "%s".', $modifier));
}
$this->normalizedModifiersOrder[$modifiersGroupNo][] = $mapping[$modifier];
}
}
}
return $this->normalizedModifiersOrder;
}
}
PK 41]Rd d N coding-standard/SlevomatCodingStandard/Sniffs/Classes/EnumCaseSpacingSniff.phpnu [
*/
public function register(): array
{
return [T_ENUM_CASE];
}
protected function isNextMemberValid(File $phpcsFile, int $pointer): bool
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$pointer]['code'] === T_ENUM_CASE) {
return true;
}
$nextPointer = TokenHelper::findNext($phpcsFile, [T_FUNCTION, T_CONST, T_VARIABLE, T_USE, T_ENUM_CASE], $pointer + 1);
return $nextPointer !== null && $tokens[$nextPointer]['code'] === T_ENUM_CASE;
}
protected function addError(File $phpcsFile, int $pointer, int $minExpectedLines, int $maxExpectedLines, int $found): bool
{
if ($minExpectedLines === $maxExpectedLines) {
$errorMessage = $minExpectedLines === 1
? 'Expected 1 blank line after enum case, found %3$d.'
: 'Expected %2$d blank lines after enum case, found %3$d.';
} else {
$errorMessage = 'Expected %1$d to %2$d blank lines after enum case, found %3$d.';
}
$error = sprintf($errorMessage, $minExpectedLines, $maxExpectedLines, $found);
return $phpcsFile->addFixableError($error, $pointer, self::CODE_INCORRECT_COUNT_OF_BLANK_LINES_AFTER_ENUM_CASE);
}
}
PK 41]A9"
"
V coding-standard/SlevomatCodingStandard/Sniffs/Classes/ForbiddenPublicPropertySniff.phpnu [
*/
public function register(): array
{
return TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES;
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): void
{
$tokens = $phpcsFile->getTokens();
$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $pointer - 1);
if ($tokens[$asPointer]['code'] === T_AS) {
return;
}
$nextPointer = TokenHelper::findNextEffective($phpcsFile, $pointer + 1);
if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
// We don't want to report the same property multiple times
return;
}
// Ignore other class members with same mofidiers
$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_CONST, T_FUNCTION, T_CLASS], $pointer + 1);
if (
$propertyPointer === null
|| $tokens[$propertyPointer]['code'] !== T_VARIABLE
|| !PropertyHelper::isProperty($phpcsFile, $propertyPointer, $this->checkPromoted)
) {
return;
}
// Skip sniff classes, they have public properties for configuration (unfortunately)
if ($this->isSniffClass($phpcsFile, $propertyPointer)) {
return;
}
$propertyStartPointer = PropertyHelper::getStartPointer($phpcsFile, $propertyPointer);
$modifiersPointers = TokenHelper::findNextAll(
$phpcsFile,
TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
$propertyStartPointer,
$propertyPointer,
);
$modifiersCodes = array_map(static fn (int $modifierPointer) => $tokens[$modifierPointer]['code'], $modifiersPointers);
if (in_array(T_PROTECTED, $modifiersCodes, true) || in_array(T_PRIVATE, $modifiersCodes, true)) {
return;
}
if ($this->allowReadonly && in_array(T_READONLY, $modifiersCodes, true)) {
return;
}
if (
$this->allowNonPublicSet
&& (
in_array(T_PROTECTED_SET, $modifiersCodes, true)
|| in_array(T_PRIVATE_SET, $modifiersCodes, true)
)
) {
return;
}
$phpcsFile->addError(
'Do not use public properties. Use method access instead.',
$propertyPointer,
self::CODE_FORBIDDEN_PUBLIC_PROPERTY,
);
}
private function isSniffClass(File $phpcsFile, int $position): bool
{
$classTokenPosition = ClassHelper::getClassPointer($phpcsFile, $position);
$classNameToken = ClassHelper::getName($phpcsFile, $classTokenPosition);
return StringHelper::endsWith($classNameToken, 'Sniff');
}
}
PK 41]
?({ { Z coding-standard/SlevomatCodingStandard/Sniffs/Classes/EmptyLinesAroundClassBracesSniff.phpnu [
*/
public function register(): array
{
return array_values(Tokens::$ooScopeTokens);
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $stackPointer
*/
public function process(File $phpcsFile, $stackPointer): void
{
$this->linesCountAfterOpeningBrace = SniffSettingsHelper::normalizeInteger($this->linesCountAfterOpeningBrace);
$this->linesCountBeforeClosingBrace = SniffSettingsHelper::normalizeInteger($this->linesCountBeforeClosingBrace);
$this->processOpeningBrace($phpcsFile, $stackPointer);
$this->processClosingBrace($phpcsFile, $stackPointer);
}
private function processOpeningBrace(File $phpcsFile, int $stackPointer): void
{
$tokens = $phpcsFile->getTokens();
$typeToken = $tokens[$stackPointer];
$openerPointer = $typeToken['scope_opener'];
$openerToken = $tokens[$openerPointer];
$nextPointerAfterOpeningBrace = TokenHelper::findNextNonWhitespace($phpcsFile, $openerPointer + 1);
$nextTokenAfterOpeningBrace = $tokens[$nextPointerAfterOpeningBrace];
$lines = $nextTokenAfterOpeningBrace['line'] - $openerToken['line'] - 1;
if ($lines === $this->linesCountAfterOpeningBrace) {
return;
}
if ($this->linesCountAfterOpeningBrace === 1) {
$fix = $phpcsFile->addFixableError(
sprintf('There must be one empty line after %s opening brace.', $typeToken['content']),
$openerPointer,
$lines === 0
? self::CODE_NO_EMPTY_LINE_AFTER_OPENING_BRACE
: self::CODE_MULTIPLE_EMPTY_LINES_AFTER_OPENING_BRACE,
);
} else {
$fix = $phpcsFile->addFixableError(sprintf(
'There must be exactly %d empty lines after %s opening brace.',
$this->linesCountAfterOpeningBrace,
$typeToken['content'],
), $openerPointer, self::CODE_INCORRECT_EMPTY_LINES_AFTER_OPENING_BRACE);
}
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
if ($lines < $this->linesCountAfterOpeningBrace) {
for ($i = $lines; $i < $this->linesCountAfterOpeningBrace; $i++) {
$phpcsFile->fixer->addNewline($openerPointer);
}
} else {
for ($i = $openerPointer + $this->linesCountAfterOpeningBrace + 2; $i < $nextPointerAfterOpeningBrace; $i++) {
if ($phpcsFile->fixer->getTokenContent($i) !== $phpcsFile->eolChar) {
break;
}
FixerHelper::replace($phpcsFile, $i, '');
}
}
$phpcsFile->fixer->endChangeset();
}
private function processClosingBrace(File $phpcsFile, int $stackPointer): void
{
$tokens = $phpcsFile->getTokens();
$typeToken = $tokens[$stackPointer];
$closerPointer = $typeToken['scope_closer'];
$closerToken = $tokens[$closerPointer];
$previousPointerBeforeClosingBrace = TokenHelper::findPreviousNonWhitespace($phpcsFile, $closerPointer - 1);
$previousTokenBeforeClosingBrace = $tokens[$previousPointerBeforeClosingBrace];
$lines = $closerToken['line'] - $previousTokenBeforeClosingBrace['line'] - 1;
if ($lines === $this->linesCountBeforeClosingBrace) {
return;
}
if ($this->linesCountBeforeClosingBrace === 1) {
$fix = $phpcsFile->addFixableError(
sprintf('There must be one empty line before %s closing brace.', $typeToken['content']),
$closerPointer,
$lines === 0
? self::CODE_NO_EMPTY_LINE_BEFORE_CLOSING_BRACE
: self::CODE_MULTIPLE_EMPTY_LINES_BEFORE_CLOSING_BRACE,
);
} else {
$fix = $phpcsFile->addFixableError(sprintf(
'There must be exactly %d empty lines before %s closing brace.',
$this->linesCountBeforeClosingBrace,
$typeToken['content'],
), $closerPointer, self::CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE);
}
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
if ($lines < $this->linesCountBeforeClosingBrace) {
for ($i = $lines; $i < $this->linesCountBeforeClosingBrace; $i++) {
$phpcsFile->fixer->addNewlineBefore($closerPointer);
}
} else {
FixerHelper::removeBetween(
$phpcsFile,
$previousPointerBeforeClosingBrace + $this->linesCountBeforeClosingBrace + 1,
$closerPointer,
);
}
$phpcsFile->fixer->endChangeset();
}
}
PK 41]RZ V coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassConstantVisibilitySniff.phpnu [
*/
public function register(): array
{
return [
T_CONST,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $constantPointer
*/
public function process(File $phpcsFile, $constantPointer): void
{
$tokens = $phpcsFile->getTokens();
if (count($tokens[$constantPointer]['conditions']) === 0) {
return;
}
/** @var int $classPointer */
$classPointer = array_keys($tokens[$constantPointer]['conditions'])[count($tokens[$constantPointer]['conditions']) - 1];
if (!in_array($tokens[$classPointer]['code'], Tokens::$ooScopeTokens, true)) {
return;
}
$visibilityPointer = TokenHelper::findPreviousEffective($phpcsFile, $constantPointer - 1);
if ($tokens[$visibilityPointer]['code'] === T_FINAL) {
$visibilityPointer = TokenHelper::findPreviousEffective($phpcsFile, $visibilityPointer - 1);
}
if (in_array($tokens[$visibilityPointer]['code'], [T_PUBLIC, T_PROTECTED, T_PRIVATE], true)) {
return;
}
$equalSignPointer = TokenHelper::findNext($phpcsFile, T_EQUAL, $constantPointer + 1);
$namePointer = TokenHelper::findPreviousEffective($phpcsFile, $equalSignPointer - 1);
$message = sprintf(
'Constant %s::%s visibility missing.',
ClassHelper::getFullyQualifiedName($phpcsFile, $classPointer),
$tokens[$namePointer]['content'],
);
if ($this->fixable) {
$fix = $phpcsFile->addFixableError($message, $constantPointer, self::CODE_MISSING_CONSTANT_VISIBILITY);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
FixerHelper::addBefore($phpcsFile, $constantPointer, 'public ');
$phpcsFile->fixer->endChangeset();
}
} else {
$phpcsFile->addError($message, $constantPointer, self::CODE_MISSING_CONSTANT_VISIBILITY);
}
}
}
PK 41]hqw2 2 X coding-standard/SlevomatCodingStandard/Sniffs/Classes/UnsupportedClassGroupException.phpnu [
*/
public function register(): array
{
return [T_OBJECT_OPERATOR];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $objectOperatorPointer
*/
public function process(File $phpcsFile, $objectOperatorPointer): void
{
$tokens = $phpcsFile->getTokens();
$curlyBracketOpenerPointer = TokenHelper::findNextEffective($phpcsFile, $objectOperatorPointer + 1);
if ($tokens[$curlyBracketOpenerPointer]['code'] !== T_OPEN_CURLY_BRACKET) {
return;
}
$curlyBracketCloserPointer = $tokens[$curlyBracketOpenerPointer]['bracket_closer'];
if (TokenHelper::findNextExcluding(
$phpcsFile,
T_CONSTANT_ENCAPSED_STRING,
$curlyBracketOpenerPointer + 1,
$curlyBracketCloserPointer,
) !== null) {
return;
}
$pointerAfterCurlyBracketCloser = TokenHelper::findNextEffective($phpcsFile, $curlyBracketCloserPointer + 1);
if ($tokens[$pointerAfterCurlyBracketCloser]['code'] === T_OPEN_PARENTHESIS) {
return;
}
if (preg_match(
'~^(["\'])([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\1$~',
$tokens[$curlyBracketOpenerPointer + 1]['content'],
$matches,
) !== 1) {
return;
}
$fix = $phpcsFile->addFixableError(
'String expression property fetch is disallowed, use identifier property fetch.',
$curlyBracketOpenerPointer,
self::CODE_DISALLOWED_STRING_EXPRESSION_PROPERTY_FETCH,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::change($phpcsFile, $curlyBracketOpenerPointer, $curlyBracketCloserPointer, $matches[2]);
$phpcsFile->fixer->endChangeset();
}
}
PK 41]2
d coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractPropertyConstantAndEnumCaseSpacing.phpnu [ minLinesCountBeforeWithComment = SniffSettingsHelper::normalizeInteger($this->minLinesCountBeforeWithComment);
$this->maxLinesCountBeforeWithComment = SniffSettingsHelper::normalizeInteger($this->maxLinesCountBeforeWithComment);
$this->minLinesCountBeforeWithoutComment = SniffSettingsHelper::normalizeInteger($this->minLinesCountBeforeWithoutComment);
$this->maxLinesCountBeforeWithoutComment = SniffSettingsHelper::normalizeInteger($this->maxLinesCountBeforeWithoutComment);
$this->minLinesCountBeforeMultiline = SniffSettingsHelper::normalizeNullableInteger($this->minLinesCountBeforeMultiline);
$this->maxLinesCountBeforeMultiline = SniffSettingsHelper::normalizeNullableInteger($this->maxLinesCountBeforeMultiline);
$tokens = $phpcsFile->getTokens();
$classPointer = ClassHelper::getClassPointer($phpcsFile, $pointer);
$endPointer = $this->getEndPointer($phpcsFile, $pointer);
$firstOnLinePointer = TokenHelper::findFirstTokenOnNextLine($phpcsFile, $endPointer);
assert($firstOnLinePointer !== null);
$nextFunctionPointer = TokenHelper::findNext(
$phpcsFile,
[T_FUNCTION, T_ENUM_CASE, T_CONST, T_VARIABLE, T_USE],
$firstOnLinePointer + 1,
);
if (
$nextFunctionPointer === null
|| $tokens[$nextFunctionPointer]['code'] === T_FUNCTION
|| $tokens[$nextFunctionPointer]['conditions'] !== $tokens[$pointer]['conditions']
) {
return $nextFunctionPointer ?? $firstOnLinePointer;
}
$types = [T_COMMENT, T_DOC_COMMENT_OPEN_TAG, T_ATTRIBUTE, T_ENUM_CASE, T_CONST, T_USE, ...TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES];
$nextPointer = TokenHelper::findNext($phpcsFile, $types, $firstOnLinePointer + 1, $tokens[$classPointer]['scope_closer']);
if (!$this->isNextMemberValid($phpcsFile, $nextPointer)) {
return $nextPointer;
}
$linesBetween = $tokens[$nextPointer]['line'] - $tokens[$endPointer]['line'] - 1;
if (in_array($tokens[$nextPointer]['code'], [T_DOC_COMMENT_OPEN_TAG, T_COMMENT, T_ATTRIBUTE], true)) {
$minExpectedLines = $this->minLinesCountBeforeWithComment;
$maxExpectedLines = $this->maxLinesCountBeforeWithComment;
} else {
$minExpectedLines = $this->minLinesCountBeforeWithoutComment;
$maxExpectedLines = $this->maxLinesCountBeforeWithoutComment;
}
if (
$this->minLinesCountBeforeMultiline !== null
&& !$this instanceof EnumCaseSpacingSniff
&& $tokens[$pointer]['line'] !== $tokens[$endPointer]['line']
) {
$minExpectedLines = max($minExpectedLines, $this->minLinesCountBeforeMultiline);
$maxExpectedLines = max($minExpectedLines, $maxExpectedLines);
}
if (
$this->maxLinesCountBeforeMultiline !== null
&& !$this instanceof EnumCaseSpacingSniff
&& $tokens[$pointer]['line'] !== $tokens[$endPointer]['line']
) {
$maxExpectedLines = max($minExpectedLines, $this->maxLinesCountBeforeMultiline);
}
if ($linesBetween >= $minExpectedLines && $linesBetween <= $maxExpectedLines) {
return $firstOnLinePointer;
}
$fix = $this->addError($phpcsFile, $pointer, $minExpectedLines, $maxExpectedLines, $linesBetween);
if (!$fix) {
return $firstOnLinePointer;
}
if ($linesBetween > $maxExpectedLines) {
$lastPointerOnLine = TokenHelper::findLastTokenOnLine($phpcsFile, $endPointer);
$firstPointerOnNextLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $nextPointer);
$phpcsFile->fixer->beginChangeset();
if ($maxExpectedLines > 0) {
FixerHelper::add(
$phpcsFile,
$lastPointerOnLine,
str_repeat($phpcsFile->eolChar, $maxExpectedLines),
);
}
FixerHelper::removeBetween($phpcsFile, $lastPointerOnLine, $firstPointerOnNextLine);
$phpcsFile->fixer->endChangeset();
} elseif ($linesBetween < $minExpectedLines) {
$phpcsFile->fixer->beginChangeset();
for ($i = 0; $i < $minExpectedLines - $linesBetween; $i++) {
$phpcsFile->fixer->addNewlineBefore($firstOnLinePointer);
}
$phpcsFile->fixer->endChangeset();
}
return $firstOnLinePointer;
}
private function getEndPointer(File $phpcsFile, int $pointer): int
{
$tokens = $phpcsFile->getTokens();
$endPointer = TokenHelper::findNext($phpcsFile, [T_SEMICOLON, T_OPEN_CURLY_BRACKET], $pointer + 1);
return $tokens[$endPointer]['code'] === T_OPEN_CURLY_BRACKET
? $tokens[$endPointer]['bracket_closer']
: $endPointer;
}
}
PK 41]KJ J N coding-standard/SlevomatCodingStandard/Sniffs/Classes/ConstantSpacingSniff.phpnu [
*/
public function register(): array
{
return [T_CONST];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $constantPointer
*/
public function process(File $phpcsFile, $constantPointer): int
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$constantPointer]['conditions'] === []) {
return $constantPointer;
}
/** @var int $classPointer */
$classPointer = array_keys($tokens[$constantPointer]['conditions'])[count($tokens[$constantPointer]['conditions']) - 1];
if (!in_array($tokens[$classPointer]['code'], Tokens::$ooScopeTokens, true)) {
return $constantPointer;
}
return parent::process($phpcsFile, $constantPointer);
}
protected function isNextMemberValid(File $phpcsFile, int $pointer): bool
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$pointer]['code'] === T_CONST) {
return true;
}
$nextPointer = TokenHelper::findNext($phpcsFile, [T_FUNCTION, T_ENUM_CASE, T_CONST, T_VARIABLE, T_USE], $pointer + 1);
return $nextPointer !== null && $tokens[$nextPointer]['code'] === T_CONST;
}
protected function addError(File $phpcsFile, int $pointer, int $minExpectedLines, int $maxExpectedLines, int $found): bool
{
if ($minExpectedLines === $maxExpectedLines) {
$errorMessage = $minExpectedLines === 1
? 'Expected 1 blank line after constant, found %3$d.'
: 'Expected %2$d blank lines after constant, found %3$d.';
} else {
$errorMessage = 'Expected %1$d to %2$d blank lines after constant, found %3$d.';
}
$error = sprintf($errorMessage, $minExpectedLines, $maxExpectedLines, $found);
return $phpcsFile->addFixableError($error, $pointer, self::CODE_INCORRECT_COUNT_OF_BLANK_LINES_AFTER_CONSTANT);
}
}
PK 41]ñ ] Y coding-standard/SlevomatCodingStandard/Sniffs/Classes/SuperfluousInterfaceNamingSniff.phpnu [
*/
public function register(): array
{
return [
T_INTERFACE,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $interfacePointer
*/
public function process(File $phpcsFile, $interfacePointer): void
{
$interfaceName = ClassHelper::getName($phpcsFile, $interfacePointer);
$this->checkPrefix($phpcsFile, $interfacePointer, $interfaceName);
$this->checkSuffix($phpcsFile, $interfacePointer, $interfaceName);
}
private function checkPrefix(File $phpcsFile, int $interfacePointer, string $interfaceName): void
{
$prefix = substr($interfaceName, 0, 9);
if (strtolower($prefix) !== 'interface') {
return;
}
$phpcsFile->addError(sprintf('Superfluous prefix "%s".', $prefix), $interfacePointer, self::CODE_SUPERFLUOUS_PREFIX);
}
private function checkSuffix(File $phpcsFile, int $interfacePointer, string $interfaceName): void
{
$suffix = substr($interfaceName, -9);
if (strtolower($suffix) !== 'interface') {
return;
}
$phpcsFile->addError(sprintf('Superfluous suffix "%s".', $suffix), $interfacePointer, self::CODE_SUPERFLUOUS_SUFFIX);
}
}
PK 41]\h" " Q coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassMemberSpacingSniff.phpnu [
*/
public function register(): array
{
return TokenHelper::CLASS_TYPE_WITH_ANONYMOUS_CLASS_TOKEN_CODES;
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $classPointer
*/
public function process(File $phpcsFile, $classPointer): void
{
$this->linesCountBetweenMembers = SniffSettingsHelper::normalizeInteger($this->linesCountBetweenMembers);
$tokens = $phpcsFile->getTokens();
$memberPointer = null;
do {
$previousMemberPointer = $memberPointer;
$memberPointer = $this->findNextMember(
$phpcsFile,
$classPointer,
$previousMemberPointer ?? $tokens[$classPointer]['scope_opener'],
);
if ($memberPointer === null) {
break;
}
if ($previousMemberPointer === null) {
continue;
}
if ($tokens[$previousMemberPointer]['code'] === $tokens[$memberPointer]['code']) {
continue;
}
$previousMemberEndPointer = $this->getMemberEndPointer($phpcsFile, $previousMemberPointer);
$hasCommentWithNewLineAfterPreviousMember = false;
$commentPointerAfterPreviousMember = TokenHelper::findNextNonWhitespace($phpcsFile, $previousMemberEndPointer + 1);
if (
in_array($tokens[$commentPointerAfterPreviousMember]['code'], TokenHelper::INLINE_COMMENT_TOKEN_CODES, true)
&& (
$tokens[$previousMemberEndPointer]['line'] === $tokens[$commentPointerAfterPreviousMember]['line']
|| $tokens[$previousMemberEndPointer]['line'] + 1 === $tokens[$commentPointerAfterPreviousMember]['line']
)
) {
$previousMemberEndPointer = CommentHelper::getCommentEndPointer($phpcsFile, $commentPointerAfterPreviousMember);
if (StringHelper::endsWith($tokens[$commentPointerAfterPreviousMember]['content'], $phpcsFile->eolChar)) {
$hasCommentWithNewLineAfterPreviousMember = true;
}
}
$memberStartPointer = $this->getMemberStartPointer($phpcsFile, $memberPointer, $previousMemberEndPointer);
$actualLinesCount = $tokens[$memberStartPointer]['line'] - $tokens[$previousMemberEndPointer]['line'] - 1;
if ($actualLinesCount === $this->linesCountBetweenMembers) {
continue;
}
$errorMessage = $this->linesCountBetweenMembers === 1
? 'Expected 1 blank line between class members, found %2$d.'
: 'Expected %1$d blank lines between class members, found %2$d.';
$firstPointerOnMemberLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $memberStartPointer);
$nonWhitespaceBetweenMembersPointer = TokenHelper::findNextNonWhitespace(
$phpcsFile,
$previousMemberEndPointer + 1,
$firstPointerOnMemberLine,
);
$errorParameters = [
sprintf($errorMessage, $this->linesCountBetweenMembers, $actualLinesCount),
$memberPointer,
self::CODE_INCORRECT_COUNT_OF_BLANK_LINES_BETWEEN_MEMBERS,
];
if ($nonWhitespaceBetweenMembersPointer !== null) {
$phpcsFile->addError(...$errorParameters);
continue;
}
$fix = $phpcsFile->addFixableError(...$errorParameters);
if (!$fix) {
continue;
}
$newLines = str_repeat(
$phpcsFile->eolChar,
$this->linesCountBetweenMembers + ($hasCommentWithNewLineAfterPreviousMember ? 0 : 1),
);
$phpcsFile->fixer->beginChangeset();
FixerHelper::add($phpcsFile, $previousMemberEndPointer, $newLines);
FixerHelper::removeBetween($phpcsFile, $previousMemberEndPointer, $firstPointerOnMemberLine);
$phpcsFile->fixer->endChangeset();
} while (true);
}
private function findNextMember(File $phpcsFile, int $classPointer, int $previousMemberPointer): ?int
{
$tokens = $phpcsFile->getTokens();
$memberTokenCodes = [T_USE, T_CONST, T_FUNCTION, T_ENUM_CASE, ...TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES];
$memberPointer = $previousMemberPointer;
do {
$memberPointer = TokenHelper::findNext(
$phpcsFile,
$memberTokenCodes,
$memberPointer + 1,
$tokens[$classPointer]['scope_closer'],
);
if ($memberPointer === null) {
return null;
}
if ($tokens[$memberPointer]['code'] === T_USE) {
if (!UseStatementHelper::isTraitUse($phpcsFile, $memberPointer)) {
continue;
}
} elseif (in_array($tokens[$memberPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $memberPointer - 1);
if ($tokens[$asPointer]['code'] === T_AS) {
continue;
}
$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_FUNCTION, T_CONST], $memberPointer + 1);
if (
$propertyPointer === null
|| $tokens[$propertyPointer]['code'] !== T_VARIABLE
|| !PropertyHelper::isProperty($phpcsFile, $propertyPointer)
) {
continue;
}
$memberPointer = $propertyPointer;
}
if (ScopeHelper::isInSameScope($phpcsFile, $memberPointer, $previousMemberPointer)) {
break;
}
} while (true);
return $memberPointer;
}
private function getMemberStartPointer(File $phpcsFile, int $memberPointer, int $previousMemberEndPointer): int
{
$tokens = $phpcsFile->getTokens();
$memberFirstCodePointer = $this->getMemberFirstCodePointer($phpcsFile, $memberPointer);
do {
if ($memberFirstCodePointer <= $previousMemberEndPointer) {
return TokenHelper::findNextNonWhitespace($phpcsFile, $memberFirstCodePointer + 1);
}
$pointerBefore = TokenHelper::findPreviousNonWhitespace($phpcsFile, $memberFirstCodePointer - 1);
if ($tokens[$pointerBefore]['code'] === T_ATTRIBUTE_END) {
$memberFirstCodePointer = $tokens[$pointerBefore]['attribute_opener'];
continue;
}
if (in_array($tokens[$pointerBefore]['code'], Tokens::$commentTokens, true)) {
$pointerBeforeComment = TokenHelper::findPreviousEffective($phpcsFile, $pointerBefore - 1);
if ($tokens[$pointerBeforeComment]['line'] !== $tokens[$pointerBefore]['line']) {
$memberFirstCodePointer = array_key_exists('comment_opener', $tokens[$pointerBefore])
? $tokens[$pointerBefore]['comment_opener']
: CommentHelper::getMultilineCommentStartPointer($phpcsFile, $pointerBefore);
continue;
}
}
break;
} while (true);
return $memberFirstCodePointer;
}
private function getMemberFirstCodePointer(File $phpcsFile, int $memberPointer): int
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$memberPointer]['code'] === T_USE) {
return $memberPointer;
}
$endTokenCodes = [T_SEMICOLON, T_CLOSE_CURLY_BRACKET];
$startOrEndTokenCodes = [...TokenHelper::MODIFIERS_TOKEN_CODES, ...$endTokenCodes];
$firstCodePointer = $memberPointer;
$previousFirstCodePointer = $memberPointer;
do {
/** @var int $firstCodePointer */
$firstCodePointer = TokenHelper::findPrevious($phpcsFile, $startOrEndTokenCodes, $firstCodePointer - 1);
if (in_array($tokens[$firstCodePointer]['code'], $endTokenCodes, true)) {
break;
}
$previousFirstCodePointer = $firstCodePointer;
} while (true);
return $previousFirstCodePointer;
}
private function getMemberEndPointer(File $phpcsFile, int $memberPointer): int
{
$tokens = $phpcsFile->getTokens();
if (
$tokens[$memberPointer]['code'] === T_USE
// Property with hooks
|| $tokens[$memberPointer]['code'] === T_VARIABLE
) {
$pointer = TokenHelper::findNextLocal($phpcsFile, [T_SEMICOLON, T_OPEN_CURLY_BRACKET], $memberPointer + 1);
return $tokens[$pointer]['code'] === T_OPEN_CURLY_BRACKET
? $tokens[$pointer]['bracket_closer']
: $pointer;
}
if ($tokens[$memberPointer]['code'] === T_FUNCTION && !FunctionHelper::isAbstract($phpcsFile, $memberPointer)) {
return $tokens[$memberPointer]['scope_closer'];
}
return TokenHelper::findNext($phpcsFile, T_SEMICOLON, $memberPointer + 1);
}
}
PK 41])m )m M coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassStructureSniff.phpnu [ [
self::GROUP_PUBLIC_CONSTANTS,
self::GROUP_PROTECTED_CONSTANTS,
self::GROUP_PRIVATE_CONSTANTS,
],
self::GROUP_SHORTCUT_STATIC_PROPERTIES => [
self::GROUP_PUBLIC_STATIC_PROPERTIES,
self::GROUP_PROTECTED_STATIC_PROPERTIES,
self::GROUP_PRIVATE_STATIC_PROPERTIES,
],
self::GROUP_SHORTCUT_PROPERTIES => [
self::GROUP_SHORTCUT_STATIC_PROPERTIES,
self::GROUP_PUBLIC_PROPERTIES,
self::GROUP_PROTECTED_PROPERTIES,
self::GROUP_PRIVATE_PROPERTIES,
],
self::GROUP_SHORTCUT_PUBLIC_METHODS => [
self::GROUP_PUBLIC_FINAL_METHODS,
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
self::GROUP_PUBLIC_ABSTRACT_METHODS,
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
self::GROUP_PUBLIC_STATIC_METHODS,
self::GROUP_PUBLIC_METHODS,
],
self::GROUP_SHORTCUT_PROTECTED_METHODS => [
self::GROUP_PROTECTED_FINAL_METHODS,
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
self::GROUP_PROTECTED_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_METHODS,
self::GROUP_PROTECTED_METHODS,
],
self::GROUP_SHORTCUT_PRIVATE_METHODS => [
self::GROUP_PRIVATE_STATIC_METHODS,
self::GROUP_PRIVATE_METHODS,
],
self::GROUP_SHORTCUT_FINAL_METHODS => [
self::GROUP_PUBLIC_FINAL_METHODS,
self::GROUP_PROTECTED_FINAL_METHODS,
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
],
self::GROUP_SHORTCUT_ABSTRACT_METHODS => [
self::GROUP_PUBLIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_ABSTRACT_METHODS,
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
],
self::GROUP_SHORTCUT_STATIC_METHODS => [
self::GROUP_STATIC_CONSTRUCTORS,
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
self::GROUP_PUBLIC_STATIC_METHODS,
self::GROUP_PROTECTED_STATIC_METHODS,
self::GROUP_PRIVATE_STATIC_METHODS,
],
self::GROUP_SHORTCUT_METHODS => [
self::GROUP_SHORTCUT_FINAL_METHODS,
self::GROUP_SHORTCUT_ABSTRACT_METHODS,
self::GROUP_SHORTCUT_STATIC_METHODS,
self::GROUP_CONSTRUCTOR,
self::GROUP_DESTRUCTOR,
self::GROUP_PUBLIC_METHODS,
self::GROUP_PROTECTED_METHODS,
self::GROUP_PRIVATE_METHODS,
self::GROUP_MAGIC_METHODS,
],
];
private const SPECIAL_METHODS = [
'__construct' => self::GROUP_CONSTRUCTOR,
'__destruct' => self::GROUP_DESTRUCTOR,
'__call' => self::GROUP_MAGIC_METHODS,
'__callstatic' => self::GROUP_MAGIC_METHODS,
'__get' => self::GROUP_MAGIC_METHODS,
'__set' => self::GROUP_MAGIC_METHODS,
'__isset' => self::GROUP_MAGIC_METHODS,
'__unset' => self::GROUP_MAGIC_METHODS,
'__sleep' => self::GROUP_MAGIC_METHODS,
'__wakeup' => self::GROUP_MAGIC_METHODS,
'__serialize' => self::GROUP_MAGIC_METHODS,
'__unserialize' => self::GROUP_MAGIC_METHODS,
'__tostring' => self::GROUP_MAGIC_METHODS,
'__invoke' => self::GROUP_INVOKE_METHOD,
'__set_state' => self::GROUP_MAGIC_METHODS,
'__clone' => self::GROUP_MAGIC_METHODS,
'__debuginfo' => self::GROUP_MAGIC_METHODS,
];
/** @var array */
public array $methodGroups = [];
/** @var list */
public array $groups = [];
/** @var array, annotations: array}>>|null */
private ?array $normalizedMethodGroups = null;
/** @var array|null */
private ?array $normalizedGroups = null;
/**
* @return array
*/
public function register(): array
{
return array_values(Tokens::$ooScopeTokens);
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): int
{
$tokens = $phpcsFile->getTokens();
$rootScopeToken = $tokens[$pointer];
assert(array_key_exists('scope_opener', $rootScopeToken));
$groupsOrder = $this->getNormalizedGroups();
$groupLastMemberPointer = $rootScopeToken['scope_opener'];
$expectedGroup = null;
$groupsFirstMembers = [];
while (true) {
$nextGroup = $this->findNextGroup($phpcsFile, $groupLastMemberPointer, $rootScopeToken);
if ($nextGroup === null) {
break;
}
[$groupFirstMemberPointer, $groupLastMemberPointer, $group] = $nextGroup;
// Use "magic methods" group for __invoke() when "invoke" group is not explicitly defined
if ($group === self::GROUP_INVOKE_METHOD && !array_key_exists($group, $groupsOrder)) {
$group = self::GROUP_MAGIC_METHODS;
}
if ($groupsOrder[$group] >= ($expectedGroup !== null ? $groupsOrder[$expectedGroup] : 0)) {
$groupsFirstMembers[$group] = $groupFirstMemberPointer;
$expectedGroup = $group;
continue;
}
$expectedGroups = array_filter(
$groupsOrder,
static fn (int $order): bool => $order >= $groupsOrder[$expectedGroup],
);
$fix = $phpcsFile->addFixableError(
sprintf(
'The placement of "%s" group is invalid. Last group was "%s" and one of these is expected after it: %s',
$group,
$expectedGroup,
implode(', ', array_keys($expectedGroups)),
),
$groupFirstMemberPointer,
self::CODE_INCORRECT_GROUP_ORDER,
);
if (!$fix) {
continue;
}
foreach ($groupsFirstMembers as $memberGroup => $firstMemberPointer) {
if ($groupsOrder[$memberGroup] <= $groupsOrder[$group]) {
continue;
}
$this->fixIncorrectGroupOrder($phpcsFile, $groupFirstMemberPointer, $groupLastMemberPointer, $firstMemberPointer);
// run the sniff again to fix the rest of the groups
return $pointer - 1;
}
}
return $pointer + 1;
}
/**
* @param array{scope_closer: int, level: int} $rootScopeToken
* @return array{int, int, string}|null
*/
private function findNextGroup(File $phpcsFile, int $pointer, array $rootScopeToken): ?array
{
$tokens = $phpcsFile->getTokens();
$currentTokenPointer = $pointer;
while (true) {
$currentTokenPointer = TokenHelper::findNext(
$phpcsFile,
[T_USE, T_ENUM_CASE, T_CONST, T_VARIABLE, T_FUNCTION],
$currentTokenPointer + 1,
$rootScopeToken['scope_closer'],
);
if ($currentTokenPointer === null) {
break;
}
$currentToken = $tokens[$currentTokenPointer];
if ($currentToken['code'] === T_VARIABLE && !PropertyHelper::isProperty($phpcsFile, $currentTokenPointer)) {
continue;
}
if ($currentToken['level'] - $rootScopeToken['level'] !== 1) {
continue;
}
$group = $this->getGroupForToken($phpcsFile, $currentTokenPointer);
if (!isset($currentGroup)) {
$currentGroup = $group;
$groupFirstMemberPointer = $currentTokenPointer;
}
if ($group !== $currentGroup) {
break;
}
$groupLastMemberPointer = $currentTokenPointer;
$currentTokenPointer = $currentToken['code'] === T_VARIABLE
// Skip to the end of the property definition
? PropertyHelper::getEndPointer($phpcsFile, $currentTokenPointer)
: ($currentToken['scope_closer'] ?? $currentTokenPointer);
}
if (!isset($currentGroup)) {
return null;
}
assert(isset($groupFirstMemberPointer) === true);
assert(isset($groupLastMemberPointer) === true);
return [$groupFirstMemberPointer, $groupLastMemberPointer, $currentGroup];
}
private function getGroupForToken(File $phpcsFile, int $pointer): string
{
$tokens = $phpcsFile->getTokens();
switch ($tokens[$pointer]['code']) {
case T_USE:
return self::GROUP_USES;
case T_ENUM_CASE:
return self::GROUP_ENUM_CASES;
case T_CONST:
switch ($this->getVisibilityForToken($phpcsFile, $pointer)) {
case T_PUBLIC:
return self::GROUP_PUBLIC_CONSTANTS;
case T_PROTECTED:
return self::GROUP_PROTECTED_CONSTANTS;
}
return self::GROUP_PRIVATE_CONSTANTS;
case T_FUNCTION:
$name = strtolower(FunctionHelper::getName($phpcsFile, $pointer));
if (array_key_exists($name, self::SPECIAL_METHODS)) {
return self::SPECIAL_METHODS[$name];
}
$methodGroup = $this->resolveMethodGroup($phpcsFile, $pointer, $name);
if ($methodGroup !== null) {
return $methodGroup;
}
$visibility = $this->getVisibilityForToken($phpcsFile, $pointer);
$isStatic = $this->isMemberStatic($phpcsFile, $pointer);
$isFinal = $this->isMethodFinal($phpcsFile, $pointer);
if ($this->isMethodAbstract($phpcsFile, $pointer)) {
if ($visibility === T_PUBLIC) {
return $isStatic ? self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS : self::GROUP_PUBLIC_ABSTRACT_METHODS;
}
return $isStatic ? self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS : self::GROUP_PROTECTED_ABSTRACT_METHODS;
}
if ($isStatic && $visibility === T_PUBLIC && $this->isStaticConstructor($phpcsFile, $pointer)) {
return self::GROUP_STATIC_CONSTRUCTORS;
}
switch ($visibility) {
case T_PUBLIC:
if ($isFinal) {
return $isStatic ? self::GROUP_PUBLIC_STATIC_FINAL_METHODS : self::GROUP_PUBLIC_FINAL_METHODS;
}
return $isStatic ? self::GROUP_PUBLIC_STATIC_METHODS : self::GROUP_PUBLIC_METHODS;
case T_PROTECTED:
if ($isFinal) {
return $isStatic ? self::GROUP_PROTECTED_STATIC_FINAL_METHODS : self::GROUP_PROTECTED_FINAL_METHODS;
}
return $isStatic ? self::GROUP_PROTECTED_STATIC_METHODS : self::GROUP_PROTECTED_METHODS;
}
return $isStatic ? self::GROUP_PRIVATE_STATIC_METHODS : self::GROUP_PRIVATE_METHODS;
default:
$isStatic = $this->isMemberStatic($phpcsFile, $pointer);
$visibility = $this->getVisibilityForToken($phpcsFile, $pointer);
switch ($visibility) {
case T_PUBLIC:
case T_PUBLIC_SET:
return $isStatic ? self::GROUP_PUBLIC_STATIC_PROPERTIES : self::GROUP_PUBLIC_PROPERTIES;
case T_PROTECTED:
return $isStatic
? self::GROUP_PROTECTED_STATIC_PROPERTIES
: self::GROUP_PROTECTED_PROPERTIES;
default:
return $isStatic ? self::GROUP_PRIVATE_STATIC_PROPERTIES : self::GROUP_PRIVATE_PROPERTIES;
}
}
}
private function resolveMethodGroup(File $phpcsFile, int $pointer, string $method): ?string
{
foreach ($this->getNormalizedMethodGroups() as $group => $methodRequirements) {
foreach ($methodRequirements as $methodRequirement) {
if ($methodRequirement['name'] !== null) {
$requiredName = strtolower($methodRequirement['name']);
if (StringHelper::endsWith($requiredName, '*')) {
$methodNamePrefix = substr($requiredName, 0, -1);
if ($method === $methodNamePrefix || !StringHelper::startsWith($method, $methodNamePrefix)) {
continue;
}
} elseif ($method !== $requiredName) {
continue;
}
}
if (
$this->hasRequiredAnnotations($phpcsFile, $pointer, $methodRequirement['annotations'])
&& $this->hasRequiredAttributes($phpcsFile, $pointer, $methodRequirement['attributes'])
) {
return $group;
}
}
}
return null;
}
/**
* @param array $requiredAnnotations
*/
private function hasRequiredAnnotations(File $phpcsFile, int $pointer, array $requiredAnnotations): bool
{
if ($requiredAnnotations === []) {
return true;
}
$annotations = [];
foreach (AnnotationHelper::getAnnotations($phpcsFile, $pointer) as $annotation) {
$annotations[$annotation->getName()] = true;
}
foreach ($requiredAnnotations as $requiredAnnotation) {
if (!array_key_exists('@' . $requiredAnnotation, $annotations)) {
return false;
}
}
return true;
}
/**
* @param array $requiredAttributes
*/
private function hasRequiredAttributes(File $phpcsFile, int $pointer, array $requiredAttributes): bool
{
if ($requiredAttributes === []) {
return true;
}
$attributesClassNames = $this->getAttributeClassNamesForToken($phpcsFile, $pointer);
foreach ($requiredAttributes as $requiredAttribute) {
if (!array_key_exists(strtolower($requiredAttribute), $attributesClassNames)) {
return false;
}
}
return true;
}
/**
* @return array
*/
private function getAttributeClassNamesForToken(File $phpcsFile, int $pointer): array
{
$attributes = [];
foreach (AttributeHelper::getAttributes($phpcsFile, $pointer) as $attribute) {
$attributes[strtolower(ltrim($attribute->getFullyQualifiedName(), '\\'))] = $attribute->getFullyQualifiedName();
}
return $attributes;
}
/**
* @return int|string
*/
private function getVisibilityForToken(File $phpcsFile, int $pointer)
{
$tokens = $phpcsFile->getTokens();
$previousPointer = $pointer - 1;
$endTokenCodes = [T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON];
$tokenCodesToSearch = [...array_values(Tokens::$scopeModifiers), ...$endTokenCodes];
do {
$previousPointer = TokenHelper::findPrevious($phpcsFile, $tokenCodesToSearch, $previousPointer - 1);
if (in_array($tokens[$previousPointer]['code'], $endTokenCodes, true)) {
// No visibility modifier found -> public
return T_PUBLIC;
}
if (in_array($tokens[$previousPointer]['code'], [T_PROTECTED_SET, T_PRIVATE_SET], true)) {
continue;
}
return $tokens[$previousPointer]['code'];
} while (true);
}
private function isMemberStatic(File $phpcsFile, int $pointer): bool
{
$previousPointer = TokenHelper::findPrevious(
$phpcsFile,
[T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON, T_STATIC],
$pointer - 1,
);
return $phpcsFile->getTokens()[$previousPointer]['code'] === T_STATIC;
}
private function isMethodFinal(File $phpcsFile, int $pointer): bool
{
$previousPointer = TokenHelper::findPrevious(
$phpcsFile,
[T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON, T_FINAL],
$pointer - 1,
);
return $phpcsFile->getTokens()[$previousPointer]['code'] === T_FINAL;
}
private function isMethodAbstract(File $phpcsFile, int $pointer): bool
{
$previousPointer = TokenHelper::findPrevious(
$phpcsFile,
[T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON, T_ABSTRACT],
$pointer - 1,
);
return $phpcsFile->getTokens()[$previousPointer]['code'] === T_ABSTRACT;
}
private function isStaticConstructor(File $phpcsFile, int $pointer): bool
{
$parentClassName = $this->getParentClassName($phpcsFile, $pointer);
$returnTypeHint = FunctionHelper::findReturnTypeHint($phpcsFile, $pointer);
if ($returnTypeHint !== null) {
return in_array($returnTypeHint->getTypeHintWithoutNullabilitySymbol(), ['self', $parentClassName], true);
}
$returnAnnotation = FunctionHelper::findReturnAnnotation($phpcsFile, $pointer);
if ($returnAnnotation === null) {
return false;
}
return in_array((string) $returnAnnotation->getValue()->type, ['static', 'self', $parentClassName], true);
}
private function getParentClassName(File $phpcsFile, int $pointer): string
{
$classPointer = TokenHelper::findPrevious($phpcsFile, Tokens::$ooScopeTokens, $pointer - 1);
assert($classPointer !== null);
return ClassHelper::getName($phpcsFile, $classPointer);
}
private function fixIncorrectGroupOrder(
File $file,
int $groupFirstMemberPointer,
int $groupLastMemberPointer,
int $nextGroupMemberPointer
): void
{
$previousMemberEndPointer = $this->findPreviousMemberEndPointer($file, $groupFirstMemberPointer);
$groupStartPointer = $this->findGroupStartPointer($file, $groupFirstMemberPointer, $previousMemberEndPointer);
$groupEndPointer = $this->findGroupEndPointer($file, $groupLastMemberPointer);
$groupContent = TokenHelper::getContent($file, $groupStartPointer, $groupEndPointer);
$nextGroupMemberStartPointer = $this->findGroupStartPointer($file, $nextGroupMemberPointer);
$file->fixer->beginChangeset();
FixerHelper::removeBetweenIncluding($file, $groupStartPointer, $groupEndPointer);
$linesBetween = $this->removeBlankLinesAfterMember($file, $previousMemberEndPointer, $groupStartPointer);
$newLines = str_repeat($file->eolChar, $linesBetween);
FixerHelper::addBefore($file, $nextGroupMemberStartPointer, $groupContent . $newLines);
$file->fixer->endChangeset();
}
private function findPreviousMemberEndPointer(File $phpcsFile, int $memberPointer): int
{
$endTypes = [T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON];
$previousMemberEndPointer = TokenHelper::findPrevious($phpcsFile, $endTypes, $memberPointer - 1);
assert($previousMemberEndPointer !== null);
return $previousMemberEndPointer;
}
private function findGroupStartPointer(File $phpcsFile, int $memberPointer, ?int $previousMemberEndPointer = null): int
{
$startPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $memberPointer - 1);
if ($startPointer === null) {
$previousMemberEndPointer ??= $this->findPreviousMemberEndPointer($phpcsFile, $memberPointer);
$startPointer = TokenHelper::findNextEffective($phpcsFile, $previousMemberEndPointer + 1);
assert($startPointer !== null);
}
$types = [T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON];
return (int) $phpcsFile->findFirstOnLine($types, $startPointer, true);
}
private function findGroupEndPointer(File $phpcsFile, int $memberPointer): int
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$memberPointer]['code'] === T_FUNCTION && !FunctionHelper::isAbstract($phpcsFile, $memberPointer)) {
return $tokens[$memberPointer]['scope_closer'];
}
if ($tokens[$memberPointer]['code'] === T_USE && array_key_exists('scope_closer', $tokens[$memberPointer])) {
return $tokens[$memberPointer]['scope_closer'];
}
$endPointer = TokenHelper::findNext($phpcsFile, [T_SEMICOLON, T_OPEN_CURLY_BRACKET], $memberPointer + 1);
return $tokens[$endPointer]['code'] === T_OPEN_CURLY_BRACKET
? $tokens[$endPointer]['bracket_closer']
: $endPointer;
}
private function removeBlankLinesAfterMember(File $phpcsFile, int $memberEndPointer, int $endPointer): int
{
$whitespacePointer = $memberEndPointer;
$linesToRemove = 0;
while (true) {
$whitespacePointer = TokenHelper::findNext($phpcsFile, T_WHITESPACE, $whitespacePointer, $endPointer);
if ($whitespacePointer === null) {
break;
}
$linesToRemove++;
FixerHelper::replace($phpcsFile, $whitespacePointer, '');
$whitespacePointer++;
}
return $linesToRemove;
}
/**
* @return array, annotations: array}>>
*/
private function getNormalizedMethodGroups(): array
{
if ($this->normalizedMethodGroups === null) {
$this->normalizedMethodGroups = [];
$methodGroups = SniffSettingsHelper::normalizeAssociativeArray($this->methodGroups);
foreach ($methodGroups as $group => $groupDefinition) {
$group = strtolower((string) $group);
$this->normalizedMethodGroups[$group] = [];
$methodDefinitions = preg_split('~\\s*,\\s*~', (string) $groupDefinition, -1, PREG_SPLIT_NO_EMPTY);
/** @var list $methodDefinitions */
foreach ($methodDefinitions as $methodDefinition) {
$tokens = preg_split('~(?=[#@])~', $methodDefinition);
/** @var non-empty-list $tokens */
$method = array_shift($tokens);
$methodRequirement = [
'name' => $method !== '' ? $method : null,
'attributes' => [],
'annotations' => [],
];
foreach ($tokens as $token) {
$key = $token[0] === '#' ? 'attributes' : 'annotations';
$methodRequirement[$key][] = substr($token, 1);
}
$this->normalizedMethodGroups[$group][] = $methodRequirement;
}
}
}
return $this->normalizedMethodGroups;
}
/**
* @return array
*/
private function getNormalizedGroups(): array
{
if ($this->normalizedGroups === null) {
$supportedGroups = [
self::GROUP_USES,
self::GROUP_ENUM_CASES,
self::GROUP_PUBLIC_CONSTANTS,
self::GROUP_PROTECTED_CONSTANTS,
self::GROUP_PRIVATE_CONSTANTS,
self::GROUP_PUBLIC_PROPERTIES,
self::GROUP_PUBLIC_STATIC_PROPERTIES,
self::GROUP_PROTECTED_PROPERTIES,
self::GROUP_PROTECTED_STATIC_PROPERTIES,
self::GROUP_PRIVATE_PROPERTIES,
self::GROUP_PRIVATE_STATIC_PROPERTIES,
self::GROUP_PUBLIC_STATIC_FINAL_METHODS,
self::GROUP_PUBLIC_STATIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_STATIC_FINAL_METHODS,
self::GROUP_PROTECTED_STATIC_ABSTRACT_METHODS,
self::GROUP_PUBLIC_FINAL_METHODS,
self::GROUP_PUBLIC_ABSTRACT_METHODS,
self::GROUP_PROTECTED_FINAL_METHODS,
self::GROUP_PROTECTED_ABSTRACT_METHODS,
self::GROUP_CONSTRUCTOR,
self::GROUP_STATIC_CONSTRUCTORS,
self::GROUP_DESTRUCTOR,
self::GROUP_PUBLIC_METHODS,
self::GROUP_PUBLIC_STATIC_METHODS,
self::GROUP_PROTECTED_METHODS,
self::GROUP_PROTECTED_STATIC_METHODS,
self::GROUP_PRIVATE_METHODS,
self::GROUP_PRIVATE_STATIC_METHODS,
self::GROUP_MAGIC_METHODS,
];
$normalizedMethodGroups = $this->getNormalizedMethodGroups();
$normalizedGroupsWithShortcuts = [];
$order = 1;
foreach (SniffSettingsHelper::normalizeArray($this->groups) as $groupsString) {
/** @var list $groups */
$groups = preg_split('~\\s*,\\s*~', strtolower($groupsString), -1, PREG_SPLIT_NO_EMPTY);
foreach ($groups as $groupOrShortcut) {
$groupOrShortcut = preg_replace('~\\s+~', ' ', $groupOrShortcut);
if (
!in_array($groupOrShortcut, $supportedGroups, true)
&& !array_key_exists($groupOrShortcut, self::SHORTCUTS)
&& $groupOrShortcut !== self::GROUP_INVOKE_METHOD
&& !array_key_exists($groupOrShortcut, $normalizedMethodGroups)
) {
throw new UnsupportedClassGroupException($groupOrShortcut);
}
$normalizedGroupsWithShortcuts[$groupOrShortcut] = $order;
}
$order++;
}
$normalizedGroups = [];
foreach ($normalizedGroupsWithShortcuts as $groupOrShortcut => $groupOrder) {
if (
in_array($groupOrShortcut, $supportedGroups, true)
|| $groupOrShortcut === self::GROUP_INVOKE_METHOD
|| array_key_exists($groupOrShortcut, $normalizedMethodGroups)
) {
$normalizedGroups[$groupOrShortcut] = $groupOrder;
} else {
foreach ($this->unpackShortcut($groupOrShortcut, $supportedGroups) as $group) {
if (
array_key_exists($group, $normalizedGroupsWithShortcuts)
|| array_key_exists($group, $normalizedGroups)
) {
continue;
}
$normalizedGroups[$group] = $groupOrder;
}
}
}
if ($normalizedGroups === [] && $normalizedMethodGroups === []) {
$normalizedGroups = array_flip($supportedGroups);
} else {
$missingGroups = array_diff(
array_merge($supportedGroups, array_keys($normalizedMethodGroups)),
array_keys($normalizedGroups),
);
if ($missingGroups !== []) {
throw new MissingClassGroupsException(array_values($missingGroups));
}
}
$this->normalizedGroups = $normalizedGroups;
}
return $this->normalizedGroups;
}
/**
* @param array $supportedGroups
* @return array
*/
private function unpackShortcut(string $shortcut, array $supportedGroups): array
{
$groups = [];
foreach (self::SHORTCUTS[$shortcut] as $groupOrShortcut) {
if (in_array($groupOrShortcut, $supportedGroups, true)) {
$groups[] = $groupOrShortcut;
} elseif (
!array_key_exists($groupOrShortcut, self::SHORTCUTS)
&& in_array($groupOrShortcut, self::SHORTCUTS[self::GROUP_SHORTCUT_FINAL_METHODS], true)
) {
// Nothing
} else {
$groups = array_merge($groups, $this->unpackShortcut($groupOrShortcut, $supportedGroups));
}
}
return $groups;
}
}
PK 41]& U coding-standard/SlevomatCodingStandard/Sniffs/Classes/SuperfluousTraitNamingSniff.phpnu [
*/
public function register(): array
{
return [
T_TRAIT,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $traitPointer
*/
public function process(File $phpcsFile, $traitPointer): void
{
$traitName = ClassHelper::getName($phpcsFile, $traitPointer);
$this->checkSuffix($phpcsFile, $traitPointer, $traitName);
}
private function checkSuffix(File $phpcsFile, int $traitPointer, string $traitName): void
{
$suffix = substr($traitName, -5);
if (strtolower($suffix) !== 'trait') {
return;
}
$phpcsFile->addError(sprintf('Superfluous suffix "%s".', $suffix), $traitPointer, self::CODE_SUPERFLUOUS_SUFFIX);
}
}
PK 41]ő
/
/ b coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireConstructorPropertyPromotionSniff.phpnu [
*/
public function register(): array
{
return [T_FUNCTION];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $functionPointer
*/
public function process(File $phpcsFile, $functionPointer): void
{
$this->enable = SniffSettingsHelper::isEnabledByPhpVersion($this->enable, 80000);
if (!$this->enable) {
return;
}
$tokens = $phpcsFile->getTokens();
$namePointer = TokenHelper::findNextEffective($phpcsFile, $functionPointer + 1);
if (strtolower($tokens[$namePointer]['content']) !== '__construct') {
return;
}
if (FunctionHelper::isAbstract($phpcsFile, $functionPointer)) {
return;
}
$parameterPointers = $this->getParameterPointers($phpcsFile, $functionPointer);
if (count($parameterPointers) === 0) {
return;
}
$parameterWithoutPromotionPointers = [];
foreach ($parameterPointers as $parameterPointer) {
$pointerBefore = TokenHelper::findPrevious($phpcsFile, [T_COMMA, T_OPEN_PARENTHESIS], $parameterPointer - 1);
$modifierPointer = TokenHelper::findNextEffective($phpcsFile, $pointerBefore + 1);
if (in_array($tokens[$modifierPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
continue;
}
$pointerBefore = TokenHelper::findPreviousEffective($phpcsFile, $parameterPointer - 1);
if ($tokens[$pointerBefore]['code'] === T_ELLIPSIS) {
continue;
}
if ($tokens[$pointerBefore]['code'] === T_BITWISE_AND) {
$pointerBefore = TokenHelper::findPreviousEffective($phpcsFile, $pointerBefore - 1);
}
if ($tokens[$pointerBefore]['code'] === T_CALLABLE) {
continue;
}
$parameterWithoutPromotionPointers[] = $parameterPointer;
}
if (count($parameterWithoutPromotionPointers) === 0) {
return;
}
/** @var int $classPointer */
$classPointer = FunctionHelper::findClassPointer($phpcsFile, $functionPointer);
$propertyPointers = $this->getPropertyPointers($phpcsFile, $classPointer);
if (count($propertyPointers) === 0) {
return;
}
foreach ($parameterWithoutPromotionPointers as $parameterPointer) {
$parameterName = $tokens[$parameterPointer]['content'];
foreach ($propertyPointers as $propertyPointer) {
$propertyName = $tokens[$propertyPointer]['content'];
if ($parameterName !== $propertyName) {
continue;
}
$propertyEndPointer = PropertyHelper::getEndPointer($phpcsFile, $propertyPointer);
if ($tokens[$propertyEndPointer]['code'] === T_CLOSE_CURLY_BRACKET) {
// Ignore property with hooks
continue;
}
if ($this->isPropertyDocCommentUseful($phpcsFile, $propertyPointer)) {
continue;
}
if ($this->isPropertyWithAttribute($phpcsFile, $propertyPointer)) {
continue;
}
$propertyTypeHint = PropertyHelper::findTypeHint($phpcsFile, $propertyPointer);
$parameterTypeHint = FunctionHelper::getParametersTypeHints($phpcsFile, $functionPointer)[$parameterName];
if (!$this->areTypeHintEqual($parameterTypeHint, $propertyTypeHint)) {
continue;
}
$assignmentPointer = $this->getAssignment($phpcsFile, $functionPointer, $parameterName);
if ($assignmentPointer === null) {
continue;
}
if ($this->isParameterModifiedBeforeAssignment($phpcsFile, $functionPointer, $parameterName, $assignmentPointer)) {
continue;
}
$fix = $phpcsFile->addFixableError(
sprintf('Required promotion of property %s.', $propertyName),
$propertyPointer,
self::CODE_REQUIRED_CONSTRUCTOR_PROPERTY_PROMOTION,
);
if (!$fix) {
continue;
}
$propertyDocCommentOpenerPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $propertyPointer);
$pointerBeforeProperty = TokenHelper::findFirstTokenOnLine(
$phpcsFile,
$propertyDocCommentOpenerPointer ?? $propertyPointer,
);
$propertyStartPointer = PropertyHelper::getStartPointer($phpcsFile, $propertyPointer);
$propertyEndPointer = PropertyHelper::getEndPointer($phpcsFile, $propertyPointer);
$modifiersPointers = TokenHelper::findNextAll(
$phpcsFile,
TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
$propertyStartPointer,
$propertyPointer,
);
$modifiers = TokenHelper::getContent($phpcsFile, $modifiersPointers[0], $modifiersPointers[count($modifiersPointers) - 1]);
$propertyEqualPointer = TokenHelper::findNext($phpcsFile, T_EQUAL, $propertyPointer + 1, $propertyEndPointer);
$propertyDefaultValue = $propertyEqualPointer !== null
? trim(TokenHelper::getContent($phpcsFile, $propertyEqualPointer + 1, $propertyEndPointer - 1))
: null;
$propertyEndPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $propertyPointer + 1);
$pointerAfterProperty = TokenHelper::findFirstTokenOnLine(
$phpcsFile,
TokenHelper::findNextNonWhitespace($phpcsFile, $propertyEndPointer + 1),
);
$pointerBeforeParameterStart = TokenHelper::findPrevious(
$phpcsFile,
[T_COMMA, T_OPEN_PARENTHESIS, T_ATTRIBUTE_END],
$parameterPointer - 1,
);
$parameterStartPointer = TokenHelper::findNextEffective($phpcsFile, $pointerBeforeParameterStart + 1);
$parameterEqualPointer = TokenHelper::findNextEffective($phpcsFile, $parameterPointer + 1);
$parameterHasDefaultValue = $tokens[$parameterEqualPointer]['code'] === T_EQUAL;
$pointerBeforeAssignment = TokenHelper::findFirstTokenOnLine($phpcsFile, $assignmentPointer - 1);
$pointerAfterAssignment = TokenHelper::findLastTokenOnLine($phpcsFile, $assignmentPointer);
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetweenIncluding($phpcsFile, $pointerBeforeProperty, $pointerAfterProperty - 1);
FixerHelper::addBefore($phpcsFile, $parameterStartPointer, sprintf('%s ', $modifiers));
if (!$parameterHasDefaultValue && $propertyDefaultValue !== null) {
FixerHelper::add(
$phpcsFile,
$parameterPointer,
sprintf(' = %s', $propertyDefaultValue),
);
}
FixerHelper::removeBetweenIncluding($phpcsFile, $pointerBeforeAssignment, $pointerAfterAssignment);
$phpcsFile->fixer->endChangeset();
}
}
}
private function getAssignment(File $phpcsFile, int $constructorPointer, string $parameterName): ?int
{
$tokens = $phpcsFile->getTokens();
$parameterNameWithoutDollar = substr($parameterName, 1);
for ($i = $tokens[$constructorPointer]['scope_opener'] + 1; $i < $tokens[$constructorPointer]['scope_closer']; $i++) {
if ($tokens[$i]['content'] !== '$this') {
continue;
}
$objectOperatorPointer = TokenHelper::findNextEffective($phpcsFile, $i + 1);
if ($tokens[$objectOperatorPointer]['code'] !== T_OBJECT_OPERATOR) {
continue;
}
$namePointer = TokenHelper::findNextEffective($phpcsFile, $objectOperatorPointer + 1);
if ($tokens[$namePointer]['content'] !== $parameterNameWithoutDollar) {
continue;
}
$equalPointer = TokenHelper::findNextEffective($phpcsFile, $namePointer + 1);
if ($tokens[$equalPointer]['code'] !== T_EQUAL) {
continue;
}
$variablePointer = TokenHelper::findNextEffective($phpcsFile, $equalPointer + 1);
if ($tokens[$variablePointer]['content'] !== $parameterName) {
continue;
}
$semicolonPointer = TokenHelper::findNextEffective($phpcsFile, $variablePointer + 1);
if ($tokens[$semicolonPointer]['code'] !== T_SEMICOLON) {
continue;
}
foreach (array_reverse($tokens[$semicolonPointer]['conditions']) as $conditionTokenCode) {
if (in_array($conditionTokenCode, [T_IF, T_ELSEIF, T_ELSE, T_SWITCH], true)) {
return null;
}
}
return $i;
}
return null;
}
/**
* @return list
*/
private function getParameterPointers(File $phpcsFile, int $functionPointer): array
{
$tokens = $phpcsFile->getTokens();
return TokenHelper::findNextAll(
$phpcsFile,
T_VARIABLE,
$tokens[$functionPointer]['parenthesis_opener'] + 1,
$tokens[$functionPointer]['parenthesis_closer'],
);
}
/**
* @return list
*/
private function getPropertyPointers(File $phpcsFile, int $classPointer): array
{
$tokens = $phpcsFile->getTokens();
return array_values(array_filter(
TokenHelper::findNextAll(
$phpcsFile,
T_VARIABLE,
$tokens[$classPointer]['scope_opener'] + 1,
$tokens[$classPointer]['scope_closer'],
),
static fn (int $variablePointer): bool => PropertyHelper::isProperty($phpcsFile, $variablePointer),
));
}
private function isPropertyDocCommentUseful(File $phpcsFile, int $propertyPointer): bool
{
if (DocCommentHelper::hasDocCommentDescription($phpcsFile, $propertyPointer)) {
return true;
}
foreach (AnnotationHelper::getAnnotations($phpcsFile, $propertyPointer) as $annotation) {
$annotationValue = $annotation->getValue();
if (!$annotationValue instanceof VarTagValueNode) {
return true;
}
if ($annotationValue->description !== '') {
return true;
}
}
return false;
}
private function isPropertyWithAttribute(File $phpcsFile, int $propertyPointer): bool
{
$tokens = $phpcsFile->getTokens();
$previousPointer = TokenHelper::findPrevious(
$phpcsFile,
[T_ATTRIBUTE_END, T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET],
$propertyPointer - 1,
);
return $tokens[$previousPointer]['code'] === T_ATTRIBUTE_END;
}
private function areTypeHintEqual(?TypeHint $parameterTypeHint, ?TypeHint $propertyTypeHint): bool
{
if ($parameterTypeHint === null && $propertyTypeHint === null) {
return true;
}
if ($parameterTypeHint === null || $propertyTypeHint === null) {
return false;
}
return $parameterTypeHint->getTypeHint() === $propertyTypeHint->getTypeHint();
}
private function isParameterModifiedBeforeAssignment(
File $phpcsFile,
int $functionPointer,
string $parameterName,
int $assignmentPointer
): bool
{
$tokens = $phpcsFile->getTokens();
for ($i = $assignmentPointer - 1; $i > $tokens[$functionPointer]['scope_opener']; $i--) {
if ($tokens[$i]['code'] !== T_VARIABLE) {
continue;
}
if ($tokens[$i]['content'] !== $parameterName) {
continue;
}
$nextPointer = TokenHelper::findNextEffective($phpcsFile, $i + 1);
if (in_array($tokens[$nextPointer]['code'], Tokens::$assignmentTokens, true)) {
return true;
}
if ($tokens[$nextPointer]['code'] === T_INC) {
return true;
}
$previousPointer = TokenHelper::findNextEffective($phpcsFile, $i - 1);
if ($tokens[$previousPointer]['code'] === T_DEC) {
return true;
}
}
return false;
}
}
PK 41][$ $ Y coding-standard/SlevomatCodingStandard/Sniffs/Classes/SuperfluousExceptionNamingSniff.phpnu [
*/
public function register(): array
{
return [
T_CLASS,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $classPointer
*/
public function process(File $phpcsFile, $classPointer): void
{
$className = ClassHelper::getName($phpcsFile, $classPointer);
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $classPointer - 1);
if ($phpcsFile->getTokens()[$previousPointer]['code'] === T_ABSTRACT) {
return;
}
if (strtolower($className) === 'exception') {
return;
}
$suffix = substr($className, -9);
if (strtolower($suffix) !== 'exception') {
return;
}
$phpcsFile->addError(sprintf('Superfluous suffix "%s".', $suffix), $classPointer, self::CODE_SUPERFLUOUS_SUFFIX);
}
}
PK 41]u J coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassLengthSniff.phpnu [
*/
public function register(): array
{
return array_values(Tokens::$ooScopeTokens);
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): void
{
$this->maxLinesLength = SniffSettingsHelper::normalizeInteger($this->maxLinesLength);
$flags = array_keys(array_filter([
FunctionHelper::LINE_INCLUDE_COMMENT => $this->includeComments,
FunctionHelper::LINE_INCLUDE_WHITESPACE => $this->includeWhitespace,
]));
$flags = array_reduce($flags, static fn ($carry, $flag): int => $carry | $flag, 0);
$length = FunctionHelper::getLineCount($phpcsFile, $pointer, $flags);
if ($length <= $this->maxLinesLength) {
return;
}
$errorMessage = sprintf('Your class is too long. Currently using %d lines. Can be up to %d lines.', $length, $this->maxLinesLength);
$phpcsFile->addError($errorMessage, $pointer, self::CODE_CLASS_TOO_LONG);
}
}
PK 41]K\ ^ coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireMultiLineMethodSignatureSniff.phpnu [ */
public array $includedMethodPatterns = [];
/** @var list|null */
public ?array $includedMethodNormalizedPatterns = null;
/** @var list */
public array $excludedMethodPatterns = [];
/** @var list|null */
public ?array $excludedMethodNormalizedPatterns = null;
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $methodPointer
*/
public function process(File $phpcsFile, $methodPointer): void
{
$this->minLineLength = SniffSettingsHelper::normalizeNullableInteger($this->minLineLength);
$this->minParametersCount = SniffSettingsHelper::normalizeNullableInteger($this->minParametersCount);
if ($this->minLineLength !== null && $this->minParametersCount !== null) {
throw new UnexpectedValueException('Either minLineLength or minParametersCount can be set.');
}
// Maintain backward compatibility if no configuration provided
if ($this->minLineLength === null && $this->minParametersCount === null) {
$this->minLineLength = self::DEFAULT_MIN_LINE_LENGTH;
}
if (!FunctionHelper::isMethod($phpcsFile, $methodPointer)) {
return;
}
$tokens = $phpcsFile->getTokens();
[$signatureStartPointer, $signatureEndPointer] = $this->getSignatureStartAndEndPointers($phpcsFile, $methodPointer);
if ($tokens[$signatureStartPointer]['line'] < $tokens[$signatureEndPointer]['line']) {
return;
}
$parameters = $phpcsFile->getMethodParameters($methodPointer);
$parametersCount = count($parameters);
if ($parametersCount === 0) {
return;
}
$signature = $this->getSignature($phpcsFile, $signatureStartPointer, $signatureEndPointer);
$methodName = FunctionHelper::getName($phpcsFile, $methodPointer);
if (
count($this->includedMethodPatterns) !== 0
&& !$this->isMethodNameInPatterns($methodName, $this->getIncludedMethodNormalizedPatterns())
) {
return;
}
if (
count($this->excludedMethodPatterns) !== 0
&& $this->isMethodNameInPatterns($methodName, $this->getExcludedMethodNormalizedPatterns())
) {
return;
}
$splitPromotedProperties = false;
if ($this->withPromotedProperties) {
foreach ($parameters as $parameter) {
if (isset($parameter['property_visibility'])) {
$splitPromotedProperties = true;
break;
}
}
}
if (!$splitPromotedProperties) {
if ($this->minLineLength !== null && $this->minLineLength !== 0 && strlen($signature) < $this->minLineLength) {
return;
}
if ($this->minParametersCount !== null && $parametersCount < $this->minParametersCount) {
return;
}
}
$error = sprintf('Signature of method "%s" should be split to more lines so each parameter is on its own line.', $methodName);
$fix = $phpcsFile->addFixableError($error, $methodPointer, self::CODE_REQUIRED_MULTI_LINE_SIGNATURE);
if (!$fix) {
return;
}
$indentation = $tokens[$signatureStartPointer]['content'];
$phpcsFile->fixer->beginChangeset();
foreach ($parameters as $parameter) {
$pointerBeforeParameter = TokenHelper::findPrevious(
$phpcsFile,
T_COMMA,
$parameter['token'] - 1,
$tokens[$methodPointer]['parenthesis_opener'],
);
$pointerBeforeParameter ??= $tokens[$methodPointer]['parenthesis_opener'];
FixerHelper::add(
$phpcsFile,
$pointerBeforeParameter,
$phpcsFile->eolChar . IndentationHelper::addIndentation($phpcsFile, $indentation),
);
FixerHelper::removeWhitespaceAfter($phpcsFile, $pointerBeforeParameter);
}
FixerHelper::addBefore($phpcsFile, $tokens[$methodPointer]['parenthesis_closer'], $phpcsFile->eolChar . $indentation);
$phpcsFile->fixer->endChangeset();
}
/**
* @param list $normalizedPatterns
*/
private function isMethodNameInPatterns(string $methodName, array $normalizedPatterns): bool
{
foreach ($normalizedPatterns as $pattern) {
if (!SniffSettingsHelper::isValidRegularExpression($pattern)) {
throw new Exception(sprintf('%s is not valid PCRE pattern.', $pattern));
}
if (preg_match($pattern, $methodName) !== 0) {
return true;
}
}
return false;
}
/**
* @return list
*/
private function getIncludedMethodNormalizedPatterns(): array
{
$this->includedMethodNormalizedPatterns ??= SniffSettingsHelper::normalizeArray($this->includedMethodPatterns);
return $this->includedMethodNormalizedPatterns;
}
/**
* @return list
*/
private function getExcludedMethodNormalizedPatterns(): array
{
$this->excludedMethodNormalizedPatterns ??= SniffSettingsHelper::normalizeArray($this->excludedMethodPatterns);
return $this->excludedMethodNormalizedPatterns;
}
}
PK 41]O ^ coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiPropertyDefinitionSniff.phpnu [
*/
public function register(): array
{
return TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES;
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $modifierPointer
*/
public function process(File $phpcsFile, $modifierPointer): void
{
$tokens = $phpcsFile->getTokens();
$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $modifierPointer - 1);
if ($tokens[$asPointer]['code'] === T_AS) {
return;
}
$nextPointer = TokenHelper::findNextEffective($phpcsFile, $modifierPointer + 1);
if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
// We don't want to report the same property multiple times
return;
}
// Ignore other class members with same mofidiers
$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_CONST, T_FUNCTION, T_CLASS], $modifierPointer + 1);
if (
$propertyPointer === null
|| $tokens[$propertyPointer]['code'] !== T_VARIABLE
|| !PropertyHelper::isProperty($phpcsFile, $propertyPointer)
) {
return;
}
$semicolonPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $propertyPointer + 1);
$commaPointers = [];
$nextPointer = $propertyPointer;
do {
$nextPointer = TokenHelper::findNext($phpcsFile, [T_COMMA, T_OPEN_SHORT_ARRAY, T_ARRAY], $nextPointer + 1, $semicolonPointer);
if ($nextPointer === null) {
break;
}
if ($tokens[$nextPointer]['code'] === T_OPEN_SHORT_ARRAY) {
$nextPointer = $tokens[$nextPointer]['bracket_closer'];
continue;
}
if ($tokens[$nextPointer]['code'] === T_ARRAY) {
$nextPointer = $tokens[$nextPointer]['parenthesis_closer'];
continue;
}
$commaPointers[] = $nextPointer;
} while (true);
if (count($commaPointers) === 0) {
return;
}
$fix = $phpcsFile->addFixableError(
'Use of multi property definition is disallowed.',
$modifierPointer,
self::CODE_DISALLOWED_MULTI_PROPERTY_DEFINITION,
);
if (!$fix) {
return;
}
$propertyStartPointer = PropertyHelper::getStartPointer($phpcsFile, $propertyPointer);
$pointerBeforeProperty = TokenHelper::findPreviousEffective($phpcsFile, $propertyPointer - 1);
$pointerBeforeSemicolon = TokenHelper::findPreviousEffective($phpcsFile, $semicolonPointer - 1);
$indentation = IndentationHelper::getIndentation($phpcsFile, $propertyStartPointer);
$docCommentPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $propertyPointer);
$docComment = $docCommentPointer !== null
? trim(TokenHelper::getContent($phpcsFile, $docCommentPointer, $tokens[$docCommentPointer]['comment_closer']))
: null;
$data = [];
foreach ($commaPointers as $commaPointer) {
$data[$commaPointer] = [
'pointerBeforeComma' => TokenHelper::findPreviousEffective($phpcsFile, $commaPointer - 1),
'pointerAfterComma' => TokenHelper::findNextEffective($phpcsFile, $commaPointer + 1),
];
}
$propertyContent = TokenHelper::getContent($phpcsFile, $propertyStartPointer, $pointerBeforeProperty);
$phpcsFile->fixer->beginChangeset();
FixerHelper::change($phpcsFile, $pointerBeforeProperty + 1, $propertyPointer - 1, ' ');
foreach ($commaPointers as $commaPointer) {
FixerHelper::removeBetween($phpcsFile, $data[$commaPointer]['pointerBeforeComma'], $commaPointer);
FixerHelper::replace(
$phpcsFile,
$commaPointer,
sprintf(
';%s%s%s%s ',
$phpcsFile->eolChar,
$docComment !== null
? sprintf('%s%s%s', $indentation, $docComment, $phpcsFile->eolChar)
: '',
$indentation,
$propertyContent,
),
);
FixerHelper::removeBetween($phpcsFile, $commaPointer, $data[$commaPointer]['pointerAfterComma']);
}
FixerHelper::removeBetween($phpcsFile, $pointerBeforeSemicolon, $semicolonPointer);
$phpcsFile->fixer->endChangeset();
}
}
PK 41]eYu
u
N coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertySpacingSniff.phpnu [
*/
public function register(): array
{
return TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES;
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): int
{
$tokens = $phpcsFile->getTokens();
$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $pointer - 1);
if ($tokens[$asPointer]['code'] === T_AS) {
return $pointer;
}
$nextPointer = TokenHelper::findNextEffective($phpcsFile, $pointer + 1);
if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
// We don't want to report the same property multiple times
return $nextPointer;
}
// Ignore other class members with same mofidiers
$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_FUNCTION, T_CONST, T_CLASS], $pointer + 1);
if (
$propertyPointer === null
|| $tokens[$propertyPointer]['code'] !== T_VARIABLE
|| !PropertyHelper::isProperty($phpcsFile, $propertyPointer)
) {
return $propertyPointer ?? $pointer;
}
return parent::process($phpcsFile, $propertyPointer);
}
protected function isNextMemberValid(File $phpcsFile, int $pointer): bool
{
$nextPointer = TokenHelper::findNext($phpcsFile, [T_FUNCTION, T_VARIABLE], $pointer + 1);
return $nextPointer !== null && $phpcsFile->getTokens()[$nextPointer]['code'] === T_VARIABLE;
}
protected function addError(File $phpcsFile, int $pointer, int $minExpectedLines, int $maxExpectedLines, int $found): bool
{
if ($minExpectedLines === $maxExpectedLines) {
$errorMessage = $minExpectedLines === 1
? 'Expected 1 blank line after property, found %3$d.'
: 'Expected %2$d blank lines after property, found %3$d.';
} else {
$errorMessage = 'Expected %1$d to %2$d blank lines after property, found %3$d.';
}
$error = sprintf($errorMessage, $minExpectedLines, $maxExpectedLines, $found);
return $phpcsFile->addFixableError($error, $pointer, self::CODE_INCORRECT_COUNT_OF_BLANK_LINES_AFTER_PROPERTY);
}
}
PK 41]~$: : ] coding-standard/SlevomatCodingStandard/Sniffs/Classes/SuperfluousAbstractClassNamingSniff.phpnu [
*/
public function register(): array
{
return [
T_CLASS,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $classPointer
*/
public function process(File $phpcsFile, $classPointer): void
{
$className = ClassHelper::getName($phpcsFile, $classPointer);
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $classPointer - 1);
if ($phpcsFile->getTokens()[$previousPointer]['code'] !== T_ABSTRACT) {
return;
}
$this->checkPrefix($phpcsFile, $classPointer, $className);
$this->checkSuffix($phpcsFile, $classPointer, $className);
}
private function checkPrefix(File $phpcsFile, int $classPointer, string $className): void
{
$prefix = substr($className, 0, 8);
if (strtolower($prefix) !== 'abstract') {
return;
}
$phpcsFile->addError(sprintf('Superfluous prefix "%s".', $prefix), $classPointer, self::CODE_SUPERFLUOUS_PREFIX);
}
private function checkSuffix(File $phpcsFile, int $classPointer, string $className): void
{
$suffix = substr($className, -8);
if (strtolower($suffix) !== 'abstract') {
return;
}
$phpcsFile->addError(sprintf('Superfluous suffix "%s".', $suffix), $classPointer, self::CODE_SUPERFLUOUS_SUFFIX);
}
}
PK 41]kn|
|
P coding-standard/SlevomatCodingStandard/Sniffs/Classes/ParentCallSpacingSniff.phpnu [ linesCountBefore = SniffSettingsHelper::normalizeInteger($this->linesCountBefore);
$this->linesCountBeforeFirst = SniffSettingsHelper::normalizeInteger($this->linesCountBeforeFirst);
$this->linesCountAfter = SniffSettingsHelper::normalizeInteger($this->linesCountAfter);
$this->linesCountAfterLast = SniffSettingsHelper::normalizeInteger($this->linesCountAfterLast);
$tokens = $phpcsFile->getTokens();
if (array_key_exists('nested_parenthesis', $tokens[$parentPointer])) {
return;
}
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $parentPointer - 1);
if (in_array($tokens[$previousPointer]['code'], array_merge(Tokens::$castTokens, [T_ASPERAND]), true)) {
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $previousPointer - 1);
}
$tokensToIgnore = array_merge(
Tokens::$assignmentTokens,
Tokens::$equalityTokens,
Tokens::$booleanOperators,
[T_RETURN, T_YIELD, T_YIELD_FROM, T_COLON, T_STRING_CONCAT, T_INLINE_THEN, T_INLINE_ELSE, T_COALESCE, T_MATCH_ARROW],
);
if (in_array($tokens[$previousPointer]['code'], $tokensToIgnore, true)) {
return;
}
$previousShortArrayOpenerPointer = TokenHelper::findPrevious($phpcsFile, T_OPEN_SHORT_ARRAY, $parentPointer - 1);
if ($previousShortArrayOpenerPointer !== null && $tokens[$previousShortArrayOpenerPointer]['bracket_closer'] > $parentPointer) {
return;
}
parent::process($phpcsFile, $parentPointer);
}
/**
* @return list
*/
protected function getSupportedKeywords(): array
{
return [self::KEYWORD_PARENT];
}
/**
* @return list
*/
protected function getKeywordsToCheck(): array
{
return [self::KEYWORD_PARENT];
}
protected function getLinesCountBefore(): int
{
return $this->linesCountBefore;
}
/**
* @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
*/
protected function getLinesCountBeforeFirst(File $phpcsFile, int $parentPointer): int
{
return $this->linesCountBeforeFirst;
}
protected function getLinesCountAfter(): int
{
return $this->linesCountAfter;
}
/**
* @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
*/
protected function getLinesCountAfterLast(File $phpcsFile, int $parentPointer, int $parentEndPointer): int
{
return $this->linesCountAfterLast;
}
}
PK 41][>| L coding-standard/SlevomatCodingStandard/Sniffs/Classes/MethodSpacingSniff.phpnu [
*/
public function register(): array
{
return [T_FUNCTION];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $methodPointer
*/
public function process(File $phpcsFile, $methodPointer): void
{
$this->minLinesCount = SniffSettingsHelper::normalizeInteger($this->minLinesCount);
$this->maxLinesCount = SniffSettingsHelper::normalizeInteger($this->maxLinesCount);
if (!FunctionHelper::isMethod($phpcsFile, $methodPointer)) {
return;
}
$tokens = $phpcsFile->getTokens();
$methodEndPointer = array_key_exists('scope_closer', $tokens[$methodPointer])
? $tokens[$methodPointer]['scope_closer']
: TokenHelper::findNext($phpcsFile, T_SEMICOLON, $methodPointer + 1);
$classPointer = ClassHelper::getClassPointer($phpcsFile, $methodPointer);
$nextMethodPointer = TokenHelper::findNext($phpcsFile, T_FUNCTION, $methodEndPointer + 1, $tokens[$classPointer]['scope_closer']);
if ($nextMethodPointer === null) {
return;
}
$nextMethodAttributeStartPointer = null;
$nextMethodDocCommentStartPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $nextMethodPointer);
if (
$nextMethodDocCommentStartPointer !== null
&& $tokens[$tokens[$nextMethodDocCommentStartPointer]['comment_closer']]['line'] + 1 !== $tokens[$nextMethodPointer]['line']
) {
$nextMethodDocCommentStartPointer = null;
} else {
$nextMethodAttributeStartPointer = TokenHelper::findPrevious(
$phpcsFile,
T_ATTRIBUTE,
$nextMethodPointer - 1,
$methodEndPointer,
);
if ($nextMethodAttributeStartPointer !== null) {
do {
$pointerBefore = TokenHelper::findPreviousNonWhitespace(
$phpcsFile,
$nextMethodAttributeStartPointer - 1,
$methodEndPointer,
);
if ($tokens[$pointerBefore]['code'] === T_ATTRIBUTE_END) {
$nextMethodAttributeStartPointer = $tokens[$pointerBefore]['attribute_opener'];
continue;
}
break;
} while (true);
}
}
$nextMethodFirstLinePointer = $tokens[$nextMethodPointer]['line'] === $tokens[$methodEndPointer]['line']
? TokenHelper::findNextEffective($phpcsFile, $methodEndPointer + 1)
: TokenHelper::findFirstTokenOnLine(
$phpcsFile,
$nextMethodDocCommentStartPointer ?? $nextMethodAttributeStartPointer ?? $nextMethodPointer,
);
if (TokenHelper::findNextNonWhitespace($phpcsFile, $methodEndPointer + 1, $nextMethodFirstLinePointer) !== null) {
return;
}
$linesBetween = $tokens[$nextMethodFirstLinePointer]['line'] !== $tokens[$methodEndPointer]['line']
? $tokens[$nextMethodFirstLinePointer]['line'] - $tokens[$methodEndPointer]['line'] - 1
: null;
if ($linesBetween !== null && $linesBetween >= $this->minLinesCount && $linesBetween <= $this->maxLinesCount) {
return;
}
if ($this->minLinesCount === $this->maxLinesCount) {
$errorMessage = $this->minLinesCount === 1
? 'Expected 1 blank line after method, found %3$d.'
: 'Expected %2$d blank lines after method, found %3$d.';
} else {
$errorMessage = 'Expected %1$d to %2$d blank lines after method, found %3$d.';
}
$fix = $phpcsFile->addFixableError(
sprintf($errorMessage, $this->minLinesCount, $this->maxLinesCount, $linesBetween ?? 0),
$methodPointer,
self::CODE_INCORRECT_LINES_COUNT_BETWEEN_METHODS,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
if ($linesBetween === null) {
FixerHelper::add(
$phpcsFile,
$methodEndPointer,
$phpcsFile->eolChar . str_repeat($phpcsFile->eolChar, $this->minLinesCount) . IndentationHelper::getIndentation(
$phpcsFile,
TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $methodPointer),
),
);
FixerHelper::removeBetween($phpcsFile, $methodEndPointer, $nextMethodFirstLinePointer);
} elseif ($linesBetween > $this->maxLinesCount) {
FixerHelper::add(
$phpcsFile,
$methodEndPointer,
str_repeat($phpcsFile->eolChar, $this->maxLinesCount + 1),
);
$firstPointerOnNextMethodLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $nextMethodFirstLinePointer);
FixerHelper::removeBetween($phpcsFile, $methodEndPointer, $firstPointerOnNextMethodLine);
} else {
FixerHelper::add(
$phpcsFile,
$methodEndPointer,
str_repeat($phpcsFile->eolChar, $this->minLinesCount - $linesBetween),
);
}
$phpcsFile->fixer->endChangeset();
}
}
PK 41]Jcg g ^ coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiConstantDefinitionSniff.phpnu [
*/
public function register(): array
{
return [T_CONST];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $constantPointer
*/
public function process(File $phpcsFile, $constantPointer): void
{
$tokens = $phpcsFile->getTokens();
$semicolonPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $constantPointer + 1);
$commaPointers = [];
$nextPointer = $constantPointer;
do {
$nextPointer = TokenHelper::findNext($phpcsFile, [T_COMMA, T_OPEN_SHORT_ARRAY], $nextPointer + 1, $semicolonPointer);
if ($nextPointer === null) {
break;
}
if ($tokens[$nextPointer]['code'] === T_OPEN_SHORT_ARRAY) {
$nextPointer = $tokens[$nextPointer]['bracket_closer'];
continue;
}
$commaPointers[] = $nextPointer;
} while (true);
if (count($commaPointers) === 0) {
return;
}
$fix = $phpcsFile->addFixableError(
'Use of multi constant definition is disallowed.',
$constantPointer,
self::CODE_DISALLOWED_MULTI_CONSTANT_DEFINITION,
);
if (!$fix) {
return;
}
$possibleVisibilityPointer = TokenHelper::findPreviousEffective($phpcsFile, $constantPointer - 1);
$visibilityPointer = in_array($tokens[$possibleVisibilityPointer]['code'], Tokens::$scopeModifiers, true)
? $possibleVisibilityPointer
: null;
$visibility = $visibilityPointer !== null ? $tokens[$possibleVisibilityPointer]['content'] : null;
$pointerAfterConst = TokenHelper::findNextEffective($phpcsFile, $constantPointer + 1);
$pointerBeforeSemicolon = TokenHelper::findPreviousEffective($phpcsFile, $semicolonPointer - 1);
$indentation = IndentationHelper::getIndentation($phpcsFile, $visibilityPointer ?? $constantPointer);
$docCommentPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $constantPointer);
$docComment = $docCommentPointer !== null
? trim(TokenHelper::getContent($phpcsFile, $docCommentPointer, $tokens[$docCommentPointer]['comment_closer']))
: null;
$data = [];
foreach ($commaPointers as $commaPointer) {
$data[$commaPointer] = [
'pointerBeforeComma' => TokenHelper::findPreviousEffective($phpcsFile, $commaPointer - 1),
'pointerAfterComma' => TokenHelper::findNextEffective($phpcsFile, $commaPointer + 1),
];
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::add($phpcsFile, $constantPointer, ' ');
FixerHelper::removeBetween($phpcsFile, $constantPointer, $pointerAfterConst);
foreach ($commaPointers as $commaPointer) {
FixerHelper::removeBetween($phpcsFile, $data[$commaPointer]['pointerBeforeComma'], $commaPointer);
FixerHelper::replace(
$phpcsFile,
$commaPointer,
sprintf(
';%s%s%s%sconst ',
$phpcsFile->eolChar,
$docComment !== null
? sprintf('%s%s%s', $indentation, $docComment, $phpcsFile->eolChar)
: '',
$indentation,
$visibility !== null ? sprintf('%s ', $visibility) : '',
),
);
FixerHelper::removeBetween($phpcsFile, $commaPointer, $data[$commaPointer]['pointerAfterComma']);
}
FixerHelper::removeBetween($phpcsFile, $pointerBeforeSemicolon, $semicolonPointer);
$phpcsFile->fixer->endChangeset();
}
}
PK 41]v W coding-standard/SlevomatCodingStandard/Sniffs/Classes/ModernClassNameReferenceSniff.phpnu [
*/
public function register(): array
{
return [
T_CLASS_C,
...TokenHelper::ONLY_NAME_TOKEN_CODES,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): void
{
$this->enableOnObjects = SniffSettingsHelper::isEnabledByPhpVersion($this->enableOnObjects, 80000);
$tokens = $phpcsFile->getTokens();
if ($tokens[$pointer]['code'] === T_CLASS_C) {
$this->checkMagicConstant($phpcsFile, $pointer);
return;
}
$this->checkFunctionCall($phpcsFile, $pointer);
}
private function checkMagicConstant(File $phpcsFile, int $pointer): void
{
$fix = $phpcsFile->addFixableError(
'Class name referenced via magic constant.',
$pointer,
self::CODE_CLASS_NAME_REFERENCED_VIA_MAGIC_CONSTANT,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::replace($phpcsFile, $pointer, 'self::class');
$phpcsFile->fixer->endChangeset();
}
private function checkFunctionCall(File $phpcsFile, int $functionPointer): void
{
$tokens = $phpcsFile->getTokens();
$functionName = ltrim(strtolower($tokens[$functionPointer]['content']), '\\');
$functionNames = [
'get_class',
'get_parent_class',
'get_called_class',
];
if (!in_array($functionName, $functionNames, true)) {
return;
}
$openParenthesisPointer = TokenHelper::findNextEffective($phpcsFile, $functionPointer + 1);
if ($tokens[$openParenthesisPointer]['code'] !== T_OPEN_PARENTHESIS) {
return;
}
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $functionPointer - 1);
if (in_array($tokens[$previousPointer]['code'], [T_OBJECT_OPERATOR, T_DOUBLE_COLON, T_FUNCTION], true)) {
return;
}
$parameterPointer = TokenHelper::findNextEffective(
$phpcsFile,
$openParenthesisPointer + 1,
$tokens[$openParenthesisPointer]['parenthesis_closer'],
);
$isObjectParameter = static function () use ($phpcsFile, $tokens, $openParenthesisPointer, $parameterPointer): bool {
if ($tokens[$parameterPointer]['code'] !== T_VARIABLE) {
return false;
}
$pointerAfterParameterPointer = TokenHelper::findNextEffective($phpcsFile, $parameterPointer + 1);
return $pointerAfterParameterPointer === $tokens[$openParenthesisPointer]['parenthesis_closer'];
};
$isThisParameter = static function () use ($tokens, $parameterPointer, $isObjectParameter): bool {
if (!$isObjectParameter()) {
return false;
}
$parameterName = strtolower($tokens[$parameterPointer]['content']);
return $parameterName === '$this';
};
if ($functionName === 'get_class') {
if ($parameterPointer === null) {
$fixedContent = 'self::class';
} elseif ($isThisParameter()) {
$fixedContent = 'static::class';
} elseif ($this->enableOnObjects && $isObjectParameter()) {
$fixedContent = sprintf('%s::class', $tokens[$parameterPointer]['content']);
} else {
return;
}
} elseif ($functionName === 'get_parent_class') {
if ($parameterPointer !== null) {
if (!$isThisParameter()) {
return;
}
$classPointer = FunctionHelper::findClassPointer($phpcsFile, $functionPointer);
if ($classPointer === null || !ClassHelper::isFinal($phpcsFile, $classPointer)) {
return;
}
}
$fixedContent = 'parent::class';
} else {
$fixedContent = 'static::class';
}
$fix = $phpcsFile->addFixableError(
sprintf('Class name referenced via call of function %s().', $functionName),
$functionPointer,
self::CODE_CLASS_NAME_REFERENCED_VIA_FUNCTION_CALL,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
if ($tokens[$functionPointer - 1]['code'] === T_NS_SEPARATOR) {
FixerHelper::replace($phpcsFile, $functionPointer - 1, '');
}
FixerHelper::change($phpcsFile, $functionPointer, $tokens[$openParenthesisPointer]['parenthesis_closer'], $fixedContent);
$phpcsFile->fixer->endChangeset();
}
}
PK 41]O< U coding-standard/SlevomatCodingStandard/Sniffs/Classes/SuperfluousErrorNamingSniff.phpnu [
*/
public function register(): array
{
return [
T_CLASS,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $classPointer
*/
public function process(File $phpcsFile, $classPointer): void
{
$className = ClassHelper::getName($phpcsFile, $classPointer);
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $classPointer - 1);
if ($phpcsFile->getTokens()[$previousPointer]['code'] === T_ABSTRACT) {
return;
}
if (strtolower($className) === 'error') {
return;
}
$suffix = substr($className, -5);
if (strtolower($suffix) !== 'error') {
return;
}
$phpcsFile->addError(sprintf('Superfluous suffix "%s".', $suffix), $classPointer, self::CODE_SUPERFLUOUS_SUFFIX);
}
}
PK 41], U coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireAbstractOrFinalSniff.phpnu [
*/
public function register(): array
{
return [
T_CLASS,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $classPointer
*/
public function process(File $phpcsFile, $classPointer): void
{
$tokens = $phpcsFile->getTokens();
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $classPointer - 1);
if ($tokens[$previousPointer]['code'] === T_READONLY) {
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $previousPointer - 1);
}
if (in_array($tokens[$previousPointer]['code'], [T_ABSTRACT, T_FINAL], true)) {
return;
}
$fix = $phpcsFile->addFixableError(
'All classes should be declared using either the "abstract" or "final" keyword.',
$classPointer,
self::CODE_NO_ABSTRACT_OR_FINAL,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::addBefore($phpcsFile, $classPointer, 'final ');
$phpcsFile->fixer->endChangeset();
}
}
PK 41]+0 c coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowConstructorPropertyPromotionSniff.phpnu [
*/
public function register(): array
{
return [T_FUNCTION];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $functionPointer
*/
public function process(File $phpcsFile, $functionPointer): void
{
$tokens = $phpcsFile->getTokens();
$namePointer = TokenHelper::findNextEffective($phpcsFile, $functionPointer + 1);
if (strtolower($tokens[$namePointer]['content']) !== '__construct') {
return;
}
$modifierPointers = TokenHelper::findNextAll(
$phpcsFile,
[...array_values(Tokens::$scopeModifiers), T_READONLY],
$tokens[$functionPointer]['parenthesis_opener'] + 1,
$tokens[$functionPointer]['parenthesis_closer'],
);
if ($modifierPointers === []) {
return;
}
foreach ($modifierPointers as $modifierPointer) {
$variablePointer = TokenHelper::findNext($phpcsFile, T_VARIABLE, $modifierPointer + 1);
$phpcsFile->addError(
sprintf(
'Constructor property promotion is disallowed, promotion of property %s found.',
$tokens[$variablePointer]['content'],
),
$variablePointer,
self::CODE_DISALLOWED_CONSTRUCTOR_PROPERTY_PROMOTION,
);
}
}
}
PK 41];
R coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseDeclarationSniff.phpnu [
*/
public function register(): array
{
return [
T_CLASS,
T_ANON_CLASS,
T_TRAIT,
T_ENUM,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $classPointer
*/
public function process(File $phpcsFile, $classPointer): void
{
$usePointers = ClassHelper::getTraitUsePointers($phpcsFile, $classPointer);
foreach ($usePointers as $usePointer) {
$this->checkDeclaration($phpcsFile, $usePointer);
}
}
private function checkDeclaration(File $phpcsFile, int $usePointer): void
{
$commaPointer = TokenHelper::findNextLocal($phpcsFile, T_COMMA, $usePointer + 1);
if ($commaPointer === null) {
return;
}
$endPointer = TokenHelper::findNext($phpcsFile, [T_OPEN_CURLY_BRACKET, T_SEMICOLON], $usePointer + 1);
$tokens = $phpcsFile->getTokens();
if ($tokens[$endPointer]['code'] === T_OPEN_CURLY_BRACKET) {
$phpcsFile->addError(
'Multiple traits per use statement are forbidden.',
$usePointer,
self::CODE_MULTIPLE_TRAITS_PER_DECLARATION,
);
return;
}
$fix = $phpcsFile->addFixableError(
'Multiple traits per use statement are forbidden.',
$usePointer,
self::CODE_MULTIPLE_TRAITS_PER_DECLARATION,
);
if (!$fix) {
return;
}
$indentation = '';
$currentPointer = $usePointer - 1;
while (
$tokens[$currentPointer]['code'] === T_WHITESPACE
&& $tokens[$currentPointer]['content'] !== $phpcsFile->eolChar
) {
$indentation .= $tokens[$currentPointer]['content'];
$currentPointer--;
}
$phpcsFile->fixer->beginChangeset();
$otherCommaPointers = TokenHelper::findNextAll($phpcsFile, T_COMMA, $usePointer + 1, $endPointer);
foreach ($otherCommaPointers as $otherCommaPointer) {
$pointerAfterComma = TokenHelper::findNextEffective($phpcsFile, $otherCommaPointer + 1);
FixerHelper::change(
$phpcsFile,
$otherCommaPointer,
$pointerAfterComma - 1,
sprintf(';%s%suse ', $phpcsFile->eolChar, $indentation),
);
}
$phpcsFile->fixer->endChangeset();
}
}
PK 41]&:y
y
T coding-standard/SlevomatCodingStandard/Sniffs/Classes/BackedEnumTypeSpacingSniff.phpnu [
*/
public function register(): array
{
return [T_ENUM];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $enumPointer
*/
public function process(File $phpcsFile, $enumPointer): void
{
$this->spacesCountBeforeColon = SniffSettingsHelper::normalizeInteger($this->spacesCountBeforeColon);
$this->spacesCountBeforeType = SniffSettingsHelper::normalizeInteger($this->spacesCountBeforeType);
$tokens = $phpcsFile->getTokens();
$colonPointer = TokenHelper::findNext($phpcsFile, T_COLON, $enumPointer + 1, $tokens[$enumPointer]['scope_opener']);
if ($colonPointer === null) {
return;
}
$this->checkSpacesBeforeColon($phpcsFile, $colonPointer);
$this->checkSpacesBeforeType($phpcsFile, $colonPointer);
}
public function checkSpacesBeforeColon(File $phpcsFile, int $colonPointer): void
{
$namePointer = TokenHelper::findPreviousEffective($phpcsFile, $colonPointer - 1);
$whitespace = TokenHelper::getContent($phpcsFile, $namePointer + 1, $colonPointer - 1);
if ($this->spacesCountBeforeColon === strlen($whitespace)) {
return;
}
$fix = $phpcsFile->addFixableError(
$this->formatErrorMessage('before colon', $this->spacesCountBeforeColon),
$colonPointer,
self::CODE_INCORRECT_SPACES_BEFORE_COLON,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $namePointer, $colonPointer);
FixerHelper::addBefore($phpcsFile, $colonPointer, str_repeat(' ', $this->spacesCountBeforeColon));
$phpcsFile->fixer->endChangeset();
}
public function checkSpacesBeforeType(File $phpcsFile, int $colonPointer): void
{
$typePointer = TokenHelper::findNextEffective($phpcsFile, $colonPointer + 1);
$whitespace = TokenHelper::getContent($phpcsFile, $colonPointer + 1, $typePointer - 1);
if ($this->spacesCountBeforeType === strlen($whitespace)) {
return;
}
$fix = $phpcsFile->addFixableError(
$this->formatErrorMessage('before type', $this->spacesCountBeforeType),
$typePointer,
self::CODE_INCORRECT_SPACES_BEFORE_TYPE,
);
if (!$fix) {
return;
}
$phpcsFile->fixer->beginChangeset();
FixerHelper::removeBetween($phpcsFile, $colonPointer, $typePointer);
FixerHelper::addBefore($phpcsFile, $typePointer, str_repeat(' ', $this->spacesCountBeforeType));
$phpcsFile->fixer->endChangeset();
}
private function formatErrorMessage(string $suffix, int $requiredSpaces): string
{
return $requiredSpaces === 0
? sprintf('There must be no whitespace %s.', $suffix)
: sprintf('There must be exactly %d whitespace%s %s.', $requiredSpaces, $requiredSpaces !== 1 ? 's' : '', $suffix);
}
}
PK 41] {< S coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSelfReferenceSniff.phpnu [
*/
public function register(): array
{
return [
T_OPEN_TAG,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $openTagPointer
*/
public function process(File $phpcsFile, $openTagPointer): void
{
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
$tokens = $phpcsFile->getTokens();
$referencedNames = array_merge(
ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer),
ReferencedNameHelper::getAllReferencedNamesInAttributes($phpcsFile, $openTagPointer),
);
foreach ($referencedNames as $referencedName) {
if (!$referencedName->isClass()) {
continue;
}
$anonymousClassPointer = TokenHelper::findPrevious($phpcsFile, T_ANON_CLASS, $referencedName->getStartPointer() - 1);
if (
$anonymousClassPointer !== null
&& $tokens[$anonymousClassPointer]['scope_closer'] > $referencedName->getEndPointer()
) {
continue;
}
$classPointer = ClassHelper::getClassPointer($phpcsFile, $referencedName->getStartPointer());
if ($classPointer === null) {
continue;
}
$className = ClassHelper::getFullyQualifiedName($phpcsFile, $classPointer);
$resolvedName = NamespaceHelper::resolveClassName(
$phpcsFile,
$referencedName->getNameAsReferencedInFile(),
$referencedName->getStartPointer(),
);
if ($className !== $resolvedName) {
continue;
}
$fix = $phpcsFile->addFixableError(
'"self" for local reference is required.',
$referencedName->getStartPointer(),
self::CODE_REQUIRED_SELF_REFERENCE,
);
if (!$fix) {
continue;
}
$inAttribute = $tokens[$referencedName->getStartPointer()]['code'] === T_ATTRIBUTE;
$phpcsFile->fixer->beginChangeset();
if ($inAttribute) {
$attributeContent = TokenHelper::getContent(
$phpcsFile,
$referencedName->getStartPointer(),
$referencedName->getEndPointer(),
);
$fixedAttributeContent = preg_replace(
'~(?<=\W)' . preg_quote($referencedName->getNameAsReferencedInFile(), '~') . '(?=\W)~',
'self',
$attributeContent,
);
FixerHelper::replace(
$phpcsFile,
$referencedName->getStartPointer(),
$fixedAttributeContent,
);
} else {
FixerHelper::replace($phpcsFile, $referencedName->getStartPointer(), 'self');
}
FixerHelper::removeBetweenIncluding($phpcsFile, $referencedName->getStartPointer() + 1, $referencedName->getEndPointer());
$phpcsFile->fixer->endChangeset();
}
}
}
PK 41]) Q coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractMethodSignature.phpnu [
*/
public function register(): array
{
return [T_FUNCTION];
}
/**
* @return array
*/
protected function getSignatureStartAndEndPointers(File $phpcsFile, int $methodPointer): array
{
$signatureStartPointer = TokenHelper::findFirstTokenOnLine($phpcsFile, $methodPointer);
/** @var int $pointerAfterSignatureEnd */
$pointerAfterSignatureEnd = TokenHelper::findNext($phpcsFile, [T_OPEN_CURLY_BRACKET, T_SEMICOLON], $methodPointer + 1);
if ($phpcsFile->getTokens()[$pointerAfterSignatureEnd]['code'] === T_SEMICOLON) {
return [$signatureStartPointer, $pointerAfterSignatureEnd];
}
/** @var int $signatureEndPointer */
$signatureEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $pointerAfterSignatureEnd - 1);
return [$signatureStartPointer, $signatureEndPointer];
}
protected function getSignature(File $phpcsFile, int $signatureStartPointer, int $signatureEndPointer): string
{
$signature = TokenHelper::getContent($phpcsFile, $signatureStartPointer, $signatureEndPointer);
$signature = preg_replace(sprintf('~%s[ \t]*~', $phpcsFile->eolChar), ' ', $signature);
assert(is_string($signature));
$signature = str_replace(['( ', ' )'], ['(', ')'], $signature);
$signature = rtrim($signature);
return $signature;
}
}
PK 41]H U coding-standard/SlevomatCodingStandard/Sniffs/Classes/MissingClassGroupsException.phpnu [ $groups */
public function __construct(array $groups)
{
parent::__construct(
sprintf(
'You need configure all class groups. These groups are missing from your configuration: %s.',
implode(', ', $groups),
),
);
}
}
PK 41]>&