Skip to content
This repository has been archived by the owner on Dec 3, 2023. It is now read-only.

[CodingStandard] add ArrayPropertyDefaultValueFixer #165

Merged
merged 14 commits into from
Jun 29, 2017
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
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@
"symfony/http-kernel": "^3.3",
"symfony/twig-bundle": "^3.3",
"symfony/yaml": "^3.3",
"tracy/tracy": "^2.4",
"yooper/php-text-analysis": "^1.1"
},
"require-dev": {
"phpstan/phpstan": "^0.7",
"phpunit/phpunit": "^6.2",
"phpstan/phpstan": "^0.7"
"tracy/tracy": "^2.4",
"gecko-packages/gecko-php-unit": "dev-master#b32f1d8 as 2.1"
},
"autoload": {
"psr-4": {
Expand Down
4 changes: 3 additions & 1 deletion easy-coding-standard.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
checkers:
- Symplify\CodingStandard\Fixer\Property\ArrayPropertyDefaultValueFixer

# Classes
- PHP_CodeSniffer\Standards\Generic\Sniffs\Classes\DuplicateClassNameSniff
- PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\PropertyDeclarationSniff
Expand Down Expand Up @@ -271,4 +273,4 @@ parameters:

Symplify\CodingStandard\Sniffs\Classes\EqualInterfaceImplementationSniff:
- packages/EasyCodingStandard/packages/SniffRunner/src/Application/SniffFileProcessor.php
- packages/EasyCodingStandard/packages/FixerRunner/src/Application/FixerFileProcessor.php
- packages/EasyCodingStandard/packages/FixerRunner/src/Application/FixerFileProcessor.php
2 changes: 0 additions & 2 deletions packages/CodingStandard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ final class SomeClass implements SomeInterface

- Except for Doctrine entities, they cannot be final.


### Block comment should be used instead of one liner

- [Commenting/BlockPropertyCommentSniff](/src/Sniffs/Commenting/BlockPropertyCommentSniff.php)
Expand Down Expand Up @@ -173,7 +172,6 @@ class SomeClass
}
```


### Controller should have max. 1 render method

- [Classes/ControllerRenderMethodLimitSniff](/src/Sniffs/Classes/ControllerRenderMethodLimitSniff.php)
Expand Down
1 change: 1 addition & 0 deletions packages/CodingStandard/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"nette/finder": "^2.4|^3.0",
"slevomat/coding-standard": "^3.0",
"squizlabs/php_codesniffer": "^3.0.1",
"friendsofphp/php-cs-fixer": "^2.3",
"nikic/php-parser": "^3.0"
},
"require-dev": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ final class ClassWrapper
/**
* @var mixed[]
*/
private $classToken;
private $classToken = [];

/**
* @var mixed[]
*/
private $tokens;
private $tokens = [];

/**
* @var MethodWrapper[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ final class DocBlockWrapper
private $indentationType = 'spaces';

/**
* @var string[]
* @var mixed[]
*/
private $tokens;
private $tokens = [];

/**
* @var Fixer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ final class MethodWrapper
/**
* @var ParameterWrapper[]
*/
private $parameters;
private $parameters = [];

/**
* @var mixed[]
*/
private $methodToken;
private $methodToken = [];

/**
* @var int
Expand All @@ -47,7 +47,7 @@ final class MethodWrapper
/**
* @var mixed[]
*/
private $tokens;
private $tokens = [];

private function __construct(File $file, int $position)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class ParameterWrapper
/**
* @var mixed[]
*/
private $tokens;
private $tokens = [];

private function __construct(File $file, int $position)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ final class PropertyWrapper
/**
* @var mixed[]
*/
private $propertyToken;
private $propertyToken = [];

/**
* @var mixed[]
*/
private $tokens;
private $tokens = [];

/**
* @var ?int
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php declare(strict_types=1);

namespace Symplify\CodingStandard\Fixer\Property;

use Nette\Utils\Strings;
use PhpCsFixer\DocBlock\DocBlock;
use PhpCsFixer\Fixer\DefinedFixerInterface;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use SplFileInfo;

final class ArrayPropertyDefaultValueFixer implements DefinedFixerInterface
{
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Array property should have default value, to prevent undefined array issues.',
[]
);
}

public function isCandidate(Tokens $tokens): bool
{
// analyze only properties with comments
return $tokens->isAllTokenKindsFound([T_DOC_COMMENT, T_VARIABLE]);
}

public function isRisky(): bool
{
return false;
}

public function fix(SplFileInfo $file, Tokens $tokens): void
{
for ($index = count($tokens) - 1; $index > 1; --$index) {
$token = $tokens[$index];

if (! $token->isGivenKind(T_DOC_COMMENT)) {
continue;
}

if (! $this->isArrayPropertyDocComment($token)) {
continue;
}

// @todo: how to get variable here?
$equalTokenPosition = $tokens->getNextTokenOfKind($index, ['=']);
$semicolonTokenPosition = $tokens->getNextTokenOfKind($index, [';']);

// default definition is set
if (is_numeric($equalTokenPosition) && $equalTokenPosition < $semicolonTokenPosition) {
continue;
}

$this->addDefaultValueForArrayProperty($tokens, $semicolonTokenPosition);
}
}

public function getName(): string
{
return self::class;
}

public function getPriority(): int
{
return 0;
}

public function supports(SplFileInfo $file): bool
{
return true;
}

private function isArrayPropertyDocComment(Token $token): bool
{
if (! $token->isComment()) {
return false;
}

$docBlock = new DocBlock($token->getContent());

if (count($docBlock->getLines()) === 1) {
return false;
}

if (! $docBlock->getAnnotationsOfType('var')) {
return false;
}

$varAnnotation = $docBlock->getAnnotationsOfType('var')[0];
if (! Strings::contains($varAnnotation->getTypes()[0], '[]')) {
return false;
}

return true;
}

private function addDefaultValueForArrayProperty(Tokens $tokens, int $semicolonPosition): void
{
$tokens[$semicolonPosition]->clear();

$tokens->insertAt($semicolonPosition, [
new Token([T_WHITESPACE, ' ']),
new Token('='),
new Token([T_WHITESPACE, ' ']),
new Token([CT::T_ARRAY_SQUARE_BRACE_OPEN, '[']),
new Token([CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']']),
new Token(';'),
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class ClassMetrics
/**
* @var mixed[]
*/
private $tokens;
private $tokens = [];

public function __construct(File $file, int $classPosition)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ final class NewClassSniff implements Sniff
/**
* @var mixed[]
*/
private $tokens;
private $tokens = [];

/**
* @return int[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php declare(strict_types=1);

namespace Symplify\CodingStandard\Tests\Fixer\Property;

use PhpCsFixer\Fixer\FixerInterface;
use PhpCsFixer\Test\AbstractFixerTestCase;
use Symplify\CodingStandard\Fixer\Property\ArrayPropertyDefaultValueFixer;

final class ArrayPropertyDefaultValueFixerTest extends AbstractFixerTestCase
{
/**
* @dataProvider provideFixCases()
*/
public function testFix(string $expected, string $input): void
{
$this->doTest($expected, $input);
}

/**
* @return string[][]
*/
public function provideFixCases(): array
{
return [
[
file_get_contents(__DIR__ . '/fixed/fixed.php.inc'),
file_get_contents(__DIR__ . '/wrong/wrong.php.inc'),
],
[
file_get_contents(__DIR__ . '/fixed/fixed2.php.inc'),
file_get_contents(__DIR__ . '/wrong/wrong2.php.inc'),
],
];
}

protected function createFixer(): FixerInterface
{
return new ArrayPropertyDefaultValueFixer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

class SomeClass
{
/**
* @var int[]
*/
public $property = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

class SomeClass
{
/**
* @var int[]
*/
public static $property = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

class SomeClass
{
/**
* @var int[]
*/
public $property;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

class SomeClass
{
/**
* @var int[]
*/
public static $property;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class TokenDispatcher
/**
* @var Sniff[][]
*/
private $tokenListeners;
private $tokenListeners = [];

public function __construct(Skipper $skipper)
{
Expand Down
9 changes: 9 additions & 0 deletions src/UndefinedArray.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

class UndefinedArray
{
/**
* @var int[]
*/
public $array = [];
}