From 8d7372d2bef48ad091f76bbeef6afba01578fa0c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 18 Feb 2020 09:26:23 +0100 Subject: [PATCH 01/79] Arrays::getDoubleArrowPtr(): add extra unit test --- Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc | 4 ++++ Tests/Utils/Arrays/GetDoubleArrowPtrTest.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc index 231ecece..0d1b31d4 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc @@ -86,4 +86,8 @@ $array = [ /* testDoubleArrowTokenizedAsTstring-PHPCS2865 */ $obj->fn => 'value', + + /* testEmptyArrayItem */ + // Intentional parse error. + , ]; diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php index c1ca43c0..c1f44113 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php @@ -217,6 +217,10 @@ public function dataGetDoubleArrowPtr() '/* testDoubleArrowTokenizedAsTstring-PHPCS2865 */', 10, ], + 'test-empty-array-item' => [ + '/* testEmptyArrayItem */', + false, + ], ]; } } From 9a852195c32156c0f6ddb37ac2b3f2941ec76de9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 18 Feb 2020 09:56:53 +0100 Subject: [PATCH 02/79] PassedParameters::getParameterCount(): add extra unit test --- Tests/Utils/PassedParameters/GetParameterCountTest.inc | 4 ++++ Tests/Utils/PassedParameters/GetParameterCountTest.php | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/Tests/Utils/PassedParameters/GetParameterCountTest.inc b/Tests/Utils/PassedParameters/GetParameterCountTest.inc index 781e2c30..63c66a72 100644 --- a/Tests/Utils/PassedParameters/GetParameterCountTest.inc +++ b/Tests/Utils/PassedParameters/GetParameterCountTest.inc @@ -197,3 +197,7 @@ $bar = ['a' => $a, 'b' => $b, 'c' => (isset($c) ? $c : null)]; /* testShortArray8 */ $bar = [0 => $a, 2 => $b, 6 => (isset($c) ? $c : null)]; + +/* testArrayWithEmptyItem */ +// Intentional parse error. +$bar = [0 => $a,, 2 => $b]; diff --git a/Tests/Utils/PassedParameters/GetParameterCountTest.php b/Tests/Utils/PassedParameters/GetParameterCountTest.php index be03c7e6..82d57ed2 100644 --- a/Tests/Utils/PassedParameters/GetParameterCountTest.php +++ b/Tests/Utils/PassedParameters/GetParameterCountTest.php @@ -317,6 +317,11 @@ public function dataGetParameterCount() '/* testShortArray8 */', 3, ], + + 'array-with-empty-item' => [ + '/* testArrayWithEmptyItem */', + 3, + ], ]; } } From 51ea82bfd2ee383e8d42255b368020343fa7dd4c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 18 Feb 2020 09:58:06 +0100 Subject: [PATCH 03/79] AbstractSniffs/AbstractArrayDeclarationSniff: improve handling of parse errors Empty array items are not allowed and will trigger a parse error, but the sniff should handle this gracefully. --- .../AbstractArrayDeclarationSniff.php | 7 +++- .../AbstractArrayDeclarationSniffTest.inc | 4 +++ .../AbstractArrayDeclarationSniffTest.php | 34 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php b/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php index 9d8eedc4..63c27167 100644 --- a/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php +++ b/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php @@ -224,7 +224,12 @@ public function processArray(File $phpcsFile) } foreach ($this->arrayItems as $itemNr => $arrayItem) { - $arrowPtr = Arrays::getDoubleArrowPtr($phpcsFile, $arrayItem['start'], $arrayItem['end']); + try { + $arrowPtr = Arrays::getDoubleArrowPtr($phpcsFile, $arrayItem['start'], $arrayItem['end']); + } catch (RuntimeException $e) { + // Parse error: empty array item. Ignore. + continue; + } if ($arrowPtr !== false) { if ($this->processKey($phpcsFile, $arrayItem['start'], ($arrowPtr - 1), $itemNr) === true) { diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.inc b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.inc index 6c9e353e..f5bb0edb 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.inc +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.inc @@ -21,6 +21,10 @@ $array = [ 'string' => 'string key', ]; +/* testEmptyArrayItem */ +// Intentional parse error. +$array = array(1,, 'a' => 2); + /* testShortCircuit */ $array = [1, 'a' => 2, ]; diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php index 04983eaf..fe9f5871 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php @@ -382,6 +382,40 @@ public function testMultiLineShortArrayMixedKeysNoKeys() $this->assertAttributeSame(false, 'singleLine', $mockObj); } + /** + * Test the abstract sniff correctly ignores empty array items (parse error). + * + * @return void + */ + public function testEmptyArrayItem() + { + $target = $this->getTargetToken( + '/* testEmptyArrayItem */', + [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] + ); + + $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') + ->setMethods($this->methodsToMock) + ->getMockForAbstractClass(); + + $mockObj->expects($this->once()) + ->method('processOpenClose'); + + $mockObj->expects($this->exactly(1)) + ->method('processKey'); + + $mockObj->expects($this->exactly(1)) + ->method('processNoKey'); + + $mockObj->expects($this->exactly(2)) + ->method('processValue'); + + $mockObj->expects($this->once()) + ->method('processComma'); + + $mockObj->process(self::$phpcsFile, $target); + } + /** * Test short-circuiting the sniff on the call to processOpenClose(). * From cf90bbcc895e3c2482aa9f66bb94858deb6050fe Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 22 Feb 2020 07:51:42 +0100 Subject: [PATCH 04/79] PHPUnit: be strict about covers annotations --- phpunit.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a5223261..eb097aeb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,6 +5,7 @@ backupGlobals="true" bootstrap="./Tests/bootstrap.php" beStrictAboutTestsThatDoNotTestAnything="true" + beStrictAboutCoversAnnotation="true" colors="true" forceCoversAnnotation="true"> From b9013b1a4d87b4a50123ec60dfbf723066c51877 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 22 Feb 2020 09:07:59 +0100 Subject: [PATCH 05/79] PHPUnit: make the tests compatible with PHPUnit 9.x There is only one issue this test suite run into and that is the removal of the `assertAttributeSame()` method. As for these properties I do deem it important to test the value, I have chosen to emulate the method for PHPUnit 9+. --- .../AbstractArrayDeclarationSniffTest.php | 107 ++++++++++++++---- composer.json | 2 +- 2 files changed, 87 insertions(+), 22 deletions(-) diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php index fe9f5871..ecb155c1 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php @@ -11,6 +11,9 @@ namespace PHPCSUtils\Tests\AbstractSniffs\AbstractArrayDeclaration; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use Exception; +use ReflectionException; +use ReflectionObject; /** * Tests for the \PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff class. @@ -175,14 +178,12 @@ public function testSingleLineShortArrayNoKeysNoTrailingComma() $mockObj->process(self::$phpcsFile, $target); - // Note: these methods are deprecated in PHPUnit 8.x and removed in PHPUnit 9.x - // Verify that the properties have been correctly set. - $this->assertAttributeSame($target, 'stackPtr', $mockObj); - $this->assertAttributeSame($target, 'arrayOpener', $mockObj); - $this->assertAttributeSame(($target + 5), 'arrayCloser', $mockObj); - $this->assertAttributeSame(2, 'itemCount', $mockObj); - $this->assertAttributeSame(true, 'singleLine', $mockObj); + $this->assertAttributeValueSame($target, 'stackPtr', $mockObj); + $this->assertAttributeValueSame($target, 'arrayOpener', $mockObj); + $this->assertAttributeValueSame(($target + 5), 'arrayCloser', $mockObj); + $this->assertAttributeValueSame(2, 'itemCount', $mockObj); + $this->assertAttributeValueSame(true, 'singleLine', $mockObj); } /** @@ -274,14 +275,12 @@ public function testMultiLineLongArrayKeysTrailingComma() $mockObj->process(self::$phpcsFile, $target); - // Note: these methods are deprecated in PHPUnit 8.x and removed in PHPUnit 9.x - // Verify that the properties have been correctly set. - $this->assertAttributeSame($target, 'stackPtr', $mockObj); - $this->assertAttributeSame(($target + 1), 'arrayOpener', $mockObj); - $this->assertAttributeSame(($target + 35), 'arrayCloser', $mockObj); - $this->assertAttributeSame(4, 'itemCount', $mockObj); - $this->assertAttributeSame(false, 'singleLine', $mockObj); + $this->assertAttributeValueSame($target, 'stackPtr', $mockObj); + $this->assertAttributeValueSame(($target + 1), 'arrayOpener', $mockObj); + $this->assertAttributeValueSame(($target + 35), 'arrayCloser', $mockObj); + $this->assertAttributeValueSame(4, 'itemCount', $mockObj); + $this->assertAttributeValueSame(false, 'singleLine', $mockObj); } /** @@ -372,14 +371,12 @@ public function testMultiLineShortArrayMixedKeysNoKeys() $mockObj->process(self::$phpcsFile, $target); - // Note: these methods are deprecated in PHPUnit 8.x and removed in PHPUnit 9.x - // Verify that the properties have been correctly set. - $this->assertAttributeSame($target, 'stackPtr', $mockObj); - $this->assertAttributeSame($target, 'arrayOpener', $mockObj); - $this->assertAttributeSame(($target + 22), 'arrayCloser', $mockObj); - $this->assertAttributeSame(3, 'itemCount', $mockObj); - $this->assertAttributeSame(false, 'singleLine', $mockObj); + $this->assertAttributeValueSame($target, 'stackPtr', $mockObj); + $this->assertAttributeValueSame($target, 'arrayOpener', $mockObj); + $this->assertAttributeValueSame(($target + 22), 'arrayCloser', $mockObj); + $this->assertAttributeValueSame(3, 'itemCount', $mockObj); + $this->assertAttributeValueSame(false, 'singleLine', $mockObj); } /** @@ -643,4 +640,72 @@ public function testShortCircuitOnProcessComma() $mockObj->process(self::$phpcsFile, $target); } + + + /** + * PHPUnit cross-version helper method to test the value of the class properties. + * + * @param mixed $expected Expected property value. + * @param string $attributeName The name of the property to check. + * @param object $actualObject The object on which to check the property value. + * + * @return void + */ + public function assertAttributeValueSame($expected, $attributeName, $actualObject, $message = '') + { + // Will throw a warning on PHPUnit 8, but will still work. + if (method_exists($this, 'assertAttributeSame')) { + parent::assertAttributeSame($expected, $attributeName, $actualObject, $message); + return; + } + + // PHPUnit 9.0+. + try { + $actual = $this->getObjectAttributeValue($actualObject, $attributeName); + } catch (\Exception $e) { + $this->fail($e->getMessage()); + } + + $this->assertSame($expected, $actual); + } + + /** + * Retrieve the value of an object's attribute. + * This also works for attributes that are declared protected or private. + * + * @param object|string $object The object or class on which to check the property value. + * @param string $attributeName The name of the property to check. + * + * @return mixed Property value. + * + * @throws Exception + */ + public static function getObjectAttributeValue($object, $attributeName) + { + $reflector = new ReflectionObject($object); + + do { + try { + $attribute = $reflector->getProperty($attributeName); + + if (!$attribute || $attribute->isPublic()) { + return $object->$attributeName; + } + + $attribute->setAccessible(true); + $value = $attribute->getValue($object); + $attribute->setAccessible(false); + + return $value; + } catch (ReflectionException $e) { + } + } while ($reflector = $reflector->getParentClass()); + + throw new Exception( + \sprintf( + 'Attribute "%s" not found in object.', + $attributeName + ) + ); + } } diff --git a/composer.json b/composer.json index 4af3e6a3..de910544 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "require-dev" : { "jakub-onderka/php-parallel-lint": "^1.0", "jakub-onderka/php-console-highlighter": "^0.4", - "phpunit/phpunit" : "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0" + "phpunit/phpunit" : "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "conflict": { "squizlabs/php_codesniffer": "3.5.3" From ed741fd30f2dde398aa5d901de912dfa0bff7499 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 22 Feb 2020 11:18:46 +0100 Subject: [PATCH 06/79] CI: switch to fork of Parallel-lint package ... as the original appears not to be maintained anymore and is not compatible with PHP 7.4. --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index de910544..a1a25baf 100644 --- a/composer.json +++ b/composer.json @@ -27,8 +27,8 @@ "dealerdirect/phpcodesniffer-composer-installer" : "^0.3 || ^0.4.1 || ^0.5 || ^0.6.2" }, "require-dev" : { - "jakub-onderka/php-parallel-lint": "^1.0", - "jakub-onderka/php-console-highlighter": "^0.4", + "php-parallel-lint/php-parallel-lint": "^1.1.0", + "php-parallel-lint/php-console-highlighter": "^0.4", "phpunit/phpunit" : "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "conflict": { @@ -46,7 +46,7 @@ }, "scripts" : { "lint": [ - "@php ./vendor/jakub-onderka/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git" + "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git" ], "install-devcs": [ "composer require phpcsstandards/phpcsdevcs:\"^1.0\" --no-suggest --update-no-dev" From d650e5413f180b1b21efbdd6b88f3b3a89a1dea8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 22 Feb 2020 08:30:53 +0100 Subject: [PATCH 07/79] Document that the TestUtils are compatible with PHPUnit 9.x Tested & found compatible. --- PHPCSUtils/TestUtils/UtilityMethodTestCase.php | 2 +- README.md | 2 +- docs/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php index 8949855e..4fce2bc4 100644 --- a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php @@ -21,7 +21,7 @@ * * This class is compatible with PHP_CodeSniffer 2.x as well as 3.x. * - * This class is compatible with PHPUnit 4.5 - 8.x providing the PHPCSUtils autoload + * This class is compatible with PHPUnit 4.5 - 9.x providing the PHPCSUtils autoload * file is included in the test bootstrap. * * To allow for testing of tab vs space content, the tabWidth is set to `4` by default. diff --git a/README.md b/README.md index 887e33c3..066d95b5 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ These functions are, of course, compatible with PHPCS 2.6.0 up to PHPCS `master` ### Test utilities An abstract `UtilityMethodTestCase` class to allow for testing your own utility methods written for PHP_CodeSniffer with ease. -Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 8.x. +Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 9.x. ### Backward compatibility layer diff --git a/docs/index.html b/docs/index.html index cda68f5b..5f99d64a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -82,7 +82,7 @@

Features

Test utilities

An abstract UtilityMethodTestCase class to allow for testing your own utility methods written for PHP_CodeSniffer with ease.
- Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 8.x.

+ Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 9.x.

Backward compatibility layer
From fbcc5811508547f701fe31c2d61c7636deef079b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 22 Feb 2020 12:43:07 +0100 Subject: [PATCH 08/79] Minor CS clean up --- .../AbstractArrayDeclarationSniffTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php index ecb155c1..c8bb8b3a 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php @@ -10,8 +10,8 @@ namespace PHPCSUtils\Tests\AbstractSniffs\AbstractArrayDeclaration; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; use Exception; +use PHPCSUtils\TestUtils\UtilityMethodTestCase; use ReflectionException; use ReflectionObject; @@ -641,20 +641,20 @@ public function testShortCircuitOnProcessComma() $mockObj->process(self::$phpcsFile, $target); } - /** * PHPUnit cross-version helper method to test the value of the class properties. * * @param mixed $expected Expected property value. * @param string $attributeName The name of the property to check. * @param object $actualObject The object on which to check the property value. + * @param string $message Optional. Custom error message. * * @return void */ public function assertAttributeValueSame($expected, $attributeName, $actualObject, $message = '') { // Will throw a warning on PHPUnit 8, but will still work. - if (method_exists($this, 'assertAttributeSame')) { + if (\method_exists($this, 'assertAttributeSame')) { parent::assertAttributeSame($expected, $attributeName, $actualObject, $message); return; } @@ -662,11 +662,11 @@ public function assertAttributeValueSame($expected, $attributeName, $actualObjec // PHPUnit 9.0+. try { $actual = $this->getObjectAttributeValue($actualObject, $attributeName); - } catch (\Exception $e) { + } catch (Exception $e) { $this->fail($e->getMessage()); } - $this->assertSame($expected, $actual); + $this->assertSame($expected, $actual, $message); } /** @@ -678,7 +678,7 @@ public function assertAttributeValueSame($expected, $attributeName, $actualObjec * * @return mixed Property value. * - * @throws Exception + * @throws \Exception */ public static function getObjectAttributeValue($object, $attributeName) { From 7f35949e328803e406a2fef584fc282aef9f8ddd Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 22 Feb 2020 12:36:11 +0100 Subject: [PATCH 09/79] CI: fix CS check not always running Travis clones into a `/home/travis/build/...` directory, so the `build` exclusion for the PHPDoc structure files-only, was now causing all files to be excluded. Making this exclusion more specific fixes it. --- phpcs.xml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index fea3a4bd..3eed24a6 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -12,7 +12,7 @@ . - */build/* + */build/docs/structure/* */vendor/* From 79a8aef4b7b81b82bb61245c4c583d97d9434884 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 13 Mar 2020 19:47:54 +0100 Subject: [PATCH 10/79] Tokens\Collections: add new `$magicConstants` property Ref: https://www.php.net/manual/en/language.constants.predefined.php --- PHPCSUtils/Tokens/Collections.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 8c41bcfe..f78698ac 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -185,6 +185,26 @@ class Collections \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET, ]; + /** + * Tokens for the PHP magic constants. + * + * @since 1.0.0 + * + * @link https://www.php.net/manual/en/language.constants.predefined.php. + * + * @var array => + */ + public static $magicConstants = [ + \T_CLASS_C => \T_CLASS_C, + \T_DIR => \T_DIR, + \T_FILE => \T_FILE, + \T_FUNC_C => \T_FUNC_C, + \T_LINE => \T_LINE, + \T_METHOD_C => \T_METHOD_C, + \T_NS_C => \T_NS_C, + \T_TRAIT_C => \T_TRAIT_C, + ]; + /** * List of tokens which can end a namespace declaration statement. * From 51ffb4be4a3a9042b06d0cd68c952759f7063700 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 10:17:10 +0100 Subject: [PATCH 11/79] Revert "PHPUnit: be strict about covers annotations" Bit too strict and too fiddly for my liking. This reverts commit cf90bbcc895e3c2482aa9f66bb94858deb6050fe. --- phpunit.xml.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index eb097aeb..a5223261 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,7 +5,6 @@ backupGlobals="true" bootstrap="./Tests/bootstrap.php" beStrictAboutTestsThatDoNotTestAnything="true" - beStrictAboutCoversAnnotation="true" colors="true" forceCoversAnnotation="true"> From 34f0dce9679399bcfa3b10f1151f3d6580ab93ee Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 07:27:07 +0100 Subject: [PATCH 12/79] TestUtils\UtilityMethodTestCase: add new $phpcsVersion property Tests will often enough need access to the PHPCS version on which the tests are being run. This adds a `$phpcsVersion` property to the `PHPCSUtils\TestUtils\UtilityMethodTestCase` class to make that version number easily and always available. **Note**: if the PHPCS version is needed within a data provider method for a test, `Helper::getVersion()` still needs to be used as the data providers are run before the `setUpBeforeClass()` type methods. --- PHPCSUtils/TestUtils/UtilityMethodTestCase.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php index 4fce2bc4..c057d89c 100644 --- a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php @@ -98,6 +98,15 @@ abstract class UtilityMethodTestCase extends TestCase { + /** + * The PHPCS version the tests are being run on. + * + * @since 1.0.0 + * + * @var string + */ + protected static $phpcsVersion = '0'; + /** * The file extension of the test case file (without leading dot). * @@ -173,6 +182,8 @@ public static function setUpTestFile() { parent::setUpBeforeClass(); + self::$phpcsVersion = Helper::getVersion(); + $caseFile = static::$caseFile; if (\is_string($caseFile) === false || $caseFile === '') { $testClass = \get_called_class(); @@ -186,7 +197,7 @@ public static function setUpTestFile() $contents = \file_get_contents($caseFile); - if (\version_compare(Helper::getVersion(), '2.99.99', '>')) { + if (\version_compare(self::$phpcsVersion, '2.99.99', '>')) { // PHPCS 3.x. $config = new \PHP_CodeSniffer\Config(); From 788a52b5609e37087bf8628dae1a5e8c3dadd2af Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 07:28:12 +0100 Subject: [PATCH 13/79] Tests: implement use of the UtilityMethodTestCase::$phpcsVersion property ... in all relevant places in the existing tests. --- .../BackCompat/BCFile/GetDeclarationNameJSTest.php | 3 +-- Tests/BackCompat/Helper/GetCommandLineDataTest.php | 14 +++++++------- Tests/Utils/Numbers/GetCompleteNumberTest.php | 12 +++++------- Tests/Utils/ObjectDeclarations/GetNameJSTest.php | 3 +-- Tests/Utils/Operators/IsUnaryPlusMinusTest.php | 3 +-- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php b/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php index 32fec5ee..5e5e82e9 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php +++ b/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php @@ -11,7 +11,6 @@ namespace PHPCSUtils\Tests\BackCompat\BCFile; use PHPCSUtils\BackCompat\BCFile; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; /** @@ -135,7 +134,7 @@ public function dataGetDeclarationName() */ public function testGetDeclarationNameES6Method() { - if (\version_compare(Helper::getVersion(), '3.0.0', '<') === true) { + if (\version_compare(static::$phpcsVersion, '3.0.0', '<') === true) { $this->markTestSkipped('Support for JS ES6 method has not been backfilled for PHPCS 2.x (yet)'); } diff --git a/Tests/BackCompat/Helper/GetCommandLineDataTest.php b/Tests/BackCompat/Helper/GetCommandLineDataTest.php index b37e1c83..99baed7f 100644 --- a/Tests/BackCompat/Helper/GetCommandLineDataTest.php +++ b/Tests/BackCompat/Helper/GetCommandLineDataTest.php @@ -34,7 +34,7 @@ public function testGetCommandLineData() { // Use the default values which are different across PHPCS versions. $expected = 'utf-8'; - if (\version_compare(Helper::getVersion(), '2.99.99', '<=') === true) { + if (\version_compare(static::$phpcsVersion, '2.99.99', '<=') === true) { // Will effectively come down to `iso-8859-1`. $expected = null; } @@ -68,7 +68,7 @@ public function testGetTabWidth() $result = Helper::getTabWidth(self::$phpcsFile); $this->assertSame(4, $result, 'Failed retrieving the default tab width'); - if (\version_compare(Helper::getVersion(), '2.99.99', '>') === true) { + if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { // PHPCS 3.x. self::$phpcsFile->config->tabWidth = 2; } else { @@ -80,7 +80,7 @@ public function testGetTabWidth() $this->assertSame(2, $result, 'Failed retrieving the custom set tab width'); // Restore defaults before moving to the next test. - if (\version_compare(Helper::getVersion(), '2.99.99', '>') === true) { + if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { self::$phpcsFile->config->restoreDefaults(); } else { self::$phpcsFile->phpcs->cli->setCommandLineValues(['--tab-width=4']); @@ -96,7 +96,7 @@ public function testGetTabWidth() */ public function testIgnoreAnnotationsV2() { - if (\version_compare(Helper::getVersion(), '2.99.99', '>') === true) { + if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { $this->markTestSkipped('Test only applicable to PHPCS 2.x'); } @@ -112,7 +112,7 @@ public function testIgnoreAnnotationsV2() */ public function testIgnoreAnnotationsV3Default() { - if (\version_compare(Helper::getVersion(), '2.99.99', '<=') === true) { + if (\version_compare(static::$phpcsVersion, '2.99.99', '<=') === true) { $this->markTestSkipped('Test only applicable to PHPCS 3.x'); } @@ -135,7 +135,7 @@ public function testIgnoreAnnotationsV3Default() */ public function testIgnoreAnnotationsV3SetViaMethod() { - if (\version_compare(Helper::getVersion(), '2.99.99', '<=') === true) { + if (\version_compare(static::$phpcsVersion, '2.99.99', '<=') === true) { $this->markTestSkipped('Test only applicable to PHPCS 3.x'); } @@ -157,7 +157,7 @@ public function testIgnoreAnnotationsV3SetViaMethod() */ public function testIgnoreAnnotationsV3SetViaProperty() { - if (\version_compare(Helper::getVersion(), '2.99.99', '<=') === true) { + if (\version_compare(static::$phpcsVersion, '2.99.99', '<=') === true) { $this->markTestSkipped('Test only applicable to PHPCS 3.x'); } diff --git a/Tests/Utils/Numbers/GetCompleteNumberTest.php b/Tests/Utils/Numbers/GetCompleteNumberTest.php index 4b69becb..89337bab 100644 --- a/Tests/Utils/Numbers/GetCompleteNumberTest.php +++ b/Tests/Utils/Numbers/GetCompleteNumberTest.php @@ -31,7 +31,7 @@ class GetCompleteNumberTest extends UtilityMethodTestCase * * @var string */ - public static $phpcsVersion = null; + public static $phpcsVersion = '0'; /** * Whether or not the tests are being run on PHP 7.4 or higher. @@ -54,7 +54,7 @@ class GetCompleteNumberTest extends UtilityMethodTestCase */ public static function setUpStaticProperties() { - if (isset(self::$phpcsVersion)) { + if (self::$phpcsVersion !== '0') { return; } @@ -83,8 +83,7 @@ public function testNotANumberException() */ public function testUnsupportedPhpcsException() { - self::setUpStaticProperties(); - if (\version_compare(self::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '!=') === true) { + if (\version_compare(static::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '!=') === true) { $this->markTestSkipped('Test specific to a limited set of PHPCS versions'); } @@ -109,10 +108,9 @@ public function testUnsupportedPhpcsException() public function testGetCompleteNumber($testMarker, $expected) { // Skip the test(s) on unsupported PHPCS versions. - self::setUpStaticProperties(); - if (\version_compare(self::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '==') === true) { + if (\version_compare(static::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '==') === true) { $this->markTestSkipped( - 'PHPCS ' . self::$phpcsVersion . ' is not supported due to buggy numeric string literal backfill.' + 'PHPCS ' . static::$phpcsVersion . ' is not supported due to buggy numeric string literal backfill.' ); } diff --git a/Tests/Utils/ObjectDeclarations/GetNameJSTest.php b/Tests/Utils/ObjectDeclarations/GetNameJSTest.php index 85d9ea9a..c9835127 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameJSTest.php +++ b/Tests/Utils/ObjectDeclarations/GetNameJSTest.php @@ -10,7 +10,6 @@ namespace PHPCSUtils\Tests\Utils\ObjectDeclarations; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tests\BackCompat\BCFile\GetDeclarationNameJSTest as BCFile_GetDeclarationNameJSTest; use PHPCSUtils\Utils\ObjectDeclarations; @@ -113,7 +112,7 @@ public function testGetDeclarationName($testMarker, $expected, $targetType = nul */ public function testGetDeclarationNameES6Method() { - if (\version_compare(Helper::getVersion(), '3.0.0', '<') === true) { + if (\version_compare(static::$phpcsVersion, '3.0.0', '<') === true) { $this->markTestSkipped('Support for JS ES6 method has not been backfilled for PHPCS 2.x (yet)'); } diff --git a/Tests/Utils/Operators/IsUnaryPlusMinusTest.php b/Tests/Utils/Operators/IsUnaryPlusMinusTest.php index 77d7bd0d..68c0c75a 100644 --- a/Tests/Utils/Operators/IsUnaryPlusMinusTest.php +++ b/Tests/Utils/Operators/IsUnaryPlusMinusTest.php @@ -10,7 +10,6 @@ namespace PHPCSUtils\Tests\Utils\Operators; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Utils\Numbers; use PHPCSUtils\Utils\Operators; @@ -72,7 +71,7 @@ public function testIsUnaryPlusMinus($testMarker, $expected, $maybeSkip = false) $this->markTestSkipped($skipMessage); } - if (\version_compare(Helper::getVersion(), Numbers::UNSUPPORTED_PHPCS_VERSION, '>=') === true) { + if (\version_compare(static::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '>=') === true) { $this->markTestSkipped($skipMessage); } } From 55369a5ef49ce61f8ac67639276c92f29654948f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 06:25:43 +0100 Subject: [PATCH 14/79] Collections: compatibility with PHPCS 4.x ** BREAKING CHANGE ** This adds three new methods to the `PHPCSUtils\Tokens\Collections` class: * `parameterTypeTokensBC()` * `propertyTypeTokensBC()` * `returnTypeTokensBC()` ... and adjusts the existing `$parameterTypeTokens`, `$propertyTypeTokens` and `$returnTypeTokens` properties to no longer contain token constants which will be removed in PHPCS 4.x. As things stands at this time, standards implementing PHPCSUtils which only support PHPCS 3.5.4 or higher, can safely use the properties. If an external standard wants to continue support for PHPCS < 3.5.4 (return types) or PHPCS < 3.3.0 (parameter and property types), the standard should use the methods instead. Includes dedicated unit tests for the new methods. Refs: * https://github.com/squizlabs/PHP_CodeSniffer/commit/cba0001d0cfdb2349b29655d42ba27f1fba315c6 --- PHPCSUtils/Tokens/Collections.php | 150 +++++++++++++++++- .../Collections/ParameterTypeTokensBCTest.php | 45 ++++++ .../Collections/PropertyTypeTokensBCTest.php | 45 ++++++ .../Collections/ReturnTypeTokensBCTest.php | 50 ++++++ 4 files changed, 285 insertions(+), 5 deletions(-) create mode 100644 Tests/Tokens/Collections/ParameterTypeTokensBCTest.php create mode 100644 Tests/Tokens/Collections/PropertyTypeTokensBCTest.php create mode 100644 Tests/Tokens/Collections/ReturnTypeTokensBCTest.php diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index f78698ac..06d11636 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -10,6 +10,8 @@ namespace PHPCSUtils\Tokens; +use PHPCSUtils\BackCompat\Helper; + /** * Collections of related tokens as often used and needed for sniffs. * @@ -276,12 +278,23 @@ class Collections /** * Token types which can be encountered in a parameter type declaration. * + * Sister-property to the `Collections::parameterTypeTokensBC()` method. + * The property supports PHPCS 3.3.0 and up. + * The method supports PHPCS 2.6.0 and up. + * + * Notable difference: + * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. + * This token constant will no longer exist in PHPCS 4.x. + * + * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.3.0. + * + * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC() Related method (cross-version). + * @since 1.0.0 * * @var array => */ public static $parameterTypeTokens = [ - \T_ARRAY_HINT => \T_ARRAY_HINT, // PHPCS < 3.3.0. \T_CALLABLE => \T_CALLABLE, \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, @@ -307,12 +320,23 @@ class Collections /** * Token types which can be encountered in a property type declaration. * + * Sister-property to the `Collections::propertyTypeTokensBC()` method. + * The property supports PHPCS 3.3.0 and up. + * The method supports PHPCS 2.6.0 and up. + * + * Notable difference: + * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. + * This token constant will no longer exist in PHPCS 4.x. + * + * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.3.0. + * + * @see \PHPCSUtils\Tokens\Collections::propertyTypeTokensBC() Related method (cross-version). + * * @since 1.0.0 * * @var array => */ public static $propertyTypeTokens = [ - \T_ARRAY_HINT => \T_ARRAY_HINT, // PHPCS < 3.3.0. \T_CALLABLE => \T_CALLABLE, \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, @@ -323,6 +347,19 @@ class Collections /** * Token types which can be encountered in a return type declaration. * + * Sister-property to the `Collections::returnTypeTokensBC()` method. + * The property supports PHPCS 3.5.4 and up. + * The method supports PHPCS 2.6.0 and up. + * + * Notable differences: + * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE tokens when used with PHPCS 2.x and 3.x. + * These token constants will no longer exist in PHPCS 4.x. + * - The method will include the `T_ARRAY` token which is needed for select arrow functions in PHPCS < 3.5.4. + * + * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.5.4. + * + * @see \PHPCSUtils\Tokens\Collections::returnTypeTokensBC() Related method (cross-version). + * * @since 1.0.0 * * @var array => @@ -333,9 +370,6 @@ class Collections \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, \T_NS_SEPARATOR => \T_NS_SEPARATOR, - \T_RETURN_TYPE => \T_RETURN_TYPE, // PHPCS 2.4.0 < 3.3.0. - \T_ARRAY_HINT => \T_ARRAY_HINT, // PHPCS < 2.8.0 / PHPCS < 3.5.3 for arrow functions. - \T_ARRAY => \T_ARRAY, // PHPCS < 3.5.4 for select arrow functions. ]; /** @@ -442,4 +476,110 @@ public static function arrowFunctionTokensBC() return $tokens; } + + /** + * Token types which can be encountered in a parameter type declaration (cross-version). + * + * Sister-method to the `$parameterTypeTokens` property. + * The property supports PHPCS 3.3.0 and up. + * The method supports PHPCS 2.6.0 and up. + * + * Notable difference: + * The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. + * This token constant will no longer exist in PHPCS 4.x. + * + * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.3.0. + * + * @see \PHPCSUtils\Tokens\Collections::$parameterTypeTokens Related property (PHPCS 3.3.0+). + * + * @since 1.0.0 + * + * @return array => + */ + public static function parameterTypeTokensBC() + { + $tokens = self::$parameterTypeTokens; + + // PHPCS < 4.0; Needed for support of PHPCS < 3.3.0. For PHPCS 3.3.0+ the constant is no longer used. + if (\defined('T_ARRAY_HINT') === true) { + $tokens[\T_ARRAY_HINT] = \T_ARRAY_HINT; + } + + return $tokens; + } + + /** + * Token types which can be encountered in a property type declaration (cross-version). + * + * Sister-method to the `$propertyTypeTokens` property. + * The property supports PHPCS 3.3.0 and up. + * The method supports PHPCS 2.6.0 and up. + * + * Notable difference: + * The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. + * This token constant will no longer exist in PHPCS 4.x. + * + * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.3.0. + * + * @see \PHPCSUtils\Tokens\Collections::$propertyTypeTokens Related property (PHPCS 3.3.0+). + * + * @since 1.0.0 + * + * @return array => + */ + public static function propertyTypeTokensBC() + { + return self::parameterTypeTokensBC(); + } + + /** + * Token types which can be encountered in a return type declaration (cross-version). + * + * Sister-property to the `Collections::returnTypeTokensBC()` method. + * The property supports PHPCS 3.5.4 and up. + * The method supports PHPCS 2.6.0 and up. + * + * Notable differences: + * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE tokens when used with PHPCS 2.x and 3.x. + * These token constants will no longer exist in PHPCS 4.x. + * - The method will include the `T_ARRAY` token which is needed for select arrow functions in PHPCS < 3.5.4. + * + * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.5.4. + * + * @see \PHPCSUtils\Tokens\Collections::$returnTypeTokens Related property (PHPCS 3.5.4+). + * + * @since 1.0.0 + * + * @return array => + */ + public static function returnTypeTokensBC() + { + $tokens = self::$returnTypeTokens; + + /* + * PHPCS < 4.0. Needed for support of PHPCS 2.4.0 < 3.3.0. + * For PHPCS 3.3.0+ the constant is no longer used. + */ + if (\defined('T_RETURN_TYPE') === true) { + $tokens[\T_RETURN_TYPE] = \T_RETURN_TYPE; + } + + /* + * PHPCS < 4.0. Needed for support of PHPCS < 2.8.0 / PHPCS < 3.5.3 for arrow functions. + * For PHPCS 3.5.3+ the constant is no longer used. + */ + if (\defined('T_ARRAY_HINT') === true) { + $tokens[\T_ARRAY_HINT] = \T_ARRAY_HINT; + } + + /* + * PHPCS < 3.5.4. Needed for support of PHPCS < 3.5.4 for select arrow functions. + * For PHPCS 3.5.4+ the constant is no longer used in return type tokenization. + */ + if (\version_compare(Helper::getVersion(), '3.5.4', '<')) { + $tokens[\T_ARRAY] = \T_ARRAY; + } + + return $tokens; + } } diff --git a/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php b/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php new file mode 100644 index 00000000..0fcb7cf1 --- /dev/null +++ b/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php @@ -0,0 +1,45 @@ +assertSame($expected, Collections::parameterTypeTokensBC()); + } +} diff --git a/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php b/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php new file mode 100644 index 00000000..b743eaad --- /dev/null +++ b/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php @@ -0,0 +1,45 @@ +assertSame($expected, Collections::propertyTypeTokensBC()); + } +} diff --git a/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php b/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php new file mode 100644 index 00000000..347ca673 --- /dev/null +++ b/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php @@ -0,0 +1,50 @@ +assertSame($expected, Collections::returnTypeTokensBC()); + } +} From 12fdc0c43ef415b564d3904a24a92104716fc1f7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 06:29:37 +0100 Subject: [PATCH 15/79] BCFile/FunctionDeclarations::getMethodProperties(): compatibility with PHPCS 4.x This implements use of the `PHPCSUtils\Tokens\Collections::returnTypeTokensBC()` method in the `BCFile::getMethodProperties()` and the `FunctionDeclarations::getProperties()` methods to allow them to be cross-version compatible with PHPCS 2.6.0 - 4.x. --- PHPCSUtils/BackCompat/BCFile.php | 3 ++- PHPCSUtils/Utils/FunctionDeclarations.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index d1cfc680..9220fc62 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -617,6 +617,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) $returnTypeToken = false; $nullableReturnType = false; $hasBody = true; + $returnTypeTokens = Collections::returnTypeTokensBC(); $parenthesisCloser = null; if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { @@ -653,7 +654,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) $nullableReturnType = true; } - if (isset(Collections::$returnTypeTokens[$tokens[$i]['code']]) === true) { + if (isset($returnTypeTokens[$tokens[$i]['code']]) === true) { if ($returnTypeToken === false) { $returnTypeToken = $i; } diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index e6e397bf..fbb0340a 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -266,6 +266,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) $returnTypeEndToken = false; $nullableReturnType = false; $hasBody = false; + $returnTypeTokens = Collections::returnTypeTokensBC(); $parenthesisCloser = null; if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { @@ -306,7 +307,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) $nullableReturnType = true; } - if (isset(Collections::$returnTypeTokens[$tokens[$i]['code']]) === true) { + if (isset($returnTypeTokens[$tokens[$i]['code']]) === true) { if ($returnTypeToken === false) { $returnTypeToken = $i; } From 73299d6e133bf6f1ad665204ea8e1d271d3b1609 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 06:31:24 +0100 Subject: [PATCH 16/79] BCFile/Variables::getMemberProperties(): compatibility with PHPCS 4.x This implements use of the `PHPCSUtils\Tokens\Collections::propertyTypeTokensBC()` method in the `BCFile::getMemberProperties()` and the `Variables::getMemberProperties()` methods to allow them to be cross-version compatible with PHPCS 2.6.0 - 4.x. --- PHPCSUtils/BackCompat/BCFile.php | 11 ++++++----- PHPCSUtils/Utils/Variables.php | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 9220fc62..8ec9c3b7 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -834,10 +834,11 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) } } - $type = ''; - $typeToken = false; - $typeEndToken = false; - $nullableType = false; + $type = ''; + $typeToken = false; + $typeEndToken = false; + $nullableType = false; + $propertyTypeTokens = Collections::propertyTypeTokensBC(); if ($i < $stackPtr) { // We've found a type. @@ -854,7 +855,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) $nullableType = true; } - if (isset(Collections::$propertyTypeTokens[$tokens[$i]['code']]) === true) { + if (isset($propertyTypeTokens[$tokens[$i]['code']]) === true) { $typeEndToken = $i; if ($typeToken === false) { $typeToken = $i; diff --git a/PHPCSUtils/Utils/Variables.php b/PHPCSUtils/Utils/Variables.php index fee9b535..c420943f 100644 --- a/PHPCSUtils/Utils/Variables.php +++ b/PHPCSUtils/Utils/Variables.php @@ -163,10 +163,11 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) } } - $type = ''; - $typeToken = false; - $typeEndToken = false; - $nullableType = false; + $type = ''; + $typeToken = false; + $typeEndToken = false; + $nullableType = false; + $propertyTypeTokens = Collections::propertyTypeTokensBC(); if ($i < $stackPtr) { // We've found a type. @@ -183,7 +184,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) $nullableType = true; } - if (isset(Collections::$propertyTypeTokens[$tokens[$i]['code']]) === true) { + if (isset($propertyTypeTokens[$tokens[$i]['code']]) === true) { $typeEndToken = $i; if ($typeToken === false) { $typeToken = $i; From 1737d224cdb0d5aa63c65c1fc5da7dd1b7eb7224 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 06:32:29 +0100 Subject: [PATCH 17/79] FunctionDeclarations::getArrowFunctionOpenClose(): compatibility with PHPCS 4.x This implements use of the `PHPCSUtils\Tokens\Collections::returnTypeTokensBC()` method in the `FunctionDeclarations::getArrowFunctionOpenClose()` method to allow it to be cross-version compatible with PHPCS 2.6.0 - 4.x. --- PHPCSUtils/Utils/FunctionDeclarations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index fbb0340a..edf222e1 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -713,7 +713,7 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) $returnValue['parenthesis_closer'] = $tokens[$nextNonEmpty]['parenthesis_closer']; $ignore = Tokens::$emptyTokens; - $ignore += Collections::$returnTypeTokens; + $ignore += Collections::returnTypeTokensBC(); $ignore[\T_COLON] = \T_COLON; $ignore[\T_INLINE_ELSE] = \T_INLINE_ELSE; // Return type colon on PHPCS < 2.9.1. $ignore[\T_INLINE_THEN] = \T_INLINE_THEN; // Nullable type indicator on PHPCS < 2.9.1. From 02411290cf5bd806111d73afe4e49999f87b120e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 09:22:24 +0100 Subject: [PATCH 18/79] BCFile/ObjectDeclarations::getDeclarationName(): compatibility with PHPCS 4.x PHPCS removes support for the JS and CSS tokenizers, which includes removing the `File::$tokenizerType` property. This commit makes it so the `BCFile::getDeclarationName()` and the `ObjectDeclarations::getDeclarationName()` methods won't throw an error for the property not existing. And just to be clear: while PHPCSUtils in combination with PHPCS 2.x and 3.x _may_ incidentally support JS/CSS, in combination with PHPCS 4.x, JS/CSS will explicitly not be supported. Ref: https://github.com/squizlabs/PHP_CodeSniffer/commit/ea52e7b48165edbcb96b10a0a5de04567e4d73f8 --- PHPCSUtils/BackCompat/BCFile.php | 3 ++- PHPCSUtils/Utils/ObjectDeclarations.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index d1cfc680..adb301c3 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -136,7 +136,8 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) /* * BC: Work-around JS ES6 classes not being tokenized as T_CLASS in PHPCS < 3.0.0. */ - if ($phpcsFile->tokenizerType === 'JS' + if (isset($phpcsFile->tokenizerType) + && $phpcsFile->tokenizerType === 'JS' && $tokenCode === T_STRING && $tokens[$stackPtr]['content'] === 'class' ) { diff --git a/PHPCSUtils/Utils/ObjectDeclarations.php b/PHPCSUtils/Utils/ObjectDeclarations.php index cc61128d..a154e502 100644 --- a/PHPCSUtils/Utils/ObjectDeclarations.php +++ b/PHPCSUtils/Utils/ObjectDeclarations.php @@ -78,7 +78,8 @@ public static function getName(File $phpcsFile, $stackPtr) /* * BC: Work-around JS ES6 classes not being tokenized as T_CLASS in PHPCS < 3.0.0. */ - if ($phpcsFile->tokenizerType === 'JS' + if (isset($phpcsFile->tokenizerType) + && $phpcsFile->tokenizerType === 'JS' && $tokenCode === \T_STRING && $tokens[$stackPtr]['content'] === 'class' ) { From 68118d01f8119d46ad58cc87a7c2c8c230fcab62 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 09:33:05 +0100 Subject: [PATCH 19/79] UtilityMethodTestCase: auto-skip JS/CSS tests when using PHPCS 4.x This implements automatic test skipping for JS/CSS tests on PHPCS 4.x, on which support for JS/CSS has been dropped. Ref: https://github.com/squizlabs/PHP_CodeSniffer/commit/ea52e7b48165edbcb96b10a0a5de04567e4d73f8 --- .../TestUtils/UtilityMethodTestCase.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php index c057d89c..42b44b57 100644 --- a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php @@ -258,6 +258,28 @@ public static function setUpTestFile() } } + /** + * Skip JS and CSS related tests on PHPCS 4.x. + * + * @since 1.0.0 + * + * @before + * + * @return void + */ + public function skipJSCSSTestsOnPHPCS4() + { + if (static::$fileExtension !== 'js' && static::$fileExtension !== 'css') { + return; + } + + if (\version_compare(self::$phpcsVersion, '3.99.99', '<=')) { + return; + } + + $this->markTestSkipped('JS and CSS support has been removed in PHPCS 4.'); + } + /** * Clean up after finished test. * From 101a19a6b1fb143a0497320baf802be1fb07eadd Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 11:49:13 +0100 Subject: [PATCH 20/79] Composer: allow installation with PHPCS 4.x for testing purposes Until PHPCS 4.x has been released, PHPCSUtils does not formally support it, though an effort will be made to keep up with the changes and anticipate potential compatibility issues. For testing purposes, installation of PHPCSUtils with PHPCS 4.x-dev should already be supported though. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a1a25baf..978c3960 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "require" : { "php" : ">=5.4", - "squizlabs/php_codesniffer" : "^2.6.0 || ^3.1.0", + "squizlabs/php_codesniffer" : "^2.6.0 || ^3.1.0 || 4.0.x-dev@dev", "dealerdirect/phpcodesniffer-composer-installer" : "^0.3 || ^0.4.1 || ^0.5 || ^0.6.2" }, "require-dev" : { From a9ee40aeecee570ffa2c16ba98ec9b94d9423811 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 05:27:42 +0100 Subject: [PATCH 21/79] Travis: add a test run against PHPCS 4.x-dev Start testing against PHPCS 4.x-dev, for which development has started, to get early warning about cross-version compatibility issues which need fixing. The build against `4.x-dev` has been added to `allow_failures for now. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 20b8b7a8..ccb79674 100644 --- a/.travis.yml +++ b/.travis.yml @@ -109,6 +109,9 @@ jobs: - php: 7.2 env: PHPCS_VERSION="3.2.0" + - php: 7.4 + env: PHPCS_VERSION="4.0.x-dev@dev" + - php: "nightly" env: PHPCS_VERSION="n/a" LINT=1 @@ -132,6 +135,7 @@ jobs: allow_failures: # Allow failures for unstable builds. - php: "nightly" + - env: PHPCS_VERSION="4.0.x-dev@dev" before_install: From 0c243bf124e3736158f2034f6d4f0f2edcc3923f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 12:53:05 +0100 Subject: [PATCH 22/79] Tests: Helper::getVersion(): update to allow for PHPCS 4.x-dev --- Tests/BackCompat/Helper/GetVersionTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/BackCompat/Helper/GetVersionTest.php b/Tests/BackCompat/Helper/GetVersionTest.php index cc20e3b7..c00df963 100644 --- a/Tests/BackCompat/Helper/GetVersionTest.php +++ b/Tests/BackCompat/Helper/GetVersionTest.php @@ -32,7 +32,7 @@ class GetVersionTest extends TestCase * * @var string */ - const DEVMASTER = '3.5.3'; + const DEVMASTER = '3.5.4'; /** * Test the method. @@ -54,6 +54,8 @@ public function testGetVersion() if ($expected === 'dev-master') { $this->assertTrue(\version_compare(self::DEVMASTER, $result, '<=')); + } elseif ($expected === '4.0.x-dev@dev') { + $this->assertTrue(\version_compare('4.0.0', $result, '==')); } else { $this->assertSame($expected, $result); } From 28673373ddc040ef9436e409006dd216190c486b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 21 Mar 2020 08:46:56 +0100 Subject: [PATCH 23/79] Tokens\Collections: add $OONameTokens property ... containing token which can be part of a partially/fully qualified name when used in inline code. --- PHPCSUtils/Tokens/Collections.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 06d11636..0fe845a4 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -260,6 +260,21 @@ class Collections \T_INTERFACE => \T_INTERFACE, ]; + /** + * Tokens types which can be encountered in the fully/partially qualified name of an OO structure. + * + * Example: `echo namespace\Sub\ClassName::method();` + * + * @since 1.0.0 + * + * @var array => + */ + public static $OONameTokens = [ + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_STRING => \T_STRING, + \T_NAMESPACE => \T_NAMESPACE, + ]; + /** * OO scopes in which properties can be declared. * From 6e8b0475e7963f73bac9547440a5c086e7dff5a4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 21 Mar 2020 09:20:34 +0100 Subject: [PATCH 24/79] Operators::isReference(): use the new `Collections::$OONameTokens` property --- PHPCSUtils/Utils/Operators.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/PHPCSUtils/Utils/Operators.php b/PHPCSUtils/Utils/Operators.php index 272b4c8d..557a9239 100644 --- a/PHPCSUtils/Utils/Operators.php +++ b/PHPCSUtils/Utils/Operators.php @@ -13,6 +13,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCTokens; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; use PHPCSUtils\Utils\Parentheses; @@ -147,12 +148,10 @@ public static function isReference(File $phpcsFile, $stackPtr) return true; } else { $skip = Tokens::$emptyTokens; - $skip[] = \T_NS_SEPARATOR; + $skip += Collections::$OONameTokens; $skip[] = \T_SELF; $skip[] = \T_PARENT; $skip[] = \T_STATIC; - $skip[] = \T_STRING; - $skip[] = \T_NAMESPACE; $skip[] = \T_DOUBLE_COLON; $nextSignificantAfter = $phpcsFile->findNext( From 744393d5542b49510edb557b8db8e5b1a16ccf0a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 21 Mar 2020 08:52:14 +0100 Subject: [PATCH 25/79] Utils\ControlStructures: new `getCaughtExceptions()` method This adds a new utility method to retrieve information on the Exceptions being caught in a `catch` expression. Includes unit tests. --- PHPCSUtils/Utils/ControlStructures.php | 82 +++++++ .../GetCaughtExceptionsTest.inc | 32 +++ .../GetCaughtExceptionsTest.php | 202 ++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 Tests/Utils/ControlStructures/GetCaughtExceptionsTest.inc create mode 100644 Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php diff --git a/PHPCSUtils/Utils/ControlStructures.php b/PHPCSUtils/Utils/ControlStructures.php index df36f5e3..892987db 100644 --- a/PHPCSUtils/Utils/ControlStructures.php +++ b/PHPCSUtils/Utils/ControlStructures.php @@ -10,6 +10,7 @@ namespace PHPCSUtils\Utils; +use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Tokens\Collections; @@ -335,4 +336,85 @@ public static function getDeclareScopeOpenClose(File $phpcsFile, $stackPtr) return false; } + + /** + * Retrieve the exception(s) being caught in a CATCH condition. + * + * The returned array will contain the following information for each caught exception: + * + * + * 0 => array( + * 'type' => string, // The type declaration for the exception being caught. + * 'type_token' => integer, // The stack pointer to the start of the type declaration. + * 'type_end_token' => integer, // The stack pointer to the end of the type declaration. + * ) + * + * + * @since 1.0.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the token we are checking. + * + * @return array + * + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified $stackPtr is not of + * type T_CATCH or doesn't exist or in case + * of a parse error. + */ + public static function getCaughtExceptions(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]) === false + || $tokens[$stackPtr]['code'] !== \T_CATCH + ) { + throw new RuntimeException('$stackPtr must be of type T_CATCH'); + } + + if (isset($tokens[$stackPtr]['parenthesis_opener'], $tokens[$stackPtr]['parenthesis_closer']) === false) { + throw new RuntimeException('Parentheses opener/closer of the T_CATCH could not be determined'); + } + + $opener = $tokens[$stackPtr]['parenthesis_opener']; + $closer = $tokens[$stackPtr]['parenthesis_closer']; + $exceptions = []; + + $foundName = ''; + $firstToken = null; + $lastToken = null; + + for ($i = ($opener + 1); $i < $closer; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']])) { + continue; + } + + if (isset(Collections::$OONameTokens[$tokens[$i]['code']]) === false) { + // Add the current exception to the result array. + $exceptions[] = [ + 'type' => $foundName, + 'type_token' => $firstToken, + 'type_end_token' => $lastToken, + ]; + + if ($tokens[$i]['code'] === \T_BITWISE_OR) { + // Multi-catch. Reset and continue. + $foundName = ''; + $firstToken = null; + $lastToken = null; + continue; + } + + break; + } + + if (isset($firstToken) === false) { + $firstToken = $i; + } + + $foundName .= $tokens[$i]['content']; + $lastToken = $i; + } + + return $exceptions; + } } diff --git a/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.inc b/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.inc new file mode 100644 index 00000000..b1b45855 --- /dev/null +++ b/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.inc @@ -0,0 +1,32 @@ +expectPhpcsException('$stackPtr must be of type T_CATCH'); + ControlStructures::getCaughtExceptions(self::$phpcsFile, 10000); + } + + /** + * Test receiving an expected exception when a non-CATCH token is passed. + * + * @return void + */ + public function testNotCatch() + { + $this->expectPhpcsException('$stackPtr must be of type T_CATCH'); + + $target = $this->getTargetToken('/* testNotCatch */', \T_TRY); + ControlStructures::getCaughtExceptions(self::$phpcsFile, $target); + } + + /** + * Test receiving an expected exception when a parse error is encountered. + * + * @return void + */ + public function testParseError() + { + $this->expectPhpcsException('Parentheses opener/closer of the T_CATCH could not be determined'); + + $target = $this->getTargetToken('/* testLiveCoding */', \T_CATCH); + ControlStructures::getCaughtExceptions(self::$phpcsFile, $target); + } + + /** + * Test retrieving the exceptions caught in a `catch` condition. + * + * @dataProvider dataGetCaughtExceptions + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected The expected return value. + * + * @return void + */ + public function testGetCaughtExceptions($testMarker, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, \T_CATCH); + + // Translate offsets to absolute token positions. + foreach ($expected as $key => $value) { + $expected[$key]['type_token'] += $stackPtr; + $expected[$key]['type_end_token'] += $stackPtr; + } + + $result = ControlStructures::getCaughtExceptions(self::$phpcsFile, $stackPtr); + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetCaughtExceptions() For the array format. + * + * @return array + */ + public function dataGetCaughtExceptions() + { + return [ + 'single-name-only' => [ + 'target' => '/* testSingleCatchNameOnly */', + 'expected' => [ + [ + 'type' => 'RuntimeException', + 'type_token' => 3, + 'type_end_token' => 3, + ], + ], + ], + 'single-name-leading-backslash' => [ + 'target' => '/* testSingleCatchNameLeadingBackslash */', + 'expected' => [ + [ + 'type' => '\RuntimeException', + 'type_token' => 3, + 'type_end_token' => 4, + ], + ], + ], + 'single-partially-qualified' => [ + 'target' => '/* testSingleCatchPartiallyQualified */', + 'expected' => [ + [ + 'type' => 'MyNS\RuntimeException', + 'type_token' => 4, + 'type_end_token' => 6, + ], + ], + ], + 'single-fully-qualified' => [ + 'target' => '/* testSingleCatchFullyQualified */', + 'expected' => [ + [ + 'type' => '\MyNS\RuntimeException', + 'type_token' => 4, + 'type_end_token' => 7, + ], + ], + ], + 'single-name-with-comments-whitespace' => [ + 'target' => '/* testSingleCatchPartiallyQualifiedWithCommentAndWhitespace */', + 'expected' => [ + [ + 'type' => 'My\NS\Sub\RuntimeException', + 'type_token' => 4, + 'type_end_token' => 15, + ], + ], + ], + 'single-namespace-operator' => [ + 'target' => '/* testSingleCatchNamespaceOperator */', + 'expected' => [ + [ + 'type' => 'namespace\RuntimeException', + 'type_token' => 4, + 'type_end_token' => 6, + ], + ], + ], + 'multi-unqualified-names' => [ + 'target' => '/* testMultiCatchSingleNames */', + 'expected' => [ + [ + 'type' => 'RuntimeException', + 'type_token' => 3, + 'type_end_token' => 3, + ], + [ + 'type' => 'ParseErrorException', + 'type_token' => 7, + 'type_end_token' => 7, + ], + [ + 'type' => 'AnotherException', + 'type_token' => 11, + 'type_end_token' => 11, + ], + ], + ], + + 'multi-qualified-names' => [ + 'target' => '/* testMultiCatchCompoundNames */', + 'expected' => [ + [ + 'type' => '\NS\RuntimeException', + 'type_token' => 3, + 'type_end_token' => 6, + ], + [ + 'type' => 'My\ParseErrorException', + 'type_token' => 10, + 'type_end_token' => 12, + ], + [ + 'type' => 'namespace\AnotherException', + 'type_token' => 16, + 'type_end_token' => 20, + ], + ], + ], + ]; + } +} From 1b9a7fa7609bbe0ff05aac67349ba96e4c676e2d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 21 Mar 2020 20:50:27 +0100 Subject: [PATCH 26/79] Tokens\Collections: add $OOHierarchyKeywords property ... containing tokens representing the keywords to access properties or methods from inside a class definition. Refs: * https://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php * https://www.php.net/manual/en/language.oop5.late-static-bindings.php --- PHPCSUtils/Tokens/Collections.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 0fe845a4..a192e0e3 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -260,6 +260,21 @@ class Collections \T_INTERFACE => \T_INTERFACE, ]; + /** + * Tokens types used for "forwarding" calls within OO structures. + * + * @link https://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php + * + * @since 1.0.0 + * + * @var array => + */ + public static $OOHierarchyKeywords = [ + \T_PARENT => \T_PARENT, + \T_SELF => \T_SELF, + \T_STATIC => \T_STATIC, + ]; + /** * Tokens types which can be encountered in the fully/partially qualified name of an OO structure. * From a0a119fe4f049823390a43b7aa0ce81e3dced24c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 21 Mar 2020 20:53:02 +0100 Subject: [PATCH 27/79] Operators::isReference(): use the new `Collections::$OOHierarchyKeywords` property --- PHPCSUtils/Utils/Operators.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/PHPCSUtils/Utils/Operators.php b/PHPCSUtils/Utils/Operators.php index 557a9239..016af66f 100644 --- a/PHPCSUtils/Utils/Operators.php +++ b/PHPCSUtils/Utils/Operators.php @@ -149,9 +149,7 @@ public static function isReference(File $phpcsFile, $stackPtr) } else { $skip = Tokens::$emptyTokens; $skip += Collections::$OONameTokens; - $skip[] = \T_SELF; - $skip[] = \T_PARENT; - $skip[] = \T_STATIC; + $skip += Collections::$OOHierarchyKeywords; $skip[] = \T_DOUBLE_COLON; $nextSignificantAfter = $phpcsFile->findNext( From 72f0dcab4eaa4234625aa262195c4be941dd9143 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 24 Mar 2020 01:40:44 +0100 Subject: [PATCH 28/79] Tests: abstract the assertAttributeSame backfill out to a trait ... to allow use of this functionality in other tests. At some point in the future this may be (should probably be) abstracted out altogether to a separate package or to the `TestUtils`, but I need to think about that a little more. For now, setting it up as a `trait` solves the more immediate pressing issue. --- .../AbstractArrayDeclarationSniffTest.php | 74 +------------- Tests/AssertAttributeSame.php | 96 +++++++++++++++++++ 2 files changed, 99 insertions(+), 71 deletions(-) create mode 100644 Tests/AssertAttributeSame.php diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php index c8bb8b3a..1ea377ca 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php @@ -10,10 +10,8 @@ namespace PHPCSUtils\Tests\AbstractSniffs\AbstractArrayDeclaration; -use Exception; +use PHPCSUtils\Tests\AssertAttributeSame; use PHPCSUtils\TestUtils\UtilityMethodTestCase; -use ReflectionException; -use ReflectionObject; /** * Tests for the \PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff class. @@ -26,6 +24,8 @@ */ class AbstractArrayDeclarationSniffTest extends UtilityMethodTestCase { + // Backfill for the assertAttributeSame() method on PHPUnit 9.x. + use AssertAttributeSame; /** * List of methods in the abstract which should be mocked. @@ -640,72 +640,4 @@ public function testShortCircuitOnProcessComma() $mockObj->process(self::$phpcsFile, $target); } - - /** - * PHPUnit cross-version helper method to test the value of the class properties. - * - * @param mixed $expected Expected property value. - * @param string $attributeName The name of the property to check. - * @param object $actualObject The object on which to check the property value. - * @param string $message Optional. Custom error message. - * - * @return void - */ - public function assertAttributeValueSame($expected, $attributeName, $actualObject, $message = '') - { - // Will throw a warning on PHPUnit 8, but will still work. - if (\method_exists($this, 'assertAttributeSame')) { - parent::assertAttributeSame($expected, $attributeName, $actualObject, $message); - return; - } - - // PHPUnit 9.0+. - try { - $actual = $this->getObjectAttributeValue($actualObject, $attributeName); - } catch (Exception $e) { - $this->fail($e->getMessage()); - } - - $this->assertSame($expected, $actual, $message); - } - - /** - * Retrieve the value of an object's attribute. - * This also works for attributes that are declared protected or private. - * - * @param object|string $object The object or class on which to check the property value. - * @param string $attributeName The name of the property to check. - * - * @return mixed Property value. - * - * @throws \Exception - */ - public static function getObjectAttributeValue($object, $attributeName) - { - $reflector = new ReflectionObject($object); - - do { - try { - $attribute = $reflector->getProperty($attributeName); - - if (!$attribute || $attribute->isPublic()) { - return $object->$attributeName; - } - - $attribute->setAccessible(true); - $value = $attribute->getValue($object); - $attribute->setAccessible(false); - - return $value; - } catch (ReflectionException $e) { - } - } while ($reflector = $reflector->getParentClass()); - - throw new Exception( - \sprintf( - 'Attribute "%s" not found in object.', - $attributeName - ) - ); - } } diff --git a/Tests/AssertAttributeSame.php b/Tests/AssertAttributeSame.php new file mode 100644 index 00000000..6bc8c914 --- /dev/null +++ b/Tests/AssertAttributeSame.php @@ -0,0 +1,96 @@ +assertAttributeSame($expected, $attributeName, $actualObject, $message); + return; + } + + // PHPUnit 9.0+. + try { + $actual = $this->getObjectAttributeValue($actualObject, $attributeName); + } catch (Exception $e) { + $this->fail($e->getMessage()); + } + + $this->assertSame($expected, $actual, $message); + } + + /** + * Retrieve the value of an object's attribute. + * This also works for attributes that are declared protected or private. + * + * @param object|string $object The object or class on which to check the property value. + * @param string $attributeName The name of the property to check. + * + * @return mixed Property value. + * + * @throws \Exception + */ + public static function getObjectAttributeValue($object, $attributeName) + { + $reflector = new ReflectionObject($object); + + do { + try { + $attribute = $reflector->getProperty($attributeName); + + if (!$attribute || $attribute->isPublic()) { + return $object->$attributeName; + } + + $attribute->setAccessible(true); + $value = $attribute->getValue($object); + $attribute->setAccessible(false); + + return $value; + } catch (ReflectionException $e) { + } + } while ($reflector = $reflector->getParentClass()); + + throw new Exception( + \sprintf( + 'Attribute "%s" not found in object.', + $attributeName + ) + ); + } +} From 491adbc5423ba8dd4005a9c8058166edb0aaab1d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 24 Mar 2020 19:44:26 +0100 Subject: [PATCH 29/79] Utils\UseStatements: add new `splitAndMergeImportUseStatement()` method ... which uses the `UseStatements::splitImportUseStatement()` method to retrieve the information on the current `use` import statement and merge the result with an array of previously seen import use statements. Includes dedicated unit tests. --- PHPCSUtils/Utils/UseStatements.php | 52 +++++++ .../SplitAndMergeImportUseStatementTest.inc | 24 ++++ .../SplitAndMergeImportUseStatementTest.php | 129 ++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.inc create mode 100644 Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.php diff --git a/PHPCSUtils/Utils/UseStatements.php b/PHPCSUtils/Utils/UseStatements.php index 9ebea8d2..5a834acb 100644 --- a/PHPCSUtils/Utils/UseStatements.php +++ b/PHPCSUtils/Utils/UseStatements.php @@ -344,4 +344,56 @@ public static function splitImportUseStatement(File $phpcsFile, $stackPtr) return $statements; } + + /** + * Split an import use statement into individual imports and merge it with an array of previously + * seen import use statements. + * + * Beware: this method should only be used to combine the import use statements found in *one* file. + * Do NOT combine the statements of multiple files as the result will be inaccurate and unreliable. + * + * In most cases when tempted to use this method, the AbstractFileContextSniff should be used instead. + * + * @see \PHPCSUtils\AbstractSniffs\AbstractFileContextSniff + * @see \PHPCSUtils\Utils\UseStatements::splitImportUseStatement() + * + * @since 1.0.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. + * @param int $stackPtr The position in the stack of the T_USE token. + * @param array $previousUseStatements The import `use` statements collected so far. + * This should be either the output of a previous + * call to this method or the output of an earlier + * call to the UseStatements::splitImportUseStatement() + * method. + * + * @return array A multi-level array containing information about the current `use` statement combined with + * the previously collected `use` statement information. + */ + public static function splitAndMergeImportUseStatement(File $phpcsFile, $stackPtr, $previousUseStatements) + { + try { + $useStatements = self::splitImportUseStatement($phpcsFile, $stackPtr); + + if (isset($previousUseStatements['name']) === false) { + $previousUseStatements['name'] = $useStatements['name']; + } else { + $previousUseStatements['name'] += $useStatements['name']; + } + if (isset($previousUseStatements['function']) === false) { + $previousUseStatements['function'] = $useStatements['function']; + } else { + $previousUseStatements['function'] += $useStatements['function']; + } + if (isset($previousUseStatements['const']) === false) { + $previousUseStatements['const'] = $useStatements['const']; + } else { + $previousUseStatements['const'] += $useStatements['const']; + } + } catch (RuntimeException $e) { + // Not an import use statement. + } + + return $previousUseStatements; + } } diff --git a/Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.inc b/Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.inc new file mode 100644 index 00000000..d9bc5bb1 --- /dev/null +++ b/Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.inc @@ -0,0 +1,24 @@ +getTargetToken($testMarker, \T_USE); + $result = UseStatements::splitAndMergeImportUseStatement(self::$phpcsFile, $stackPtr, $previousUse); + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testSplitAndMergeImportUseStatement() For the array format. + * + * @return array + */ + public function dataSplitAndMergeImportUseStatement() + { + $data = [ + 'name-plain' => [ + '/* testUseNamePlainAliased */', + [ + 'name' => ['ClassAlias' => 'MyNamespace\YourClass'], + 'function' => [], + 'const' => [], + ], + ], + 'function-plain' => [ + '/* testUseFunctionPlain */', + [ + 'name' => ['ClassAlias' => 'MyNamespace\YourClass'], + 'function' => ['myFunction' => 'MyNamespace\myFunction'], + 'const' => [], + ], + ], + 'const-plain' => [ + '/* testUseConstPlain */', + [ + 'name' => ['ClassAlias' => 'MyNamespace\YourClass'], + 'function' => ['myFunction' => 'MyNamespace\myFunction'], + 'const' => ['MY_CONST' => 'MyNamespace\MY_CONST'], + ], + ], + 'group-mixed' => [ + '/* testGroupUseMixed */', + [ + 'name' => [ + 'ClassAlias' => 'MyNamespace\YourClass', + 'ClassName' => 'Some\NS\ClassName', + 'AnotherLevel' => 'Some\NS\AnotherLevel', + ], + 'function' => [ + 'myFunction' => 'MyNamespace\myFunction', + 'functionName' => 'Some\NS\SubLevel\functionName', + 'AnotherName' => 'Some\NS\SubLevel\AnotherName', + ], + 'const' => [ + 'MY_CONST' => 'MyNamespace\MY_CONST', + 'SOME_CONSTANT' => 'Some\NS\Constants\CONSTANT_NAME', + ], + ], + ], + 'trait-use' => [ + '/* testTraitUse */', + // Same as previous. + [ + 'name' => [ + 'ClassAlias' => 'MyNamespace\YourClass', + 'ClassName' => 'Some\NS\ClassName', + 'AnotherLevel' => 'Some\NS\AnotherLevel', + ], + 'function' => [ + 'myFunction' => 'MyNamespace\myFunction', + 'functionName' => 'Some\NS\SubLevel\functionName', + 'AnotherName' => 'Some\NS\SubLevel\AnotherName', + ], + 'const' => [ + 'MY_CONST' => 'MyNamespace\MY_CONST', + 'SOME_CONSTANT' => 'Some\NS\Constants\CONSTANT_NAME', + ], + ], + ], + ]; + + $previousUse = []; + foreach ($data as $key => $value) { + $data[$key][] = $previousUse; + $previousUse = $value[1]; + } + + return $data; + } +} From f717efc84aeb8f305a046297feac405ed9bc93f8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 25 Mar 2020 18:49:53 +0100 Subject: [PATCH 30/79] BackCompat\Helper: add `getEncoding()`helper method ... to retrieve the file encoding a project supposedly uses. No check is done to see if the `encoding` set is actually correct for the files presented to PHPCS. In PHPCS, the `encoding` can be set via `--config-set` or `--encoding` from the command-line or via a custom ruleset like ``. The default encoding encoding used by PHPCS changed between PHPCS 2.x (`iso-8859-1`) and 3.x `utf-8`. Using the `utf-8` file encoding is strongly advised for all PHP projects. Includes minimal unit tests. --- PHPCSUtils/BackCompat/Helper.php | 42 ++++++++++++++ .../Helper/GetCommandLineDataTest.php | 58 +++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/PHPCSUtils/BackCompat/Helper.php b/PHPCSUtils/BackCompat/Helper.php index cdc6edf5..7a122105 100644 --- a/PHPCSUtils/BackCompat/Helper.php +++ b/PHPCSUtils/BackCompat/Helper.php @@ -151,6 +151,48 @@ public static function getTabWidth(File $phpcsFile) return self::DEFAULT_TABWIDTH; } + /** + * Get the applicable (file) encoding as passed to PHP_CodeSniffer from the + * command-line or the ruleset. + * + * @since 1.0.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile Optional. The current file being processed. + * + * @return string Encoding. Defaults to the PHPCS native default, which is 'utf-8' + * for PHPCS 3.x and was 'iso-8859-1' for PHPCS 2.x. + */ + public static function getEncoding(File $phpcsFile = null) + { + static $default; + + if (isset($default) === false) { + $default = 'utf-8'; + if (version_compare(self::getVersion(), '2.99.99', '<=') === true) { + // In PHPCS 2.x, the default encoding is `iso-8859-1`. + $default = 'iso-8859-1'; + } + } + + if ($phpcsFile instanceof File) { + // Most reliable. + $encoding = self::getCommandLineData($phpcsFile, 'encoding'); + if ($encoding === null) { + $encoding = $default; + } + + return $encoding; + } + + // Less reliable. + $encoding = self::getConfigData('encoding'); + if ($encoding === null) { + $encoding = $default; + } + + return $encoding; + } + /** * Check whether the `--ignore-annotations` option has been used. * diff --git a/Tests/BackCompat/Helper/GetCommandLineDataTest.php b/Tests/BackCompat/Helper/GetCommandLineDataTest.php index 99baed7f..7ce9c868 100644 --- a/Tests/BackCompat/Helper/GetCommandLineDataTest.php +++ b/Tests/BackCompat/Helper/GetCommandLineDataTest.php @@ -87,6 +87,64 @@ public function testGetTabWidth() } } + /** + * Test the getEncoding() method. + * + * @covers \PHPCSUtils\BackCompat\Helper::getEncoding + * + * @return void + */ + public function testGetEncoding() + { + $result = Helper::getEncoding(self::$phpcsFile); + $expected = \version_compare(static::$phpcsVersion, '2.99.99', '>') ? 'utf-8' : 'iso-8859-1'; + $this->assertSame($expected, $result, 'Failed retrieving the default encoding'); + + if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { + // PHPCS 3.x. + self::$phpcsFile->config->encoding = 'utf-16'; + } else { + // PHPCS 2.x. + self::$phpcsFile->phpcs->cli->setCommandLineValues(['--encoding=utf-16']); + } + + $result = Helper::getEncoding(self::$phpcsFile); + $this->assertSame('utf-16', $result, 'Failed retrieving the custom set encoding'); + + // Restore defaults before moving to the next test. + if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { + self::$phpcsFile->config->restoreDefaults(); + } else { + self::$phpcsFile->phpcs->cli->setCommandLineValues(['--encoding=iso-8859-1']); + } + } + + /** + * Test the getEncoding() method when not passing the PHPCS file parameter. + * + * @covers \PHPCSUtils\BackCompat\Helper::getEncoding + * + * @return void + */ + public function testGetEncodingWithoutPHPCSFile() + { + $result = Helper::getEncoding(); + $expected = \version_compare(static::$phpcsVersion, '2.99.99', '>') ? 'utf-8' : 'iso-8859-1'; + $this->assertSame($expected, $result, 'Failed retrieving the default encoding'); + + Helper::setConfigData('encoding', 'utf-16', true); + + $result = Helper::getEncoding(); + $this->assertSame('utf-16', $result, 'Failed retrieving the custom set encoding'); + + // Restore defaults before moving to the next test. + if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { + Helper::setConfigData('encoding', 'utf-8', true); + } else { + Helper::setConfigData('encoding', 'iso-8859-1', true); + } + } + /** * Test the ignoreAnnotations() method. * From 7bea6a17fe3c8d9fcf337549f798ff0c0c14d748 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 25 Mar 2020 19:47:34 +0100 Subject: [PATCH 31/79] Orthography::isLastCharPunctuation(): implement use of the ` Helper::getEncoding()` method --- PHPCSUtils/Utils/Orthography.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCSUtils/Utils/Orthography.php b/PHPCSUtils/Utils/Orthography.php index 5e204e5e..f79fbe56 100644 --- a/PHPCSUtils/Utils/Orthography.php +++ b/PHPCSUtils/Utils/Orthography.php @@ -102,7 +102,7 @@ public static function isLastCharPunctuation($string, $allowedChars = self::TERM static $encoding; if (isset($encoding) === false) { - $encoding = Helper::getConfigData('encoding'); + $encoding = Helper::getEncoding(); } $string = \rtrim($string); From 2156b5960fe0405aade41336d8854ee0c9119f95 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 26 Mar 2020 02:39:38 +0100 Subject: [PATCH 32/79] :sparkles: New `NamingConventions` class .. for working with identifier names (namespace names, class/trait/interface names, function names, variable and constant names). Initially this class comes with two new utility methods, but the intention is to add a range of additional utilities for common naming conventions (camelCase, snake_case etc) and conversions between those conventions in the near future. For now, the class contains the following methods: * `isValidIdentifierName()` - to verify whether an arbitrary text string is valid as an identifier name in PHP. A leading `$` for a variable should be removed prior to passing the name to this method. Returns boolean. * `isEqual()` - to check if two arbitrary identifier names will be seen as the same in PHP. This method is specifically aimed at the "case-insensitive" (but not really) identifier names, like namespace, class and function names. Do NOT use this method for variables or constants! Returns boolean. Includes dedicated unit tests. --- PHPCSUtils/Utils/NamingConventions.php | 113 +++++++++++++++ Tests/Utils/NamingConventions/IsEqualTest.php | 101 ++++++++++++++ .../IsValidIdentifierNameTest.php | 130 ++++++++++++++++++ 3 files changed, 344 insertions(+) create mode 100644 PHPCSUtils/Utils/NamingConventions.php create mode 100644 Tests/Utils/NamingConventions/IsEqualTest.php create mode 100644 Tests/Utils/NamingConventions/IsValidIdentifierNameTest.php diff --git a/PHPCSUtils/Utils/NamingConventions.php b/PHPCSUtils/Utils/NamingConventions.php new file mode 100644 index 00000000..385ba21c --- /dev/null +++ b/PHPCSUtils/Utils/NamingConventions.php @@ -0,0 +1,113 @@ +assertSame($expected, NamingConventions::isEqual($inputA, $inputB)); + } + + /** + * Data provider. + * + * @see testIsEqual() For the array format. + * + * @return array + */ + public function dataIsEqual() + { + return [ + 'a-z-0-9-only-same-case' => [ + 'abcdefghijklmnopqrstuvwxyz_0123456789', + 'abcdefghijklmnopqrstuvwxyz_0123456789', + true, + ], + 'a-z-0-9-only-different-case' => [ + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789', + 'abcdefghijklmnopqrstuvwxyz_0123456789', + true, + ], + 'extended-ascii-same-case' => [ + 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', + 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', + true, + ], + 'extended-ascii-different-case' => [ + 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', + 'çÜÉÂÄÀÅÇÊËÈÏÎÌäåéÆæÔÖÒÛÙŸöü¢ÁÍÓÚÑñ', + false, + ], + 'mixed-ascii-extended-ascii-same-case' => [ + 'Déjàvü', + 'Déjàvü', + true, + ], + 'mixed-ascii-extended-ascii-different-case-only-for-ascii' => [ + 'Déjàvü', + 'déJàVü', + true, + ], + 'mixed-ascii-extended-ascii-different-case' => [ + 'Déjàvü', + 'DÉJÀVÜ', + false, + ], + 'emoji-name' => [ + '💩💩💩', + '💩💩💩', + true, + ], + 'invalid-input-but-not-relevant' => [ + true, + true, + true, + ], + ]; + } +} diff --git a/Tests/Utils/NamingConventions/IsValidIdentifierNameTest.php b/Tests/Utils/NamingConventions/IsValidIdentifierNameTest.php new file mode 100644 index 00000000..316a0283 --- /dev/null +++ b/Tests/Utils/NamingConventions/IsValidIdentifierNameTest.php @@ -0,0 +1,130 @@ +assertSame($expected, NamingConventions::isValidIdentifierName($input)); + } + + /** + * Data provider. + * + * @see testIsValidIdentifierName() For the array format. + * + * @return array + */ + public function dataIsValidIdentifierName() + { + return [ + // Valid names. + 'a-z-only' => [ + 'valid_name', + true, + ], + 'a-z-uppercase' => [ + 'VALID_NAME', + true, + ], + 'a-z-camel-caps' => [ + 'Valid_Name', + true, + ], + 'alphanum-mixed-case' => [ + 'VaLiD128NaMe', + true, + ], + 'underscore-prefix' => [ + '_valid_name', + true, + ], + 'double-underscore-prefix' => [ + '__valid_name', + true, + ], + 'extended-ascii-lowercase' => [ + 'пасха', + true, + ], + 'extended-ascii-mixed-case' => [ + 'Пасха', + true, + ], + 'extended-ascii-non-letter' => [ + '¢£¥ƒ¿½¼«»±÷˜°²', + true, + ], + 'emoji-name-1' => [ + '💩💩💩', + true, + ], + 'emoji-name-2' => [ + '😎', + true, + ], + + // Invalid names. + 'not-a-string' => [ + 12345, + false, + ], + 'empty-string' => [ + '', + false, + ], + 'name-with-whitespace' => [ + 'aa bb', + false, + ], + 'starts-with-number' => [ + '2beornot2be', + false, + ], + 'name-with-quotes-in-it' => [ + "aa'1'", + false, + ], + 'name-with-dash' => [ + 'some-thing', + false, + ], + 'name-with-punctuation-chars' => [ + '!@#$%&*(){}[]', + false, + ], + ]; + } +} From 75fd255b4dc6202a87bc1ac214394bc3f1afa7a6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 26 Mar 2020 04:35:22 +0100 Subject: [PATCH 33/79] TestUtils\UtilityMethodTestCase: add test for the skipJSCSSTestsOnPHPCS4() method PR 111 added test skipping for JS and CSS files when run on PHPCS 4.x, but did not (yet) add tests for the new method. Fixed now. --- .../UtilityMethodTestCase/SkipCSJSTest.js | 3 + .../UtilityMethodTestCase/SkipCSJSTest.php | 75 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.js create mode 100644 Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.php diff --git a/Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.js b/Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.js new file mode 100644 index 00000000..70208997 --- /dev/null +++ b/Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.js @@ -0,0 +1,3 @@ +') === true) { + $msg = 'JS and CSS support has been removed in PHPCS 4.'; + $exception = 'PHPUnit\Framework\SkippedTestError'; + if (\class_exists('PHPUnit_Framework_SkippedTestError')) { + // PHPUnit < 6. + $exception = 'PHPUnit_Framework_SkippedTestError'; + } + + if (\method_exists($this, 'expectException')) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($msg); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $msg); + } + } + + parent::skipJSCSSTestsOnPHPCS4(); + } +} From 64d2afae4fadf76bdec13ab7a51228cae79d6bb9 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Sat, 28 Mar 2020 13:29:07 +0000 Subject: [PATCH 34/79] Docs: Minor fixes for home page content --- README.md | 56 ++++++++++++++++++++++++------------------------- docs/index.html | 44 +++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 066d95b5..dec13a48 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ PHPCSUtils: A suite of utility functions for use with PHP_CodeSniffer * [Features](#features) * [Minimum Requirements](#minimum-requirements) * [Integrating PHPCSUtils in your external PHPCS standard](#integrating-phpcsutils-in-your-external-phpcs-standard) - + [Composer based with a minimum PHPCS requirement of PHPCS 3.1.0](#composer-based-with-a-minimum-phpcs-requirement-of-phpcs-310) - + [Composer based with a minimum PHPCS requirement of PHPCS 2.6.0](#composer-based-with-a-minimum-phpcs-requirement-of-phpcs-260) + + [Composer-based with a minimum PHPCS requirement of PHPCS 3.1.0](#composer-based-with-a-minimum-phpcs-requirement-of-phpcs-310) + + [Composer-based with a minimum PHPCS requirement of PHPCS 2.6.0](#composer-based-with-a-minimum-phpcs-requirement-of-phpcs-260) + [Non-Composer based integration](#non-composer-based-integration) * [Frequently Asked Questions](#frequently-asked-questions) * [Contributing](#contributing) @@ -31,7 +31,7 @@ PHPCSUtils: A suite of utility functions for use with PHP_CodeSniffer Features ------------------------------------------- -This is a set of utilities to aid developers of sniffs for [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). +This is a set of utilities to aid developers of sniffs for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). This package offers the following features: @@ -41,50 +41,50 @@ Normally to use the latest version of PHP_CodeSniffer native utility functions, Now you won't have to anymore. This package allows you to use the latest version of those utility functions in all PHP_CodeSniffer versions from PHPCS 2.6.0 and up. -### A number of abstract sniff classes which your sniffs can extend. +### Several abstract sniff classes which your sniffs can extend. -These classes take some of the heavy lifting away for a number of frequently occuring sniff types. +These classes take most of the heavy lifting away for some frequently occurring sniff types. -### A collection of static properties for often used token groups. +### A collection of static properties for often-used token groups. -Collections of related tokens as often used and needed for sniffs. +Collections of related tokens often-used and needed for sniffs. These are additional "token groups" to compliment the ones available through the PHPCS native `PHP_CodeSniffer\Util\Tokens` class. -### An ever growing number of utility functions for use with PHP_CodeSniffer. +### An ever-growing number of utility functions for use with PHP_CodeSniffer. -Whether you need to split an `array` into the individual items, are trying to determine which variables are being assigned to in a `list()` or are figuring out whether a function has a docblock, PHPCSUtils got you covered! +Whether you need to split an `array` into the individual items, are trying to determine which variables are being assigned to in a `list()` or are figuring out whether a function has a DocBlock, PHPCSUtils has you covered! -Includes improved versions of the PHPCS native utility functions and plenty new utility functions. +Includes improved versions of the PHPCS native utility functions and plenty of new utility functions. These functions are, of course, compatible with PHPCS 2.6.0 up to PHPCS `master`. ### Test utilities -An abstract `UtilityMethodTestCase` class to allow for testing your own utility methods written for PHP_CodeSniffer with ease. +An abstract `UtilityMethodTestCase` class to support testing of your utility methods written for PHP_CodeSniffer. Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 9.x. ### Backward compatibility layer -A `PHPCS23Utils` standard which allows sniffs to work in both PHPCS 2.x and 3.x, as well as a number of helper functions for external standards which still want to support both PHP_CodeSniffer 2.x as well as 3.x. +A `PHPCS23Utils` standard which allows sniffs to work in both PHPCS 2.x and 3.x, as well as a few helper functions for external standards which still want to support both PHP_CodeSniffer 2.x as well as 3.x. ### Fully documented -To see detailed information about all available abstract sniffs, utility functions and PHPCS helper functions, have a read through the [extensive documentation](https://phpcsutils.com/). +To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the [extensive documentation](https://phpcsutils.com/). Minimum Requirements ------------------------------------------- * PHP 5.4 or higher. -* [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 2.6.0+, 3.1.0+ (with the exception of PHPCS 3.5.3). +* [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 2.6.0+, 3.1.0+ (with the exception of PHPCS 3.5.3). Integrating PHPCSUtils in your external PHPCS standard ------------------------------------------- -### Composer based with a minimum PHPCS requirement of PHPCS 3.1.0 +### Composer-based with a minimum PHPCS requirement of PHPCS 3.1.0 -If your external PHP_CodeSniffer standard only supports Composer based installs and has a minimum PHPCS requirement of PHP_CodeSniffer 3.1.0, integrating PHPCSUtils is pretty straight forward. +If your external PHP_CodeSniffer standard only supports Composer-based installs and has a minimum PHPCS requirement of PHP_CodeSniffer 3.1.0, integrating PHPCSUtils is pretty straight forward. Run the following from the root of your external PHPCS standard's project: ```bash @@ -97,18 +97,18 @@ No further action needed. You can start using all the utility functions, abstrac > > This plugin will automatically register PHPCSUtils (and your own external standard) with PHP_CodeSniffer, so you and your users don't have to worry about this anymore. > -> :warning: Note: if your end-user installation instructions include instructions on adding a Composer PHPCS plugin or on manually registering your standard with PHPCS using the `--config-set installed_paths` command, you may want to remove those instructions as they are no longer needed. +> :warning: Note: if your end-user installation instructions include instructions on adding a Composer PHPCS plugin or on manually registering your standard with PHPCS using the `--config-set installed_paths` command, you can remove those instructions as they are no longer needed. #### Running your unit tests If your unit tests use the PHP_CodeSniffer native unit test suite, all is good. -If you have your own unit test suite to test your sniffs, make sure to load the composer `vendor/autoload.php` file in your PHPUnit bootstrap file or _as_ the PHPUnit bootstrap file. +If you have your own unit test suite to test your sniffs, make sure to load the Composer `vendor/autoload.php` file in your PHPUnit bootstrap file or _as_ the PHPUnit bootstrap file. If you intend to use the test utilities provided in the `PHPCSUtils/TestUtils` directory, make sure you also load the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file in your PHPUnit bootstrap file. -### Composer based with a minimum PHPCS requirement of PHPCS 2.6.0 +### Composer-based with a minimum PHPCS requirement of PHPCS 2.6.0 Follow the above instructions for use with PHPCS 3.x. @@ -124,7 +124,7 @@ In addition to that, add the following to the `ruleset.xml` file of your standar If your standard supports both PHPCS 2.x as well as 3.x, you are bound to already have a PHPUnit `bootstrap.php` file in place. -To allow the unit tests to find the relevant files for PHPCSUtils, make sure that the bootstrap loads both the composer `vendor/autoload.php` file, as well as the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file. +To allow the unit tests to find the relevant files for PHPCSUtils, make sure that the bootstrap loads both the Composer `vendor/autoload.php` file, as well as the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file. ### Non-Composer based integration @@ -135,11 +135,11 @@ To use a non-Composer based installation for your sniff development environment, Your installation instructions for a non-Composer based installation will probably look similar to this: -> * Install [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) via [your preferred method](https://github.com/squizlabs/PHP_CodeSniffer#installation). +> * Install [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) via [your preferred method](https://github.com/squizlabs/PHP_CodeSniffer#installation). > * Register the path to PHPCS in your system `$PATH` environment variable to make the `phpcs` command available from anywhere in your file system. > * Download the [latest _YourStandardName_ release] and unzip/untar it into an arbitrary directory. > You can also choose to clone the repository using git. -> * Add the path to the directory in which you placed your copy of the _YourStandardName_ repo to the PHP CodeSniffer configuration using the below command: +> * Add the path to the directory in which you placed your copy of the _YourStandardName_ repo to the PHP_CodeSniffer configuration using the below command: > ```bash > phpcs --config-set installed_paths /path/to/YourStandardName > ``` @@ -152,7 +152,7 @@ For things to continue working when you add PHPCSUtils to your standard, you nee > * **Next, download the [latest PHPCSUtils release](https://github.com/PHPCSStandards/PHPCSUtils/releases) and unzip/untar it into an arbitrary directory.** > You can also choose to clone the repository using git. -> * Add the path to the **directories** in which you placed your copy of the _YourStandardName_ repo **and the PHPCSUtils repo** to the PHP CodeSniffer configuration using the below command: +> * Add the path to the **directories** in which you placed your copy of the _YourStandardName_ repo **and the PHPCSUtils repo** to the PHP_CodeSniffer configuration using the below command: > ```bash > phpcs --config-set installed_paths /path/to/YourStandardName,/path/to/PHPCSUtils > ``` @@ -203,7 +203,7 @@ pointing to the PHPCS directory. -Once that's done, you will need to make a small tweak to your own dev environment to get the unit tests runnning for a non-composer based install: +Once that's done, you will need to make a small tweak to your own dev environment to get the unit tests runnning for a non-Composer based install: * Copy your project's `phpunit.xml.dist` file to `phpunit.xml`. * Add the following to the `phpunit.xml` file within the `` tags, replacing `/path/to/PHPCSUtils` with the path in which you installed PHPCSUtils on your local system: ```xml @@ -216,17 +216,17 @@ Once that's done, you will need to make a small tweak to your own dev environmen Frequently Asked Questions ------- -#### Q: How does this all work without an external standard needing to register an autoloader ? +#### Q: How does this all work without an external standard needing to register an autoloader? A: As PHPCSUtils is registered with PHPCS as an external standard and PHPCSUtils complies with the naming requirements of PHPCS, the PHPCS native autoloader will automatically take care of loading the classes you use from PHPCSUtils. -#### Q: What does the `PHPCS23Utils` standard do ? +#### Q: What does the `PHPCS23Utils` standard do? A: All the `PHPCS23Utils` standard does is load the `phpcsutils-autoload.php` file. PHPCS 3.x uses namespaces, while PHPCS 2.x does not. The `phpcsutils-autoload.php` file creates `class_alias`-es for the most commonly used PHPCS classes, including all PHPCS classes used by PHPCSUtils. That way, both your external standard as well as PHPCSUtils can refer to the PHPCS 3.x class names and the code will still work in PHPCS 2.x. -#### Q: Why is PHP_CodeSniffer 3.5.3 not supported ? +#### Q: Why is PHP_CodeSniffer 3.5.3 not supported? A: The backfill for PHP 7.4 numeric literals with underscores in PHP_CodeSniffer 3.5.3 is broken and there is no way to reliably provide support for anything to do with numbers or `T_STRING` tokens when using PHP_CodeSniffer 3.5.3 as the tokens returned by the tokenizer are unpredictable and unreliable. @@ -237,7 +237,7 @@ Contributing ------- Contributions to this project are welcome. Clone the repo, branch off from `develop`, make your changes, commit them and send in a pull request. -If unsure whether the changes you are proposing would be welcome, open an issue first to discuss your proposal. +If you are unsure whether the changes you are proposing would be welcome, please open an issue first to discuss your proposal. License ------- diff --git a/docs/index.html b/docs/index.html index 5f99d64a..ed782b26 100644 --- a/docs/index.html +++ b/docs/index.html @@ -47,7 +47,7 @@

PHPCSUtils

Features

-

PHPCSUtils is a set of utilities to aid developers of sniffs for PHP CodeSniffer.

+

PHPCSUtils is a set of utilities to aid developers of sniffs for PHP_CodeSniffer.

This package offers the following features:

@@ -59,40 +59,40 @@

Features

Now you won't have to anymore. This package allows you to use the latest version of those utility functions in all PHP_CodeSniffer versions from PHPCS 2.6.0 and up.

-
A number of abstract sniff classes which your sniffs can extend.
+
Several abstract sniff classes which your sniffs can extend.
-

These classes take some of the heavy lifting away for a number of frequently occuring sniff types.

+

These classes take most of the heavy lifting away for some frequently occurring sniff types.

-
A collection of static properties for often used token groups.
+
A collection of static properties for often-used token groups.
-

Collections of related tokens as often used and needed for sniffs.
+

Collections of related tokens often-used and needed for sniffs.
These are additional "token groups" to compliment the ones available through the PHPCS native PHP_CodeSniffer\Util\Tokens class.

-
An ever growing number of utility functions for use with PHP_CodeSniffer.
+
An ever-growing number of utility functions for use with PHP_CodeSniffer.
-

Whether you need to split an array into the individual items, are trying to determine which variables are being assigned to in a list() or are figuring out whether a function has a docblock, PHPCSUtils got you covered!

+

Whether you need to split an array into the individual items, are trying to determine which variables are being assigned to in a list() or are figuring out whether a function has a DocBlock, PHPCSUtils has you covered!

-

Includes improved versions of the PHPCS native utility functions and plenty new utility functions.

+

Includes improved versions of the PHPCS native utility functions and plenty of new utility functions.

These functions are, of course, compatible with PHPCS 2.6.0 up to PHPCS master.

Test utilities
-

An abstract UtilityMethodTestCase class to allow for testing your own utility methods written for PHP_CodeSniffer with ease.
+

An abstract UtilityMethodTestCase class to support testing of your utility methods written for PHP_CodeSniffer.
Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 9.x.

Backward compatibility layer
-

A PHPCS23Utils standard which allows sniffs to work in both PHPCS 2.x and 3.x, as well as a number of helper functions for external standards which still want to support both PHP_CodeSniffer 2.x as well as 3.x.

+

A PHPCS23Utils standard which allows sniffs to work in both PHPCS 2.x and 3.x, as well as a few helper functions for external standards which still want to support both PHP_CodeSniffer 2.x as well as 3.x.

Fully documented
-

To see detailed information about all available abstract sniffs, utility functions and PHPCS helper functions, have a read through the extensive documentation.

+

To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the extensive documentation.

@@ -101,15 +101,15 @@

Minimum Requirements

  • PHP 5.4 or higher.
  • -
  • PHP CodeSniffer 2.6.0+, 3.1.0+ (with the exception of PHPCS 3.5.3).
  • +
  • PHP_CodeSniffer 2.6.0+, 3.1.0+ (with the exception of PHPCS 3.5.3).

Integrating PHPCSUtils in your external PHPCS standard

-

Composer based with a minimum PHPCS requirement of PHPCS 3.1.0

+

Composer-based with a minimum PHPCS requirement of PHPCS 3.1.0

-

If your external PHP_CodeSniffer standard only supports Composer based installs and has a minimum PHPCS requirement of PHP_CodeSniffer 3.1.0, integrating PHPCSUtils is pretty straight forward.

+

If your external PHP_CodeSniffer standard only supports Composer-based installs and has a minimum PHPCS requirement of PHP_CodeSniffer 3.1.0, integrating PHPCSUtils is pretty straight forward.

Run the following from the root of your external PHPCS standard's project:

composer require phpcsstandards/phpcsutils:"^1.0"
@@ -122,19 +122,19 @@ 

Composer based with a minimum PHPCS requirement of PHPCS 3.1.0

This plugin will automatically register PHPCSUtils (and your own external standard) with PHP_CodeSniffer, so you and your users don't have to worry about this anymore.

-

Note: if your end-user installation instructions include instructions on adding a Composer PHPCS plugin or on manually registering your standard with PHPCS using the --config-set installed_paths command, you may want to remove those instructions as they are no longer needed.

+

Note: if your end-user installation instructions include instructions on adding a Composer PHPCS plugin or on manually registering your standard with PHPCS using the --config-set installed_paths command, you can remove those instructions as they are no longer needed.

Running your unit tests

If your unit tests use the PHP_CodeSniffer native unit test suite, all is good.

-

If you have your own unit test suite to test your sniffs, make sure to load the composer vendor/autoload.php file in your PHPUnit bootstrap file or as the PHPUnit bootstrap file.

+

If you have your own unit test suite to test your sniffs, make sure to load the Composer vendor/autoload.php file in your PHPUnit bootstrap file or as the PHPUnit bootstrap file.

If you intend to use the test utilities provided in the PHPCSUtils/TestUtils directory, make sure you also load the vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php file in your PHPUnit bootstrap file.

-

Composer based with a minimum PHPCS requirement of PHPCS 2.6.0

+

Composer-based with a minimum PHPCS requirement of PHPCS 2.6.0

Follow the above instructions for use with PHPCS 3.x.

@@ -151,23 +151,23 @@

Running your unit tests

If your standard supports both PHPCS 2.x as well as 3.x, you are bound to already have a PHPUnit bootstrap.php file in place.

-

To allow the unit tests to find the relevant files for PHPCSUtils, make sure that the bootstrap loads both the composer vendor/autoload.php file, as well as the vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php file.

+

To allow the unit tests to find the relevant files for PHPCSUtils, make sure that the bootstrap loads both the Composer vendor/autoload.php file, as well as the vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php file.

Frequently Asked Questions

-

Q: How does this all work without an external standard needing to register an autoloader ?

+

Q: How does this all work without an external standard needing to register an autoloader?

A: As PHPCSUtils is registered with PHPCS as an external standard and PHPCSUtils complies with the naming requirements of PHPCS, the PHPCS native autoloader will automatically take care of loading the classes you use from PHPCSUtils.

-

Q: What does the PHPCS23Utils standard do ?

+

Q: What does the PHPCS23Utils standard do?

A: All the PHPCS23Utils standard does is load the phpcsutils-autoload.php file.

PHPCS 3.x uses namespaces, while PHPCS 2.x does not. The phpcsutils-autoload.php file creates class_alias-es for the most commonly used PHPCS classes, including all PHPCS classes used by PHPCSUtils. That way, both your external standard as well as PHPCSUtils can refer to the PHPCS 3.x class names and the code will still work in PHPCS 2.x.

-

Q: Why is PHP_CodeSniffer 3.5.3 not supported ?

+

Q: Why is PHP_CodeSniffer 3.5.3 not supported?

A: The backfill for PHP 7.4 numeric literals with underscores in PHP_CodeSniffer 3.5.3 is broken and there is no way to reliably provide support for anything to do with numbers or T_STRING tokens when using PHP_CodeSniffer 3.5.3 as the tokens returned by the tokenizer are unpredictable and unreliable.

@@ -178,7 +178,7 @@

Contributing

Contributions to this project are welcome. Clone the repo, branch off from develop, make your changes, commit them and send in a pull request.

-

If unsure whether the changes you are proposing would be welcome, open an issue first to discuss your proposal.

+

If you are unsure whether the changes you are proposing would be welcome, please open an issue first to discuss your proposal.

License

From 585f69d653322180a94eb958f366f01ed34785d9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 29 Mar 2020 21:03:59 +0200 Subject: [PATCH 35/79] FunctionDeclarations::isMagicFunction(): bug fix for nested functions Function declarations nested in a class method declare the function in the global namespace. See: https://3v4l.org/R32Sl This was no handled correctly by the function so far. Fixed now. Includes unit tests covering the fix. --- PHPCSUtils/Utils/FunctionDeclarations.php | 3 +- .../SpecialFunctionsTest.inc | 13 +++++++ .../SpecialFunctionsTest.php | 37 +++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index edf222e1..54382489 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -16,7 +16,6 @@ use PHPCSUtils\BackCompat\BCTokens; use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; -use PHPCSUtils\Utils\Conditions; use PHPCSUtils\Utils\GetTokensAsString; use PHPCSUtils\Utils\ObjectDeclarations; use PHPCSUtils\Utils\Scopes; @@ -819,7 +818,7 @@ public static function isMagicFunction(File $phpcsFile, $stackPtr) return false; } - if (Conditions::hasCondition($phpcsFile, $stackPtr, BCTokens::ooScopeTokens()) === true) { + if (Scopes::isOOMethod($phpcsFile, $stackPtr) === true) { return false; } diff --git a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.inc b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.inc index 374c28da..ffc59a77 100644 --- a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.inc +++ b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.inc @@ -94,3 +94,16 @@ interface MagicInterface /* testMethodInInterfaceNotMagicName */ function __myFunction(); } + +// Verify that nested functions are correctly seen as declared in the global namespace. +class FunctionsDeclaredNestedInMethod extends \SoapClient { + /* testNonMagicMethod */ + public function methodName() { + /* testNestedFunctionDeclarationMagicFunction */ + function __autoload($class) {} + /* testNestedFunctionDeclarationNonMagicFunction */ + function __isset() {} + /* testNestedFunctionDeclarationNonSpecialFunction */ + function __getLastResponse() {} + } +} diff --git a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php index 10adfcfe..ae747601 100644 --- a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php +++ b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php @@ -391,6 +391,43 @@ public function dataItsAKindOfMagic() 'special' => false, ], ], + + 'NonMagicMethod' => [ + '/* testNonMagicMethod */', + [ + 'function' => false, + 'method' => false, + 'double' => false, + 'special' => false, + ], + ], + 'NestedFunctionDeclarationMagicFunction' => [ + '/* testNestedFunctionDeclarationMagicFunction */', + [ + 'function' => true, + 'method' => false, + 'double' => false, + 'special' => false, + ], + ], + 'NestedFunctionDeclarationNonMagicFunction' => [ + '/* testNestedFunctionDeclarationNonMagicFunction */', + [ + 'function' => false, + 'method' => false, + 'double' => false, + 'special' => false, + ], + ], + 'NestedFunctionDeclarationNonSpecialFunction' => [ + '/* testNestedFunctionDeclarationNonSpecialFunction */', + [ + 'function' => false, + 'method' => false, + 'double' => false, + 'special' => false, + ], + ], ]; } } From 5a75cc5c1e83e2b840a1eee9757bbc3cdab259dc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 31 Mar 2020 19:54:47 +0200 Subject: [PATCH 36/79] Travis: fix the build The Travis docs say that `$TRAVIS_BUILD_STAGE_NAME` is in "proper case" form: > TRAVIS_BUILD_STAGE_NAME: The build stage in capitalized form, e.g. Test or Deploy. If a build does not use build stages, this variable is empty (""). However, it looks like they made an (undocumented) change (probably a bug in their script handling) which means that the `$TRAVIS_BUILD_STAGE_NAME` name is now in the case as given, which in this case is _lowercase_. This means that some of the comparisons are failing and the wrong things are executed for certain builds. As I expect this to be a bug in Travis, I'm not changing the case for the comparisons at this time. Instead I'm fixing this by inline fixing the case of the variable for the comparisons. Refs: * https://docs.travis-ci.com/user/environment-variables#default-environment-variables (near the bottom of the list) --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index ccb79674..c83d89cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -141,14 +141,14 @@ jobs: before_install: # Speed up build time by disabling Xdebug when its not needed. - | - if [[ "$TRAVIS_BUILD_STAGE_NAME" != "Coverage" ]]; then + if [[ "${TRAVIS_BUILD_STAGE_NAME^}" != "Coverage" ]]; then phpenv config-rm xdebug.ini || echo 'No xdebug config.' fi # On stable PHPCS versions, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. - | - if [[ "$TRAVIS_BUILD_STAGE_NAME" != "Sniff" && $PHPCS_VERSION != "dev-master" && "$PHPCS_VERSION" != "n/a" ]]; then + if [[ "${TRAVIS_BUILD_STAGE_NAME^}" != "Sniff" && $PHPCS_VERSION != "dev-master" && "$PHPCS_VERSION" != "n/a" ]]; then echo 'error_reporting = E_ALL & ~E_DEPRECATED' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini fi @@ -162,7 +162,7 @@ install: composer require --no-update --no-scripts squizlabs/php_codesniffer:${PHPCS_VERSION} fi - | - if [[ "$TRAVIS_BUILD_STAGE_NAME" == "Coverage" ]]; then + if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" ]]; then composer require --dev --no-update --no-suggest --no-scripts php-coveralls/php-coveralls:${COVERALLS_VERSION} fi - | @@ -177,7 +177,7 @@ install: before_script: - - if [[ "$TRAVIS_BUILD_STAGE_NAME" == "Coverage" ]]; then mkdir -p build/logs; fi + - if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" ]]; then mkdir -p build/logs; fi - phpenv rehash @@ -187,18 +187,18 @@ script: # Run the unit tests. - | - if [[ $PHPCS_VERSION != "n/a" && "$TRAVIS_BUILD_STAGE_NAME" != "Coverage" ]]; then + if [[ $PHPCS_VERSION != "n/a" && "${TRAVIS_BUILD_STAGE_NAME^}" != "Coverage" ]]; then composer test - elif [[ $PHPCS_VERSION != "n/a" && "$TRAVIS_BUILD_STAGE_NAME" == "Coverage" ]]; then + elif [[ $PHPCS_VERSION != "n/a" && "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" ]]; then composer coverage fi after_success: - | - if [[ "$TRAVIS_BUILD_STAGE_NAME" == "Coverage" && $COVERALLS_VERSION == "^1.0" ]]; then + if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" && $COVERALLS_VERSION == "^1.0" ]]; then php vendor/bin/coveralls -v -x build/logs/clover.xml fi - | - if [[ "$TRAVIS_BUILD_STAGE_NAME" == "Coverage" && $COVERALLS_VERSION == "^2.0" ]]; then + if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" && $COVERALLS_VERSION == "^2.0" ]]; then php vendor/bin/php-coveralls -v -x build/logs/clover.xml fi From 58abda8df0baecde9aab25714b5e5b238aa2af56 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 31 Mar 2020 23:05:00 +0200 Subject: [PATCH 37/79] Lists::getAssignments(): improve the return value :warning: **BREAKING CHANGE** :warning: In the initial commit, the `Lists::getAssignments()` method would have three different arrays as potential output. 1. An array with just the `raw` and `is_empty` keys for an empty list item. 2. An array with the above + detailed information about the assignments for non-keyed list items. 3. An array with the above + detail information about the keys found for keyed list items. This meant that - aside from for the `raw` and `is_empty` keys -, a dev looping over the list items would always need to do an `isset()` check for each array index before the value could be compared or used. That made the method return value fiddly to work with. In this commit, the above three different arrays is now reduced to two different arrays (type 2 and 3) with either an empty string or `false` as the default value for all keys. Additionally: * The `nested_list` index key has been renamed to `is_nested_list` to make it clearer that this will be a boolean value and not the detailed information about the nested list. * And while this will rarely be relevant for sniffs implementing this method, the order of the array indexes in the return array has also been adjusted. Includes updated unit tests. --- PHPCSUtils/Utils/Lists.php | 90 ++-- Tests/Utils/Lists/GetAssignmentsTest.php | 613 +++++++++++++---------- 2 files changed, 414 insertions(+), 289 deletions(-) diff --git a/PHPCSUtils/Utils/Lists.php b/PHPCSUtils/Utils/Lists.php index 0623722f..4ffc0eee 100644 --- a/PHPCSUtils/Utils/Lists.php +++ b/PHPCSUtils/Utils/Lists.php @@ -25,6 +25,27 @@ class Lists { + /** + * Default values for individual list items. + * + * Used by the `getAssignments()` method. + * + * @since 1.0.0 + * + * @var array + */ + private static $listItemDefaults = [ + 'raw' => '', + 'assignment' => '', + 'is_empty' => false, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, + ]; + /** * Determine whether a `T_OPEN/CLOSE_SHORT_ARRAY` token is a short list() construct. * @@ -229,27 +250,23 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortList = n * * * 0 => array( - * 'raw' => string, // The full content of the variable definition, including - * // whitespace and comments. - * // This may be an empty string when an item is being skipped. - * 'is_empty' => bool, // Whether this is an empty list item, i.e. the - * // second item in `list($a, , $b)`. - * ) - * - * - * Non-empty list items will have the following additional array indexes set: - * - * 'assignment' => string, // The content of the assignment part, cleaned of comments. - * // This could be a nested list. - * 'nested_list' => bool, // Whether this is a nested list. + * 'raw' => string, // The full content of the variable definition, including + * // whitespace and comments. + * // This may be an empty string when an item is being skipped. + * 'assignment' => string, // The content of the assignment part, _cleaned of comments_. + * // This may be an empty string for an empty list item; + * // it could also be a nested list represented as a string. + * 'is_empty' => bool, // Whether this is an empty list item, i.e. the + * // second item in `list($a, , $b)`. + * 'is_nested_list' => bool, // Whether this is a nested list. + * 'variable' => string|false, // The base variable being assigned to or + * // FALSE in case of a nested list or avariable variable. + * // I.e. `$a` in `list($a['key'])`. + * 'assignment_token' => int|false, // The start pointer for the assignment. + * 'assignment_end_token' => int|false, // The end pointer for the assignment. * 'assign_by_reference' => bool, // Is the variable assigned by reference? * 'reference_token' => int|false, // The stack pointer to the reference operator or * // FALSE when not a reference assignment. - * 'variable' => string|false, // The base variable being assigned to or - * // FALSE in case of a nested list or variable variable. - * // I.e. `$a` in `list($a['key'])`. - * 'assignment_token' => int, // The start pointer for the assignment. - * 'assignment_end_token' => int, // The end pointer for the assignment. * * * @@ -293,7 +310,7 @@ public static function getAssignments(File $phpcsFile, $stackPtr) $reference = null; $list = null; $lastComma = $opener; - $current = []; + $keys = []; for ($i = ($opener + 1); $i <= $closer; $i++) { if (isset(Tokens::$emptyTokens[$tokens[$i]['code']])) { @@ -302,11 +319,10 @@ public static function getAssignments(File $phpcsFile, $stackPtr) switch ($tokens[$i]['code']) { case \T_DOUBLE_ARROW: - $current['key'] = GetTokensAsString::compact($phpcsFile, $start, $lastNonEmpty, true); - - $current['key_token'] = $start; - $current['key_end_token'] = $lastNonEmpty; - $current['double_arrow_token'] = $i; + $keys['key'] = GetTokensAsString::compact($phpcsFile, $start, $lastNonEmpty, true); + $keys['key_token'] = $start; + $keys['key_end_token'] = $lastNonEmpty; + $keys['double_arrow_token'] = $i; // Partial reset. $start = null; @@ -316,6 +332,7 @@ public static function getAssignments(File $phpcsFile, $stackPtr) case \T_COMMA: case $tokens[$closer]['code']: + // Check if this is the end of the list or only a token with the same type as the list closer. if ($tokens[$i]['code'] === $tokens[$closer]['code']) { if ($i !== $closer) { $lastNonEmpty = $i; @@ -326,23 +343,17 @@ public static function getAssignments(File $phpcsFile, $stackPtr) } } + // Ok, so this is actually the end of the list item. + $current = self::$listItemDefaults; $current['raw'] = \trim(GetTokensAsString::normal($phpcsFile, ($lastComma + 1), ($i - 1))); if ($start === null) { $current['is_empty'] = true; } else { - $current['is_empty'] = false; - $current['assignment'] = \trim( + $current['assignment'] = \trim( GetTokensAsString::compact($phpcsFile, $start, $lastNonEmpty, true) ); - $current['nested_list'] = isset($list); - - $current['assign_by_reference'] = false; - $current['reference_token'] = false; - if (isset($reference)) { - $current['assign_by_reference'] = true; - $current['reference_token'] = $reference; - } + $current['is_nested_list'] = isset($list); $current['variable'] = false; if (isset($list) === false && $tokens[$start]['code'] === \T_VARIABLE) { @@ -350,6 +361,15 @@ public static function getAssignments(File $phpcsFile, $stackPtr) } $current['assignment_token'] = $start; $current['assignment_end_token'] = $lastNonEmpty; + + if (isset($reference)) { + $current['assign_by_reference'] = true; + $current['reference_token'] = $reference; + } + } + + if (empty($keys) === false) { + $current += $keys; } $vars[] = $current; @@ -360,7 +380,7 @@ public static function getAssignments(File $phpcsFile, $stackPtr) $reference = null; $list = null; $lastComma = $i; - $current = []; + $keys = []; break; diff --git a/Tests/Utils/Lists/GetAssignmentsTest.php b/Tests/Utils/Lists/GetAssignmentsTest.php index bc7f3213..7876d464 100644 --- a/Tests/Utils/Lists/GetAssignmentsTest.php +++ b/Tests/Utils/Lists/GetAssignmentsTest.php @@ -105,10 +105,10 @@ public function testGetAssignments($testMarker, $targetToken, $expected) if (isset($subset['reference_token']) && $subset['reference_token'] !== false) { $expected[$index]['reference_token'] += $stackPtr; } - if (isset($subset['assignment_token'])) { + if (isset($subset['assignment_token']) && $subset['assignment_token'] !== false) { $expected[$index]['assignment_token'] += $stackPtr; } - if (isset($subset['assignment_end_token'])) { + if (isset($subset['assignment_end_token']) && $subset['assignment_end_token'] !== false) { $expected[$index]['assignment_end_token'] += $stackPtr; } } @@ -145,19 +145,47 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ 'raw' => '/* comment */', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 2 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 3 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -172,25 +200,25 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '$id', - 'is_empty' => false, 'assignment' => '$id', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$id', 'assignment_token' => 2, 'assignment_end_token' => 2, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ 'raw' => '$name', - 'is_empty' => false, 'assignment' => '$name', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$name', 'assignment_token' => 5, 'assignment_end_token' => 5, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -200,25 +228,25 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '$this->propA', - 'is_empty' => false, 'assignment' => '$this->propA', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$this', 'assignment_token' => 1, 'assignment_end_token' => 3, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ 'raw' => '$this->propB', - 'is_empty' => false, 'assignment' => '$this->propB', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$this', 'assignment_token' => 6, 'assignment_end_token' => 8, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -227,34 +255,34 @@ public function dataGetAssignments() \T_OPEN_SHORT_ARRAY, [ 0 => [ - 'key' => "'id'", - 'key_token' => 1, - 'key_end_token' => 1, - 'double_arrow_token' => 3, 'raw' => '\'id\' => & $id', - 'is_empty' => false, 'assignment' => '$id', - 'nested_list' => false, - 'assign_by_reference' => true, - 'reference_token' => 5, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$id', 'assignment_token' => 7, 'assignment_end_token' => 7, + 'assign_by_reference' => true, + 'reference_token' => 5, + 'key' => "'id'", + 'key_token' => 1, + 'key_end_token' => 1, + 'double_arrow_token' => 3, ], 1 => [ - 'key' => "'name'", - 'key_token' => 10, - 'key_end_token' => 10, - 'double_arrow_token' => 12, 'raw' => '\'name\' => $name', - 'is_empty' => false, 'assignment' => '$name', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$name', 'assignment_token' => 14, 'assignment_end_token' => 14, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'name'", + 'key_token' => 10, + 'key_end_token' => 10, + 'double_arrow_token' => 12, ], ], ], @@ -264,25 +292,25 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '$a', - 'is_empty' => false, 'assignment' => '$a', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$a', 'assignment_token' => 2, 'assignment_end_token' => 2, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ 'raw' => 'list($b, $c)', - 'is_empty' => false, 'assignment' => 'list($b, $c)', - 'nested_list' => true, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => true, 'variable' => false, 'assignment_token' => 5, 'assignment_end_token' => 11, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -291,49 +319,49 @@ public function dataGetAssignments() \T_LIST, [ 0 => [ - 'key' => "'name'", - 'key_token' => 2, - 'key_end_token' => 2, - 'double_arrow_token' => 4, 'raw' => '\'name\' => $a', - 'is_empty' => false, 'assignment' => '$a', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$a', 'assignment_token' => 6, 'assignment_end_token' => 6, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'name'", + 'key_token' => 2, + 'key_end_token' => 2, + 'double_arrow_token' => 4, ], 1 => [ - 'key' => "'id'", - 'key_token' => 9, - 'key_end_token' => 9, - 'double_arrow_token' => 11, 'raw' => '\'id\' => $b', - 'is_empty' => false, 'assignment' => '$b', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$b', 'assignment_token' => 13, 'assignment_end_token' => 13, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'id'", + 'key_token' => 9, + 'key_end_token' => 9, + 'double_arrow_token' => 11, ], 2 => [ - 'key' => "'field'", - 'key_token' => 16, - 'key_end_token' => 16, - 'double_arrow_token' => 18, 'raw' => '\'field\' => $c', - 'is_empty' => false, 'assignment' => '$c', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$c', 'assignment_token' => 20, 'assignment_end_token' => 20, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'field'", + 'key_token' => 16, + 'key_end_token' => 16, + 'double_arrow_token' => 18, ], ], ], @@ -343,56 +371,91 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ 'raw' => '$a', - 'is_empty' => false, 'assignment' => '$a', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$a', 'assignment_token' => 5, 'assignment_end_token' => 5, + 'assign_by_reference' => false, + 'reference_token' => false, ], 2 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 3 => [ 'raw' => '$b', - 'is_empty' => false, 'assignment' => '$b', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$b', 'assignment_token' => 10, 'assignment_end_token' => 10, + 'assign_by_reference' => false, + 'reference_token' => false, ], 4 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 5 => [ 'raw' => '$c', - 'is_empty' => false, 'assignment' => '$c', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$c', 'assignment_token' => 14, 'assignment_end_token' => 14, + 'assign_by_reference' => false, + 'reference_token' => false, ], 6 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 7 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -401,68 +464,75 @@ public function dataGetAssignments() \T_LIST, [ 0 => [ - 'key' => '"name"', - 'key_token' => 4, - 'key_end_token' => 4, - 'double_arrow_token' => 6, 'raw' => '"name" => $this->name', - 'is_empty' => false, 'assignment' => '$this->name', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$this', 'assignment_token' => 8, 'assignment_end_token' => 10, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '"name"', + 'key_token' => 4, + 'key_end_token' => 4, + 'double_arrow_token' => 6, ], 1 => [ - 'key' => '"colour"', - 'key_token' => 14, - 'key_end_token' => 14, - 'double_arrow_token' => 16, 'raw' => '"colour" => $this->colour', - 'is_empty' => false, 'assignment' => '$this->colour', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$this', 'assignment_token' => 18, 'assignment_end_token' => 20, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '"colour"', + 'key_token' => 14, + 'key_end_token' => 14, + 'double_arrow_token' => 16, ], 2 => [ - 'key' => '"age"', - 'key_token' => 24, - 'key_end_token' => 24, - 'double_arrow_token' => 26, 'raw' => '"age" => $this->age', - 'is_empty' => false, 'assignment' => '$this->age', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$this', 'assignment_token' => 28, 'assignment_end_token' => 30, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '"age"', + 'key_token' => 24, + 'key_end_token' => 24, + 'double_arrow_token' => 26, ], 3 => [ - 'key' => '"cuteness"', - 'key_token' => 34, - 'key_end_token' => 34, - 'double_arrow_token' => 36, 'raw' => '"cuteness" => $this->cuteness', - 'is_empty' => false, 'assignment' => '$this->cuteness', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$this', 'assignment_token' => 38, 'assignment_end_token' => 40, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '"cuteness"', + 'key_token' => 34, + 'key_end_token' => 34, + 'double_arrow_token' => 36, ], 4 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -471,34 +541,34 @@ public function dataGetAssignments() [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET], [ 0 => [ - 'key' => "'a'", - 'key_token' => 1, - 'key_end_token' => 1, - 'double_arrow_token' => 3, 'raw' => '\'a\' => [&$a, $b]', - 'is_empty' => false, 'assignment' => '[&$a, $b]', - 'nested_list' => true, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => true, 'variable' => false, 'assignment_token' => 5, 'assignment_end_token' => 11, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'a'", + 'key_token' => 1, + 'key_end_token' => 1, + 'double_arrow_token' => 3, ], 1 => [ - 'key' => "'b'", - 'key_token' => 14, - 'key_end_token' => 14, - 'double_arrow_token' => 16, 'raw' => '\'b\' => [$c, &$d]', - 'is_empty' => false, 'assignment' => '[$c, &$d]', - 'nested_list' => true, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => true, 'variable' => false, 'assignment_token' => 18, 'assignment_end_token' => 24, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'b'", + 'key_token' => 14, + 'key_end_token' => 14, + 'double_arrow_token' => 16, ], ], ], @@ -508,36 +578,36 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '$a[]', - 'is_empty' => false, 'assignment' => '$a[]', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$a', 'assignment_token' => 2, 'assignment_end_token' => 4, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ 'raw' => '$a[0]', - 'is_empty' => false, 'assignment' => '$a[0]', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$a', 'assignment_token' => 7, 'assignment_end_token' => 10, + 'assign_by_reference' => false, + 'reference_token' => false, ], 2 => [ 'raw' => '$a[]', - 'is_empty' => false, 'assignment' => '$a[]', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$a', 'assignment_token' => 13, 'assignment_end_token' => 15, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -546,129 +616,136 @@ public function dataGetAssignments() \T_OPEN_SHORT_ARRAY, [ 0 => [ - 'key' => "'a' . 'b'", - 'key_token' => 3, - 'key_end_token' => 7, - 'double_arrow_token' => 9, 'raw' => '\'a\' . \'b\' => $a', - 'is_empty' => false, 'assignment' => '$a', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$a', 'assignment_token' => 11, 'assignment_end_token' => 11, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'a' . 'b'", + 'key_token' => 3, + 'key_end_token' => 7, + 'double_arrow_token' => 9, ], 1 => [ - 'key' => '($a * 2)', - 'key_token' => 15, - 'key_end_token' => 21, - 'double_arrow_token' => 24, 'raw' => '($a * 2) => $b->prop->prop /* comment */ [\'index\']', - 'is_empty' => false, 'assignment' => '$b->prop->prop [\'index\']', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$b', 'assignment_token' => 26, 'assignment_end_token' => 36, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '($a * 2)', + 'key_token' => 15, + 'key_end_token' => 21, + 'double_arrow_token' => 24, ], 2 => [ - 'key' => 'CONSTANT & OTHER', - 'key_token' => 40, - 'key_end_token' => 46, - 'double_arrow_token' => 48, 'raw' => 'CONSTANT & /*comment*/ OTHER => $c', - 'is_empty' => false, 'assignment' => '$c', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$c', 'assignment_token' => 50, 'assignment_end_token' => 50, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => 'CONSTANT & OTHER', + 'key_token' => 40, + 'key_end_token' => 46, + 'double_arrow_token' => 48, ], 3 => [ - 'key' => '(string) &$c', - 'key_token' => 54, - 'key_end_token' => 57, - 'double_arrow_token' => 59, 'raw' => '(string) &$c => &$d["D"]', - 'is_empty' => false, 'assignment' => '$d["D"]', - 'nested_list' => false, - 'assign_by_reference' => true, - 'reference_token' => 61, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$d', 'assignment_token' => 62, 'assignment_end_token' => 65, + 'assign_by_reference' => true, + 'reference_token' => 61, + 'key' => '(string) &$c', + 'key_token' => 54, + 'key_end_token' => 57, + 'double_arrow_token' => 59, ], 4 => [ - 'key' => 'get_key()[1]', - 'key_token' => 69, - 'key_end_token' => 74, - 'double_arrow_token' => 76, 'raw' => 'get_key()[1] => $e', - 'is_empty' => false, 'assignment' => '$e', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$e', 'assignment_token' => 78, 'assignment_end_token' => 78, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => 'get_key()[1]', + 'key_token' => 69, + 'key_end_token' => 74, + 'double_arrow_token' => 76, ], 5 => [ - 'key' => '$prop[\'index\']', - 'key_token' => 82, - 'key_end_token' => 85, - 'double_arrow_token' => 87, 'raw' => '$prop[\'index\'] => $f->prop[\'index\']', - 'is_empty' => false, 'assignment' => '$f->prop[\'index\']', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$f', 'assignment_token' => 89, 'assignment_end_token' => 94, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '$prop[\'index\']', + 'key_token' => 82, + 'key_end_token' => 85, + 'double_arrow_token' => 87, ], 6 => [ - 'key' => '$obj->fieldname', - 'key_token' => 98, - 'key_end_token' => 100, - 'double_arrow_token' => 102, 'raw' => '$obj->fieldname => ${$g}', - 'is_empty' => false, 'assignment' => '${$g}', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => false, 'assignment_token' => 104, 'assignment_end_token' => 107, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '$obj->fieldname', + 'key_token' => 98, + 'key_end_token' => 100, + 'double_arrow_token' => 102, ], 7 => [ - 'key' => '$simple', - 'key_token' => 111, - 'key_end_token' => 111, - 'double_arrow_token' => 113, 'raw' => '$simple => &$h', - 'is_empty' => false, 'assignment' => '$h', - 'nested_list' => false, - 'assign_by_reference' => true, - 'reference_token' => 115, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$h', 'assignment_token' => 116, 'assignment_end_token' => 116, + 'assign_by_reference' => true, + 'reference_token' => 115, + 'key' => '$simple', + 'key_token' => 111, + 'key_end_token' => 111, + 'double_arrow_token' => 113, ], 8 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -677,19 +754,19 @@ public function dataGetAssignments() \T_LIST, [ 0 => [ - 'key' => 'get_key()[1]', - 'key_token' => 2, - 'key_end_token' => 7, - 'double_arrow_token' => 9, 'raw' => 'get_key()[1] => &$e', - 'is_empty' => false, 'assignment' => '$e', - 'nested_list' => false, - 'assign_by_reference' => true, - 'reference_token' => 11, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$e', 'assignment_token' => 12, 'assignment_end_token' => 12, + 'assign_by_reference' => true, + 'reference_token' => 11, + 'key' => 'get_key()[1]', + 'key_token' => 2, + 'key_end_token' => 7, + 'double_arrow_token' => 9, ], ], ], @@ -699,25 +776,25 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '${$drink}', - 'is_empty' => false, 'assignment' => '${$drink}', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => false, 'assignment_token' => 3, 'assignment_end_token' => 6, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ 'raw' => '$foo->{$bar[\'baz\']}', - 'is_empty' => false, 'assignment' => '$foo->{$bar[\'baz\']}', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$foo', 'assignment_token' => 9, 'assignment_end_token' => 16, + 'assign_by_reference' => false, + 'reference_token' => false, ], ], ], @@ -726,36 +803,36 @@ public function dataGetAssignments() \T_LIST, [ 0 => [ - 'key' => "'a'", - 'key_token' => 4, - 'key_end_token' => 4, - 'double_arrow_token' => 6, 'raw' => '\'a\' => list("x" => $x1, "y" => $y1)', - 'is_empty' => false, 'assignment' => 'list("x" => $x1, "y" => $y1)', - 'nested_list' => true, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => true, 'variable' => false, 'assignment_token' => 9, 'assignment_end_token' => 23, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'a'", + 'key_token' => 4, + 'key_end_token' => 4, + 'double_arrow_token' => 6, ], 1 => [ - 'key' => "'b'", - 'key_token' => 27, - 'key_end_token' => 27, - 'double_arrow_token' => 29, 'raw' => '\'b\' => list("x" => $x2, "y" => $y2)', - 'is_empty' => false, 'assignment' => 'list("x" => $x2, "y" => $y2)', - 'nested_list' => true, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => true, 'variable' => false, 'assignment_token' => 32, 'assignment_end_token' => 46, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => "'b'", + 'key_token' => 27, + 'key_end_token' => 27, + 'double_arrow_token' => 29, ], ], ], @@ -765,29 +842,29 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '$unkeyed', - 'is_empty' => false, 'assignment' => '$unkeyed', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$unkeyed', 'assignment_token' => 2, 'assignment_end_token' => 2, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ - 'key' => '"key"', - 'key_token' => 5, - 'key_end_token' => 5, - 'double_arrow_token' => 7, 'raw' => '"key" => $keyed', - 'is_empty' => false, 'assignment' => '$keyed', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$keyed', 'assignment_token' => 9, 'assignment_end_token' => 9, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '"key"', + 'key_token' => 5, + 'key_end_token' => 5, + 'double_arrow_token' => 7, ], ], ], @@ -797,34 +874,62 @@ public function dataGetAssignments() [ 0 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 1 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 2 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 3 => [ 'raw' => '', + 'assignment' => '', 'is_empty' => true, + 'is_nested_list' => false, + 'variable' => false, + 'assignment_token' => false, + 'assignment_end_token' => false, + 'assign_by_reference' => false, + 'reference_token' => false, ], 4 => [ - 'key' => '"key"', - 'key_token' => 6, - 'key_end_token' => 6, - 'double_arrow_token' => 8, 'raw' => '"key" => $keyed', - 'is_empty' => false, 'assignment' => '$keyed', - 'nested_list' => false, - 'assign_by_reference' => false, - 'reference_token' => false, + 'is_empty' => false, + 'is_nested_list' => false, 'variable' => '$keyed', 'assignment_token' => 10, 'assignment_end_token' => 10, + 'assign_by_reference' => false, + 'reference_token' => false, + 'key' => '"key"', + 'key_token' => 6, + 'key_end_token' => 6, + 'double_arrow_token' => 8, ], ], ], From 59739e89c6e700d7b28358e5b3f3f5d3d879374f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 6 Apr 2020 13:26:07 +0200 Subject: [PATCH 38/79] Tokens\Collections: add two new properties * `$incrementDecrementOperators` containing the tokens for the increment and decrement operators. * `$objectOperators` containing the tokens used as object operators. --- PHPCSUtils/Tokens/Collections.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index a192e0e3..1df8dcee 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -150,6 +150,18 @@ class Collections \T_DECLARE => \T_DECLARE, ]; + /** + * Increment/decrement operator tokens. + * + * @since 1.0.0-alpha3 + * + * @var array => + */ + public static $incrementDecrementOperators = [ + \T_DEC => \T_DEC, + \T_INC => \T_INC, + ]; + /** * Tokens which are used to create lists. * @@ -220,6 +232,18 @@ class Collections \T_CLOSE_TAG => \T_CLOSE_TAG, ]; + /** + * Object operators. + * + * @since 1.0.0-alpha3 + * + * @var array => + */ + public static $objectOperators = [ + \T_OBJECT_OPERATOR => \T_OBJECT_OPERATOR, + \T_DOUBLE_COLON => \T_DOUBLE_COLON, + ]; + /** * OO structures which can use the `extends` keyword. * From 614972aa5343589e335bebc43dddf1f3718ee3fa Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 26 Apr 2020 07:16:43 +0200 Subject: [PATCH 39/79] ObjectDeclarations::getName(): bug fix for functions returning by reference Includes unit tests. --- PHPCSUtils/Utils/ObjectDeclarations.php | 1 + Tests/BackCompat/BCFile/GetDeclarationNameTest.inc | 6 ++++++ Tests/BackCompat/BCFile/GetDeclarationNameTest.php | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/PHPCSUtils/Utils/ObjectDeclarations.php b/PHPCSUtils/Utils/ObjectDeclarations.php index a154e502..8f38fb7e 100644 --- a/PHPCSUtils/Utils/ObjectDeclarations.php +++ b/PHPCSUtils/Utils/ObjectDeclarations.php @@ -120,6 +120,7 @@ public static function getName(File $phpcsFile, $stackPtr) $exclude = Tokens::$emptyTokens; $exclude[] = \T_OPEN_PARENTHESIS; $exclude[] = \T_OPEN_CURLY_BRACKET; + $exclude[] = \T_BITWISE_AND; $nameStart = $phpcsFile->findNext($exclude, ($stackPtr + 1), $stopPoint, true); if ($nameStart === false) { diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc b/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc index 466f07df..fcb3ad05 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc @@ -27,6 +27,9 @@ $class = new class extends SomeClass { /* testFunction */ function functionName() {} +/* testFunctionReturnByRef */ +function & functionNameByRef(); + /* testClass */ abstract class ClassName { /* testMethod */ @@ -34,6 +37,9 @@ abstract class ClassName { /* testAbstractMethod */ abstract protected function abstractMethodName(); + + /* testMethodReturnByRef */ + private function &MethodNameByRef(); } /* testExtendedClass */ diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php index e8a5cb37..95aa9981 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php @@ -133,6 +133,10 @@ public function dataGetDeclarationName() '/* testFunction */', 'functionName', ], + 'function-return-by-reference' => [ + '/* testFunctionReturnByRef */', + 'functionNameByRef', + ], 'class' => [ '/* testClass */', 'ClassName', @@ -145,6 +149,10 @@ public function dataGetDeclarationName() '/* testAbstractMethod */', 'abstractMethodName', ], + 'method-return-by-reference' => [ + '/* testMethodReturnByRef */', + 'MethodNameByRef', + ], 'extended-class' => [ '/* testExtendedClass */', 'ExtendedClass', From 49324bbabb37cf8f90e4ccd42948b09a98ccc230 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 1 May 2020 02:35:26 +0200 Subject: [PATCH 40/79] Namespaces::getType(): improve detection of namespace keyword as operator When the `namespace` keyword is used in the global namespace, it is less easy to determine with 100% certainty whether it used for a declaration or as an operator, especially when taking into account potential coding errors, such as the use of reserved keywords in the namespace name and/or a leading backslash used in a namespace declaration. This PR hardens the code and will more often correctly detect whether the namespace keyword is used as an operator when used in the global namespace. Includes unit tests. --- PHPCSUtils/Utils/Namespaces.php | 26 ++++++++++++++++-- Tests/Utils/Namespaces/NamespaceTypeTest.inc | 19 ++++++++++--- Tests/Utils/Namespaces/NamespaceTypeTest.php | 28 ++++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/PHPCSUtils/Utils/Namespaces.php b/PHPCSUtils/Utils/Namespaces.php index 68009e3a..34b0d27c 100644 --- a/PHPCSUtils/Utils/Namespaces.php +++ b/PHPCSUtils/Utils/Namespaces.php @@ -14,6 +14,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCFile; +use PHPCSUtils\BackCompat\BCTokens; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Conditions; use PHPCSUtils\Utils\GetTokensAsString; @@ -46,6 +47,26 @@ class Namespaces */ public static function getType(File $phpcsFile, $stackPtr) { + static $findAfter; + + if (isset($findAfter) === false) { + /* + * Set up array of tokens which can only be used in combination with the keyword as operator + * and which cannot be confused with other keywords. + */ + $findAfter = BCTokens::assignmentTokens() + + BCTokens::comparisonTokens() + + BCTokens::operators() + + Tokens::$castTokens + + Tokens::$blockOpeners + + Collections::$incrementDecrementOperators + + Collections::$objectOperators; + + $findAfter[\T_OPEN_CURLY_BRACKET] = \T_OPEN_CURLY_BRACKET; + $findAfter[\T_OPEN_SQUARE_BRACKET] = \T_OPEN_SQUARE_BRACKET; + $findAfter[\T_OPEN_SHORT_ARRAY] = \T_OPEN_SHORT_ARRAY; + } + $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]) === false || $tokens[$stackPtr]['code'] !== \T_NAMESPACE) { @@ -80,8 +101,9 @@ public static function getType(File $phpcsFile, $stackPtr) return 'declaration'; } - if ($start !== $stackPtr - && $tokens[$next]['code'] === \T_NS_SEPARATOR + if ($tokens[$next]['code'] === \T_NS_SEPARATOR + && ($start !== $stackPtr + || $phpcsFile->findNext($findAfter, ($stackPtr + 1), null, false, null, true) !== false) ) { return 'operator'; } diff --git a/Tests/Utils/Namespaces/NamespaceTypeTest.inc b/Tests/Utils/Namespaces/NamespaceTypeTest.inc index f2927f8e..99e13c1a 100644 --- a/Tests/Utils/Namespaces/NamespaceTypeTest.inc +++ b/Tests/Utils/Namespaces/NamespaceTypeTest.inc @@ -28,11 +28,24 @@ function closedScope() { echo namespace\ClassName::method(); while( true ) { - /* testNamespaceOperatorInParentheses */ - function_call( namespace\ClassName::$property ); - } + /* testNamespaceOperatorInParentheses */ + function_call( namespace\ClassName::$property ); + } } +/* testNamespaceOperatorGlobalNamespaceStartOfStatementFunctionCall */ +namespace\functionCall(); + +/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken1 */ +namespace\CONSTANT === 'test' or die(); + +/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken2 */ +namespace\ClassName::$property++; + +/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken3 */ +namespace\CONSTANT['key']; + + /* testParseErrorScopedNamespaceDeclaration */ function testScope() { namespace My\Namespace; diff --git a/Tests/Utils/Namespaces/NamespaceTypeTest.php b/Tests/Utils/Namespaces/NamespaceTypeTest.php index 23dffcdf..5eb39394 100644 --- a/Tests/Utils/Namespaces/NamespaceTypeTest.php +++ b/Tests/Utils/Namespaces/NamespaceTypeTest.php @@ -156,6 +156,34 @@ public function dataNamespaceType() 'operator' => true, ], ], + 'namespace-operator-global-namespace-start-of-statement-function-call' => [ + '/* testNamespaceOperatorGlobalNamespaceStartOfStatementFunctionCall */', + [ + 'declaration' => false, + 'operator' => true, + ], + ], + 'namespace-operator-global-namespace-start-of-statement-with-non-confusing-token-1' => [ + '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken1 */', + [ + 'declaration' => false, + 'operator' => true, + ], + ], + 'namespace-operator-global-namespace-start-of-statement-with-non-confusing-token-2' => [ + '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken2 */', + [ + 'declaration' => false, + 'operator' => true, + ], + ], + 'namespace-operator-global-namespace-start-of-statement-with-non-confusing-token-3' => [ + '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken3 */', + [ + 'declaration' => false, + 'operator' => true, + ], + ], 'parse-error-scoped-namespace-declaration' => [ '/* testParseErrorScopedNamespaceDeclaration */', [ From c4692ca36664ad12c878bbb2dbf622b7a3867dc6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 May 2020 17:34:28 +0200 Subject: [PATCH 41/79] Tokens\Collections: add two new methods * `functionDeclarationTokens()` returning the tokens which can represent a keyword which starts a function declaration. * `functionDeclarationTokensBC()` same, but allowing for BC down to PHPCS 2.6.0 (arrow functions). Includes unit tests. --- PHPCSUtils/Tokens/Collections.php | 66 +++++++++++++++++++ .../FunctionDeclarationTokensBCTest.php | 51 ++++++++++++++ .../FunctionDeclarationTokensTest.php | 50 ++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 Tests/Tokens/Collections/FunctionDeclarationTokensBCTest.php create mode 100644 Tests/Tokens/Collections/FunctionDeclarationTokensTest.php diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 1df8dcee..d9d0bbe9 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -531,6 +531,72 @@ public static function arrowFunctionTokensBC() return $tokens; } + /** + * Tokens which can represent a keyword which starts a function declaration. + * + * Note: this is a method, not a property as the `T_FN` token may not exist. + * + * Sister-method to the `functionDeclarationTokensBC()` method. + * This method supports PHPCS 3.5.3 and up. + * The `functionDeclarationTokensBC()` method supports PHPCS 2.6.0 and up. + * + * @see \PHPCSUtils\Tokens\Collections::functionDeclarationTokensBC() Related method (PHPCS 2.6.0+). + * + * @since 1.0.0 + * + * @return array => + */ + public static function functionDeclarationTokens() + { + $tokens = [ + \T_FUNCTION => \T_FUNCTION, + \T_CLOSURE => \T_CLOSURE, + ]; + + if (\defined('T_FN') === true) { + // PHP 7.4 or PHPCS 3.5.3+. + $tokens[\T_FN] = \T_FN; + } + + return $tokens; + } + + /** + * Tokens which can represent a keyword which starts a function declaration. + * + * Note: this is a method, not a property as the `T_FN` token may not exist. + * + * Sister-method to the `functionDeclarationTokens()` method. + * The `functionDeclarationTokens()` method supports PHPCS 3.5.3 and up. + * This method supports PHPCS 2.6.0 and up. + * + * Notable difference: + * This method accounts for when the `T_FN` token doesn't exist. + * Note: if this method is used, the `FunctionDeclarations::isArrowFunction() method + * needs to be used on arrow function tokens to verify whether it really is an arrow function + * declaration or not. + * + * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.3.0. + * + * @see \PHPCSUtils\Tokens\Collections::functionDeclarationTokens() Related method (PHPCS 3.5.3+). + * @see \PHPCSUtils\Tokens\FunctionDeclarations::isArrowFunction() Arrow function verification. + * + * @since 1.0.0 + * + * @return array => + */ + public static function functionDeclarationTokensBC() + { + $tokens = [ + \T_FUNCTION => \T_FUNCTION, + \T_CLOSURE => \T_CLOSURE, + ]; + + $tokens += self::arrowFunctionTokensBC(); + + return $tokens; + } + /** * Token types which can be encountered in a parameter type declaration (cross-version). * diff --git a/Tests/Tokens/Collections/FunctionDeclarationTokensBCTest.php b/Tests/Tokens/Collections/FunctionDeclarationTokensBCTest.php new file mode 100644 index 00000000..4a40ecfc --- /dev/null +++ b/Tests/Tokens/Collections/FunctionDeclarationTokensBCTest.php @@ -0,0 +1,51 @@ + \T_FUNCTION, + \T_CLOSURE => \T_CLOSURE, + \T_STRING => \T_STRING, + ]; + + if (\version_compare($version, '3.5.3', '>=') === true + || \version_compare(\PHP_VERSION_ID, '70399', '>=') === true + ) { + $expected[\T_FN] = \T_FN; + } + + $this->assertSame($expected, Collections::functionDeclarationTokensBC()); + } +} diff --git a/Tests/Tokens/Collections/FunctionDeclarationTokensTest.php b/Tests/Tokens/Collections/FunctionDeclarationTokensTest.php new file mode 100644 index 00000000..e5e2c3cd --- /dev/null +++ b/Tests/Tokens/Collections/FunctionDeclarationTokensTest.php @@ -0,0 +1,50 @@ + \T_FUNCTION, + \T_CLOSURE => \T_CLOSURE, + ]; + + if (\version_compare($version, '3.5.3', '>=') === true + || \version_compare(\PHP_VERSION_ID, '70399', '>=') === true + ) { + $expected[\T_FN] = \T_FN; + } + + $this->assertSame($expected, Collections::functionDeclarationTokens()); + } +} From eb061fda8fc22d063aa3c1fda414e046b4f2b9f1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 May 2020 01:15:08 +0200 Subject: [PATCH 42/79] Tokens\Collections::$returnTypeTokens: allow for "static" (PHP 8) As of PHP 8.0, `static` can be used as a return type for function declarations. Ref: https://wiki.php.net/rfc/static_return_type Includes adding a unit test for the `BCFile::getMethodProperties()`/`FunctionDeclarations::getProperties()` methods to safeguard this. Sister-PR to the upstream squizlabs/PHP_CodeSniffer 2952 --- PHPCSUtils/Tokens/Collections.php | 1 + .../BCFile/GetMethodPropertiesTest.inc | 7 ++++++ .../BCFile/GetMethodPropertiesTest.php | 22 +++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index d9d0bbe9..2c5dc19c 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -423,6 +423,7 @@ class Collections \T_CALLABLE => \T_CALLABLE, \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, + \T_STATIC => \T_STATIC, \T_NS_SEPARATOR => \T_NS_SEPARATOR, ]; diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc index f21ecdb3..106d65b1 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc @@ -67,6 +67,13 @@ $result = array_map( $numbers ); +class ReturnMe { + /* testReturnTypeStatic */ + private function myFunction(): static { + return $this; + } +} + /* testNotAFunction */ return true; diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php index 97649bc3..8ad64dc4 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php @@ -433,6 +433,28 @@ public function testArrowFunction() $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } + /** + * Test a function with return type "static". + * + * @return void + */ + public function testReturnTypeStatic() + { + $expected = [ + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => 'static', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0. * From fa703bd8f1d824ce5041e10ac220d9cb5faaf691 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 5 May 2020 23:55:05 +0200 Subject: [PATCH 43/79] Composer: set minimum Composer PHPCS plugin dependency version to `0.4.1` Support for the `installed_paths` being set when the plugin is a requirement of a standard itself, was only added in version `0.4.0` and a pertinent bug in this feature was fixed in `0.4.1`, which effectively makes version `0.4.1` the minimum workable version for both use as a stand-alone standard, as well as when this standard is required as a dependency. Refs: * https://github.com/Dealerdirect/phpcodesniffer-composer-installer/releases/tag/v0.4.0 * https://github.com/Dealerdirect/phpcodesniffer-composer-installer/releases/tag/v0.4.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 978c3960..e077ce88 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "require" : { "php" : ">=5.4", "squizlabs/php_codesniffer" : "^2.6.0 || ^3.1.0 || 4.0.x-dev@dev", - "dealerdirect/phpcodesniffer-composer-installer" : "^0.3 || ^0.4.1 || ^0.5 || ^0.6.2" + "dealerdirect/phpcodesniffer-composer-installer" : "^0.4.1 || ^0.5 || ^0.6.2" }, "require-dev" : { "php-parallel-lint/php-parallel-lint": "^1.1.0", From 5a0379adb8e18304b25c412348d89867edb2d93f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 12 May 2020 12:49:12 +0200 Subject: [PATCH 44/79] TextStrings::getCompleteTextString(): remove newline at end of heredoc/nowdoc PHP itself does not include the last new line in a heredoc/nowdoc text string when handling it, so this method shouldn't either. Included adjusted unit tests. --- PHPCSUtils/Utils/TextStrings.php | 21 +++++++++++++------ .../TextStrings/GetCompleteTextStringTest.php | 12 ++++------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/PHPCSUtils/Utils/TextStrings.php b/PHPCSUtils/Utils/TextStrings.php index 5b2a46e2..3c314e36 100644 --- a/PHPCSUtils/Utils/TextStrings.php +++ b/PHPCSUtils/Utils/TextStrings.php @@ -62,17 +62,21 @@ public static function getCompleteTextString(File $phpcsFile, $stackPtr, $stripQ } } + $stripNewline = false; + switch ($tokens[$stackPtr]['code']) { case \T_START_HEREDOC: - $stripQuotes = false; - $targetType = \T_HEREDOC; - $current = ($stackPtr + 1); + $stripQuotes = false; + $stripNewline = true; + $targetType = \T_HEREDOC; + $current = ($stackPtr + 1); break; case \T_START_NOWDOC: - $stripQuotes = false; - $targetType = \T_NOWDOC; - $current = ($stackPtr + 1); + $stripQuotes = false; + $stripNewline = true; + $targetType = \T_NOWDOC; + $current = ($stackPtr + 1); break; default: @@ -87,6 +91,11 @@ public static function getCompleteTextString(File $phpcsFile, $stackPtr, $stripQ ++$current; } while (isset($tokens[$current]) && $tokens[$current]['code'] === $targetType); + if ($stripNewline === true) { + // Heredoc/nowdoc: strip the new line at the end of the string to emulate how PHP sees the string. + $string = rtrim($string, "\r\n"); + } + if ($stripQuotes === true) { return self::stripQuotes($string); } diff --git a/Tests/Utils/TextStrings/GetCompleteTextStringTest.php b/Tests/Utils/TextStrings/GetCompleteTextStringTest.php index f31193bd..0a8bc022 100644 --- a/Tests/Utils/TextStrings/GetCompleteTextStringTest.php +++ b/Tests/Utils/TextStrings/GetCompleteTextStringTest.php @@ -156,26 +156,22 @@ public function dataGetCompleteTextString() 'first line second $line third line -fourth line -', +fourth line', 'first line second $line third line -fourth line -', +fourth line', ], 'nowdoc' => [ '/* testNowdocString */', 'first line second line third line -fourth line -', +fourth line', 'first line second line third line -fourth line -', +fourth line', ], 'text-string-at-end-of-file' => [ '/* testTextStringAtEndOfFile */', From 2ffa09baf333435969ede40aa4619af33efdcc89 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 15 May 2020 01:02:38 +0200 Subject: [PATCH 45/79] Helper::setConfigData(): PHPCS 4.x compatibility As of PHPCS 4.x, the `PHP_CodeSniffer\Config::setConfigData()` method is no longer static. Ref: https://github.com/squizlabs/PHP_CodeSniffer/commit/10a89a2c8c33a26466ccb3368a69a5e99549f80e This commit adds a new `$config` parameter to the `Helper::setConfigData()` method which will be a required parameter for PHPCS 4.x. Includes adjusted unit tests. --- PHPCSUtils/BackCompat/Helper.php | 27 ++++++-- Tests/BackCompat/Helper/ConfigDataTest.php | 62 ++++++++++++++++++- .../Helper/GetCommandLineDataTest.php | 20 ++++-- 3 files changed, 95 insertions(+), 14 deletions(-) diff --git a/PHPCSUtils/BackCompat/Helper.php b/PHPCSUtils/BackCompat/Helper.php index 7a122105..aeb0cf5a 100644 --- a/PHPCSUtils/BackCompat/Helper.php +++ b/PHPCSUtils/BackCompat/Helper.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\BackCompat; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Exceptions\RuntimeException; /** * Utility methods to retrieve (configuration) information from PHP_CodeSniffer. @@ -60,21 +61,35 @@ public static function getVersion() * * @since 1.0.0 * - * @param string $key The name of the config value. - * @param string|null $value The value to set. If null, the config entry - * is deleted, reverting it to the default value. - * @param bool $temp Set this config data temporarily for this script run. - * This will not write the config data to the config file. + * @param string $key The name of the config value. + * @param string|null $value The value to set. If null, the config entry + * is deleted, reverting it to the default value. + * @param bool $temp Set this config data temporarily for this script run. + * This will not write the config data to the config file. + * @param \PHP_CodeSniffer\Config $config The PHPCS config object. + * This parameter is required for PHPCS 4.x, optional + * for PHPCS 3.x and not possible to pass for PHPCS 2.x. + * Passing the `$phpcsFile->config` property should work + * in PHPCS 3.x and higher. * * @return bool Whether the setting of the data was successfull. */ - public static function setConfigData($key, $value, $temp = false) + public static function setConfigData($key, $value, $temp = false, $config = null) { if (\method_exists('\PHP_CodeSniffer\Config', 'setConfigData') === false) { // PHPCS 2.x. return \PHP_CodeSniffer::setConfigData($key, $value, $temp); } + if (isset($config) === true) { + // PHPCS 3.x and 4.x. + return $config->setConfigData($key, $value, $temp); + } + + if (version_compare(self::getVersion(), '3.99.99', '>') === true) { + throw new RuntimeException('Passing the $config parameter is required in PHPCS 4.x'); + } + // PHPCS 3.x. return \PHP_CodeSniffer\Config::setConfigData($key, $value, $temp); } diff --git a/Tests/BackCompat/Helper/ConfigDataTest.php b/Tests/BackCompat/Helper/ConfigDataTest.php index f570e0f2..9cd2a74e 100644 --- a/Tests/BackCompat/Helper/ConfigDataTest.php +++ b/Tests/BackCompat/Helper/ConfigDataTest.php @@ -10,6 +10,7 @@ namespace PHPCSUtils\Tests\BackCompat\Helper; +use PHP_CodeSniffer\Config; use PHPCSUtils\BackCompat\Helper; use PHPUnit\Framework\TestCase; @@ -27,12 +28,41 @@ class ConfigDataTest extends TestCase { /** - * Test the getConfigData() and setConfigData() method. + * Test the getConfigData() and setConfigData() method when used in a cross-version compatible manner. * * @return void */ - public function testConfigData() + public function testConfigData34() { + if (version_compare(Helper::getVersion(), '2.99.99', '<=') === true) { + $this->markTestSkipped('Test only applicable to PHPCS > 2.x'); + } + + $config = new Config(); + $original = Helper::getConfigData('arbitrary_name'); + $expected = 'expected'; + + $return = Helper::setConfigData('arbitrary_name', $expected, true, $config); + $this->assertTrue($return); + + $result = Helper::getConfigData('arbitrary_name'); + $this->assertSame($expected, $result); + + // Reset the value after the test. + Helper::setConfigData('arbitrary_name', $original, true, $config); + } + + /** + * Test the getConfigData() and setConfigData() method when used in a non-PHPCS 4.x compatible manner. + * + * @return void + */ + public function testConfigDataPHPCS23() + { + if (version_compare(Helper::getVersion(), '3.99.99', '>') === true) { + $this->markTestSkipped('Test only applicable to PHPCS < 4.x'); + } + $original = Helper::getConfigData('arbitrary_name'); $expected = 'expected'; @@ -43,6 +73,32 @@ public function testConfigData() $this->assertSame($expected, $result); // Reset the value after the test. - $return = Helper::setConfigData('arbitrary_name', $original, true); + Helper::setConfigData('arbitrary_name', $original, true); + } + + /** + * Test the getConfigData() and setConfigData() method when used in a non-PHPCS 4.x compatible manner. + * + * @return void + */ + public function testConfigDataPHPCS4Exception() + { + if (version_compare(Helper::getVersion(), '3.99.99', '<=') === true) { + $this->markTestSkipped('Test only applicable to PHPCS 4.x'); + } + + $msg = 'Passing the $config parameter is required in PHPCS 4.x'; + $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + + if (\method_exists($this, 'expectException')) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($msg); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $msg); + } + + Helper::setConfigData('arbitrary_name', 'test', true); } } diff --git a/Tests/BackCompat/Helper/GetCommandLineDataTest.php b/Tests/BackCompat/Helper/GetCommandLineDataTest.php index 7ce9c868..9c143091 100644 --- a/Tests/BackCompat/Helper/GetCommandLineDataTest.php +++ b/Tests/BackCompat/Helper/GetCommandLineDataTest.php @@ -132,16 +132,21 @@ public function testGetEncodingWithoutPHPCSFile() $expected = \version_compare(static::$phpcsVersion, '2.99.99', '>') ? 'utf-8' : 'iso-8859-1'; $this->assertSame($expected, $result, 'Failed retrieving the default encoding'); - Helper::setConfigData('encoding', 'utf-16', true); + $config = null; + if (isset(self::$phpcsFile->config) === true) { + $config = self::$phpcsFile->config; + } + + Helper::setConfigData('encoding', 'utf-16', true, $config); $result = Helper::getEncoding(); $this->assertSame('utf-16', $result, 'Failed retrieving the custom set encoding'); // Restore defaults before moving to the next test. if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { - Helper::setConfigData('encoding', 'utf-8', true); + Helper::setConfigData('encoding', 'utf-8', true, $config); } else { - Helper::setConfigData('encoding', 'iso-8859-1', true); + Helper::setConfigData('encoding', 'iso-8859-1', true, $config); } } @@ -197,13 +202,18 @@ public function testIgnoreAnnotationsV3SetViaMethod() $this->markTestSkipped('Test only applicable to PHPCS 3.x'); } - Helper::setConfigData('annotations', false, true); + $config = null; + if (isset(self::$phpcsFile->config) === true) { + $config = self::$phpcsFile->config; + } + + Helper::setConfigData('annotations', false, true, $config); $result = Helper::ignoreAnnotations(); $this->assertTrue($result); // Restore defaults before moving to the next test. - Helper::setConfigData('annotations', true, true); + Helper::setConfigData('annotations', true, true, $config); } /** From 6593f61c5e7ad7c582c00903d52284c22af834f1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 May 2020 01:42:00 +0200 Subject: [PATCH 46/79] ControlStructures::getCaughtExceptions(): allow for PHP8 non-capturing catch PHP 8 will introduce non-capturing catch statements. This tiny fix makes sure the method can handle these correctly. Includes unit test. Ref: https://wiki.php.net/rfc/non-capturing_catches --- PHPCSUtils/Utils/ControlStructures.php | 2 +- .../ControlStructures/GetCaughtExceptionsTest.inc | 3 +++ .../ControlStructures/GetCaughtExceptionsTest.php | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/Utils/ControlStructures.php b/PHPCSUtils/Utils/ControlStructures.php index 892987db..f2a53a9e 100644 --- a/PHPCSUtils/Utils/ControlStructures.php +++ b/PHPCSUtils/Utils/ControlStructures.php @@ -383,7 +383,7 @@ public static function getCaughtExceptions(File $phpcsFile, $stackPtr) $firstToken = null; $lastToken = null; - for ($i = ($opener + 1); $i < $closer; $i++) { + for ($i = ($opener + 1); $i <= $closer; $i++) { if (isset(Tokens::$emptyTokens[$tokens[$i]['code']])) { continue; } diff --git a/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.inc b/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.inc index b1b45855..aee219ad 100644 --- a/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.inc +++ b/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.inc @@ -27,6 +27,9 @@ try { /* testMultiCatchCompoundNames */ } catch (\NS\RuntimeException | My\ParseErrorException | namespace \ AnotherException $e) { +/* testPHP8NonCapturingCatch */ +} catch (RuntimeException | AnotherException) { + /* testLiveCoding */ // Intentional parse error. } catch ( diff --git a/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php b/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php index d52c8074..0c7811a5 100644 --- a/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php +++ b/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php @@ -197,6 +197,21 @@ public function dataGetCaughtExceptions() ], ], ], + 'non-capturing-catch' => [ + 'target' => '/* testPHP8NonCapturingCatch */', + 'expected' => [ + [ + 'type' => 'RuntimeException', + 'type_token' => 3, + 'type_end_token' => 3, + ], + [ + 'type' => 'AnotherException', + 'type_token' => 7, + 'type_end_token' => 7, + ], + ], + ], ]; } } From 8eefd10233ffc963b6b8ca259a8d3c00b37cf200 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 28 May 2020 21:03:13 +0200 Subject: [PATCH 47/79] BCTokens: change property visibility :warning: Breaking Change :warning: The `$phpcsCommentTokensTypes`, `$ooScopeTokens`, `$textStringTokens` properties all had `protected` visibility. These properties are not intended to be used directly by implementing standards and with them being `protected`, they would only be accessible if the implementing standard would extend the `BCTokens` class, which doesn't really make sense as it only contains static method anyhow. So to make the intention clearer, these have now all be reclassified as `private` properties. --- PHPCSUtils/BackCompat/BCTokens.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCTokens.php b/PHPCSUtils/BackCompat/BCTokens.php index 26d2829a..10e5e9a4 100644 --- a/PHPCSUtils/BackCompat/BCTokens.php +++ b/PHPCSUtils/BackCompat/BCTokens.php @@ -51,7 +51,7 @@ class BCTokens * * @var string[] */ - protected static $phpcsCommentTokensTypes = [ + private static $phpcsCommentTokensTypes = [ 'T_PHPCS_ENABLE', 'T_PHPCS_DISABLE', 'T_PHPCS_SET', @@ -66,7 +66,7 @@ class BCTokens * * @var array => */ - protected static $ooScopeTokens = [ + private static $ooScopeTokens = [ \T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE, @@ -80,7 +80,7 @@ class BCTokens * * @var array => */ - protected static $textStringTokens = [ + private static $textStringTokens = [ \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING, \T_INLINE_HTML => \T_INLINE_HTML, From e4a3ccbc63e267c6feb61dd8213979c4a9d63752 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 18 Mar 2020 06:58:27 +0100 Subject: [PATCH 48/79] Various minor tweaks --- PHPCSUtils/BackCompat/Helper.php | 6 +++--- PHPCSUtils/Utils/NamingConventions.php | 2 +- PHPCSUtils/Utils/Numbers.php | 2 +- PHPCSUtils/Utils/TextStrings.php | 2 +- Tests/BackCompat/Helper/ConfigDataTest.php | 6 +++--- Tests/BackCompat/Helper/GetVersionTest.php | 2 +- Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php | 4 ++-- Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php | 4 ++-- Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/PHPCSUtils/BackCompat/Helper.php b/PHPCSUtils/BackCompat/Helper.php index aeb0cf5a..4ae37784 100644 --- a/PHPCSUtils/BackCompat/Helper.php +++ b/PHPCSUtils/BackCompat/Helper.php @@ -10,8 +10,8 @@ namespace PHPCSUtils\BackCompat; -use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Exceptions\RuntimeException; +use PHP_CodeSniffer\Files\File; /** * Utility methods to retrieve (configuration) information from PHP_CodeSniffer. @@ -86,7 +86,7 @@ public static function setConfigData($key, $value, $temp = false, $config = null return $config->setConfigData($key, $value, $temp); } - if (version_compare(self::getVersion(), '3.99.99', '>') === true) { + if (\version_compare(self::getVersion(), '3.99.99', '>') === true) { throw new RuntimeException('Passing the $config parameter is required in PHPCS 4.x'); } @@ -183,7 +183,7 @@ public static function getEncoding(File $phpcsFile = null) if (isset($default) === false) { $default = 'utf-8'; - if (version_compare(self::getVersion(), '2.99.99', '<=') === true) { + if (\version_compare(self::getVersion(), '2.99.99', '<=') === true) { // In PHPCS 2.x, the default encoding is `iso-8859-1`. $default = 'iso-8859-1'; } diff --git a/PHPCSUtils/Utils/NamingConventions.php b/PHPCSUtils/Utils/NamingConventions.php index 385ba21c..4eefa224 100644 --- a/PHPCSUtils/Utils/NamingConventions.php +++ b/PHPCSUtils/Utils/NamingConventions.php @@ -66,7 +66,7 @@ class NamingConventions */ public static function isValidIdentifierName($name) { - if (is_string($name) === false || $name === '' || \strpos($name, ' ') !== false) { + if (\is_string($name) === false || $name === '' || \strpos($name, ' ') !== false) { return false; } diff --git a/PHPCSUtils/Utils/Numbers.php b/PHPCSUtils/Utils/Numbers.php index c05788f9..662e0072 100644 --- a/PHPCSUtils/Utils/Numbers.php +++ b/PHPCSUtils/Utils/Numbers.php @@ -254,7 +254,7 @@ public static function getCompleteNumber(File $phpcsFile, $stackPtr) while (isset($tokens[++$next], self::$numericLiteralAcceptedTokens[$tokens[$next]['code']]) === true) { if ($tokens[$next]['code'] === \T_STRING - && \preg_match($regex, $tokens[$next]['content'], $matches) !== 1 + && \preg_match($regex, $tokens[$next]['content']) !== 1 ) { break; } diff --git a/PHPCSUtils/Utils/TextStrings.php b/PHPCSUtils/Utils/TextStrings.php index 3c314e36..87c5b45b 100644 --- a/PHPCSUtils/Utils/TextStrings.php +++ b/PHPCSUtils/Utils/TextStrings.php @@ -93,7 +93,7 @@ public static function getCompleteTextString(File $phpcsFile, $stackPtr, $stripQ if ($stripNewline === true) { // Heredoc/nowdoc: strip the new line at the end of the string to emulate how PHP sees the string. - $string = rtrim($string, "\r\n"); + $string = \rtrim($string, "\r\n"); } if ($stripQuotes === true) { diff --git a/Tests/BackCompat/Helper/ConfigDataTest.php b/Tests/BackCompat/Helper/ConfigDataTest.php index 9cd2a74e..5677d454 100644 --- a/Tests/BackCompat/Helper/ConfigDataTest.php +++ b/Tests/BackCompat/Helper/ConfigDataTest.php @@ -34,7 +34,7 @@ class ConfigDataTest extends TestCase */ public function testConfigData34() { - if (version_compare(Helper::getVersion(), '2.99.99', '<=') === true) { + if (\version_compare(Helper::getVersion(), '2.99.99', '<=') === true) { $this->markTestSkipped('Test only applicable to PHPCS > 2.x'); } @@ -59,7 +59,7 @@ public function testConfigData34() */ public function testConfigDataPHPCS23() { - if (version_compare(Helper::getVersion(), '3.99.99', '>') === true) { + if (\version_compare(Helper::getVersion(), '3.99.99', '>') === true) { $this->markTestSkipped('Test only applicable to PHPCS < 4.x'); } @@ -83,7 +83,7 @@ public function testConfigDataPHPCS23() */ public function testConfigDataPHPCS4Exception() { - if (version_compare(Helper::getVersion(), '3.99.99', '<=') === true) { + if (\version_compare(Helper::getVersion(), '3.99.99', '<=') === true) { $this->markTestSkipped('Test only applicable to PHPCS 4.x'); } diff --git a/Tests/BackCompat/Helper/GetVersionTest.php b/Tests/BackCompat/Helper/GetVersionTest.php index c00df963..da6862aa 100644 --- a/Tests/BackCompat/Helper/GetVersionTest.php +++ b/Tests/BackCompat/Helper/GetVersionTest.php @@ -32,7 +32,7 @@ class GetVersionTest extends TestCase * * @var string */ - const DEVMASTER = '3.5.4'; + const DEVMASTER = '3.5.6'; /** * Test the method. diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php index 47e41207..1fd02d75 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php @@ -53,7 +53,7 @@ class SpacesFixerNoSpaceTest extends UtilityMethodTestCase * * @var string */ - const CODE = 'PHPCSUtils.SpacerFixer.Test.Found'; + const CODE = 'PHPCSUtils.SpacesFixer.Test.Found'; /** * Dummy metric name to use for the test. @@ -88,7 +88,7 @@ class SpacesFixerNoSpaceTest extends UtilityMethodTestCase * * @var array */ - protected static $selectedSniff = ['PHPCSUtils.SpacerFixer.Test']; + protected static $selectedSniff = ['PHPCSUtils.SpacesFixer.Test']; /** * Initialize PHPCS & tokenize the test case file. diff --git a/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php b/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php index 12329cf3..a04858b3 100644 --- a/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php +++ b/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php @@ -53,7 +53,7 @@ class TrailingCommentHandlingTest extends UtilityMethodTestCase * * @var string */ - const CODE = 'PHPCSUtils.SpacerFixer.Test.Found'; + const CODE = 'PHPCSUtils.SpacesFixer.Test.Found'; /** * Dummy metric name to use for the test. @@ -67,7 +67,7 @@ class TrailingCommentHandlingTest extends UtilityMethodTestCase * * @var array */ - protected static $selectedSniff = ['PHPCSUtils.SpacerFixer.Test']; + protected static $selectedSniff = ['PHPCSUtils.SpacesFixer.Test']; /** * Test that violations are correctly reported. diff --git a/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php b/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php index c0c0767c..2d45f09c 100644 --- a/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php +++ b/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php @@ -44,6 +44,6 @@ public function testArrowFunctionTokensBC() $expected[\T_FN] = \T_FN; } - $this->assertSame($expected, Collections::ArrowFunctionTokensBC()); + $this->assertSame($expected, Collections::arrowFunctionTokensBC()); } } From a983cd659a150371989a72b9e734f458b8af5095 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 30 May 2020 20:25:05 +0200 Subject: [PATCH 49/79] Docs website: convert to using Jekyll The initial homepage was set up in HTML as it (temporarily) had to be hosted elsewhere. The intention was always to use GH Pages for hosting the site and to use Jekyll to generate the homepage content based on the `README` of the project. To allow for that to happen, some changes were needed which are contained in this PR. 1. Add a `Gemfile` pointing enabling the GH Pages gem, including enabling a new GH flavoured markdown interpreter. 2. Add a `_config.yml` file. - Enable the new GH flavoured markdown interpreter. - Set the theme. - Enable a variety of plugins. - Add the `repository` and `github` keys to allow for local testing. - Add a range of keys with information for the theme and SEO plugin. - Explicitly exclude a number of files from being included in the generated site. 3. The initial homepage was already based on the GH Pages Jekyll `minimal` theme. To allow the site to take full advantage of that, most copied in files from the theme can be removed as they will automatically be added now, as well as updated when needed. 4. A `.gitignore` file is put in place to ignore the typical Gem related files as well as the Jekyll output in `_site` from being committed. 5. A `.nojekyll` file is put in place in the `phpdoc` subdirectory to prevent Jekyll trying to parse the PHPDocumentor generated documentation. 6. The CSS customizations have been moved from the (theme generated) `style.css` file to `style.scss`. This makes it crystal clear what the customizations are and what comes from the theme. The Jekyll build will combine the CSS into one `style.css` file for the generated site. 7. The theme `_default.html` layout has been copied in from the theme and minimal adjustments have been made to: - Overrule the syntax highlighting styles by setting a separate stylesheet for those. - Add the "Read the docs" button in the left column. - Add the "Install using Composer" section in the left column. - Add the Twitter share button in the left column. 8. Add a `robots.txt` file pointing to the plugin generated XML sitemap fo search engines. 9. Replace the `index.html` file with an `index.md` file which contains the same basic contents as the `README.md` file. Includes making a few small adjustments to the `README.md` file. This should now allow for doing a plain copy & paste of the README content into the `docs/index.md` just before each release to update the homepage to the latest content. Note: there is a "readme to index" plugin available, but that does not allow for the readme and the docs being in different directories. A [feature request](https://github.com/benbalter/jekyll-readme-index/issues/19) to allow for that has been opened. Once this is merged, to update the website means: 1. Running PHPDocumentor. 2. Copy & pasting the content from the `README.md` file to `docs/index.md` (and double-checking the few remaining differences are intact). 3. Once those changes have been merged and `develop` has been merged into `master`, the website should be updated. The website can be viewed locally by running: ```bash bundle update bundle exec jekyll serve ``` and then visiting http://localhost:4000/ to see the result. --- README.md | 10 +- docs/.gitignore | 4 + docs/Gemfile | 5 + docs/_config.yml | 36 ++ docs/_layouts/default.html | 79 ++++ docs/assets/css/style.css | 322 ----------------- docs/assets/css/style.scss | 125 +++++++ .../fonts/Noto-Sans-700/Noto-Sans-700.eot | Bin 16716 -> 0 bytes .../fonts/Noto-Sans-700/Noto-Sans-700.svg | 336 ----------------- .../fonts/Noto-Sans-700/Noto-Sans-700.ttf | Bin 29704 -> 0 bytes .../fonts/Noto-Sans-700/Noto-Sans-700.woff | Bin 12632 -> 0 bytes .../fonts/Noto-Sans-700/Noto-Sans-700.woff2 | Bin 9724 -> 0 bytes .../Noto-Sans-700italic.eot | Bin 16849 -> 0 bytes .../Noto-Sans-700italic.svg | 334 ----------------- .../Noto-Sans-700italic.ttf | Bin 28932 -> 0 bytes .../Noto-Sans-700italic.woff | Bin 12612 -> 0 bytes .../Noto-Sans-700italic.woff2 | Bin 9612 -> 0 bytes .../Noto-Sans-italic/Noto-Sans-italic.eot | Bin 15864 -> 0 bytes .../Noto-Sans-italic/Noto-Sans-italic.svg | 337 ------------------ .../Noto-Sans-italic/Noto-Sans-italic.ttf | Bin 26644 -> 0 bytes .../Noto-Sans-italic/Noto-Sans-italic.woff | Bin 12536 -> 0 bytes .../Noto-Sans-italic/Noto-Sans-italic.woff2 | Bin 9572 -> 0 bytes .../Noto-Sans-regular/Noto-Sans-regular.eot | Bin 16639 -> 0 bytes .../Noto-Sans-regular/Noto-Sans-regular.svg | 335 ----------------- .../Noto-Sans-regular/Noto-Sans-regular.ttf | Bin 29288 -> 0 bytes .../Noto-Sans-regular/Noto-Sans-regular.woff | Bin 12840 -> 0 bytes .../Noto-Sans-regular/Noto-Sans-regular.woff2 | Bin 9932 -> 0 bytes docs/assets/js/scale.fix.js | 27 -- docs/index.html | 204 ----------- docs/index.md | 146 ++++++++ docs/phpdoc/.nojekyll | 0 docs/robots.txt | 5 + 32 files changed, 408 insertions(+), 1897 deletions(-) create mode 100644 docs/.gitignore create mode 100644 docs/Gemfile create mode 100644 docs/_config.yml create mode 100644 docs/_layouts/default.html delete mode 100644 docs/assets/css/style.css create mode 100644 docs/assets/css/style.scss delete mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.eot delete mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.svg delete mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.ttf delete mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.woff delete mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.woff2 delete mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.eot delete mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.svg delete mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.ttf delete mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff delete mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff2 delete mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.eot delete mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.svg delete mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.ttf delete mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff delete mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff2 delete mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.eot delete mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.svg delete mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.ttf delete mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff delete mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff2 delete mode 100644 docs/assets/js/scale.fix.js delete mode 100644 docs/index.html create mode 100644 docs/index.md create mode 100644 docs/phpdoc/.nojekyll create mode 100644 docs/robots.txt diff --git a/README.md b/README.md index dec13a48..7a55f8dc 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,12 @@ PHPCSUtils: A suite of utility functions for use with PHP_CodeSniffer Features ------------------------------------------- -This is a set of utilities to aid developers of sniffs for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). +[PHPCSUtils](https://github.com/PHPCSStandards/PHPCSUtils) is a set of utilities to aid developers of sniffs for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). This package offers the following features: +
+ ### Use the latest version of PHP_CodeSniffer native utility functions. Normally to use the latest version of PHP_CodeSniffer native utility functions, you would have to raise the minimum requirements of your external PHPCS standard. @@ -71,6 +73,7 @@ A `PHPCS23Utils` standard which allows sniffs to work in both PHPCS 2.x and 3.x, To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the [extensive documentation](https://phpcsutils.com/). +
Minimum Requirements ------------------------------------------- @@ -216,6 +219,8 @@ Once that's done, you will need to make a small tweak to your own dev environmen Frequently Asked Questions ------- +
+ #### Q: How does this all work without an external standard needing to register an autoloader? A: As PHPCSUtils is registered with PHPCS as an external standard and PHPCSUtils complies with the naming requirements of PHPCS, the PHPCS native autoloader will automatically take care of loading the classes you use from PHPCSUtils. @@ -232,6 +237,7 @@ A: The backfill for PHP 7.4 numeric literals with underscores in PHP_CodeSniffer The backfill was fixed in PHP_CodeSniffer 3.5.4. +
Contributing ------- @@ -241,4 +247,4 @@ If you are unsure whether the changes you are proposing would be welcome, please License ------- -This code is released under the GNU Lesser General Public License (LGPLv3). For more information, visit http://www.gnu.org/copyleft/lesser.html +This code is released under the [GNU Lesser General Public License (LGPLv3)](http://www.gnu.org/copyleft/lesser.html). diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..a5a45a8b --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,4 @@ +_site/* +Gemfile.lock +.sass-cache +*.gem diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 00000000..b78190ab --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,5 @@ +source 'https://rubygems.org' + +gem "github-pages", group: :jekyll_plugins do + gem 'jekyll-commonmark-ghpages' +end \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 00000000..285eb8e2 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,36 @@ +baseurl: / +highlighter: rouge +markdown: CommonMarkGhPages +encoding: UTF-8 +theme: jekyll-theme-minimal +repository: "PHPCSStandards/PHPCSUtils" +github: [metadata] +url: "https://phpcsutils.com" + +plugins: + - jekyll-github-metadata + - jemoji + - jekyll-mentions + - jekyll-seo-tag + - jekyll-sitemap + +phpcsutils: + packagist: phpcsstandards/phpcsutils + +# Theme info. +title: PHPCSUtils +description: "A suite of utility functions for use with PHP_CodeSniffer." +logo: +show_downloads: false +google_analytics: + +# SEO info. +tagline: "PHPCSUtils: A suite of utility functions for use with PHP_CodeSniffer." +twitter: + username: jrf_nl + card: summary + hashtags: PHPCSUtils +author: + twitter: jrf_nl + +exclude: ['CNAME', '.gitignore', 'Gemfile', '*.bak', '*.orig'] diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 00000000..e9d910d8 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,79 @@ + + + + + + + +{% seo %} + + + + + +
+
+

{{ site.title | default: site.github.repository_name }}

+ + {% if site.logo %} + Logo + {% endif %} + +

{{ site.description | default: site.github.project_tagline }}

+ + {% if site.github.is_project_page %} +

Visit the Project on GitHub {{ site.github.repository_nwo }}

+ {% endif %} + +

Read the Documentation

+ +
+ Install using Composer:
+
composer require {{ site.phpcsutils.packagist }}
+
+ + {% if site.show_downloads %} + + {% endif %} + +

+ +
+ + +
+ + {{ content }} + +
+ +
+ + + {% if site.google_analytics %} + + {% endif %} + + + + diff --git a/docs/assets/css/style.css b/docs/assets/css/style.css deleted file mode 100644 index bbda1925..00000000 --- a/docs/assets/css/style.css +++ /dev/null @@ -1,322 +0,0 @@ -@font-face { - font-family:'Noto Sans'; - font-weight:400; - font-style:normal; - src:url("../fonts/Noto-Sans-regular/Noto-Sans-regular.eot"); - src:url("../fonts/Noto-Sans-regular/Noto-Sans-regular.eot?#iefix") format("embedded-opentype"),local("Noto Sans"),local("Noto-Sans-regular"),url("../fonts/Noto-Sans-regular/Noto-Sans-regular.woff2") format("woff2"),url("../fonts/Noto-Sans-regular/Noto-Sans-regular.woff") format("woff"),url("../fonts/Noto-Sans-regular/Noto-Sans-regular.ttf") format("truetype"),url("../fonts/Noto-Sans-regular/Noto-Sans-regular.svg#NotoSans") format("svg"); -} -@font-face { - font-family:'Noto Sans'; - font-weight:700; - font-style:normal; - src:url("../fonts/Noto-Sans-700/Noto-Sans-700.eot"); - src:url("../fonts/Noto-Sans-700/Noto-Sans-700.eot?#iefix") format("embedded-opentype"),local("Noto Sans Bold"),local("Noto-Sans-700"),url("../fonts/Noto-Sans-700/Noto-Sans-700.woff2") format("woff2"),url("../fonts/Noto-Sans-700/Noto-Sans-700.woff") format("woff"),url("../fonts/Noto-Sans-700/Noto-Sans-700.ttf") format("truetype"),url("../fonts/Noto-Sans-700/Noto-Sans-700.svg#NotoSans") format("svg"); -} -@font-face { - font-family:'Noto Sans'; - font-weight:400; - font-style:italic; - src:url("../fonts/Noto-Sans-italic/Noto-Sans-italic.eot"); - src:url("../fonts/Noto-Sans-italic/Noto-Sans-italic.eot?#iefix") format("embedded-opentype"),local("Noto Sans Italic"),local("Noto-Sans-italic"),url("../fonts/Noto-Sans-italic/Noto-Sans-italic.woff2") format("woff2"),url("../fonts/Noto-Sans-italic/Noto-Sans-italic.woff") format("woff"),url("../fonts/Noto-Sans-italic/Noto-Sans-italic.ttf") format("truetype"),url("../fonts/Noto-Sans-italic/Noto-Sans-italic.svg#NotoSans") format("svg"); -} -@font-face { - font-family:'Noto Sans'; - font-weight:700; - font-style:italic; - src:url("../fonts/Noto-Sans-700italic/Noto-Sans-700italic.eot"); - src:url("../fonts/Noto-Sans-700italic/Noto-Sans-700italic.eot?#iefix") format("embedded-opentype"),local("Noto Sans Bold Italic"),local("Noto-Sans-700italic"),url("../fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff2") format("woff2"),url("../fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff") format("woff"),url("../fonts/Noto-Sans-700italic/Noto-Sans-700italic.ttf") format("truetype"),url("../fonts/Noto-Sans-700italic/Noto-Sans-700italic.svg#NotoSans") format("svg"); -} -.highlight table td { - padding:5px; -} -.highlight table pre { - margin:0; -} - -body { - background-color:#fff; - padding:50px; - font:14px/1.5 "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; - color:#727272; - font-weight:400; -} -h1, h2, h3, h4, h5, h6 { - color:#222; - margin:0 0 20px; -} -p, ul, ol, table, pre, dl { - margin:0 0 15px; -} -h1, h2, h3 { - line-height:1.1; -} -h1 { - font-size:28px; - margin-top: 1.5em; -} -header h1, h1#header-1 { - margin-top: 0em; -} -h2 { - color:#393939; - font-size: 18px -} -h3 { - font-size: - 14px; - margin-top: 1.5em; -} -h3, h4, h5, h6 { - color:#494949; -} -a { - color:#267CB9; - text-decoration:none; -} -a:hover, a:focus { - color:#069; - font-weight:bold; -} -a small { - font-size:11px; - color:#777; - margin-top:-0.3em; - display:block; -} -a:hover small { - color:#777; -} -.wrapper{ - width:100%; - margin:0 auto; -} -blockquote{ - border-left:2px solid #e5e5e5; - border-right:2px solid #e5e5e5; - margin:0 20px 0 10px; - padding:0 10px 0 20px; - font-style:italic; -} -blockquote p { - margin:2px 0 8px; -} -code, pre { - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal, Consolas, Liberation Mono, DejaVu Sans Mono, Courier New, monospace; - color:#333; -} -span code { - background:#f8f8f8; - display:inline-block; -} -pre { - padding:8px 15px; - background:#f8f8f8; - border-radius:5px; - border:1px solid #e5e5e5; - overflow-x:auto; -} -table{ - width:100%; - border-collapse:collapse; -} -th, td { - text-align:left; - padding:5px 10px; - border-bottom:1px solid #e5e5e5; -} -dt { - color:#444; - font-weight:700; -} -dd p { - margin:2px 0 8px; -} -th { - color:#444; -} -img { - max-width:100%; -} -header { - width:28%; - float:left; - position:fixed; - -webkit-font-smoothing:subpixel-antialiased; -} - -.install pre.highlight { - padding: 6px 10px; - text-align: center; - font-size: 89%; -} -.docs { - box-shadow:inset 0px 1px 0px 0px #97c4fe; - background:linear-gradient(to bottom, #3d94f6 5%, #1e62d0 100%); - background-color:#267CB9; - border-radius:6px; - border:1px solid #337fed; - display:inline-block; - cursor:pointer; - color:#ffffff; - font-family:Arial; - font-size:15px; - font-weight:bold; - padding:8px 24px; - text-decoration:none; - text-shadow:0px 1px 0px #1570cd; -} -.docs:hover { - background:linear-gradient(to bottom, #1e62d0 5%, #3d94f6 100%); - background-color:#1e62d0; -} -.docs:active { - position:relative; - top:1px; -} -.docs a { - color: #ffffff; -} - -ul.downloads { - list-style:none; - height:40px; - padding:0; - background:#f4f4f4; - border-radius:5px; - border:1px solid #e0e0e0; - width:270px; -} -.downloads li { - width:89px; - float:left; - border-right:1px solid #e0e0e0; - height:40px; -} -.downloads li:first-child a { - border-radius:5px 0 0 5px; -} -.downloads li:last-child a { - border-radius:0 5px 5px 0; -} -.downloads a { - line-height:1; - font-size:11px; - color:#676767; - display:block; - text-align:center; - padding-top:6px; - height:34px; -} -.downloads a:hover, .downloads a:focus{ - color:#675C5C; - font-weight:bold; -} -.downloads ul a:active { - background-color:#f0f0f0; -} -strong { - color:#222; - font-weight:700; -} -.downloads li+li+li { - border-right:none; - width:89px; -} -.downloads a strong { - font-size:14px; - display:block; - color:#222; -} -#faq span.q, #faq span.a { - color:#267CB9; - font-weight: bold; -} - -.twitter-share-button { - font-size: 70%; - margin: 0; - padding-top: 1em; -} - -section { - width:60%; - float:right; - padding-bottom:50px; - padding-right: 50px; -} -small { - font-size:11px; -} -hr { - border:0; - background:#e5e5e5; - height:1px; - margin:0 0 20px; -} -footer { - width:28%; - float:left; - position:fixed; - bottom:20px; - -webkit-font-smoothing:subpixel-antialiased; -} -@media print, screen and (max-width: 960px) { - div.wrapper { - width:auto; - margin:0; - } - header, section, footer { - float:none; - position:static; - width:auto; - } - header { - padding-right:320px; - } - section { - border:1px solid #e5e5e5; - border-width:1px 0; - padding:20px 0; - margin:0 0 20px; - } - header a small { - display:inline; - } - header ul { - position:absolute; - right:50px; - top:52px; - } -} -@media print, screen and (max-width: 720px) { - body { - word-wrap:break-word; - } - header { - padding:0; - } - header ul, header p.view { - position:static; - } - pre,code { - word-wrap:normal; - } -} -@media print, screen and (max-width: 480px) { - body { - padding:15px; - } - .downloads { - width:99%; - } - .downloads li, .downloads li+li+li { - width:33%; - } -} -@media print { - body { - padding:0.4in; - font-size:12pt; - color:#444; - } -} diff --git a/docs/assets/css/style.scss b/docs/assets/css/style.scss new file mode 100644 index 00000000..acf04ec4 --- /dev/null +++ b/docs/assets/css/style.scss @@ -0,0 +1,125 @@ +--- +--- + +@import "{{ site.theme }}"; + +p, ul, ol, table, pre, #feature-list { + margin:0 0 15px; +} + +h1, h2 { + margin-top: 1.5em; +} +header h1, h2#features { + margin-top: 0em; +} + +h2 { + font-size:28px; +} +h3 { + font-size: 18px; +} +h4 { + font-size: 14px; + margin-top: 1.5em; +} + +blockquote{ + border-left:2px solid #e5e5e5; + border-right:2px solid #e5e5e5; + margin:5px 20px 0 10px; + padding:0 10px 0 20px; +} +blockquote p { + margin:2px 0 8px; +} + +p code { + background:#f8f8f8; + display:inline-block; +} + +/* First section: feature list */ +#feature-list h3 { + font-size: 14px; + color: #444; + margin: 0; + line-height: 1.5; +} + +#feature-list p { + margin:2px 0 8px 40px; +} + +/* Packagist install code sample left column. */ +.install pre.highlight { + padding: 6px 10px; + text-align: center; + font-size: 89%; +} + +/* "Read the docs" button. */ +.docs { + box-shadow:inset 0px 1px 0px 0px #97c4fe; + background:linear-gradient(to bottom, #3d94f6 5%, #1e62d0 100%); + background-color:#267CB9; + border-radius:6px; + border:1px solid #337fed; + display:inline-block; + cursor:pointer; + color:#ffffff; + font-family:Arial; + font-size:15px; + font-weight:bold; + padding:8px 24px; + text-decoration:none; + text-shadow:0px 1px 0px #1570cd; +} +.docs:hover { + background:linear-gradient(to bottom, #1e62d0 5%, #3d94f6 100%); + background-color:#1e62d0; +} +.docs:active { + position:relative; + top:1px; +} +.docs a { + color: #ffffff; +} + +/* FAQ */ +#faq h4 { + font-size: 18px; + line-height: 1.1; + margin-top: 0; +} + +#faq h4::first-letter, #faq h4 + p::first-letter { + color:#267CB9; + font-weight: bold; +} + +.twitter-share-button { + font-size: 70%; + margin: 0; + padding-top: 1em; +} + +/* General space usage/layout */ +.wrapper{ + width:100%; +} + +header { + width:28%; +} +section { + width:60%; + padding-right: 50px; +} + +footer { + width:28%; + bottom:20px; +} diff --git a/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.eot b/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.eot deleted file mode 100644 index 03bf93fec2a7341b1a6192ff0d596b05c1765c93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16716 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 aO1sP&w|8H~0KVcsPu#OW` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.ttf b/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.ttf deleted file mode 100644 index 4599e3ca9af9bf758f3b5d0b79314701f853c371..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29704 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 diff --git a/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.woff2 b/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.woff2 deleted file mode 100644 index 55fc44bcd1257bb772fb9c041cea4ad61381224f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9724 zcmV5XbXcl00bZff>;M28(=%LqIR@i+KVFC zIEe=g*HM({O_lv061Xu0dqe9PMWR$KG{n)I_BJjS4by7c(RdWy@-Cf{UGU%0Ax?xa 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

;(FD;K}#opskZpBcOOtLB-BMn(Ptu%pT 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.ttf b/docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.ttf deleted file mode 100644 index 6640dbeb333be6474e52c20ced829b8c071634cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28932 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 Zg>x^Qd*R#*=U!G_8GbU#&kp(1`UCwMR@49h diff --git a/docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff b/docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff deleted file mode 100644 index 209739eeb0921ce1475ed1f357911ef9faaf0f3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12612 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.ttf b/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.ttf deleted file mode 100644 index 7f75a2d90964f801e9b9f916fc77d0fb46071a09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26644 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 Tox|}wpnWXuG8F&21R?()4C4-I diff --git a/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff b/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff deleted file mode 100644 index 6dce67cede1847a0bb49092dbd2203b1bfac8b91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12536 zcmYj%WmMhH*Y(BSDee@CJH_3dLMiTEptxRKi@UqKyBBwNcX#Jv_vQD0zPyv{nRRx~ zBy+OPWF?dBsw621fB<|JmS+I!f2~B!r~N(ITe|VZnnKiaCwEN@= zKJCAs=%|{g^)NSd{N!L5K5g{>0S7>7ZtZUN$?*dK)O7&B_l{h-`h5#iLlXdi{`%AB z`+vBLv7)i~Bmn>hnopbJ6JOB<5C<)6oZLP+`OoovMh9i^r%%w;+Sd5fk4fiq+(nHM*1>+pIiuoUlPhc86L}p z8Z=@By=FnCM{wV@seUO-@47+Pp;k0f{p&JM#WalFQu*6U=bJUAxif|NLMYF7i7W?= zH7g*G6=uL6HLYeXRt5cUbCQj`t)kuC1G@3c+64=5DE@9FHxamRJIvtcXkw<8J-=^) z&zRyYvEmpC4EA4RiXH}E9xd;)2(YKm|ltO zhB1x=W;v5N)X)Lby&H@}&ciVy7MeJe6@4ILpP0 zs>O>AO^ImL_&cBxmZ%Yau^hUw9IcYjmqiD6gUzh|5s9qnuurR8VA3@{*1YnEUk^v9 zqTnVqf|(B7@4D(rcl1L7#o5#LQi_$5OD>8ZCamGLC_u68Sl!%LBpA;u(3$i5vPpP4 zu>khdiNLth+c@*v=ywF#r$MjBR~7`?&A!Pjmo3|&B~LNV#(UQP3l1`zp>`b6ipcKj zLJ(6$kL6aMe_Z|7OPXy-QPNf9Q)qq!>m+nML(MSeSVhesMCg^urK%Sr$)R?BXv!|< zL)NY-4}RVLuxgIwAjQh7%W8Gq5`1&MgenRF5rgP*vvxLQ?SO3AMFB-;< z=ks}@tT=Wow7W78mwUP^=-&z$htQ%R)J)65IJ@7KHoEK;$UiXVavPc&kwPVv1t}rx zFv@S|?y5BEDa((c)G9azUg@Kj_?!-(*^l_Y?Q>c|`#{71U;ywiX)x@che-dgg_;4F zK?2|*A(3Dpp<$pAAfdMbkYHhe8~C#?`6mDhN{UMVoeBI7ANgJa0Ki8=YLEdSvbUB# zp9``uO`k4g0BAP|V*>*N69ZTySXdHRoM04TtpE{-;axzT8~!QY2Ri{9EIYAr+klgl zh`5NXh@yy0k8F=buDD@jTuj_C7>rEz4{5$0P{IaZrlKJtDgs+Fizz|12d)N_f`#sV zcEP>fU~m`c^`&PKE}g{Mv*xlV0`46xj>KY}&+`g>no%4QP#VeV|2a}90Q_gnr~o)H z7=Y#m5d?(LiCB3711Dc67`mdeK0HK6WU8%}!a9Ju2s6TklH#fK?7HPwC7G3$+H0dr8^#6K+?YdMZ$kwc+9ZGz)3MLtjsW-=iHHE; zC63G(^^(JeY1 z47sdM{u|DFnJD3@CM@<&p+qKulQZ)LKAL$K30kEva(rZ6hoPa?-r*-rqJv+nh5=>% z#Dt&d&i>!-8;}_VYYrc&elv5!)yg^0+g)5{^J$~5m$orofXfEqm4mc!zdKZJ%fZq9$9}NDU{Dc~!sxH4P{II8e-1rH)fQa8b z`rC$D2RweY3|;Ehl7FkB;-n;O>gd!NYKhFo-HQSTU>H6 zpZGU2iuD0p`*$qg{m5C2;j-SbBx|-MU+bg59(GRD+>!|4F z;=sJT=Wym#;j#6B;XQ7QMsWh#i+6+Ah%W<6A+4BFdLH1wz+I8sj?ReLtFaAiH$XrqIqBQ zrcux6)TGyqRCr1;lmCea&l$2Hr}se@KUU_9Pvu1Y7J^9MXwx4Fvb_c6-2CRC35ShBin%!E`RCJIkx;UPDuzQ|GQOofkq; z-4JB(B3%*BT(M zFr`6q$)@hSVf3b5?YnA}mWa&6EeB-zs3X5$dX)-zV);Gd$V1+=eP%Fj# z7bb;WV(iPhj_~4%8!7{fTqS(o{?R(j-sIO;?N`YS2_^o>Ln65fP~GuJ7yFVhs4T7! z>h62c)G##Tdk(6`1;$c@*wYN!M>$YiP>lKU4KroA@k8CzWb~9c+vvR}pWR(U=p4;~ ztcM=JA=)@7A&RSEftU4cH!>{{Hqgn!U=IJdb(4T{kW(MzJ6=HoUUr39;n8@lfyLCS z73$yT^YqMXesp?lQwUf{?h*nDa9H%I?d>hB#fu?%8AUGHKB0h|q}Z;^tkk@lyRVW7 z>zN0=7do!8z#U~N^H|v>K0m&j7`2SuMluDM-(kKxewn0VC9hrABk?n>r~IB!O9Ges zCrbXNf$);-7i=D@%SiF`SyE;w5VN{7&71+uP}J(U#(Z$G^kcCLD- zRq(hEVkc@+5JPs{>Y2<#%N|HXCs~lF#`}mvjE+O zH27vX{ zvX=rB`oMqSL=K4m*Fu<*Y}L{CTkLKvpi}4gU;MG5n7O(0j|n?a3$2BInYQes5F)tr zQi{(8e zz;cg}I^*g@eW(BEWfozI_7P$c6f9u+ouOtm#J>WSpLKBu%KwBq=8KL|sB@~(Xy`cB zmZYY1WLd3hFeFCJ&+Hb+BI2&ajh8q@NiiBwb%)}8IL))6rbyEyvKhsFcx6LJ1 zE}X8BaF-bkz_;i4pL3)LQu2!(@_vsUlOFpz#qJV6VBZA|o-}lY4Aw_n;w=7D22fUV zfCmLQY)>B^HNq}fL&wP^DdZ~2mkrh=%eXKmVa)v7;p(fX^R{N5d|(mK=3aL@-?gy_ zW~yJSn{dB{n9tPGnPLQnOa^9e z;YZmB;{Zk0Drz%sL!X%fOI9mginQMj#Q9fBXBTCL)4Jl^CV~-0nQPSVu2rxhQGO&0Z6EOcEB7_-^M)Ptt?KcaZ~}YPuY1C3!(q4s z2bVpb9YM;_4QTQ2O}Lb8!6aNq20Oe$69JEC96>c)>W&0sTKN!o=* zYG(rMtnRT_&GjqWN)tlwbWq7w_-3^Z?@=Oat_@#5?DJRoXjj{ zLAV%-u$$lq1%DMus)hu^P}()iqu*iMoxW{(Md_&VLJAsFewdH$S%@vcQ*reI!!*aX zX%{Z%fTe>09t;hB6oQG{g@Petuk_}CH5=iDi|`^DZnnI?6VFSx;pyNcK&{f~H+;j!+M2$C+( zTZ?tjBob-FrmE-t`n{lDu?N%3#RZqZ2fkBTo5AP{EnzcpyQnKB_^P*yZf`NU(O*|X zMT?1p3(I$i$?D&`;6r)VY7`53OXD4VTkwR`{LIi?(XRIst!xe9Q~KZ3YfwS5#@Cp1 zI*1d+E`zd2tjIv5Sg&O5S8b6S=6d6g7}Q~kAC66 z@6fn#YbvKCUK>c=vXP|OSe#SrWvyOpj)YFry8-hOq^{jVv>G5}`)a*1?=teEH0+GJ zP!7|FGAM>P_5i|VS=pv)h}Z0+GZ@$=A59D-K1>|E!8CxPW9_~t{g)vkR|EGYXB?}8 z@1Xlm(>j3dJb&YB5k(TL2n#n%1iu~3NN$8+PE=4d2WC_;?x7~zx!7R;=s)a-OqmAa z(^WBu(b=qIkUV9VEPytC& zobUtg{sg*0PyFVx!gT_;b~Wb#+p=G{N`yPPFNOPJ`NqKBsbcC%9Y+SbpZ98O3g}*x zbQK^Q^R4_*7qZf@QQk1`5+%LpA^V=amRpJCp+Xa))CA6NF7`d`36d7@UzHzaf+A~= z6t~w%3{J^d!rqMzHv9N|uzY4SJHCG}qm{+}vf7WEJDZp+X&ZHE*&c+dTYQx*6)m?r zN9cQBAA)V*oUdfCF=)v-cl4vp(2fi;n8`;QHHGq^^|s;pftc03G`y+J_KVlr99)u~ zU75pr^d`}ynnI@Xg`YxI+lAV#uWDiRt|7 zZzP2lRXMZGUwy0%Y{s_rO*A8q_O8FMwcSD&V-eN-a14)Bg(Msyc%7eFxT@w{#$BhpK0F?o55yMWtY#4I&FQJF!hLS)juBrxTqg!i zzA-o6e;hEOud603xX;o?*s>esAyHoqaED=3`0ame zR{e?E?Ae23j%p>(vM*q|jZf{mBq!e+df)3SRw^P9p{W0T6U<;XXjENNEtFhJ-Cr1&ebx1}~;6L{GZCtB8lKta@T5l!qr<6RSv@Pu|iQM!#&J&b7CJ`=KG(4z^RNX z6HmX^aNFhe0n~mbcyf${9dAn7T5nj5;eoPlW91rY)-_I7-tFdG^~LM}s;n@UtJFE{ z{{5v?zvex~dBis-9f-nykI~vJ4a{)_W5gK@QNIk-?r>|rhlOnVq)f=JO!Dk;13Z0` za@t@P;zGkhquA!K*;`-P@c^?%h}&Y~f7Qg``IT7xh$9Eyj~>yG$v^!?-!p!oT+k;V z?f;4St~i2kIX~a+oDABWL{wGE_B|b!LAZF8M}k5#F;WG0uCFiC^JXGUDFIvC$-c^C zK`8~UwS$T_7)7X`%WW(N^WUWhpC5x@N4F-vVJS{l-y3%mUT;{Zxxd2rbV=|9AFb+K zy*cnF&&;jko@v0sjfLMq897^B^H3U!Hn0+osYR>GVsLQF=j?F}P<;ZqYI+Z_3 z7fbFcck|lb^;%AEYKQEsTxlzZzAk6Vi6<7)>w->d5*Xy!AnribNoA2Om>O)LrAwt; zL>LGzkq&=c#0HnY%*qGnan{JLN8?N<}TSXs-s$9>KY1lKnwwiSIEVL-o~NLgrbWTWtORZSgZ)o{kkF~s)E)PEcBiR` z*2gNLRQj1YpN&3#Tn!DaX)Cdvz@P zk=Ps2XUDzP+hl^ed>t7JF9B&8JDM2&XR8-Kxk!_9h~=O9k<<=xDs%;5@Ho5kaQ!mp zs;BB=$iR8Q%ZyUV7#N$biV{_-0hW0ORu!0 zotGY(L|%yC&WnCe)S!*z9q$vji7Y(##lqRDdC%8RUhF&26E@b=3xf zs&PJsT!-(E=mbB>D1<3yio;D4Y0`0?VjkZWCSAMVDoRv8EmpV2Yx$lD8{F0qpyVcF z1qzABXpB5Zcmx!B`N$C-WIt9`kPo*cCr?$)e^?1Q`J2&T{In#oy7V=}mVaq8_Q@Py zk(b8qqxbIoNgo^7G~ zbSt_TS7;6pn`kQ&y%9k;5TQ#G1xaosiDB8c+NKF9K$)lpEu|=3MlFk4PQ&if4ZLh& zBn|^JA%d^TKdb)2k%Tm>GwJxX)jJHbsYbUx-vi~HGSnUd`bPZ*Dl(J<2=c23!a;z_>D${C9jIBn<}^~l;xCQCftp%4Z+G> zkHNbS3UtqNj_@%Q0}4U8jYwBK{4+z@RF(1FG!+H|0Xc@4+7G4}TAPGC*PvjL>bJig zEhvPG`%(u$_XCN2sRG-GNu;Sel?y#Abrk}_dbmxQP(#w)V33T}P2b-Rklr&Rg+Lo# zGcA*;O-g{XXVHX^9}#-Q-s#Ne=X6z)Fe%G&Ip|?1^tcOJLrEOXoQpSKD!%6{g1688 z1H$*YS>-aVF9eXDZzA=;NWUvY?knQ*2ZP0s1?E_dciXyev?2O4LVGEWyoF!e&RBJk zP73mTFRt~M(Vnkl5g2`xz=vb(?FrdMQfALKDupIhN}%p^V*E*k@aEDaQ|zLEZQti% zuaELwOE*TtnWoBY_oH^kn}#Qsw00{s@%&k?&X<%|h%rraKT;6y)FzA|Nwa0{(W(1f zUFZ5QV|)=b+pq8bT*CPEzu4dhDp1fWfM$HqZObF)J;AMyb46|5CN@*yaZ_jwPauo5 z{E*DXJ^$!o{0hXSmc81kv>%HJSejyH)D9Pt`AftxPC={#5DJ_HrufdQdz1PyW+uOEaZXc#|mW6#(~bZdg3f@=y{Mbt1#*(lFycK^T=XgCo**1c#P(6QRr-Q;Em=Nz;q78BoMV`_evV9$5aQwW> zR^HT)QEo-2EfbEQ+a&!7e13+WW(v1fQOhe8xLI%V;iw0t-h4Ubx)=Ee2U6?nYg=X7 zSGB%LpP3rKt4Js2BkTnmx>}uwxxL2KZOTW@4d*7D`lMwE5|i+2xZ3E>2z@x=1qC`u zi3k6C1@}Db7p!F(4ef~9gY4yC(sXN-*4Ntjw)6(5k>Q>o`pKkJ;VX_|LbArDJ zc)*u&k>AbGy5fM2;w!!j7){O|n-a=QZTd>aXnHdHv#4Nu{Ps5IZ8FM6j>}quASG#V z!JkG}+nDrjh>lMii>;!8Qise#{d3Lq;6Qwl$DAS@3Z$Ec9n#$CRE$$k{w?Xzwc_Z1OE7YezWE+p;Nks0Q z_j1v+jlfsMr`82eC3_LH+e=ORrHpsv4o8L`R&V-FvTvkUf4!O*d!ut->Nf`ZL-MIP z8|pAo_j1SP_aOjGe19QUwxaREnFa&!VG$DoA0;8f16rZBaT_S182~Vd`-TyVFMb;6 zg~Fj3UQNo_%tU9D`Io{;CSnKcIW>)4L8)n~&mg0>w~WWuIAB+{R~Lp${89P!9d5^2 zO4bLKgcf<&eKGz7EzwekD6QRJgqcPDTByjP#v?@|U9XIXF98N{N$CTHD#hU~q ztcHS?n+I!^03iw18#3i2C^D6Ca=ARJ(?UQRZQcay8_X_*k;uOzpw*rfMt#)D_^C85 zZSw4)>=Qytk}`^iafX4U;mA_kZYVBSnw2=}jXe(6DlG3G)Bnc#vS3|r3H=}Bk;pWM-J`+|2VBAgcA?W zCd4JeF=h&Gh>uH|9_wTJtq82-!5sIHWWKrcs2qbznf^>d@DO+{o9~dlmq$6S6{hEel212Mo&#Gk73nO-X{XO5($8cHloAvHR8U9Vmj2`EWtTHAQJ zwZHOgJAEN;NyZf|_g5ZoBXjQhT)LBEi7cnWc;&Xbz(be=NC`?WjaUX^=(b2s*&lVdXBN%GOh*|T{7t|1!n)=b%XvaU21tu z5}xyN$4cOG`tZ4Pm@~F3{Wu4)Od{w!xMDA#Cn>;eIzpPbW%gg20Ja;(OLFOH78q$6 zm~MJn_p;@gZx!k7P&Iap*_p?;Hs}PuI=+S+gXV=wap;JS#FX}js1*ga2e-IWx6}Q49(Q%RYe;RTVRk(p2--7)>o1RYBYk`@T8q&_ z)Q7ZLPL#Nzor-_n6SzmtewqX76HdDac)X~oioN(|WtFh*tCke&gR&?-LQmdkGSrp& z9J#a0+u#dE!Tf5tG#~8|2Jb^<(Ou{N5~#es+w2zEOWyb(PSI|@RtrcaM_tROm+%v0 z>jte(Gip{Tkvkm_(*+xe9Z;rF<29j<-O*+ z8UE+&gp1{K5@2{q?WUmfn_Dh-GnV4JeI@cv4X@N}V4)<-6G~F6W15UdKw)Qa)Hv&6 zaHz-iy~~D$OUTbO7G-_f0mWr`I!RMY~j;Vk8 zc$#BB?8x4HJ>zSmKdjEzKOk&4LODJO^*Qq7PA2FDNwJsaM=WhhI?kJ~8*h0HoP->z zgke?5Ox#X;Z#xwr3XIu1J32f1{l1Jp;4yEBL@*g;RZ*DTM4czDLa%phu~D#&G)$+q zf)L|kuf3IU9!V>49@#XlwxTmKUMy_QEeKrvTe}@O_QWdHE0z00vE~(#clI!gupmsx z6GG~VBt7{+LNXa8xw^*B(&e-YQ+VM;!)mn1I8*ihOenD466M1UO@Q*|{eCkR)@k!I zpWqQP`S_?V`nUy!cF}Yv{Fr-xq&136^aRuM(yW*qbf2LX4Kxlg)2XW~a^a*5HYh*< zSD}hzBaNaogZ0LxBPbg~==Hq=P@SX#sTjn*Gy0P?T$xBdrj35TZ&t#ZlZFsw#@CJH+&Gqnyy22(tlLO*t-yH$O)mVdhJO3)x(xw*EXCH{FcpSJxEurUx{ zc5sc;75D{4N|u9pNeuY#5fp|CF>Ix?jl4*Uh99L(oROpt( zCh%J;Y%3tew*~3Lkauxr@P*hwP_$Z9E?5!VsG|!P@e8y$OeYY?`vdGm4Gec2UGzYa z=O)NXTz*@SY~d@nYCGN$ItsnqFdY+vxOl>153f^vG7QYv)@e^6Sq^zDfAraGzUTM~nkT<@ZSWT=O-hDMS zq`Dhf$>5x{g#!hxzyIvJ`{ie7C)mQn%bSie8gIvO$qFa6*U^-6KhMbxAH68C34k`h zPv{V-yVIWVJ!fLzOyraIudv*Yd8~bScubIYWl?gntk>SXFk_vt)QRJA)aTXZU4ywU zoGWl}kiW(c_qre4o9&6Oul5EBvfIgnAS zrQfjeCQiwZG7Fn+WM9}kLBG=!Nt|A`INd~Fh=S=*yi@B7GSDK08P3#h?b$+1q3dy? zbeMQdO=;JaTf`iT{#CmdhrcbEWJhW+Y;jVU=U}c7trv&Nfya{n(@~>N|+#Q|#=_Uc-x^r(hbN-OQ zrRF5HdJnsXJh*qTH@G>z`j5O`c2;VGAhF;C6V34Crk?aAHnkYlhTQoZ>5!wHAPu~T zP02KZ6J{5;Ivn##(~CTDhqxyF3ii9y8{;?V=KvxYtw2&rj9>c)?cIsK%v*X@=Ic&e z7J!2=)<3?kncIzDcs#z@zMK_I%arx2(Z89=S~9E7HkO4T^_Y|90q!u!9NEg&>TSoO zY~WzMf7g|KXRFR|qd{b7sm+_`vXEq(dUR<1y)&Bkh{XtUZ%o&zf$!`P^V z7}AiUhDYZ2RtHnY`{{LPK}RC>ZZfyZdWd~hSDI5W1aylJ!l$0@KiwV#qCn$6G=O=fAw#BSA z$wh=5k&YkJg91oefy4h#$7&M`RiP(>9yGO)*E)rP&~zj{qlxjhnmGF~6& ziLY}BI;Nh41QY@y;s|(b%sL(&^BEq5IhSAv-xN#sGl#6^;3MTJFTcLN_G-lYHm8Kr z{Kh0Jb{{=6;Y#pu(=6mAuZ|Hep_Km=Y}o{&dUW%*i@xmiYE-(A{c0^gmfLgZ-4MrG z4FP$xm*UU#Z%SZwSC2!@j5F*EQTuE&L?*v`ao7({4{uTE^n0e!Jz460of;5xVdLI? z>g7ER!n&l*Qnl9;AF=Zvy~E`h;=03TE_^H`xvk3333^G7;~>toAeLR_)S4NAogR@t zx}U{e?3BrahI}Lqlhfyirzr)dl|0>f&6?ki-HBmLS&Pu8!mVN*@9PgJzs8|0W9e*8 z9yT9RtEi&I_pa|l-M;sbuiW9DWUHcm&^QOMXkFD_{m6I$9&O;rbB5GN+*%a1T0XYb zYuc|pqBuK{+63l0Bz z^~x%EOgh+e;qL=CyT5O0o^>EGljCGt3ujeqE$bT8arXBeoZZ_xv_8uAf1c7qC7z7_ zHnkQ1%Mpbfc^<(J3ts>uA!5t&r2$M{-Jp#nz@Sa!E?MlkJQb>=5iqo-zD`7}Rt3VgVdRLQSmUEu!BYo=IVwz8#TQN^{TeN$PtsBBg2ymshf*j_0x zyJ@rK#PBUwb;kQ1 z=Nz!vGi_jB!|4W3{46Ao;@Ed-$3lc=-gjWf?iszCKTpF)7crW@TEcT0@sdAd!OR<4 zl^1f%h*J}!x>w~!MiOqmTj)mFCCe87R=`oJND%*6z||^~6&L+8mn3qgfP->EPHwi; ziCkB%c{bplp>qWJSDKo6q$Y4N9mO1OMbm{nBFLsMcIV~V$W6#|jFV)~(p_^iEBZ(d z#Q6-gaY6#Xk|@dIIl$mu`z{eRDdWe63(Pk_aziuXSY7x14tegsPHQ}GJ%sdJrx zkqt6Lm)se;EGY2qf?1Z8S=&%p*Pu|lg{$f8xkiPXgf6qDQ&rK+7pEuHDbqWH zOU6(1vTHTD3ZQRr2W`uyE}{KtIG?DHbB#3_X+mnIUWdu#X|kdom)M`Ir+-yhzN-l_ zWX}6W91G@}t)?G%EA!&|6R?+FAXWV5UGUM<`sBIMd7tTY)VHcc>IZM1o<#5J(#dS3 zm@X;d>u%V)bh0H@a70QYcBfeNGYIuIi{r~@4jLPn89akw{?6ge;?)2E`jJq*p8@_q Di>nx! diff --git a/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff2 b/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff2 deleted file mode 100644 index a9c14c4920648bc420b1d68cf13d6672af6ded3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9572 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 O$@oD12Gp?wlQ{ ze+U^s|3Ae0Ki28LSoi;;`2gGiUI6$%?*GmK07&a7X#TIq{&SE3w!8p-A%HkPfRT(~ z<}?v*xo$AwsN(J6=|!(6YR$=$D=aYHUA;G$`T>!tq(L#8$(K+C)75-Leh%CUxQZn z%|~0Gr4Eo}zwLAM|Jw^n!p%V;bU+rQQ6iK;P3$2!vsGify#0x6l+##vq1pMQ%hG`! zga&Ipr$hO|ED*Ck$=1snXZp-|`7av~7miPNDK{gd7jfTaP4xh?lohQaf@EK-dW~kt0I^5(T<_UO~Yo;zWw(yZ(O(X`e9CzVChCUm7Be4H)|b({npZ~Gfx}H*RO{2Btr%SdREZNWf>1s8 z@br-NG>v9zP?(4J75zq%{yEi2?h?w3SMIL77;T2pLr9c96a9mw9}xR3p0Yhu?ek|s zPkk$KY{!U3#7>NLjvy|e0iBtW6H^n64MJMd|3b$|Ik0v)@MBwCkVWYHy{5e)ZCc#Q z{<$7YG2%({zU@Z!=Lj<_a@r_Jt#8PM4xgEkl>ac)Mk+aP4A=H1nYlA|FpF`-g$jsP zqu7d!`dOXT><;c4PDY4~{koIA++PkBBj6p$nwmYpm}jG>bNqrO<9AE)vhEVslSGP| z+6);5??XmoxSjFn`JR6by?9JuBGbR@=wYG`8AUVTx(~5fGU2es{1}|38l5f@^N0ey z{Gn|o_&3Yqi5RYnTVaDUr&t)-VliHv}yL)Ha$ z$|kwXF_3C#gaA<4ja=6-E7IHwkyf+5(vZT+xt{D3Y{(rIZ9iz3zXml;K5FdO4Az1w z;}{FxG1;y|yx28;iq$I}7I7RCeu0I1zqcaqC`39>{*sIeAFt1t{Roj74SMyF>!D#$ zAHi0B<>6b|dMkUOJc+eDtL``8?=Upqgs$3#G3pB(QNrk61ej~QW5n)WRLs`|YZ6Xr z%Rudjq2}7W78s2ySwJBp5-Oo>vYZAi2pJ%;8`6_^icCO;9*W1Jtr<9INOrq$?VmUv zFL`q{W=-h`Qz+s45fh*3(1)iCnqGJ&sJ=Gk!pG#oAMKD=Dnl3r(J~!qlvF#n7Rtoy zBdDZfbu`@_Awpt-MsPt5Ubve=+#y+e1o+*2cl{HM_OSVrs8ZB0l*(sc^}Ov(0gF~M z=Fwd_gNK3u5t%;A9RP7;m%*UL6GG$+{w81QO<{d~=dds{aaVy;o(5w|P_i!H=8or| zg7nnaPoVCWG7asM_J*3~F7vD<0|dmu(dS-Ho%=I1-^1Bw|Q&N>xGUkg)M} za#BpxepMHrDNn<)tH-T_c)&4wNKcm|oTU(%t?1kLdn%_PIeEzhuDeF_iECV9p`+b; z>2dAzVVC0vgo!u_7Skm#5yif%DOh@3)&*v9pRp`&$j?oEiefVVwmtTTsl4nP#LNxI-{w{;$ zZ?H1!e|5x{>pYUA8CN*0i9(ZlE^<92p@_R2%MqKOrI;Du!FdMpo16-jEeZ zi_p&EHrYaDVHo2dol!C~<(7{a0rH|^(ve`5Mb^V{nYp9)oa$<@MhXwt+Xj)(ZO6QN z#{or|PC7Dp)3+KBY15H2<014xvEdN77(5%bGM+AIaeE{I4up~wQ5aOzp>bm1#9uI? zJ{|a~j<%ujrlz38@(`%jxK@zRYt-?#Jlm{nT(o|SHC0DOLUGL4s6^I`v7BhtC>x*A zfpjX!Y=u)$>N74ouap1TiEm#3kk*~8HrMN}M0Ef52+r?U#YVJJNmhJ>cHlcxG~`2y z=v}z?qc*m;k;wxO-wCR_icPQKvj^*SOFHMC`jMU$0nxbi=$-#;&HhArHGo|-n5%u+ zTqzCZ7)w9&*~cDR!L259cJEAAvuQ_bdGOW$Wt61Yi&ui63|gU05dn0B)^>zH1f ziP;Q!%Pj+wr3lGsaTiuC5Z9gX{pzsKywsP_pFGLQ@$a!u+MGsAfXOhStwMr z53^7dlen6#_B#(68Xc_|4IdWTQrRO^H(d)GGmA^(IO{uxeHVQ1p9tP&Y11S*0?nK5djp!hBCdNaA&6E+@c@7Ny@DG8s$i2(|^&2rQT@Bj zOcEvcMZ*ra`Ce;_LP3guV5|qR{GjXkua$JEU9?QS;stHtMegKcc`2gYb>pRdz-LA8 z^S_ynQU3gY1=jU72W^N)uNT>Ua}wi!%*)1+PK9UrRLe277AO87`SHBFyD&5UHnFhf zml0t)VAK8aw<`sz37kdB^Y!|IxiTFSHQ_~CfM50+;%j}7Rc0Xlg-+Tk+E`+Ai!VdP zSIeOV&jwIEO^54WM4`UU&Hs-#)QDMXyau9X_PyqOJ(^Ty91;GBZ*&?R*s|L>_+pI= zM*3mog8l2Y#7fAl%&*~tP?mch?1x@)%m%OJjV&6+-0eX&TKIc#7tZ8HX;OZ{4jH+T)12^HDi85wcz`KK10 z#=*E-j~Qab_rX2l0u#^$7p=p-PckyW=(4D{e7KtiyCT{2k}Hzhw?_F9yOJa57n!#t z#uSkH$OT`CCIS})eU%V9V1{QnEsyxB!`gGZ}&G#T{EN#uWmit z4FkEZHUlA6zgN*dbbd`W{vUza#)g>qX?=MT018Y!Xx>2}!MEEl_e|9ZW2fRYn&305 zut(wG)W*XDqPB{nSJhwSo&f!k;@@+k-_m=g+*p|*tBg(4g8>7TK)hCk)UYbH)ikHBXoS(F)RTuBbWfyi)qg)AqogtHN=q$?iZz6{WiQb$}u}NjsVA0 zM<4#n*CQl1l1I;ublpE534(Rjn5ApZE11Td42qJR2I!z?f6!8nw0S}oXHr)HZJh>; zf33kNWFo1fNoAlwn;~$so$Q%Y`fxe9P5!KqtFG48=lT8|_SXn8k?WPMNm zb|A{I!vYDk&h#IsP~pb7h2d4-CIgYB>pfKu(o$A-|HLb`35X|5Ug(XKdC~%vp$vc!n&{W|`@;^iHI(nT|w#xNjbz2Jl!CX}OrxnQGJG zzCO(-Smo1$_BILMus{6Ju#e1?-QG23)?K%v4?_bBs&{*Of#5KG)SJ{El=QT#GQDs^>~Gy?~zFVNtxJ%-?u3rn{6f4+iyd+4ij$YV=by9Jtig<6Kqdn zIRRT%?4`2TASTO#ax7+*)^B|q$=|j_2XSb%y9Z@4*#G<_q^-m3jFyBHH>%Z;c2#h< zRRVla1nYH2U{6a*esAh%d1)9|8TYe`$vJPLu_}vUw&7>vuPikGRkO;?V>#&5d7c@S zRaH_pz`@x$(RG<8$}KUjC*LyE;i6a>M%b`m)&+M!c4({iAu#P~DwqZIo(*zOPx~h2 z>S{g(-wyK;25iODoNW=NAcea4Z~|TFaK8W1`N{Os1I4utRVNqNq-Pt>>d=Fnl=R?b z+w-^~wG5C@(J}VL?2vS8w0L9rlf3pQ0h)X>S)1TXHK6GcMn~~UoO@z(0-6{;Po5Y= zTh5_bp^{b(H{rCPu9na!1?yRtOFdJ{4VA5Q23W;_)~etSBIa91s;9wuk*oHR86v9f zx$(xp(Pd3B?G!O#{lRBPw{PczhsY1oSl3>szUpiqsZqpQ_0b= zK$6|pU<+3Cx=xm-W}#O6@5RmK?s14#B>n|#(!Uhl{gmBTvJ&;#hUpNyM)OpO6yr=u z<>>ueiY|t+Kiss0t=OScjNLYk zuBw7_aue>PV)6ptwKDRh)S-O?iVR#Y&!QeeR8vdKq|nyz$URcr`9a~Ruw0yIL~=Ik zM|uE9LFBs9PXkd3F+QsM4oj@eT4Vz-Su!NM?X$P9xE&%IBKNWoIt9!|^h$b7DZe?x zsAh(%Yrt(7?eZ7DAoXh42&5k9@k+iK+WIG&triq%`wN{H%Z zyD1&6>S5yIg0X?+Gw=bqGjUPJKAIkbzMh00@yG28pK;axsbj3FjsdS-E#4JzKQ}1Q zv}5Lp-x@!?2&&-ITjMK(%m8$}#%V=M2f*T6Q(Xzkpq7NgkNL(+Z+i|ff((MDML;$+LvTO)x6bLjnRT;ykxD1g^g9Zg34)_>>|^m2h1|EGG2+5+t#o}|YepGL z{ohNKsGUDw&kjrHrGfYLt3nL1)C3dA442&h@ju)paN~_{ih1w&gLe4CNDC&>h_&O- z%t8m{k|ogl)BU5Iz|4yl;Y{aC7^^ZNACcGP2e@Z0Fs(%;enshX);?Xg*P)u~spavM zDGob+s1lZRk@|hO@W(UE@Ui!Ag#&-rudW-6k7GSV-H4$Mj0JA z7hfAp|FMZyowKcKQxsTQ8|XFVxY;uwd~~O~%UVtf27BN~lWh_pTmFy<*)=&)#~a6N zWaULFoV}5Ciocq@ERk$O4wNUx&YVGY-YlCmmR-`*+rG#*g1-<_p7z|wKgy#ncW5M` zY9k_ACct9j6xCG2DFk$u247J)?>=oI?5|28O&CQEF|X5-jM8UEt%l@{R3naPlF(=| z5urV@a(t=#6|5qx2Tl5bWKHixcs4llDT|c~p2Iw*eiE%fFI*g|eNukY9UXKl)b-}( z;>F~R-kOn`p8UkNv=#d!R9TVi!M4m?fDQ$L$TB?nmOgV+B%-9#813oo63Zg-kJ$ULNZ{>8e>LV z^v8r&w|O*swn`}7C$|IN^;u{&*Qi|^)b`6Xv<1FMM8uJ`M%{j$^JdhK{UwO;#PNef zadT=a#Y(25^+Z`plA%}kVI9G@z02wr{tWE#64GB1p+rbAYIaEVvY)`qIY852CT@J@ zb*1wiy2M(k5{cFVPai}Hel-VL1U6{wi362#a9G?-!#L~gr(zjF{f$4XqGdjRBRTCe z_pHl(dvR+lFxd=p5uZZ!XRFs(?9tnbeJoWa#Fq001W>q3?TqfDTzoeIU=Hd;%u$DXtG)RGR--5duZ^-6%9M#A@+9 zHc)6y!^2^gR)tZXTX7l&qOw@eJm32GfQ(aP%QeKXkNZ4n2ATd-@(2!NABo<1iQni^ zchuX7pCI}+v_sBY+lx;#usCFsfAPvXxdKq5#g?Idxv@@SD2RWYSoe3q*p^6X7aUgi zGfIPgB5QT$lk*+F;_`ekW%~Dx376ILg!Hu;Ru6bk5ztgVbpW+KN2>XRz>-7_p{DYe zdB~B_fP3Tcr6672F&Hl&Ek>2wttW3HS=uMLw$^l%W+K$L?D1~YZpCeGiuBf14)y9R z<2$|~&Q-3}-7410EwhF8Py3Zd(t(m%lAT<>>ft>Ytn%s=tcwn};l6S-D|;$ReyH{F zf6B3MC*nVmwewS$CLmD(OaIRM&hJf1Vxd(qB~-e)?l@Q`*z(b<7Ksd~OSM(^p9#&D zc4~4ek=tgQs?2#}?~*y+hnOXI>rw0`>6aUWNG8E_zbjde^y{%uzpn$u=d{Q1x=geL z6{RT;Is=MDT7NS2&@OY7k-4nY;PCgA`200&4l(-~c^ldI?{gaNVW}rhE8jP*lxpFj zEvm@EsqqK-uP#;0jXpmZE3@LNf*tvDd5R`gcjE##WnSs6kke!14rpE`Q@`egif?x% zX+)_JNpmQ+KK(FV;c4=Em!2|`3hw?LLK)Oxj2f3d@=IXiyKL$|Quf18yeVfC`#&(} z_>UzC=S^7=5`C}%Oq4d#NXO|^(`t($yhXV3MCH@0og-C`fwhQ)_!q&3KjebyMkj}I z+$1Pwa##JN2{1hBi5~9a(pUaNrjz77?n#QP6Gx1LKo(<3mEz4I?E!PF)>PVIp zB|z{K22<@_Wx3QV)EieMXfI7*{C!?&Osz%Q>TK3HXxIgAR7-h`^9i3IiI940zD`nS z)iEv!izLKfXv|JN0z)e72+I2&de1hB}mGLTr~Ga7~O=lsBn(HMRe6d^xF zVmt_SXSI%uY5r`W77BR+o88ZMLg-ZoR1B{?kre7IDt8IKpA=ovQNFDc@~DfZ| ztz8LfY`7ub-TksXKkGd(U3yXi>w<9j)>ndC7e!~_Lc7_trJZAiO7JV z%Y`v$O7knJ;3i6ma!&0`L{Snn``0;LEjyS(MbcPRvA@QiIg=vrIe6Vyg%&6NnxBJ( zbs%l7glQtg=5uAo)~-A9X&t%v)qx`wKRlJ#{xx8YW#0PZ-hGT>2vju1 zt{-x-1egq^KKJ-;t;0YzjY+j(CIE^Ogl8|jqBe#MhOetnHs>#u72v{5M)5w*Ifpt_IPyitan@I$kC8P|xS^wseXKJhl8tDSBs z*suD1rWTlTh1tm9fj~ALy6Sn;l(U?}Zm;G+p)^xCFC4q!|8y zaf%lrDrV;*f0S}L5!9!T@+H&z=foYkU%*kDx#%q-Jmd|)nYT&X#bvVd55(gI%@ew$ z95_n-GYUu5vq!rIp;UK~1<#%OS&s{cU1hc9cK>Espa2FXqB$eWHlB{{JU^`>lX~Di zmL4L37PaRfEb42?Q4oGC_fMPTc>Nc1{fO%c>GC5kF=VH$(*#4L4S#J4UuOM7nQ6B4 z9&>h8F^U04y0eHaV^`lZinC?|wo;M^7URdjLL{-2issthGXu1Q1xQq- zXiv1(8{R*}?oW8o&&!rk$N~(pqWJosv}gWQi;ouwO=e-@$(JovKT~fQqF7>PKDSd_ zr9#jOmALSgBNEL7zmKFaa-JeK3xkvZ8fq6(Dqb>^T9JlIQYF5i7#fKOqLepZ76JTr zI>%>5upf$5RN6gHq28+BB-1Kkr)+ot5zHX$zDy#U=8rW6J!EPF`H}Gwb(zBYucQC? z^`_0(?Py517FVn(7Jz*lLyngdlW;hd&ESbLH9a7pcmN&Y=NVbNC(`Db41*74}%>EY!og#eu-a2iC(?GizE}lhnS=HIHjjE5y*mHooJCFEw#vK zx6Q^Z<%9HFMBkHtB_>0tI2~`ViZ|qdoG_Bl1SZQ@F*@aZ0N+h_mCP*63yFU*PnQ^D zMWi)I%EY0phiWP%n-?55I!QQCK;@x(RHL-9vdF-PdN40>3imu=#5+hfwyrB{8sIe~ zPrmf>4q7?{ZDKIqm17XKJ;u*-N>)84xFcP)2M=O-J?$gvOP~*PD3=c`{0(|leq8+M z(7A!FY|a~OK!yi6V|D-%=^+k%nO8J&-`;L?tX(yJ7D;SIsTE*$)yquoCqZ+-r4{>w zfZ~8eSWP{mSd}UoSWX;3=dLl{6vv7!vcV8JdK`E{MC6NjhPLnJ2vaI~5yt;JRJH+H zgee;9yK7(AKA+onPe+`NRojiB%3lp~ryaEM4#pt;4d$f$%>Tu)0PPPhR_A^}q^Bx} za3%Z=Zud){Jm1?a(s%t^(u7sNE)n>nqDio6y#=B+KuIw^d_1QyOh`!GV|U`}mEM|C z`;3t+9J6BZ=?Ek7tP`yvMzM=UX6lAXg~HFV_@ z;f+oQikaYquwHNAw4b=HdgBm#0FZ+2RLXFlM$zM**WwyDk|XS8-u?mFNBHo z>PkVQH2RB<6vkQRh2^bheYu~TwoMC+b?oK+z9j#>Q{UGe_EDgEMQ5Cys}x6#<=d-< ze=n3mFFvqiOR%*Olgc=o30C*p(}3Q`n2 z9_pU!cP#pUHX%3~^=`>%jb?jvy%1Aa6di%zPa}3C=Zk2`V>nv8o?q`TpIuBs0*V1O z3MRdQ6$LF_1a7YkWh&w+r~XL_^Kp2)H8;im%%$>Z5&t6k$e;3+Xym{(VpLKC42OqF zw@(qhNOz35eiOLB@wmd_v#mTJ$!>@cp+z6y)nF)M@#~sT3F^?qE;DNohxzfDxMv0% zX8GHuZ;YpF9IqH})vIh+=?_ZWdrQhL$R_^6@jq5EQdIGbgAFfz`5QqouhJusnZ*Oz zyesoJi~`$mWvqN*d2%*P9NDx+=I2S7-v@h7(vMlBN=T4cZ5M}z50gs2tNCS5_Qt2C zktGWEdNrFluejJF8*-zJG`a54m#XB}Wu0;mv61OdiVCCaP^GKS{~(omGLn>OMoD|Q z)k{1bp$*V>adK^ur`Yp~kAnX4;_>1AECi_I{tHCHj>LE4N=!y+7R181`c3E)NSqhk z@y{<@;!RT*IIMh6)E)X5`iA=>Om-`7IJ^6yFT;UARSrDIYt^4(D z?}@BE)8>?LDgeq^w}gtK*t&>YtL{9d6DP_f=I#8DOsmgQ4#aZ?Hcn-R_t5x0#d0~b zmbb-XSyF$*C98FeCmceQ)jows$sgJ{j6c28DeJpb?JD|*y7SMP8#J!6z$~}8=lC5x z!^@J92CPyo=LE%IjQLe%V}K_@aC6D?vde(1vvelScqQoSVQi?E4{B%yAS&8_m*)U! zd(zwbVqyoAOJ%7!bs@ivTPidQK6O3T}xeJj-(*{SLV zQu_OzhjT}}F+;_^%c2F)*KRD~=$$J-T9HT%RW=OIjU|S+3se=ShS)8=BTJ=<4=5vv zGABNEq|SH2L<>Ujm&*S$UACq4n^kc`HSmrh{V$>-KMhTqcut4y=G+tRDpN$g5c@w{ zS{iTo0_i)GX?==&B72G``OgI<@N0RCkD6Cs`N4&*0zsT?xAnxvjvESf>E88Cnlq^~ z_LY4v9%6rQGDv*Fu^N{HW!@&z@5=EMSSVF&BAvHKH7ULyCt9nb8lsahPM}krX5RR> za(WV%^dWptH{U6Q#9?u#nFd)Y|5+z0xfVPJm7!L#?hC#T>8To9mFX|e~1`AL@PT?a!!h=zje)cNhGsI=W9)# z$yeq|UJOdKOrZSGKC*3Pl30{Po_BH6J+DhhZPm5dmi%`zlEs&ex(t`EcRVs`oq(P} zX&D*743I+ipvfQT-jX$^7c&f7)fK~)OfLvmHu#`oI5m*OV0l7ISpMlF2;H2~yoRD7 z~}*$bKO`L1q`pl$?gTrp<0o61%0r=2fY!ukVmg-%hZyD2igus}up zi4#SEY5LuRIzGkG=_vz^2|MHpVc2^iR(a<;g(;>Kb`|=-sZY5u^HM89%TF{8bL-8X zRpWt=Hm(aSD2otV^%X$tcTLal>h%ztmCv&X!A0D*$Mjtg3ijP)N>E{thIZ_3rcw{H zr~{ilU~}CGj27E$+?jvt#D>drE8Uz_M3Z%d&lkF4o zF%WR%dn;Cx`dFek|ESVS?26>Ht{{vH9Yt+N5(pLEISS1!=2av-6NW&% zddqSlTs^>{^TeieSPFR&9=}tVIA;&~o(V81Kqy&1oOP6<;jx^?BrZ8RFtkU=o*05i z#*8oeH%|8!7AaS|e$~H0R;ky0*UBk$U-1&_h7+5==z^-+TkKa}Uf@e=dZh2Y;qy7( zEKue}y~67qjG0YJD(z&0py8JopWzu}XuIhoMm!_Nq5+5JiMrZ|~=cm&0-H4@{y7iQz&_eHfp< zR{pu6JNBcLGvAF3=jp(@cI3hK@7`|5YWTs*()kWepc>pJh+4JFkaPQ`yAp!_tsA_h zmceO)d;P`3&{ zzR5(pO3Cwoqhr4zpxji&^*2+Qv}B|c>QvN_BF~)@siF!Pj%I_zq>UNB*iGh zhN8PMPy>IJl2xZwG8Vcfv(967QaV@s^oM4VM}rX(|1~7)CKUmZ8@rta>$K5g(389q z>1xc>Iq@`h=|WF?%?l_Zftvxl8cv*URGmM&{^i>Jnt(-MJU!v>Sx19+gcEw*7LdzC zy~pqZjIR_u@Z@+DQ(_9?isfSlP{r?d7<<%DrB!Q%DvVyvV)4`z2zaqjwR6pm0 ze+crhoKgDX>FwocS!cCkc$M5-DJmYHC_jqDF-bLdm{sdpBvvKcVi%+j+i+sB+0{(^ z4MSqViA%cvaz9=6kEDx^_dZ-#g2TCy9iPjNcrEes4jd~tC52Agx?$1FDF0+0h1@^v z=zO9KdkKZI4*rx`+N!OPCuRhH7sD8+Ho*YY+-r$1$Ux?d(e^j7d62R$P~0YEHxp$n ztr`{DyPs!= z=wKR3W_3|-=oMaNf^=kvpJouBPVH&xFK!+}D| zgLx-uo?iQuTSA4mi8?w5jE||;t?E0m9E%{70%w230h(O)Z(<31!JEA6NUS>}|uurqh#W-Y3%^d`8bzZea&%S?}3gW-CR6 zBjMTf(^P?X$Eo|8Tu&rv=vgtHc}Y~p><6gQPh)Byxz zFbCxEew|LyEeCKK2P5@xx{OkURbUoER#s~QldUBV)vGKBRJR|8!j}|JP)7O?jxWzbI<~_K{>=2vkXrNPi7(uiY(H|1fh?erU2-`K_&QAT!z| z!@Q%7zm&xIkrKb)o?<%WMFenQikr7C2%8w>jCRLq;jre);@GAZGOTwkWUs9oftzwx zzMup6?6PEXgU2VRaq6|{zBmbmTu2s(Dw;G?4YoDRRGGoyxKXaX-maJkYj45FjZ3if z2Aain*{E+3#G}@lISW~Xj3v5cX?WTMTe=f_Ewg5)H3s^lfh2uuqiBSWR)AV`RAdBb z+P6v}Di7BiH-4mWib8u=I$Sbc-+6b^)@xXH`UdAU<3zwzo?MXv-h1BuIS>FX=2HgH zRz{{UGyVooUR9)2G1-un49$gJTThQZpOTz}Kt$V!i&8ZiP2mFW5a$4Ax4S72Lf@C7 zY-XbAjc*z*psOsq)d8gkj`)xC#I7uu0894`8#|ePA1m`;@)^t>$C(@VktQ(lqEjhJ zrtevTxQMGsS3TrW@pqHFc0`lAjxcnnz@I>m0BFSu$anlLgPA^G?#Pe3V-=^OSi_AO z7|4My1A`C`+aiJouMjNety1XzvI-@{(K!&0P@Cly8g9>o6~7bC&C>#?@{>7YClBs5 zxLXQC`L)>+(k)S^>KWCj-Eegjv90t2>TNoNleiW}d$7NKLRC>tB7T_a_m!sR z0|URRD0ql$dv{OG%QqhjQmmOqsmUqPA>9MFtYf6*fMLeQ(Ph)jmjXRQ+x+@9z8L;X zx?EQY2`RX-Ne2aID)4Hv-f`%=TIO9YqwWs=o=%~C;cVfixuJp*C3cgXt?VYS9^XYo z?avQ(H@!g1)W2Pd9C-u9ee<0pYuTjg2zdlE;n*!xxP`+)nZmofdyB7=NLB*4$~rF& zYn~cw`=XuUi$y1!)40rAP1`tm$)qpHUEdb-#d%LCRAxr|h zKLv?xG>7<2+jL{^jWd7@r?PzVCQ}bBM^{s*@u zlDtQmPk@ornq-#Pp)+CBDwJrF^#vSu|Zqw7#yk9II$%l5{f_?TE-#l|w3u-Ci52+M%l)HH$N|SnI@I`7OzuruzXF__{rSfRA{opeGUZG zl?l$;7DoAJYF#)8G&g@^duSs1@ik$J546W%z^7x&N`C6bb}r?lg2EyY%QB!?b;p*l z@HsFaLT811k>DUrKyp7asnY&A$iUNHHRlsF7^GD3Y4AF)*iC)nU)Yz>@Ff?llnCQ* z5flSqbvy{1SARzELE#wr5BN=++kry~M+Kva4f#f8TS3Hof8=Olsw83|bPI8g56 z`2KFRE*als1(E0bo1aM)B+vi25RqoF_FVB03h+xEaFU>~?A~ZSH`7Sc(~Y>=@Irz4 zjGYM7c#x_k6a~FPtCbO}E1vg^pD+_kIx;cdqYnbNCC9P#l(9N=`om56-$G1`sIc%W z64SX%Jfn;ASeFIs-y%K+rQUD%-+-v6#bu>_9zVRfi7xl75j{r5gGGt0xXGc(Svql_()9(AYpg{?9076QsBnbcxopW!9^aoxW$rJIKQS#10uN28 zvOfiWcsxOj7XN-KGj88qJ4qH^CdIH#pmSIMBq*Pb8PVHoz4`&ez)G6sQS45AHn3t7 z=`DNyD4K|Ruu6Yg%lt)94aKWcQO@P51gxfsZy&yF`diPjAG7_J-kNV7@ujVt03}#r z%wrSq{@D8CgcbK3I0F^UfaHfP6nR@GaAld*!YMtXj73FCNO`ojj};|zR0}D;PI3rG zw)DY@ClT$6bHyE4@%6$h+8{_i6K=DUB_32E-xv$lgJoNB@W$AcINGxl)SdFfnR`%LS*vR z#1=k&mj^&k68p#Sf;6QK@~lrZHc&NXf*iP9?ic<&Tf*UiF_Bn22rnY&Dyy$p&B~D-5%Yfk; zX}O32c`Hkt4OTBR&f)gcrg||+4N)qoqc=dmf zvC^7s&^D!J=oNNZ0{^}DO&jYZ^Kl1g=)qhTl@g|7Gp65PkU~a2kgTKAt8YieB+?vz zKW@e%YuVSts2eQB&0l`+X_{#BITy4eWa@s?=fz{+*0a!TUX3KV@`EK^aM_=7vE+WM z!_rPb6;AQ6+T@p8k9K{wxp}>@JJfQ}^+-Wv!rMQC{QaxMIpYJB?&{PYM#bvjNtLLNMHr zmN5D98j)22rdm4B3<%M}GTsy*{>zBT^MO36qGTp}P{N6r0tGFz;iG+ol2AUz7!uT1 z*EU!{Xz2aeOAiQl@$aCj4=zctWg$I{k;HrAogH@lJ6{{hVWqO9goOOG>L-~(K0fWi zV$K2(aJ6>(IQ;y}pf+Sd@7GQ;25cVjaL-^Gt|kEoN9d^`uUFIfqn4$oPwnJPa}7+| zA=4iZeUqR(9ke?WE}+!R!RSK!s9W8c9V90Hg#Py}B4(Ko?%V?)=H!R2=nyi_@!D>M zWBGGKcTY!j?x{d_!F=mw`7_uAwS!3t#dt9EOuAAnRPVa{-zD#C6AOGN>8N-tQ|7XX z{@Uf-@(YserUG0@v{auM7vP;oRvv?cmI6CF+xCl@duRCaFBTNnU+5ttL@zc-!HPo* z*(HJ3Mgx~`%gp2l%>A1nzZ$c*;lM%X(XzKIfPvOHj-%Jz#hXH|v@wHUDV&>5ih>x& zNq2*l`b9W0OT2&5y98h!jHs9vN$^YneI~kN3ZGk;Ly`Y=PcMcVRE(FQsL1Z+d%`GW z*U{d-`W|fwy<$m`JHt|ME#!*4Ohp;I9b+y*a9mIF*RRK$@2`Lw8$1B&kXEg+Hsxz6RcLZB1!t zOx0xnH-;&w%;@MenqDRmSY6~Kwy0&!5o+mYZ7$+&8|i97ivGPTdf4cwB{yC^rWjY7 zBIonh?#S;-2~6WbqzOZ8#~9tK^~Ik>ttqS0Xq36lZP~Ezm49RQrd!tLmW+eSy~ANA zM6Bntj1ON|4ve?Ryqy~Xi~}t5U#zfMWuKR$r4(S)s`9*uEUh@-lcMSAD8H+4#$ihQ ztzbM)BkBf5psIBj61g?rxtc_f$!VP+6XplaGhT@b_3vU?8uquyTSUw;xg5#KpOa92MA4%>5&^{X1M1p# zVV3nPSf3i+ME|QtZes^VPc5z)=I69r&oB5dKg~xn%w&OBjoSLM$d&O4I;{Vp%$1;L zA>jqBwN)yK-413>WpaW@bMrI=q)GUrOQWqev#GKkDD|xdbKimiWPjtZt83qDYT}w<48#a(N46LvDzbRk|pkt%CJgbhqOu{|gDj#s3SU0A2q-wZW5H zD{`lUu6lVz8B9iL#&rlZ1z8Mp7joH7HT1db+*|h;J>ed466djP Ez~snGSpWb4 diff --git a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.svg b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.svg deleted file mode 100644 index bd2894d6..00000000 --- a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.svg +++ /dev/null @@ -1,335 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.ttf b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.ttf deleted file mode 100644 index a83bbf9fc8935b8187f289299a802aa01ca008f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29288 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 E0c9`PF#rGn diff --git a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff deleted file mode 100644 index 17c85006d0de2c50a19dd67150ef4d825c92fb9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12840 zcmZvDQ*>rc(C(Xwok=G4#I`1$*tTu!jVHEkYhpW@*tTuHv2*hM|G799r}utVuX=WM zb#<*>ebKwNo1Ca901WWem?;5B|MijrU-JJj|4ILE6B8B@1pvT=zc~Ics6)Vl+lk4` zDSdH)001~V001ql$r;Nbrlj&40Dy@7(n0tipabCKlo*)5xXdqE|3A3Rq~RIa7}$St zZ(s7lmksvi`t=Pn1E((za{h}$`5#~aNX)F=O~1H(0DwXl0N}#HH@_G*H!&~<0Oc z77|UScpC%Y*St*s*(3T7;7*X-wgxsPU)GpO`&R?(3I2er;UN_GJ`IZp_7^;Q?NIio`ZuU#tgx`gyC6VxXKmwt!EUX|2EsGcW-YD1DNCXzmNtI~+bq-K zD9Yi|eKZI>lQa|9(U3mtMQ@g5y6?cxU(^x1g!PB$pWl1qs$M(L9lIzKX!ehvFmKQDv(y_w?<4w6}QpC5YitVnIn(Yd;Oq(j$5co2Kts zc4m)RkKxt+&@Tixp%jT2w}RLQqv(c3>SU^GMwRMj*1U+Uv&ys(_>R9$@-qlLo>y$m z?x!?-vmr4w4AaoPiF<`ZQAuR|NvURy !MOL$lwsjXi4GHp81C?UkMMkMGR(>&`4 zu4Bb`W>h7y4^IErxRO+e`~O-zS>pIdB!s}yOId%IYV?2Y{tgU7ArsAnkWeffNu~KR zTTxf+J*H;o^p?T!wo;|q`m(`7iAnRU_o};hj#=)dy<=zk0!)~K$eY?6jdoLnv2|>3 zd7aDPDDqX|`IyLfS}9eLZ5La-sj}rP$yitHrrX>RWAKvPO7^yK>PKKcDU7i7I5v@b zU`MQT?Oxg7?FNDW7m!uSi=s%!d$?M~3e@sS6&m)D6Gk-(9p^bA27d3X!?gdOzso|& zcyjKK%(sMkhqc=^=}KO1{-asWGcw4XcJ-J6Hb_3NS4Q(J4p&2Hn|r#fkRLKp+#@3N zd%+M(CYv>`diIC35_}O$49qXS((Eg%;Qr_ON>_+Duvh>j z00uH0@+-^12>-VSp8=SD1HgRy1`qiS0utieH;8S3|EB-|`1v)K_zM6TIaxV?008j$ z4ioiW3IM=FeN!g_faPp0eeE}rkWF7IL;wgNSX2y|av&HA6ttV$R)|nQVEX~d4r_

kN=vRciky;L+ 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 diff --git a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff2 b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff2 deleted file mode 100644 index a87d9cd7c6124a9fb103fe349dd91f55eed52c5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9932 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 K;{%RVQL6!h1TU%p diff --git a/docs/assets/js/scale.fix.js b/docs/assets/js/scale.fix.js deleted file mode 100644 index 911d33c3..00000000 --- a/docs/assets/js/scale.fix.js +++ /dev/null @@ -1,27 +0,0 @@ -(function(document) { - var metas = document.getElementsByTagName('meta'), - changeViewportContent = function(content) { - for (var i = 0; i < metas.length; i++) { - if (metas[i].name == "viewport") { - metas[i].content = content; - } - } - }, - initialize = function() { - changeViewportContent("width=device-width, minimum-scale=1.0, maximum-scale=1.0"); - }, - gestureStart = function() { - changeViewportContent("width=device-width, minimum-scale=0.25, maximum-scale=1.6"); - }, - gestureEnd = function() { - initialize(); - }; - - - if (navigator.userAgent.match(/iPhone/i)) { - initialize(); - - document.addEventListener("touchstart", gestureStart, false); - document.addEventListener("touchend", gestureEnd, false); - } -})(document); diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index ed782b26..00000000 --- a/docs/index.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - - - PHPCSUtils: utility functions for use with PHP_CodeSniffer. - - - - - - - - - - - - - - -

-
-

PHPCSUtils

- - - -

A suite of utility functions for use with PHP_CodeSniffer.

- -

Visit the Project on GitHub PHPCSStandards/PHPCSUtils

- -

Read the Documentation

- -
- Install using Composer:
-
composer require phpcsstandards/phpcsutils
-
- -

- -
-
- -

Features

- -

PHPCSUtils is a set of utilities to aid developers of sniffs for PHP_CodeSniffer.

- -

This package offers the following features:

- -
-
Use the latest version of PHP_CodeSniffer native utility functions.
-
-

Normally to use the latest version of PHP_CodeSniffer native utility functions, you would have to raise the minimum requirements of your external PHPCS standard.

- -

Now you won't have to anymore. This package allows you to use the latest version of those utility functions in all PHP_CodeSniffer versions from PHPCS 2.6.0 and up.

-
- -
Several abstract sniff classes which your sniffs can extend.
-
-

These classes take most of the heavy lifting away for some frequently occurring sniff types.

-
- -
A collection of static properties for often-used token groups.
-
-

Collections of related tokens often-used and needed for sniffs.
- These are additional "token groups" to compliment the ones available through the PHPCS native PHP_CodeSniffer\Util\Tokens class.

-
- -
An ever-growing number of utility functions for use with PHP_CodeSniffer.
-
-

Whether you need to split an array into the individual items, are trying to determine which variables are being assigned to in a list() or are figuring out whether a function has a DocBlock, PHPCSUtils has you covered!

- -

Includes improved versions of the PHPCS native utility functions and plenty of new utility functions.

- -

These functions are, of course, compatible with PHPCS 2.6.0 up to PHPCS master.

-
- -
Test utilities
-
-

An abstract UtilityMethodTestCase class to support testing of your utility methods written for PHP_CodeSniffer.
- Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 9.x.

-
- -
Backward compatibility layer
-
-

A PHPCS23Utils standard which allows sniffs to work in both PHPCS 2.x and 3.x, as well as a few helper functions for external standards which still want to support both PHP_CodeSniffer 2.x as well as 3.x.

-
- -
Fully documented
-
-

To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the extensive documentation.

-
-
- - -

Minimum Requirements

- -
    -
  • PHP 5.4 or higher.
  • -
  • PHP_CodeSniffer 2.6.0+, 3.1.0+ (with the exception of PHPCS 3.5.3).
  • -
- - -

Integrating PHPCSUtils in your external PHPCS standard

- -

Composer-based with a minimum PHPCS requirement of PHPCS 3.1.0

- -

If your external PHP_CodeSniffer standard only supports Composer-based installs and has a minimum PHPCS requirement of PHP_CodeSniffer 3.1.0, integrating PHPCSUtils is pretty straight forward.

- -

Run the following from the root of your external PHPCS standard's project:

-
composer require phpcsstandards/phpcsutils:"^1.0"
-        
- -

No further action needed. You can start using all the utility functions, abstract sniff classes and other features of PHPCSUtils straight away.

- -
-

The PHPCSUtils package includes the DealerDirect Composer PHPCS plugin.

- -

This plugin will automatically register PHPCSUtils (and your own external standard) with PHP_CodeSniffer, so you and your users don't have to worry about this anymore.

- -

Note: if your end-user installation instructions include instructions on adding a Composer PHPCS plugin or on manually registering your standard with PHPCS using the --config-set installed_paths command, you can remove those instructions as they are no longer needed.

-
- -

Running your unit tests

- -

If your unit tests use the PHP_CodeSniffer native unit test suite, all is good.

- -

If you have your own unit test suite to test your sniffs, make sure to load the Composer vendor/autoload.php file in your PHPUnit bootstrap file or as the PHPUnit bootstrap file.

- -

If you intend to use the test utilities provided in the PHPCSUtils/TestUtils directory, make sure you also load the vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php file in your PHPUnit bootstrap file.

- - -

Composer-based with a minimum PHPCS requirement of PHPCS 2.6.0

- -

Follow the above instructions for use with PHPCS 3.x.

- -

In addition to that, add the following to the ruleset.xml file of your standard(s):

-
<!-- Make the utility functions available in PHPCS 2.x -->
-        <rule ref="PHPCS23Utils"/>
-        
- -
-

The PHPCS23Utils "standard" does not add any real sniffs, it just makes sure that the Utility functions will work in PHPCS 2.x as well.

-
- -

Running your unit tests

- -

If your standard supports both PHPCS 2.x as well as 3.x, you are bound to already have a PHPUnit bootstrap.php file in place.

- -

To allow the unit tests to find the relevant files for PHPCSUtils, make sure that the bootstrap loads both the Composer vendor/autoload.php file, as well as the vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php file.

- - -

Frequently Asked Questions

- -
-

Q: How does this all work without an external standard needing to register an autoloader?

- -

A: As PHPCSUtils is registered with PHPCS as an external standard and PHPCSUtils complies with the naming requirements of PHPCS, the PHPCS native autoloader will automatically take care of loading the classes you use from PHPCSUtils.

- -

Q: What does the PHPCS23Utils standard do?

- -

A: All the PHPCS23Utils standard does is load the phpcsutils-autoload.php file.

- -

PHPCS 3.x uses namespaces, while PHPCS 2.x does not. The phpcsutils-autoload.php file creates class_alias-es for the most commonly used PHPCS classes, including all PHPCS classes used by PHPCSUtils. That way, both your external standard as well as PHPCSUtils can refer to the PHPCS 3.x class names and the code will still work in PHPCS 2.x.

- -

Q: Why is PHP_CodeSniffer 3.5.3 not supported?

- -

A: The backfill for PHP 7.4 numeric literals with underscores in PHP_CodeSniffer 3.5.3 is broken and there is no way to reliably provide support for anything to do with numbers or T_STRING tokens when using PHP_CodeSniffer 3.5.3 as the tokens returned by the tokenizer are unpredictable and unreliable.

- -

The backfill was fixed in PHP_CodeSniffer 3.5.4.

-
- -

Contributing

- -

Contributions to this project are welcome. Clone the repo, branch off from develop, make your changes, commit them and send in a pull request.

- -

If you are unsure whether the changes you are proposing would be welcome, please open an issue first to discuss your proposal.

- -

License

- -

The code of PHPCSUtils is released under the GNU Lesser General Public License (LGPLv3).

- - -
-
- -

This project is maintained by jrfnl

- -

Hosted on GitHub Pages — Theme by orderedlist

-
-
- - - - - - - diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..9dee39a2 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,146 @@ +--- +title: PHPCSUtils +description: "PHPCSUtils: A suite of utility functions for use with PHP_CodeSniffer." +anchor: home +permalink: / +seo: + type: WebSite + publisher: + type: Organisation +--- + +Features +------------------------------------------- + +[PHPCSUtils](https://github.com/PHPCSStandards/PHPCSUtils) is a set of utilities to aid developers of sniffs for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). + +This package offers the following features: + +
+ +### Use the latest version of PHP_CodeSniffer native utility functions. + +Normally to use the latest version of PHP_CodeSniffer native utility functions, you would have to raise the minimum requirements of your external PHPCS standard. + +Now you won't have to anymore. This package allows you to use the latest version of those utility functions in all PHP_CodeSniffer versions from PHPCS 2.6.0 and up. + +### Several abstract sniff classes which your sniffs can extend. + +These classes take most of the heavy lifting away for some frequently occurring sniff types. + +### A collection of static properties for often-used token groups. + +Collections of related tokens often-used and needed for sniffs. +These are additional "token groups" to compliment the ones available through the PHPCS native `PHP_CodeSniffer\Util\Tokens` class. + +### An ever-growing number of utility functions for use with PHP_CodeSniffer. + +Whether you need to split an `array` into the individual items, are trying to determine which variables are being assigned to in a `list()` or are figuring out whether a function has a DocBlock, PHPCSUtils has you covered! + +Includes improved versions of the PHPCS native utility functions and plenty of new utility functions. + +These functions are, of course, compatible with PHPCS 2.6.0 up to PHPCS `master`. + +### Test utilities + +An abstract `UtilityMethodTestCase` class to support testing of your utility methods written for PHP_CodeSniffer. +Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 9.x. + +### Backward compatibility layer + +A `PHPCS23Utils` standard which allows sniffs to work in both PHPCS 2.x and 3.x, as well as a few helper functions for external standards which still want to support both PHP_CodeSniffer 2.x as well as 3.x. + +### Fully documented + +To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the [extensive documentation](https://phpcsutils.com/). + +
+ +Minimum Requirements +------------------------------------------- + +* PHP 5.4 or higher. +* [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 2.6.0+, 3.1.0+ (with the exception of PHPCS 3.5.3). + + +Integrating PHPCSUtils in your external PHPCS standard +------------------------------------------- + +### Composer-based with a minimum PHPCS requirement of PHPCS 3.1.0 + +If your external PHP_CodeSniffer standard only supports Composer-based installs and has a minimum PHPCS requirement of PHP_CodeSniffer 3.1.0, integrating PHPCSUtils is pretty straight forward. + +Run the following from the root of your external PHPCS standard's project: + +
composer require {{ site.phpcsutils.packagist }}:"^1.0"
+
+ +No further action needed. You can start using all the utility functions, abstract sniff classes and other features of PHPCSUtils straight away. + +> :information_source: The PHPCSUtils package includes the [DealerDirect Composer PHPCS plugin](https://github.com/Dealerdirect/phpcodesniffer-composer-installer). +> +> This plugin will automatically register PHPCSUtils (and your own external standard) with PHP_CodeSniffer, so you and your users don't have to worry about this anymore. +> +> :warning: Note: if your end-user installation instructions include instructions on adding a Composer PHPCS plugin or on manually registering your standard with PHPCS using the `--config-set installed_paths` command, you can remove those instructions as they are no longer needed. + +#### Running your unit tests + +If your unit tests use the PHP_CodeSniffer native unit test suite, all is good. + +If you have your own unit test suite to test your sniffs, make sure to load the Composer `vendor/autoload.php` file in your PHPUnit bootstrap file or _as_ the PHPUnit bootstrap file. + +If you intend to use the test utilities provided in the `PHPCSUtils/TestUtils` directory, make sure you also load the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file in your PHPUnit bootstrap file. + + +### Composer-based with a minimum PHPCS requirement of PHPCS 2.6.0 + +Follow the above instructions for use with PHPCS 3.x. + +In addition to that, add the following to the `ruleset.xml` file of your standard(s): +```xml + + +``` + +> :information_source: The `PHPCS23Utils` "standard" does not add any real sniffs, it just makes sure that the Utility functions will work in PHPCS 2.x as well. + +#### Running your unit tests + +If your standard supports both PHPCS 2.x as well as 3.x, you are bound to already have a PHPUnit `bootstrap.php` file in place. + +To allow the unit tests to find the relevant files for PHPCSUtils, make sure that the bootstrap loads both the Composer `vendor/autoload.php` file, as well as the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file. + + + +Frequently Asked Questions +------- + +
+ +#### Q: How does this all work without an external standard needing to register an autoloader? + +A: As PHPCSUtils is registered with PHPCS as an external standard and PHPCSUtils complies with the naming requirements of PHPCS, the PHPCS native autoloader will automatically take care of loading the classes you use from PHPCSUtils. + +#### Q: What does the `PHPCS23Utils` standard do? + +A: All the `PHPCS23Utils` standard does is load the `phpcsutils-autoload.php` file. + +PHPCS 3.x uses namespaces, while PHPCS 2.x does not. The `phpcsutils-autoload.php` file creates `class_alias`-es for the most commonly used PHPCS classes, including all PHPCS classes used by PHPCSUtils. That way, both your external standard as well as PHPCSUtils can refer to the PHPCS 3.x class names and the code will still work in PHPCS 2.x. + +#### Q: Why is PHP_CodeSniffer 3.5.3 not supported? + +A: The backfill for PHP 7.4 numeric literals with underscores in PHP_CodeSniffer 3.5.3 is broken and there is no way to reliably provide support for anything to do with numbers or `T_STRING` tokens when using PHP_CodeSniffer 3.5.3 as the tokens returned by the tokenizer are unpredictable and unreliable. + +The backfill was fixed in PHP_CodeSniffer 3.5.4. + +
+ +Contributing +------- +Contributions to this project are welcome. Clone the repo, branch off from `develop`, make your changes, commit them and send in a pull request. + +If you are unsure whether the changes you are proposing would be welcome, please open an issue first to discuss your proposal. + +License +------- +This code is released under the [GNU Lesser General Public License (LGPLv3)](http://www.gnu.org/copyleft/lesser.html). diff --git a/docs/phpdoc/.nojekyll b/docs/phpdoc/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/robots.txt b/docs/robots.txt new file mode 100644 index 00000000..a2a00dda --- /dev/null +++ b/docs/robots.txt @@ -0,0 +1,5 @@ +# /robots.txt file for https://phpcsutils.com/ + +User-agent: * +Allow: / +Sitemap: https://phpcsutils.com/sitemap.xml From a44db1ad146c2477447bc7d773d6e242b41ce427 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 30 May 2020 20:46:18 +0200 Subject: [PATCH 50/79] Travis: add a build check for the GH Pages site Adding a stage to check on each PR and merge to `master` whether the GH pages site can be build without errors. --- .travis.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.travis.yml b/.travis.yml index c83d89cb..a1095712 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +os: linux dist: trusty language: php @@ -10,6 +11,7 @@ cache: - $HOME/.composer/cache/files # Cache directory for more recent Composer versions. - $HOME/.cache/composer/files + - /home/travis/.rvm/ php: - 5.5 @@ -31,6 +33,8 @@ env: # See: https://docs.travis-ci.com/user/conditions-v1 stages: - name: sniff + - name: docs + if: branch IN (master) - name: quicktest if: type = push AND branch NOT IN (master, develop) - name: test @@ -66,6 +70,24 @@ jobs: # Check the code-style consistency of the xml files. - diff -B ./PHPCSUtils/ruleset.xml <(xmllint --format "./PHPCSUtils/ruleset.xml") - diff -B ./PHPCS23Utils/ruleset.xml <(xmllint --format "./PHPCS23Utils/ruleset.xml") + after_success: skip + + #### DOCUMENTATION SITE TESTING STAGE #### + - stage: docs + language: ruby + cache: bundler + rvm: + - 2.5.8 + before_install: skip + install: + - cd ./docs + - gem install bundler + - bundle install + before_script: skip + script: + # Test the documentation generation. + - bundle exec jekyll build + after_success: skip #### QUICK TEST STAGE #### # This is a much quicker test which only runs the unit tests and linting against the low/high From 66388b82c9f4ca36648e2703bed555a4be6eb9cd Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 31 May 2020 02:26:52 +0200 Subject: [PATCH 51/79] Operators::isReference(): bug fix - closure return by reference not recognized The `&` in a closure declared to return by reference was not recognized as a reference. Fixed now. Includes unit test. The same fix has also been pulled upstream: squizlabs/php_codesniffer 2977 --- PHPCSUtils/Utils/Operators.php | 3 +++ Tests/Utils/Operators/IsReferenceDiffTest.inc | 3 +++ Tests/Utils/Operators/IsReferenceDiffTest.php | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/PHPCSUtils/Utils/Operators.php b/PHPCSUtils/Utils/Operators.php index 016af66f..2c9077a2 100644 --- a/PHPCSUtils/Utils/Operators.php +++ b/PHPCSUtils/Utils/Operators.php @@ -57,6 +57,8 @@ class Operators * Determine if the passed token is a reference operator. * * Main differences with the PHPCS version: + * - Bug fixed: the `&` for a closure declared to return by reference was not recognized as + * a reference. {@link https://github.com/squizlabs/PHP_CodeSniffer/pull/2977 Open PR upstream} * - Defensive coding against incorrect calls to this method. * - Improved handling of select tokenizer errors involving short lists/short arrays. * @@ -83,6 +85,7 @@ public static function isReference(File $phpcsFile, $stackPtr) $tokenBefore = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); if ($tokens[$tokenBefore]['code'] === \T_FUNCTION + || $tokens[$tokenBefore]['code'] === T_CLOSURE || FunctionDeclarations::isArrowFunction($phpcsFile, $tokenBefore) === true ) { // Function returns a reference. diff --git a/Tests/Utils/Operators/IsReferenceDiffTest.inc b/Tests/Utils/Operators/IsReferenceDiffTest.inc index 2f9f0e04..314930af 100644 --- a/Tests/Utils/Operators/IsReferenceDiffTest.inc +++ b/Tests/Utils/Operators/IsReferenceDiffTest.inc @@ -11,3 +11,6 @@ if ($foo) {} /* testTokenizerIssue1284PHPCSlt280C */ if ($foo) {} [&$a, $b]; + +/* testClosureReturnByReference */ +$closure = function &($param) use ($value) {}; diff --git a/Tests/Utils/Operators/IsReferenceDiffTest.php b/Tests/Utils/Operators/IsReferenceDiffTest.php index 86bf7c01..6ffca582 100644 --- a/Tests/Utils/Operators/IsReferenceDiffTest.php +++ b/Tests/Utils/Operators/IsReferenceDiffTest.php @@ -85,6 +85,10 @@ public function dataIsReference() '/* testTokenizerIssue1284PHPCSlt280C */', true, ], + 'closure-return-by-reference' => [ + '/* testClosureReturnByReference */', + true, + ], ]; } } From d84cfcfcf6ff8f4f461a77d6716b9bb847a63bac Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 5 Jun 2020 13:43:26 +0200 Subject: [PATCH 52/79] FunctionDeclarations::getArrowFunctionOpenClose(): arrow functions as function argument Allow for arrow functions being used as function argument as per upstream commit squizlabs/PHP_CodeSniffer/commit/2914011675cd13f8a7d5eae16ed1d5ee4f0e701d which is included in PHPCS 3.5.5. Also see: squizlabs/PHP_CodeSniffer 2895 and squizlabs/PHP_CodeSniffer 2523 Co-authored-by: Greg Sherwood --- PHPCSUtils/Utils/FunctionDeclarations.php | 15 ++++++++++-- .../IsArrowFunctionTest.inc | 10 ++++++++ .../IsArrowFunctionTest.php | 24 +++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 54382489..e40b9999 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -676,6 +676,7 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) if ($tokens[$stackPtr]['type'] === 'T_FN' && isset($tokens[$stackPtr]['scope_closer']) === true + && \version_compare(Helper::getVersion(), '3.5.4', '>') === true ) { // The keys will either all be set or none will be set, so no additional checks needed. return [ @@ -736,12 +737,20 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) $returnValue['scope_opener'] = $arrow; $inTernary = false; + $lastEndToken = null; for ($scopeCloser = ($arrow + 1); $scopeCloser < $phpcsFile->numTokens; $scopeCloser++) { if (isset(self::$arrowFunctionEndTokens[$tokens[$scopeCloser]['code']]) === true // BC for misidentified ternary else in some PHPCS versions. && ($tokens[$scopeCloser]['code'] !== \T_COLON || $inTernary === false) ) { + if ($lastEndToken !== null + && $tokens[$scopeCloser]['code'] === \T_CLOSE_PARENTHESIS + && $tokens[$scopeCloser]['parenthesis_opener'] < $arrow + ) { + $scopeCloser = $lastEndToken; + } + break; } @@ -763,12 +772,14 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) } if (isset($tokens[$scopeCloser]['parenthesis_closer']) === true) { - $scopeCloser = $tokens[$scopeCloser]['parenthesis_closer']; + $scopeCloser = $tokens[$scopeCloser]['parenthesis_closer']; + $lastEndToken = $scopeCloser; continue; } if (isset($tokens[$scopeCloser]['bracket_closer']) === true) { - $scopeCloser = $tokens[$scopeCloser]['bracket_closer']; + $scopeCloser = $tokens[$scopeCloser]['bracket_closer']; + $lastEndToken = $scopeCloser; continue; } diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc index 65d80aaf..37b96680 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc @@ -88,6 +88,16 @@ array_map( /* testTernary */ $fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b'; +$foo = foo( + /* testArrowFunctionAsArgument */ + fn() => bar() +); + +$foo = foo( + /* testArrowFunctionWithArrayAsArgument */ + fn() => [$row[0], $row[3]] +); + /* testConstantDeclaration */ const FN = 'a'; diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php index 369a1651..06ee6265 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php @@ -456,6 +456,30 @@ public function dataArrowFunction() ], ], ], + 'arrow-function-as-function-call-argument' => [ + '/* testArrowFunctionAsArgument */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 4, + 'scope_closer' => 8, + ], + ], + ], + 'arrow-function-as-function-call-argument-with-array-return' => [ + '/* testArrowFunctionWithArrayAsArgument */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 4, + 'scope_closer' => 17, + ], + ], + ], 'arrow-function-nested-in-method' => [ '/* testNestedInMethod */', [ From 26509fdd6099e14c725549f65067b851cc63bd25 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 5 Jun 2020 13:44:57 +0200 Subject: [PATCH 53/79] BCFile::findEndOfStatement(): arrow functions as function argument Allow for arrow functions being used as function argument as per upstream commit squizlabs/PHP_CodeSniffer/commit/2914011675cd13f8a7d5eae16ed1d5ee4f0e701d which is included in PHPCS 3.5.5. Also see: squizlabs/PHP_CodeSniffer 2895 and squizlabs/PHP_CodeSniffer 2523 Co-authored-by: Greg Sherwood --- PHPCSUtils/BackCompat/BCFile.php | 7 ++++- .../BCFile/FindEndOfStatementTest.inc | 10 +++++++ .../BCFile/FindEndOfStatementTest.php | 29 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 522c6490..3336ede8 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -1251,6 +1251,7 @@ public static function findStartOfStatement(File $phpcsFile, $start, $ignore = n * - PHPCS 3.5.0: Improved handling of group use statements. * - PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions. * - PHPCS 3.5.4: Improved support for PHP 7.4 T_FN arrow functions. + * - PHPCS 3.5.5: Improved support for PHP 7.4 T_FN arrow functions, PHPCS #2895. * * @see \PHP_CodeSniffer\Files\File::findEndOfStatement() Original source. * @@ -1288,7 +1289,6 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul } $lastNotEmpty = $start; - for ($i = $start; $i < $phpcsFile->numTokens; $i++) { if ($i !== $start && isset($endTokens[$tokens[$i]['code']]) === true) { // Found the end of the statement. @@ -1311,6 +1311,8 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul || $i === $tokens[$i]['scope_condition']) ) { if ($tokens[$i]['type'] === 'T_FN') { + $lastNotEmpty = $tokens[$i]['scope_closer']; + // Minus 1 as the closer can be shared. $i = ($tokens[$i]['scope_closer'] - 1); continue; @@ -1342,8 +1344,11 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul return $arrowFunctionOpenClose['scope_closer']; } + $lastNotEmpty = $arrowFunctionOpenClose['scope_closer']; + // Minus 1 as the closer can be shared. $i = ($arrowFunctionOpenClose['scope_closer'] - 1); + continue; } } diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc b/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc index a86ed250..921e7996 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc @@ -42,4 +42,14 @@ static fn ($a) => $a; /* testArrowFunctionReturnValue */ fn(): array => [a($a, $b)]; +$foo = foo( + /* testArrowFunctionAsArgument */ + fn() => bar() +); + +$foo = foo( + /* testArrowFunctionWithArrayAsArgument */ + fn() => [$row[0], $row[3]] +); + return 0; diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index bccaa733..6cb7f7d4 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -207,4 +207,33 @@ public function testArrowFunctionReturnValue() $this->assertSame(($start + 18), $found); } + + /** + * Test arrow function used as a function argument. + * + * @return void + */ + public function testArrowFunctionAsArgument() + { + $start = $this->getTargetToken('/* testArrowFunctionAsArgument */', Collections::arrowFunctionTokensBC()); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 8), $found); + } + + /** + * Test arrow function with arrays used as a function argument. + * + * @return void + */ + public function testArrowFunctionWithArrayAsArgument() + { + $start = $this->getTargetToken( + '/* testArrowFunctionWithArrayAsArgument */', + Collections::arrowFunctionTokensBC() + ); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 17), $found); + } } From 2d91603a475681aa013f25307caf487084e50e74 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 5 Jun 2020 07:09:46 +0200 Subject: [PATCH 54/79] FunctionDeclarations::getArrowFunctionOpenClose(): allow for returning heredoc/nowdoc ... as per upstream commit squizlabs/PHP_CodeSniffer/commit/ce62dee92da3b038a399a99353fc055b39d2853e which will be included in PHPCS 3.5.6. Also see: squizlabs/PHP_CodeSniffer 2926 As the PHPCS Tokenizer will hang completely when it encounters an arrow function with a heredoc/nowdoc return in PHPCS 3.5.3-3.5.5, this change needs a separate test file as these tests need to be skipped on those PHPCS versions. Co-authored-by: Greg Sherwood --- PHPCSUtils/Utils/FunctionDeclarations.php | 2 + .../IsArrowFunction2926Test.inc | 11 ++ .../IsArrowFunction2926Test.php | 182 ++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.inc create mode 100644 Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index e40b9999..911ca619 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -765,6 +765,8 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) if (isset($tokens[$scopeCloser]['scope_closer']) === true && $tokens[$scopeCloser]['code'] !== \T_INLINE_ELSE + && $tokens[$scopeCloser]['code'] !== \T_END_HEREDOC + && $tokens[$scopeCloser]['code'] !== \T_END_NOWDOC ) { // We minus 1 here in case the closer can be shared with us. $scopeCloser = ($tokens[$scopeCloser]['scope_closer'] - 1); diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.inc b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.inc new file mode 100644 index 00000000..754a689f --- /dev/null +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.inc @@ -0,0 +1,11 @@ + << <<<'HTML' +fn +HTML; diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php new file mode 100644 index 00000000..ca2431fd --- /dev/null +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php @@ -0,0 +1,182 @@ + true, + '3.5.4' => true, + '3.5.5' => true, + ]; + + /** + * Whether the test case file has been tokenized. + * + * Efficiency tweak as the tokenization is done in "before" not in "before class" + * for this test. + * + * @var bool + */ + private static $tokenized = false; + + /** + * Do NOT Initialize PHPCS & tokenize the test case file. + * + * Skip tokenizing the test case file on "before class" as at that time, we can't skip the test + * yet if the PHPCS version in incompatible and it would hang the Tokenizer (and therefore + * the test) if it is. + * + * @beforeClass + * + * @return void + */ + public static function setUpTestFile() + { + // Skip the tokenizing of the test case file at this time. + } + + /** + * Initialize PHPCS & tokenize the test case file on compatible PHPCS versions. + * + * Skip this test on PHPCS versions on which the Tokenizer will hang. + * + * @before + * + * @return void + */ + public function setUpTestFileForReal() + { + $phpcsVersion = Helper::getVersion(); + + if (isset($this->unsupportedPHPCSVersions[$phpcsVersion]) === true) { + $this->markTestSkipped("Issue 2926 can not be tested on PHPCS $phpcsVersion as the Tokenizer will hang."); + } + + if (self::$tokenized === false) { + parent::setUpTestFile(); + self::$tokenized = true; + } + } + + /** + * Test correctly detecting arrow functions. + * + * @dataProvider dataArrowFunction + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected The expected return value for the respective functions. + * @param array $targetContent The content for the target token to look for in case there could + * be confusion. + * + * @return void + */ + public function testIsArrowFunction($testMarker, $expected, $targetContent = null) + { + $targets = Collections::arrowFunctionTokensBC(); + $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); + $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); + $this->assertSame($expected['is'], $result); + } + + /** + * Test correctly detecting arrow functions. + * + * @dataProvider dataArrowFunction + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected The expected return value for the respective functions. + * @param string $targetContent The content for the target token to look for in case there could + * be confusion. + * + * @return void + */ + public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetContent = 'fn') + { + $targets = Collections::arrowFunctionTokensBC(); + $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); + + // Change from offsets to absolute token positions. + if ($expected['get'] != false) { + foreach ($expected['get'] as $key => $value) { + $expected['get'][$key] += $stackPtr; + } + } + + $result = FunctionDeclarations::getArrowFunctionOpenClose(self::$phpcsFile, $stackPtr); + $this->assertSame($expected['get'], $result); + } + + /** + * Data provider. + * + * @see testIsArrowFunction() For the array format. + * @see testgetArrowFunctionOpenClose() For the array format. + * + * @return array + */ + public function dataArrowFunction() + { + return [ + 'arrow-function-returning-heredoc' => [ + '/* testHeredoc */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 4, + 'scope_closer' => 9, + ], + ], + ], + 'arrow-function-returning-nowdoc' => [ + '/* testNowdoc */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 4, + 'scope_closer' => 9, + ], + ], + ], + ]; + } +} From ab83c4878b062d9f55e4e2398861bf0836f4a84f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 6 Jun 2020 00:07:00 +0200 Subject: [PATCH 55/79] Travis: minor tweak This was causing a warning. Fixed now. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a1095712..c03a7706 100644 --- a/.travis.yml +++ b/.travis.yml @@ -76,8 +76,7 @@ jobs: - stage: docs language: ruby cache: bundler - rvm: - - 2.5.8 + rvm: 2.5.8 before_install: skip install: - cd ./docs From 695e4f085398c9f969e0e51781c52172340dc2f1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 29 May 2020 17:11:39 +0200 Subject: [PATCH 56/79] Docs: various grammar/spelling/inline mark-up fixes --- PHPCSUtils/Tokens/Collections.php | 4 ++-- PHPCSUtils/Utils/ControlStructures.php | 4 ++-- PHPCSUtils/Utils/FunctionDeclarations.php | 4 ++-- PHPCSUtils/Utils/Lists.php | 2 +- PHPCSUtils/Utils/Numbers.php | 4 ++-- PHPCSUtils/Utils/ObjectDeclarations.php | 2 +- phpcsutils-autoload.php | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 2c5dc19c..74eefbc8 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -406,7 +406,7 @@ class Collections * The method supports PHPCS 2.6.0 and up. * * Notable differences: - * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE tokens when used with PHPCS 2.x and 3.x. + * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. * These token constants will no longer exist in PHPCS 4.x. * - The method will include the `T_ARRAY` token which is needed for select arrow functions in PHPCS < 3.5.4. * @@ -661,7 +661,7 @@ public static function propertyTypeTokensBC() * The method supports PHPCS 2.6.0 and up. * * Notable differences: - * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE tokens when used with PHPCS 2.x and 3.x. + * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. * These token constants will no longer exist in PHPCS 4.x. * - The method will include the `T_ARRAY` token which is needed for select arrow functions in PHPCS < 3.5.4. * diff --git a/PHPCSUtils/Utils/ControlStructures.php b/PHPCSUtils/Utils/ControlStructures.php index f2a53a9e..6b9798e9 100644 --- a/PHPCSUtils/Utils/ControlStructures.php +++ b/PHPCSUtils/Utils/ControlStructures.php @@ -200,7 +200,7 @@ public static function isElseIf(File $phpcsFile, $stackPtr) * Get the scope opener and closer for a `declare` statement. * * A `declare` statement can be: - * - applied to the rest of the file, like `declare(ticks=1);`; + * - applied to the rest of the file, like `declare(ticks=1);` * - applied to a limited scope using curly braces; * - applied to a limited scope using the alternative control structure syntax. * @@ -358,7 +358,7 @@ public static function getDeclareScopeOpenClose(File $phpcsFile, $stackPtr) * @return array * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified $stackPtr is not of - * type T_CATCH or doesn't exist or in case + * type T_CATCH, doesn't exist or in case * of a parse error. */ public static function getCaughtExceptions(File $phpcsFile, $stackPtr) diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 911ca619..682c1c04 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -201,7 +201,7 @@ public static function getName(File $phpcsFile, $stackPtr) * @return array * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a T_FUNCTION - * or T_CLOSURE token nor an arrow function. + * or T_CLOSURE token, nor an arrow function. */ public static function getProperties(File $phpcsFile, $stackPtr) { @@ -604,7 +604,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) * T_STRING token as those are the only two * tokens which can be the arrow function keyword. * - * @return bool TRUE is the token is the "fn" keyword for an arrow function. FALSE when not or + * @return bool TRUE if the token is the "fn" keyword for an arrow function. FALSE when not or * in case of live coding/parse error. */ public static function isArrowFunction(File $phpcsFile, $stackPtr) diff --git a/PHPCSUtils/Utils/Lists.php b/PHPCSUtils/Utils/Lists.php index 4ffc0eee..cdebae7b 100644 --- a/PHPCSUtils/Utils/Lists.php +++ b/PHPCSUtils/Utils/Lists.php @@ -260,7 +260,7 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortList = n * // second item in `list($a, , $b)`. * 'is_nested_list' => bool, // Whether this is a nested list. * 'variable' => string|false, // The base variable being assigned to or - * // FALSE in case of a nested list or avariable variable. + * // FALSE in case of a nested list or a variable variable. * // I.e. `$a` in `list($a['key'])`. * 'assignment_token' => int|false, // The start pointer for the assignment. * 'assignment_end_token' => int|false, // The end pointer for the assignment. diff --git a/PHPCSUtils/Utils/Numbers.php b/PHPCSUtils/Utils/Numbers.php index 662e0072..5f2c271d 100644 --- a/PHPCSUtils/Utils/Numbers.php +++ b/PHPCSUtils/Utils/Numbers.php @@ -95,7 +95,7 @@ class Numbers `ixD'; /** - * Regex to determine is a T_STRING following a T_[DL]NUMBER is part of a numeric literal sequence. + * Regex to determine if a T_STRING following a T_[DL]NUMBER is part of a numeric literal sequence. * * PHP cross-version compat for PHP 7.4 numeric literals with underscore separators. * @@ -144,7 +144,7 @@ class Numbers * Helper function to deal with numeric literals, potentially with underscore separators. * * PHP < 7.4 does not tokenize numeric literals containing underscores correctly. - * As of PHPCS 3.5.3, PHPCS contains a back-fill, but this backfill was buggy in the initial + * As of PHPCS 3.5.3, PHPCS contains a backfill, but this backfill was buggy in the initial * implementation. A fix for this broken backfill is included in PHPCS 3.5.4. * * Either way, this function provides a backfill for all PHPCS/PHP combinations where diff --git a/PHPCSUtils/Utils/ObjectDeclarations.php b/PHPCSUtils/Utils/ObjectDeclarations.php index 8f38fb7e..621f92f5 100644 --- a/PHPCSUtils/Utils/ObjectDeclarations.php +++ b/PHPCSUtils/Utils/ObjectDeclarations.php @@ -219,7 +219,7 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) * Works for classes, anonymous classes and interfaces, though it is strongly recommended * to use the {@see \PHPCSUtils\Utils\ObjectDeclarations::findExtendedInterfaceNames()} * method to examine interfaces instead. Interfaces can extend multiple parent interfaces, - * and that use case is not handled by this method. + * and that use-case is not handled by this method. * * Main differences with the PHPCS version: * - Bugs fixed: diff --git a/phpcsutils-autoload.php b/phpcsutils-autoload.php index d9cd9349..75fced23 100644 --- a/phpcsutils-autoload.php +++ b/phpcsutils-autoload.php @@ -102,7 +102,7 @@ class_alias('\PHP_CodeSniffer_Exception', '\PHP_CodeSniffer\Exceptions\Tokenizer /* * Alias the PHPUnit 4/5 TestCase class to its PHPUnit 6+ name. * - * This allows the both the PHPCSUtils native unit tests as well as the + * This allows both the PHPCSUtils native unit tests as well as the * `UtilityMethodTestCase` class to work cross-version with PHPUnit * below 6.x and above. * From 5818192c50a9fa05ceadf5b3f22ba2a705ee68ac Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 29 May 2020 17:14:51 +0200 Subject: [PATCH 57/79] Docs: minor docblock format fixes --- PHPCSUtils/Tokens/Collections.php | 2 +- PHPCSUtils/Utils/Arrays.php | 1 + PHPCSUtils/Utils/Lists.php | 1 - Tests/BackCompat/BCFile/FindEndOfStatementTest.php | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 74eefbc8..55524ec6 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -343,7 +343,7 @@ class Collections * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.3.0. * * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC() Related method (cross-version). - + * * @since 1.0.0 * * @var array => diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index 750da555..9b7d8feb 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -288,6 +288,7 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) /* * BC: work-around a bug in PHPCS 3.5.4 where the double arrow is incorrectly tokenized as T_STRING. + * * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2865 */ if ($tokens[$doubleArrow]['code'] === \T_STRING && $tokens[$doubleArrow]['content'] === '=>') { diff --git a/PHPCSUtils/Utils/Lists.php b/PHPCSUtils/Utils/Lists.php index cdebae7b..4f1646e1 100644 --- a/PHPCSUtils/Utils/Lists.php +++ b/PHPCSUtils/Utils/Lists.php @@ -269,7 +269,6 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortList = n * // FALSE when not a reference assignment. *
* - * * Assignments with keys will have the following additional array indexes set: * * 'key' => string, // The content of the key, cleaned of comments. diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index 6cb7f7d4..e144d598 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -15,7 +15,7 @@ * * With documentation contributions from: * @author Phil Davis - + * * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ From 33c9a8954d9a20921f4cc5b530167ab0323e618d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 29 May 2020 17:12:50 +0200 Subject: [PATCH 58/79] Docs: fix incomplete param types --- PHPCSUtils/BackCompat/Helper.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/PHPCSUtils/BackCompat/Helper.php b/PHPCSUtils/BackCompat/Helper.php index 4ae37784..ef04f69b 100644 --- a/PHPCSUtils/BackCompat/Helper.php +++ b/PHPCSUtils/BackCompat/Helper.php @@ -172,7 +172,7 @@ public static function getTabWidth(File $phpcsFile) * * @since 1.0.0 * - * @param \PHP_CodeSniffer\Files\File $phpcsFile Optional. The current file being processed. + * @param \PHP_CodeSniffer\Files\File|null $phpcsFile Optional. The current file being processed. * * @return string Encoding. Defaults to the PHPCS native default, which is 'utf-8' * for PHPCS 3.x and was 'iso-8859-1' for PHPCS 2.x. @@ -213,8 +213,7 @@ public static function getEncoding(File $phpcsFile = null) * * @since 1.0.0 * - * @param \PHP_CodeSniffer\Files\File $phpcsFile Optional. The current file - * being processed. + * @param \PHP_CodeSniffer\Files\File|null $phpcsFile Optional. The current file being processed. * * @return bool True if annotations should be ignored, false otherwise. */ From 5c38475b05a7f19408c7e4a15c5bfe433b3443ff Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 13 Jun 2020 12:53:59 +0200 Subject: [PATCH 59/79] Docs: fix incorrect FQN --- PHPCSUtils/Tokens/Collections.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 55524ec6..080fca72 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -580,7 +580,7 @@ public static function functionDeclarationTokens() * It is recommended to use the method instead of the property if a standard supports PHPCS < 3.3.0. * * @see \PHPCSUtils\Tokens\Collections::functionDeclarationTokens() Related method (PHPCS 3.5.3+). - * @see \PHPCSUtils\Tokens\FunctionDeclarations::isArrowFunction() Arrow function verification. + * @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() Arrow function verification. * * @since 1.0.0 * From 770b27850f40167ee8eb9076a7de47ec658a7ac3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 12 Jun 2020 09:00:00 +0200 Subject: [PATCH 60/79] Docs: use language agnostic links to the PHP manual Ref: https://www.php.net/urlhowto.php --- PHPCSUtils/Tokens/Collections.php | 4 ++-- PHPCSUtils/Utils/NamingConventions.php | 8 ++++---- PHPCSUtils/Utils/Numbers.php | 2 +- PHPCSUtils/Utils/Variables.php | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 080fca72..b263fd8a 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -204,7 +204,7 @@ class Collections * * @since 1.0.0 * - * @link https://www.php.net/manual/en/language.constants.predefined.php. + * @link https://www.php.net/language.constants.predefined * * @var array => */ @@ -287,7 +287,7 @@ class Collections /** * Tokens types used for "forwarding" calls within OO structures. * - * @link https://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php + * @link https://www.php.net/language.oop5.paamayim-nekudotayim * * @since 1.0.0 * diff --git a/PHPCSUtils/Utils/NamingConventions.php b/PHPCSUtils/Utils/NamingConventions.php index 4eefa224..9b7dfdd7 100644 --- a/PHPCSUtils/Utils/NamingConventions.php +++ b/PHPCSUtils/Utils/NamingConventions.php @@ -24,10 +24,10 @@ class NamingConventions /** * Regular expression to check if a given identifier name is valid for use in PHP. * - * @link http://php.net/manual/en/language.variables.basics.php - * @link http://php.net/manual/en/language.constants.php - * @link http://php.net/manual/en/functions.user-defined.php - * @link http://php.net/manual/en/language.oop5.basic.php + * @link https://www.php.net/language.variables.basics + * @link https://www.php.net/language.constants + * @link https://www.php.net/functions.user-defined + * @link https://www.php.net/en/language.oop5.basic * * @since 1.0.0 * diff --git a/PHPCSUtils/Utils/Numbers.php b/PHPCSUtils/Utils/Numbers.php index 5f2c271d..bbb81e05 100644 --- a/PHPCSUtils/Utils/Numbers.php +++ b/PHPCSUtils/Utils/Numbers.php @@ -71,7 +71,7 @@ class Numbers /** * Regex to determine whether the contents of an arbitrary string represents a float. * - * @link https://www.php.net/manual/en/language.types.float.php + * @link https://www.php.net/language.types.float * * @since 1.0.0 * diff --git a/PHPCSUtils/Utils/Variables.php b/PHPCSUtils/Utils/Variables.php index c420943f..2fe3191a 100644 --- a/PHPCSUtils/Utils/Variables.php +++ b/PHPCSUtils/Utils/Variables.php @@ -38,7 +38,7 @@ class Variables * * @since 1.0.0 * - * @link http://php.net/manual/en/reserved.variables.php + * @link http://php.net/reserved.variables * * @var array => */ From 07bac815e7ee36ff07ce9dc08b9ee485289cbf9f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 10 Jun 2020 20:16:05 +0200 Subject: [PATCH 61/79] phpDocumentor: update the configuration to v 3 * Update the configuration to the format used by phpDocumentor 3. Ref: https://docs.phpdoc.org/3.0/references/configuration.html * Rename the file from `phpdoc.xml.dist` to `phpdoc.dist.xml`. Turns out this project uses the reverse extension order compared to, for instance, PHPUnit and PHPCS. If no issue is open about this in phpDocumentor, I will open one in the near future. --- phpdoc.dist.xml | 27 +++++++++++++++++++++++++++ phpdoc.xml.dist | 22 ---------------------- 2 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 phpdoc.dist.xml delete mode 100644 phpdoc.xml.dist diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml new file mode 100644 index 00000000..f924abe8 --- /dev/null +++ b/phpdoc.dist.xml @@ -0,0 +1,27 @@ + + + + PHPCSUtils + + + docs/phpdoc/ + build/docs/structure/ + + + + + + phpcsutils-autoload.php + PHPCSUtils + + + + +