Skip to content

Commit

Permalink
Merge pull request #62 from michalbundyra/feature/iterator-generators
Browse files Browse the repository at this point in the history
Add Iterator type support + fixes for functions with yield
  • Loading branch information
michalbundyra committed Nov 20, 2019
2 parents 1206d91 + 6710b31 commit cb7a144
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 12 deletions.
29 changes: 27 additions & 2 deletions src/WebimpressCodingStandard/Sniffs/Functions/ParamSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ private function checkParam(
'iterable' => ['iterable'],
'traversable' => ['traversable', '\traversable'],
'generator' => ['generator', '\generator'],
'iterator' => ['iterator', '\iterator'],
'object' => ['object'],
];
// @phpcs:enable
Expand Down Expand Up @@ -444,7 +445,7 @@ private function checkParam(
'?\generator',
], true)
&& ! in_array($lower, ['generator', '\generator'], true)
&& in_array($lower, array_merge($simpleTypes, ['mixed']), true)
&& in_array($lower, $simpleTypes, true)
) {
$error = 'Param type contains %s which is not a generator type';
$data = [
Expand All @@ -456,10 +457,30 @@ private function checkParam(
continue;
}

// iterator
if (in_array($lowerTypeHint, [
'iterator',
'?iterator',
'\iterator',
'?\iterator',
], true)
&& ! in_array($lower, ['iterator', '\iterator'], true)
&& in_array($lower, $simpleTypes, true)
) {
$error = 'Param type contains %s which is not an Iterator type';
$data = [
$type,
];
$phpcsFile->addError($error, $tagPtr + 2, 'NotIteratorType', $data);

$break = true;
continue;
}

// object
if (in_array($lowerTypeHint, ['object', '?object'], true)
&& $lower !== 'object'
&& (in_array($lower, array_merge($simpleTypes, ['mixed']), true)
&& (in_array($lower, $simpleTypes, true)
|| strpos($type, '[]') !== false)
) {
$error = 'Param type contains %s which is not an object type';
Expand All @@ -485,6 +506,10 @@ private function checkParam(
'?generator',
'\generator',
'?\generator',
'iterator',
'?iterator',
'\iterator',
'?\iterator',
'object',
'?object',
];
Expand Down
66 changes: 66 additions & 0 deletions src/WebimpressCodingStandard/Sniffs/Functions/ReturnTypeSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@

namespace WebimpressCodingStandard\Sniffs\Functions;

use Generator;
use Iterator;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;
use Traversable;
use WebimpressCodingStandard\Helper\MethodsTrait;

use function array_filter;
Expand All @@ -19,6 +22,7 @@
use function explode;
use function implode;
use function in_array;
use function ltrim;
use function preg_grep;
use function preg_replace;
use function preg_split;
Expand Down Expand Up @@ -333,6 +337,10 @@ private function processReturnType(File $phpcsFile, int $stackPtr) : void
'?generator',
'\generator',
'?\generator',
'iterator',
'?iterator',
'\iterator',
'?\iterator',
'object',
'?object',
];
Expand Down Expand Up @@ -426,6 +434,7 @@ private function processReturnType(File $phpcsFile, int $stackPtr) : void
'iterable' => ['iterable'],
'traversable' => ['traversable', '\traversable'],
'generator' => ['generator', '\generator'],
'iterator' => ['iterator', '\iterator'],
'object' => ['object'],
];

Expand Down Expand Up @@ -491,6 +500,26 @@ private function processReturnType(File $phpcsFile, int $stackPtr) : void
}
break;

case 'iterator':
case '?iterator':
case '\iterator':
case '?\iterator':
foreach ($this->returnDocTypes as $type) {
$lower = strtolower($type);
if (in_array($lower, ['iterator', '\iterator'], true)) {
continue;
}

if (in_array($lower, $simpleTypes, true)) {
$error = 'Return type contains "%s" which is not an Iterator type';
$data = [
$type,
];
$phpcsFile->addError($error, $this->returnDoc + 2, 'NotIteratorType', $data);
}
}
break;

case 'traversable':
case '?traversable':
case '\traversable':
Expand Down Expand Up @@ -599,11 +628,48 @@ private function processReturnStatements(File $phpcsFile, int $stackPtr) : void
continue;
}

$isYield = $tokens[$i]['code'] !== T_RETURN;
if ($isYield && $this->returnType && $this->returnTypeIsValid) {
$type = strtolower(ltrim($this->returnTypeValue, '?'));

if ($type !== 'iterable'
&& ((! isset($this->importedClasses[$type]['fqn'])
&& ! in_array(ltrim($type, '\\'), [
'generator',
'iterator',
'traversable',
], true))
|| (isset($this->importedClasses[$type]['fqn'])
&& ! in_array($this->importedClasses[$type]['fqn'], [
Generator::class,
Iterator::class,
Traversable::class,
], true)))
) {
$phpcsFile->addError(
sprintf(
'Generators may only declare a return type of Generator, Iterator, Traversable,'
. ' or iterable, %s is not permitted',
$this->returnTypeValue
),
$this->returnType,
'InvalidGeneratorType'
);

return;
}
}

$next = $phpcsFile->findNext(Tokens::$emptyTokens, $i + 1, null, true);
if ($tokens[$next]['code'] === T_SEMICOLON) {
$this->returnCodeVoid($phpcsFile, $i);
} else {
$this->returnCodeValue($phpcsFile, $i);

if ($isYield) {
return;
}

$returnValues[$next] = $this->getReturnValue($phpcsFile, $next);

if ($this->returnDoc
Expand Down
5 changes: 5 additions & 0 deletions test/Sniffs/Functions/ParamUnitTest.1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,9 @@ class FunctionParam
object $static,
object $parent
) : void;

/**
* @param int|array|string|bool[]|float[]|MyIterator|\Iterator $iterator
*/
abstract protected function nonIteratorTypes(\Iterator $iterator) : void;
}
1 change: 1 addition & 0 deletions test/Sniffs/Functions/ParamUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ protected function getErrorList(string $testFile = '') : array
143 => 2,
154 => 1,
159 => 1,
201 => 4,
];
}

Expand Down
13 changes: 13 additions & 0 deletions test/Sniffs/Functions/ReturnTypeUnitTest.2.inc
Original file line number Diff line number Diff line change
Expand Up @@ -471,4 +471,17 @@ abstract class FunctionCommentReturn
{
return $this;
}

/**
* @return int[]|float[]|string|array|bool|MyClass|MyIterator|\Iterator
*/
public function generatorIterator() : \Iterator
{
yield 1;
yield 1.2;
yield 'string';
yield [];
yield true;
yield null;
}
}
13 changes: 13 additions & 0 deletions test/Sniffs/Functions/ReturnTypeUnitTest.2.inc.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -471,4 +471,17 @@ abstract class FunctionCommentReturn
{
return $this;
}

/**
* @return int[]|float[]|string|array|bool|MyClass|MyIterator
*/
public function generatorIterator() : \Iterator
{
yield 1;
yield 1.2;
yield 'string';
yield [];
yield true;
yield null;
}
}
52 changes: 52 additions & 0 deletions test/Sniffs/Functions/ReturnTypeUnitTest.3.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace MyNamespace\Test\Functions;

use Iterator as IteratorAlias;

class FunctionCommentReturn
{
/**
Expand Down Expand Up @@ -182,4 +184,54 @@ class FunctionCommentReturn
{
return [];
}

public function generator1() : iterable
{
yield 1;
yield 1.2;
yield 'string';
yield [];
yield true;
yield null;
}

public function generator2() : \Generator
{
yield 1;
yield 1.2;
yield 'string';
yield [];
yield true;
yield null;
}

public function generator3() : \Traversable
{
yield 1;
yield 1.2;
yield 'string';
yield [];
yield true;
yield null;
}

public function generator4() : IteratorAlias
{
yield 1;
yield 1.2;
yield 'string';
yield [];
yield true;
yield null;
}

public function generator5() : MyCustomGenerator
{
yield 1;
yield 1.2;
yield 'string';
yield [];
yield true;
yield null;
}
}
24 changes: 14 additions & 10 deletions test/Sniffs/Functions/ReturnTypeUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,21 @@ protected function getErrorList(string $testFile = '') : array
452 => 1,
460 => 1,
468 => 1,
476 => 4,
];
case 'ReturnTypeUnitTest.3.inc':
return [
8 => 1,
24 => 1,
40 => 1,
56 => 1,
72 => 1,
96 => 1,
120 => 1,
144 => 1,
160 => 1,
168 => 1,
10 => 1,
26 => 1,
42 => 1,
58 => 1,
74 => 1,
98 => 1,
122 => 1,
146 => 1,
162 => 1,
170 => 1,
228 => 1,
];
}

Expand All @@ -180,6 +182,8 @@ protected function getErrorList(string $testFile = '') : array
36 => 1,
41 => 1,
46 => 1,
54 => 1,
59 => 1,
95 => 1,
99 => 1,
108 => 1,
Expand Down

0 comments on commit cb7a144

Please sign in to comment.