Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PhpCollective/Sniffs/Classes/MethodDeclarationSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop
$tokens = $phpcsFile->getTokens();

$methodName = $phpcsFile->getDeclarationName($stackPtr);
if ($methodName === null) {
if (!$methodName) {
// Ignore closures.
return;
}
Expand Down
2 changes: 1 addition & 1 deletion PhpCollective/Sniffs/Classes/MethodTypeHintSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function process(File $phpcsFile, $stackPtr): void
$j = $startIndex;
$extractedUseStatement = '';
while (true) {
if (!$this->isGivenKind([T_NS_SEPARATOR, T_STRING, T_RETURN_TYPE], $tokens[$j])) {
if (!$this->isGivenKind([T_NS_SEPARATOR, T_STRING], $tokens[$j])) {
break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public function process(File $phpcsFile, $pointer): void
*/
protected function fixAnnotation(File $phpcsFile, Annotation $annotation, string $fixedAnnotation): void
{
/** @var \PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode|mixed $value */
/** @var \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode $value */
$value = $annotation->getNode()->value;
$parameterName = $value->parameterName ?? '';
$variableName = $value->variableName ?? '';
Expand Down Expand Up @@ -220,9 +220,9 @@ public function getArrayTypeNodes(Node $node): array
/**
* @param \PHPStan\PhpDocParser\Ast\Node $node
*
* @return \PHPStan\PhpDocParser\Ast\Node|list<\PHPStan\PhpDocParser\Ast\Node>|\PHPStan\PhpDocParser\Ast\NodeTraverser|int|null
* @return int|null
*/
public function enterNode(Node $node): Node|array|\PHPStan\PhpDocParser\Ast\NodeTraverser|int|null
public function enterNode(Node $node): int|null
{
if ($node instanceof ArrayTypeNode) {
$this->nodes[] = $node;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ protected function assertTypeHint(File $phpcsFile, int $stackPtr, int $docBlockR
$typehint = '?' . $typehint;
}

if ($documentedReturnType !== 'void' && $typeHintIndex !== 'void') {
if ($documentedReturnType !== 'void' && $typehint !== 'void') {
return;
}
if ($documentedReturnType === $typehint) {
Expand Down
25 changes: 22 additions & 3 deletions PhpCollective/Sniffs/Commenting/DocBlockThrowsSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ public function process(File $phpCsFile, $stackPointer): void
return;
}

if ($phpCsFile->getDeclarationName($stackPointer) === null) {
try {
$name = $phpCsFile->getDeclarationName($stackPointer);
} catch (Exception $e) {
return;
}
if (!$name) {
return;
}

Expand Down Expand Up @@ -139,6 +144,12 @@ protected function extractExceptions(File $phpCsFile, int $stackPointer): array
continue;
}

// Handle the case where there's no namespace separator, string token, or fully qualified name token
// (e.g., for parenthesis after 'new')
if (!$this->isGivenKind([T_NS_SEPARATOR, T_STRING, T_NAME_FULLY_QUALIFIED], $tokens[$contentIndex])) {
continue;
}

$exceptions[] = $this->extractException($phpCsFile, $contentIndex);

continue;
Expand Down Expand Up @@ -223,9 +234,17 @@ protected function extractException(File $phpCsFile, int $contentIndex): array
$fullClass = '';

$position = $contentIndex;
while ($this->isGivenKind([T_NS_SEPARATOR, T_STRING], $tokens[$position])) {
$fullClass .= $tokens[$position]['content'];

// Handle T_NAME_FULLY_QUALIFIED token (e.g., \BadMethodCallException)
// or separate tokens (T_NS_SEPARATOR and T_STRING)
if ($this->isGivenKind([T_NAME_FULLY_QUALIFIED], $tokens[$position])) {
$fullClass = $tokens[$position]['content'];
++$position;
} else {
while ($this->isGivenKind([T_NS_SEPARATOR, T_STRING], $tokens[$position])) {
$fullClass .= $tokens[$position]['content'];
++$position;
}
}

$class = $fullClass = ltrim($fullClass, '\\');
Expand Down
2 changes: 1 addition & 1 deletion PhpCollective/Sniffs/Commenting/TypeHintSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public function process(File $phpcsFile, $stackPtr): void
continue;
}

/** @phpstan-var \PHPStan\PhpDocParser\Ast\Type\GenericTypeNode|\PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode|\PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode|\PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode|\PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode $valueNode */
/** @phpstan-var \PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode|\PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode|\PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode $valueNode */
if ($valueNode->type instanceof UnionTypeNode) {
$types = $valueNode->type->types;
} elseif ($valueNode->type instanceof ArrayTypeNode) {
Expand Down
56 changes: 27 additions & 29 deletions PhpCollective/Sniffs/Formatting/ArrayDeclarationSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -291,39 +291,37 @@ public function processMultiLineArray(File $phpcsFile, int $stackPtr, int $array
continue;
}

if ($tokens[$nextToken]['code'] === T_DOUBLE_ARROW) {
$currentEntry['arrow'] = $nextToken;
$keyUsed = true;
$currentEntry['arrow'] = $nextToken;
$keyUsed = true;

// Find the start of index that uses this double arrow.
$indexEnd = (int)$phpcsFile->findPrevious(T_WHITESPACE, ($nextToken - 1), $arrayStart, true);
$indexStart = $phpcsFile->findStartOfStatement($indexEnd);
// Find the start of index that uses this double arrow.
$indexEnd = (int)$phpcsFile->findPrevious(T_WHITESPACE, ($nextToken - 1), $arrayStart, true);
$indexStart = $phpcsFile->findStartOfStatement($indexEnd);

if ($indexStart === $indexEnd) {
$currentEntry['index'] = $indexEnd;
$currentEntry['index_content'] = $tokens[$indexEnd]['content'];
} else {
$currentEntry['index'] = $indexStart;
$currentEntry['index_content'] = $phpcsFile->getTokensAsString($indexStart, ($indexEnd - $indexStart + 1));
}

$indexLength = strlen($currentEntry['index_content']);
if ($maxLength < $indexLength) {
$maxLength = $indexLength;
}

// Find the value of this index.
$nextContent = $phpcsFile->findNext(
Tokens::$emptyTokens,
($nextToken + 1),
$arrayEnd,
true,
);
if ($indexStart === $indexEnd) {
$currentEntry['index'] = $indexEnd;
$currentEntry['index_content'] = $tokens[$indexEnd]['content'];
} else {
$currentEntry['index'] = $indexStart;
$currentEntry['index_content'] = $phpcsFile->getTokensAsString($indexStart, ($indexEnd - $indexStart + 1));
}

$currentEntry['value'] = $nextContent;
$indices[] = $currentEntry;
$lastToken = $nextToken;
$indexLength = strlen($currentEntry['index_content']);
if ($maxLength < $indexLength) {
$maxLength = $indexLength;
}

// Find the value of this index.
$nextContent = $phpcsFile->findNext(
Tokens::$emptyTokens,
($nextToken + 1),
$arrayEnd,
true,
);

$currentEntry['value'] = $nextContent;
$indices[] = $currentEntry;
$lastToken = $nextToken;
}

$numValues = count($indices);
Expand Down
79 changes: 51 additions & 28 deletions PhpCollective/Sniffs/Namespaces/UseStatementSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ protected function checkUseForReturnTypeHint(File $phpcsFile, int $stackPtr): vo
$extractedUseStatement = '';
$lastSeparatorIndex = null;
while (true) {
if (!$this->isGivenKind([T_NS_SEPARATOR, T_STRING, T_RETURN_TYPE], $tokens[$j])) {
if (!$this->isGivenKind([T_NS_SEPARATOR, T_STRING], $tokens[$j])) {
break;
}

Expand Down Expand Up @@ -639,32 +639,45 @@ protected function checkPropertyForInstanceOf(File $phpcsFile, int $stackPtr): v
return;
}

$lastIndex = null;
$j = $startIndex;
$extractedUseStatement = '';
$lastSeparatorIndex = null;
while (true) {
if (!$this->isGivenKind([T_NS_SEPARATOR, T_STRING, T_RETURN_TYPE], $tokens[$j])) {
break;
// Handle T_NAME_FULLY_QUALIFIED token (PHP CodeSniffer v4)
$className = '';
if ($tokens[$startIndex]['code'] === T_NAME_FULLY_QUALIFIED) {
$extractedUseStatement = ltrim($tokens[$startIndex]['content'], '\\');
if (strpos($extractedUseStatement, '\\') === false) {
return; // Not a namespaced class
}
$lastSeparatorPos = strrpos($extractedUseStatement, '\\');
$className = substr($extractedUseStatement, $lastSeparatorPos + 1);
$lastIndex = $startIndex;
$lastSeparatorIndex = null; // No separate separator token in v4
} else {
// Handle separate tokens (T_NS_SEPARATOR and T_STRING)
$lastIndex = null;
$j = $startIndex;
$extractedUseStatement = '';
$lastSeparatorIndex = null;
while (true) {
if (!$this->isGivenKind([T_NS_SEPARATOR, T_STRING], $tokens[$j])) {
break;
}

$lastIndex = $j;
$extractedUseStatement .= $tokens[$j]['content'];
if ($this->isGivenKind([T_NS_SEPARATOR], $tokens[$j])) {
$lastSeparatorIndex = $j;
$lastIndex = $j;
$extractedUseStatement .= $tokens[$j]['content'];
if ($this->isGivenKind([T_NS_SEPARATOR], $tokens[$j])) {
$lastSeparatorIndex = $j;
}
++$j;
}
++$j;
}

if ($lastIndex === null || $lastSeparatorIndex === null) {
return;
}

$extractedUseStatement = ltrim($extractedUseStatement, '\\');
if ($lastIndex === null || $lastSeparatorIndex === null) {
return;
}

$className = '';
for ($k = $lastSeparatorIndex + 1; $k <= $lastIndex; ++$k) {
$className .= $tokens[$k]['content'];
$extractedUseStatement = ltrim($extractedUseStatement, '\\');
$className = '';
for ($k = $lastSeparatorIndex + 1; $k <= $lastIndex; ++$k) {
$className .= $tokens[$k]['content'];
}
}

$error = 'Use statement ' . $extractedUseStatement . ' for class ' . $className . ' should be in use block.';
Expand All @@ -677,13 +690,23 @@ protected function checkPropertyForInstanceOf(File $phpcsFile, int $stackPtr): v

$addedUseStatement = $this->addUseStatement($phpcsFile, $className, $extractedUseStatement);

for ($k = $lastSeparatorIndex; $k > $startIndex; --$k) {
$phpcsFile->fixer->replaceToken($k, '');
}
$phpcsFile->fixer->replaceToken($startIndex, '');
if ($lastSeparatorIndex !== null) {
// Legacy: remove individual tokens
for ($k = $lastSeparatorIndex; $k > $startIndex; --$k) {
$phpcsFile->fixer->replaceToken($k, '');
}
$phpcsFile->fixer->replaceToken($startIndex, '');

if ($addedUseStatement['alias'] !== null) {
$phpcsFile->fixer->replaceToken($lastIndex, $addedUseStatement['alias']);
if ($addedUseStatement['alias'] !== null) {
$phpcsFile->fixer->replaceToken($lastIndex, $addedUseStatement['alias']);
}
} else {
// PHP CodeSniffer v4: replace single T_NAME_FULLY_QUALIFIED token
if ($addedUseStatement['alias'] !== null) {
$phpcsFile->fixer->replaceToken($startIndex, $addedUseStatement['alias']);
} else {
$phpcsFile->fixer->replaceToken($startIndex, $className);
}
}

$phpcsFile->fixer->endChangeset();
Expand Down
9 changes: 8 additions & 1 deletion PhpCollective/Sniffs/WhiteSpace/DocBlockSpacingSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ class DocBlockSpacingSniff implements Sniff
*/
public function register(): array
{
return [T_CLASS, T_INTERFACE, T_TRAIT, T_FUNCTION, T_PROPERTY];
$tokens = [T_CLASS, T_INTERFACE, T_TRAIT, T_FUNCTION];

// T_PROPERTY was introduced in PHP 8.4 for property hooks
if (defined('T_PROPERTY')) {
$tokens[] = T_PROPERTY;
}

return $tokens;
}

/**
Expand Down
12 changes: 7 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
],
"require": {
"php": ">=8.1",
"phpcsstandards/phpcsextra": "^1.2.0",
"slevomat/coding-standard": "^8.16.0",
"squizlabs/php_codesniffer": "^3.11.3"
"phpcsstandards/phpcsextra": "dev-develop",
"slevomat/coding-standard": "^8.23.0",
"squizlabs/php_codesniffer": "^4.0.0"
},
"require-dev": {
"phpstan/phpstan": "^1.0.0",
"phpstan/phpstan": "^2.0.0",
"phpunit/phpunit": "^10.3 || ^11.2 || ^12.0"
},
"autoload": {
Expand Down Expand Up @@ -72,5 +72,7 @@
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
1 change: 0 additions & 1 deletion phpcs.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0"?>
<ruleset name="code-sniffer">
<config name="installed_paths" value="../../php-collective/code-sniffer"/>
<config name="php_version" value="80100"/>

<arg name="tab-width" value="4"/>
Expand Down
4 changes: 4 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ parameters:
- '%rootDir%/../../../tests/bootstrap.php'
ignoreErrors:
- identifier: missingType.generics
- identifier: trait.unused
-
message: '#Parameter \#1 \$settings of static method SlevomatCodingStandard\\Helpers\\SniffSettingsHelper::normalizeArray\(\) expects list<string>, array<string> given#'
path: PhpCollective/Sniffs/Commenting/DisallowArrayTypeHintSyntaxSniff.php
Loading