Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 9 additions & 9 deletions PhpCollective/Sniffs/Classes/Psr4/AutoloadabilityInspector.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ public function __construct(string $baseDirectory, string $namespacePrefix)
public function inspect(
ClassFileUnderInspection $classFile,
): InspectionResult {
return $this->classFileIsUnderBaseDirectory($classFile) ?
$this->inspectAutoloadability($classFile) :
new PSR4UnrelatedClass();
return $this->classFileIsUnderBaseDirectory($classFile)
? $this->inspectAutoloadability($classFile)
: new PSR4UnrelatedClass();
}

/**
Expand All @@ -69,9 +69,9 @@ protected function inspectAutoloadability(
$expectedClassName = $this->guessExpectedClassName($classFile);
$actualClassName = $classFile->getClassName();

return $expectedClassName === $actualClassName ?
new AutoloadableClass() :
new NonAutoloadableClass($expectedClassName, $actualClassName);
return $expectedClassName === $actualClassName
? new AutoloadableClass()
: new NonAutoloadableClass($expectedClassName, $actualClassName);
}

/**
Expand Down Expand Up @@ -114,9 +114,9 @@ protected function guessRelativeClassName(string $relativeFileName): string
{
$basename = basename($relativeFileName);
$filename = pathinfo($relativeFileName, PATHINFO_FILENAME);
$dirname = $basename === $relativeFileName ?
'' :
pathinfo($relativeFileName, PATHINFO_DIRNAME) . '/';
$dirname = $basename === $relativeFileName
? ''
: pathinfo($relativeFileName, PATHINFO_DIRNAME) . '/';

return str_replace('/', '\\', $dirname) . $filename;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ protected static function resolveComposerJsonPath(
?string $basePath,
string $composerJsonPath,
): string {
return $basePath === null ?
$composerJsonPath :
$basePath . '/' . $composerJsonPath;
return $basePath === null
? $composerJsonPath
: $basePath . '/' . $composerJsonPath;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,8 @@ protected function containsArrayTypeNode(array $types): bool
*/
protected function isArrayTypeNode(TypeNode $typeNode): bool
{
return $typeNode instanceof ArrayTypeNode &&
($typeNode->type instanceof IdentifierTypeNode || $typeNode->type instanceof ArrayTypeNode);
return $typeNode instanceof ArrayTypeNode
&& ($typeNode->type instanceof IdentifierTypeNode || $typeNode->type instanceof ArrayTypeNode);
}

/**
Expand Down
18 changes: 9 additions & 9 deletions PhpCollective/Sniffs/Commenting/TypeHintSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ public function process(File $phpcsFile, $stackPtr): void

foreach ($tokens[$stackPtr]['comment_tags'] as $tag) {
if (
$tokens[$tag + 2]['code'] !== T_DOC_COMMENT_STRING ||
!in_array($tokens[$tag]['content'], static::$typeHintTags, true)
$tokens[$tag + 2]['code'] !== T_DOC_COMMENT_STRING
|| !in_array($tokens[$tag]['content'], static::$typeHintTags, true)
) {
continue;
}
Expand Down Expand Up @@ -199,8 +199,8 @@ public function process(File $phpcsFile, $stackPtr): void

foreach ($tokens[$stackPtr]['comment_tags'] as $key => $tag) {
if (
$tokens[$tag + 2]['code'] !== T_DOC_COMMENT_STRING ||
!in_array($tokens[$tag]['content'], static::$typeHintTags, true)
$tokens[$tag + 2]['code'] !== T_DOC_COMMENT_STRING
|| !in_array($tokens[$tag]['content'], static::$typeHintTags, true)
) {
continue;
}
Expand Down Expand Up @@ -278,9 +278,9 @@ protected function processNativeTypeHints(File $phpcsFile, int $stackPtr): void

$methodProperties = $phpcsFile->getMethodProperties($stackPtr);
if (
$methodProperties['return_type'] === '' ||
$methodProperties['return_type_token'] === false ||
$methodProperties['return_type_end_token'] === false
$methodProperties['return_type'] === ''
|| $methodProperties['return_type_token'] === false
|| $methodProperties['return_type_end_token'] === false
) {
return;
}
Expand Down Expand Up @@ -359,8 +359,8 @@ protected function getSortedTypeHint(array $types): string
$sortName = 'array';
}
} elseif (
$type instanceof ArrayShapeNode ||
($type instanceof GenericTypeNode && $type->type->name === 'array')
$type instanceof ArrayShapeNode
|| ($type instanceof GenericTypeNode && $type->type->name === 'array')
) {
$sortName = 'array';
}
Expand Down
16 changes: 8 additions & 8 deletions PhpCollective/Sniffs/Formatting/ArrayDeclarationSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -639,8 +639,8 @@ protected function processMultiLineIndentation(File $phpcsFile, int $arrayStart,
// Look for the first properly indented item in this array to match its indentation
for ($searchIdx = $arrayStart + 1; $searchIdx < $arrayEnd; $searchIdx++) {
if (
$tokens[$searchIdx]['line'] > $tokens[$arrayStart]['line'] &&
!in_array($tokens[$searchIdx]['code'], Tokens::$emptyTokens, true)
$tokens[$searchIdx]['line'] > $tokens[$arrayStart]['line']
&& !in_array($tokens[$searchIdx]['code'], Tokens::$emptyTokens, true)
) {
// Extract actual indentation from the line (only leading whitespace)
$lineStart = $phpcsFile->findFirstOnLine([], $searchIdx);
Expand Down Expand Up @@ -670,8 +670,8 @@ protected function processMultiLineIndentation(File $phpcsFile, int $arrayStart,
$count = count($tokens);
for ($detectIdx = 0; $detectIdx < $count; $detectIdx++) {
if (
$tokens[$detectIdx]['code'] === T_WHITESPACE &&
$tokens[$detectIdx]['line'] !== $tokens[$detectIdx - 1]['line']
$tokens[$detectIdx]['code'] === T_WHITESPACE
&& $tokens[$detectIdx]['line'] !== $tokens[$detectIdx - 1]['line']
) {
$whitespace = $tokens[$detectIdx]['content'];
if (str_contains($whitespace, "\t")) {
Expand Down Expand Up @@ -707,10 +707,10 @@ protected function processMultiLineIndentation(File $phpcsFile, int $arrayStart,
// Determine if we should use chunking for this line
$useChunking = false;
if (
$this->nonAssocExceedAction === 'chunk' &&
$this->maxNonAssocItemsPerLine > 0 &&
$nonAssocCount > $this->maxNonAssocItemsPerLine &&
!$hasAssociative
$this->nonAssocExceedAction === 'chunk'
&& $this->maxNonAssocItemsPerLine > 0
&& $nonAssocCount > $this->maxNonAssocItemsPerLine
&& !$hasAssociative
) {
// Use chunking only for pure non-associative arrays
$useChunking = true;
Expand Down
146 changes: 146 additions & 0 deletions PhpCollective/Sniffs/Operators/OperatorPositionSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

/**
* MIT License
* For full license information, please view the LICENSE file that was distributed with this source code.
*/

namespace PhpCollective\Sniffs\Operators;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Utils\Operators;

/**
* Places multiline operators at the start of the continuation line.
*/
class OperatorPositionSniff implements Sniff
{
/**
* @inheritDoc
*/
public function register(): array
{
return [
T_BOOLEAN_AND, T_BOOLEAN_OR,
T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR,
T_COALESCE, T_INLINE_THEN, T_INLINE_ELSE,
T_PLUS, T_MINUS, T_MULTIPLY, T_DIVIDE, T_MODULUS, T_POW,
];
}

/**
* @inheritDoc
*/
public function process(File $phpcsFile, $stackPtr): void
{
$tokens = $phpcsFile->getTokens();
$code = $tokens[$stackPtr]['code'];

if (($code === T_PLUS || $code === T_MINUS) && Operators::isUnaryPlusMinus($phpcsFile, $stackPtr)) {
return;
}

$previous = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true);
if ($previous === false || $tokens[$previous]['line'] !== $tokens[$stackPtr]['line']) {
return;
}

if ($code === T_INLINE_ELSE && $tokens[$previous]['code'] === T_INLINE_THEN) {
return;
}

$end = $stackPtr;
if ($code === T_INLINE_THEN) {
$following = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true);
if ($following !== false && $tokens[$following]['code'] === T_INLINE_ELSE) {
if ($tokens[$following]['line'] !== $tokens[$stackPtr]['line']) {
$this->processSplitShortTernary($phpcsFile, $stackPtr, $following);

return;
}
$end = $following;
}
}

$next = $phpcsFile->findNext(Tokens::$emptyTokens, $end + 1, null, true);
if ($next === false || $tokens[$next]['line'] === $tokens[$end]['line']) {
return;
}

$hasComment = false;
for ($i = $stackPtr + 1; $i < $next; $i++) {
if (isset(Tokens::$commentTokens[$tokens[$i]['code']])) {
$hasComment = true;

break;
}
}

$operator = $end === $stackPtr ? $tokens[$stackPtr]['content'] : '?:';
$message = 'Operator "%s" must be placed at the start of the continuation line';
if ($hasComment) {
$phpcsFile->addError($message, $stackPtr, 'IncorrectWithComment', [$operator]);

return;
}

if (!$phpcsFile->addFixableError($message, $stackPtr, 'Incorrect', [$operator])) {
return;
}

$phpcsFile->fixer->beginChangeset();
for ($i = $stackPtr; $i <= $end; $i++) {
$phpcsFile->fixer->replaceToken($i, '');
}
if ($tokens[$stackPtr - 1]['code'] === T_WHITESPACE) {
$phpcsFile->fixer->replaceToken($stackPtr - 1, '');
}
if ($tokens[$end + 1]['code'] === T_WHITESPACE) {
$whitespace = $tokens[$end + 1]['content'];
$phpcsFile->fixer->replaceToken($end + 1, preg_replace('/^[ \t]+(?=\r?\n)/', '', $whitespace));
}
$phpcsFile->fixer->addContentBefore($next, $operator . ' ');
$phpcsFile->fixer->endChangeset();
}

/**
* Handles `$a ?` followed by `: $b` on the next line by joining both into `?:` there.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile
* @param int $thenPtr
* @param int $elsePtr
*
* @return void
*/
protected function processSplitShortTernary(File $phpcsFile, int $thenPtr, int $elsePtr): void
{
$tokens = $phpcsFile->getTokens();
$message = 'Operator "?:" must be placed at the start of the continuation line';

for ($i = $thenPtr + 1; $i < $elsePtr; $i++) {
if (isset(Tokens::$commentTokens[$tokens[$i]['code']])) {
$phpcsFile->addError($message, $thenPtr, 'IncorrectWithComment');

return;
}
}

if (!$phpcsFile->addFixableError($message, $thenPtr, 'Incorrect')) {
return;
}

$phpcsFile->fixer->beginChangeset();
$phpcsFile->fixer->replaceToken($thenPtr, '');
if ($tokens[$thenPtr - 1]['code'] === T_WHITESPACE) {
$phpcsFile->fixer->replaceToken($thenPtr - 1, '');
}
$whitespace = $tokens[$thenPtr + 1]['code'] === T_WHITESPACE ? $tokens[$thenPtr + 1]['content'] : '';
if ($whitespace !== '') {
$phpcsFile->fixer->replaceToken($thenPtr + 1, (string)preg_replace('/^[ \t]+(?=\r?\n)/', '', $whitespace));
}
$phpcsFile->fixer->addContentBefore($elsePtr, '?');
$phpcsFile->fixer->endChangeset();
}
}
1 change: 1 addition & 0 deletions PhpCollective/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
<rule ref="Universal.Attributes.TrailingComma"/>
<rule ref="Universal.ControlStructures.DisallowAlternativeSyntax"/>
<rule ref="Universal.Operators.ConcatPosition"/>
<rule ref="PhpCollective.Operators.OperatorPosition"/>
<rule ref="Universal.Operators.TypeSeparatorSpacing"/>
<rule ref="Universal.UseStatements.NoUselessAliases"/>
<rule ref="Universal.CodeAnalysis.NoEchoSprintf"/>
Expand Down
5 changes: 3 additions & 2 deletions docs/sniffs.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# PhpCollective Code Sniffer


The PhpCollectiveStrict standard contains 251 sniffs
The PhpCollectiveStrict standard contains 252 sniffs

Generic (27 sniffs)
-------------------
Expand Down Expand Up @@ -48,7 +48,7 @@ PEAR (4 sniffs)
- PEAR.Functions.ValidDefaultValue
- PEAR.NamingConventions.ValidClassName

PhpCollective (87 sniffs)
PhpCollective (88 sniffs)
-------------------------
- PhpCollective.Arrays.ArrayBracketSpacing
- PhpCollective.Arrays.DisallowImplicitArrayCreation
Expand Down Expand Up @@ -107,6 +107,7 @@ PhpCollective (87 sniffs)
- PhpCollective.Namespaces.FunctionNamespace
- PhpCollective.Namespaces.UseStatement
- PhpCollective.Namespaces.UseWithAliasing
- PhpCollective.Operators.OperatorPosition
- PhpCollective.Operators.OperatorSpacing
- PhpCollective.PHP.DeclareStrictTypes
- PhpCollective.PHP.DisallowFunctions
Expand Down
26 changes: 26 additions & 0 deletions tests/PhpCollective/Sniffs/Operators/OperatorPositionSniffTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/**
* MIT License
* For full license information, please view the LICENSE file that was distributed with this source code.
*/

namespace PhpCollective\Test\PhpCollective\Sniffs\Operators;

use PhpCollective\Sniffs\Operators\OperatorPositionSniff;
use PhpCollective\Test\TestCase;

class OperatorPositionSniffTest extends TestCase
{
public function testReportsOperators(): void
{
$errors = $this->assertSnifferFindsFixableErrors(new OperatorPositionSniff(), 28, 27);
$commentErrors = array_values($errors[57]);
$this->assertSame('PhpCollective.Operators.OperatorPosition.IncorrectWithComment', $commentErrors[0][0]['source']);
}

public function testFixesOperators(): void
{
$this->assertSnifferCanFixErrors(new OperatorPositionSniff(), 27);
}
}
Loading
Loading