From d8d1d3d3c34fd2b4d69f847783d2665a4648289a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jan 2020 04:50:05 +0100 Subject: [PATCH 01/48] Travis: remove redundant condition As the tests for this repo do not use the PHPCS native test classes, there is no need for toggling the PHPUnit version. --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 32a29dc4..8e6be1d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -165,12 +165,6 @@ install: if [[ $PHPCS_VERSION == "n/a" ]]; then # Don't install PHPUnit when it's not needed. composer remove --dev phpunit/phpunit --no-update --no-scripts - elif [[ "$PHPCS_VERSION" < "3.1.0" ]]; then - # PHPCS < 3.1.0 is not compatible with PHPUnit 6.x. - composer require --dev phpunit/phpunit:"^4.0||^5.0" --no-update --no-scripts - elif [[ "$PHPCS_VERSION" < "3.2.3" ]]; then - # PHPCS < 3.2.3 is not compatible with PHPUnit 7.x. - composer require --dev phpunit/phpunit:"^4.0||^5.0||^6.0" --no-update --no-scripts fi # --prefer-dist will allow for optimal use of the travis caching ability. From e76b615734f9536af0d7af2f77d5063f05e5b0ca Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 29 Jan 2020 19:38:47 +0100 Subject: [PATCH 02/48] Tokens\Collections: add new `$alternativeControlStructureSyntaxCloserTokens` property --- PHPCSUtils/Tokens/Collections.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index caa0a72e..e85f29f7 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -24,6 +24,19 @@ class Collections { + /** + * Alternative control structure syntax closer keyword tokens. + * + * @var array => + */ + public static $alternativeControlStructureSyntaxCloserTokens = [ + \T_ENDIF => \T_ENDIF, + \T_ENDFOR => \T_ENDFOR, + \T_ENDFOREACH => \T_ENDFOREACH, + \T_ENDWHILE => \T_ENDWHILE, + \T_ENDSWITCH => \T_ENDSWITCH, + ]; + /** * Tokens which are used to create arrays. * From 4961a93785668e7c129df547bc45b7039be8658f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 29 Jan 2020 20:45:53 +0100 Subject: [PATCH 03/48] Tokens\Collections::$alternativeControlStructureSyntaxCloserTokens: add missing T_ENDDECLARE --- PHPCSUtils/Tokens/Collections.php | 1 + 1 file changed, 1 insertion(+) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index e85f29f7..e5eda198 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -35,6 +35,7 @@ class Collections \T_ENDFOREACH => \T_ENDFOREACH, \T_ENDWHILE => \T_ENDWHILE, \T_ENDSWITCH => \T_ENDSWITCH, + \T_ENDDECLARE => \T_ENDDECLARE, ]; /** From 97f7bfeaa106c4d1bb461d3ca85e03a3fda23329 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 30 Jan 2020 07:02:39 +0100 Subject: [PATCH 04/48] :sparkles: New Utils\ControlStructures class This adds three new utility methods: * `hasBody()` - to check whether a control structure has a body and optionally whether that body is non-empty. Returns boolean. This is a helper function to distinguish between structures like `while (++$i < 10);` and `while (++$i < 10) { /* do something */ }`. * `isElseIf()` - to check whether an `T_IF` or `T_ELSE` token is part of an `else if`. Returns boolean. * `getDeclareScopeOpenClose()` - to retrieve the scope open/close pointers for `declare` statements. Returns an array with the stack pointers or false if a file based statement or if the scope open/close pointers could not be determined. Declare statements come in three flavours: - file based, without body: `declare(ticks=1);`; - scoped using curly braces; - scoped using the alternative control structure syntax. In that last case, PHPCS does not assign the scope open/close indexes in the `$tokens` array. A [PR is open to fix this](https://github.com/squizlabs/PHP_CodeSniffer/pull/2843), but for any sniff which needs to support versions of PHPCS prior to the version in which that PR will be merged, this helper method can retrieve the scope open/close indexes. This commit also adds two convenience token arrays for working with control structures to the `PHPCSUtils\Tokens\Collections` class. * `$alternativeControlStructureSyntaxTokens` - tokens which can use the alternative syntax for control structures. * `$controlStructureTokens` - control structure tokens. Includes extensive dedicated unit tests. --- PHPCSUtils/Tokens/Collections.php | 33 ++ PHPCSUtils/Utils/ControlStructures.php | 338 ++++++++++++++++++ ...etDeclareScopeOpenCloseParseError1Test.inc | 5 + ...etDeclareScopeOpenCloseParseError1Test.php | 39 ++ ...etDeclareScopeOpenCloseParseError2Test.inc | 5 + ...etDeclareScopeOpenCloseParseError2Test.php | 39 ++ ...etDeclareScopeOpenCloseParseError3Test.inc | 5 + ...etDeclareScopeOpenCloseParseError3Test.php | 39 ++ ...etDeclareScopeOpenCloseParseError4Test.inc | 5 + ...etDeclareScopeOpenCloseParseError4Test.php | 39 ++ .../GetDeclareScopeOpenCloseTest.inc | 53 +++ .../GetDeclareScopeOpenCloseTest.php | 171 +++++++++ .../HasBodyParseError1Test.inc | 9 + .../HasBodyParseError1Test.php | 44 +++ .../HasBodyParseError2Test.inc | 9 + .../HasBodyParseError2Test.php | 44 +++ Tests/Utils/ControlStructures/HasBodyTest.inc | 226 ++++++++++++ Tests/Utils/ControlStructures/HasBodyTest.php | 321 +++++++++++++++++ .../Utils/ControlStructures/IsElseIfTest.inc | 58 +++ .../Utils/ControlStructures/IsElseIfTest.php | 133 +++++++ 20 files changed, 1615 insertions(+) create mode 100644 PHPCSUtils/Utils/ControlStructures.php create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.inc create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.inc create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.inc create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.inc create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.inc create mode 100644 Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.php create mode 100644 Tests/Utils/ControlStructures/HasBodyParseError1Test.inc create mode 100644 Tests/Utils/ControlStructures/HasBodyParseError1Test.php create mode 100644 Tests/Utils/ControlStructures/HasBodyParseError2Test.inc create mode 100644 Tests/Utils/ControlStructures/HasBodyParseError2Test.php create mode 100644 Tests/Utils/ControlStructures/HasBodyTest.inc create mode 100644 Tests/Utils/ControlStructures/HasBodyTest.php create mode 100644 Tests/Utils/ControlStructures/IsElseIfTest.inc create mode 100644 Tests/Utils/ControlStructures/IsElseIfTest.php diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index e5eda198..0558499e 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -24,6 +24,22 @@ class Collections { + /** + * Control structures which can use the alternative control structure syntax. + * + * @var array => + */ + public static $alternativeControlStructureSyntaxTokens = [ + \T_IF => \T_IF, + \T_ELSEIF => \T_ELSEIF, + \T_ELSE => \T_ELSE, + \T_FOR => \T_FOR, + \T_FOREACH => \T_FOREACH, + \T_SWITCH => \T_SWITCH, + \T_WHILE => \T_WHILE, + \T_DECLARE => \T_DECLARE, + ]; + /** * Alternative control structure syntax closer keyword tokens. * @@ -109,6 +125,23 @@ class Collections \T_CLOSURE => \T_CLOSURE, ]; + /** + * Control structure tokens. + * + * @var array => + */ + public static $controlStructureTokens = [ + \T_IF => \T_IF, + \T_ELSEIF => \T_ELSEIF, + \T_ELSE => \T_ELSE, + \T_FOR => \T_FOR, + \T_FOREACH => \T_FOREACH, + \T_SWITCH => \T_SWITCH, + \T_DO => \T_DO, + \T_WHILE => \T_WHILE, + \T_DECLARE => \T_DECLARE, + ]; + /** * Tokens which are used to create lists. * diff --git a/PHPCSUtils/Utils/ControlStructures.php b/PHPCSUtils/Utils/ControlStructures.php new file mode 100644 index 00000000..af3c2dfa --- /dev/null +++ b/PHPCSUtils/Utils/ControlStructures.php @@ -0,0 +1,338 @@ +getTokens(); + + // Check for the existence of the token. + if (isset($tokens[$stackPtr]) === false + || isset(Collections::$controlStructureTokens[$tokens[$stackPtr]['code']]) === false + ) { + return false; + } + + // Handle `else if`. + if ($tokens[$stackPtr]['code'] === \T_ELSE && isset($tokens[$stackPtr]['scope_opener']) === false) { + $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($next !== false && $tokens[$next]['code'] === \T_IF) { + $stackPtr = $next; + } + } + + // Deal with declare alternative syntax without scope opener. + if ($tokens[$stackPtr]['code'] === \T_DECLARE && isset($tokens[$stackPtr]['scope_opener']) === false) { + $declareOpenClose = self::getDeclareScopeOpenClose($phpcsFile, $stackPtr); + if ($declareOpenClose !== false) { + // Set the opener + closer in the tokens array. This will only affect our local copy. + $tokens[$stackPtr]['scope_opener'] = $declareOpenClose['opener']; + $tokens[$stackPtr]['scope_closer'] = $declareOpenClose['closer']; + } + } + + /* + * The scope markers are set. This is the simplest situation. + */ + if (isset($tokens[$stackPtr]['scope_opener']) === true) { + if ($allowEmpty === true) { + return true; + } + + // Check whether the body is empty. + $start = ($tokens[$stackPtr]['scope_opener'] + 1); + $end = ($phpcsFile->numTokens + 1); + if (isset($tokens[$stackPtr]['scope_closer']) === true) { + $end = $tokens[$stackPtr]['scope_closer']; + } + + $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, $start, $end, true); + if ($nextNonEmpty !== false) { + return true; + } + + return false; + } + + /* + * Control structure without scope markers. + * Either single line statement or inline control structure. + * + * - Single line statement doesn't have a body and is therefore always empty. + * - Inline control structure has to have a body and can never be empty. + * + * This code also needs to take live coding into account where a scope opener is found, but + * no scope closer. + */ + $searchStart = ($stackPtr + 1); + if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { + $searchStart = ($tokens[$stackPtr]['parenthesis_closer'] + 1); + } + + $nextNonEmpty = $phpcsFile->findNext( + Tokens::$emptyTokens, + $searchStart, + null, + true + ); + if ($nextNonEmpty === false || $tokens[$nextNonEmpty]['code'] === \T_SEMICOLON) { + // Parse error or single line statement. + return false; + } + + if ($tokens[$nextNonEmpty]['code'] === \T_OPEN_CURLY_BRACKET) { + if ($allowEmpty === true) { + return true; + } + + // Unrecognized scope opener due to parse error. + $nextNext = $phpcsFile->findNext( + Tokens::$emptyTokens, + ($nextNonEmpty + 1), + null, + true + ); + + if ($nextNext === false) { + return false; + } + + return true; + } + + return true; + } + + /** + * Check whether an IF or ELSE token is part of an `else if`. + * + * @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 bool + */ + public static function isElseIf(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check for the existence of the token. + if (isset($tokens[$stackPtr]) === false) { + return false; + } + + if ($tokens[$stackPtr]['code'] === \T_ELSEIF) { + return true; + } + + if ($tokens[$stackPtr]['code'] !== \T_ELSE && $tokens[$stackPtr]['code'] !== \T_IF) { + return false; + } + + if ($tokens[$stackPtr]['code'] === \T_ELSE && isset($tokens[$stackPtr]['scope_opener']) === true) { + return false; + } + + switch ($tokens[$stackPtr]['code']) { + case \T_ELSE: + $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($next !== false && $tokens[$next]['code'] === \T_IF) { + return true; + } + break; + + case \T_IF: + $previous = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($previous !== false && $tokens[$previous]['code'] === \T_ELSE) { + return true; + } + break; + } + + return false; + } + + /** + * 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 a limited scope using curly braces; + * - applied to a limited scope using the alternative control structure syntax. + * + * In the first case, the statement - correctly - won't have a scope opener/closer. + * In the second case, the statement will have the scope opener/closer indexes. + * In the last case, due to a bug in the PHPCS Tokenizer, it won't have the scope opener/closer indexes, + * while it really should. This bug is expected to be fixed in PHPCS 3.5.4. + * + * In other words, if a sniff needs to support PHPCS < 3.5.4 and needs to take the alternative + * control structure syntax into account, this method can be used to retrieve the + * scope opener/closer for the declare statement. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/2843 + * + * @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|false Array with two keys `opener`, `closer` or false if + * not a `declare` token or if the opener/closer + * could not be determined. + */ + public static function getDeclareScopeOpenClose(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]) === false + || $tokens[$stackPtr]['code'] !== \T_DECLARE + ) { + return false; + } + + if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === true) { + return [ + 'opener' => $tokens[$stackPtr]['scope_opener'], + 'closer' => $tokens[$stackPtr]['scope_closer'], + ]; + } + + $declareCount = 0; + $opener = null; + $closer = null; + + for ($i = $stackPtr; $i < $phpcsFile->numTokens; $i++) { + if ($tokens[$i]['code'] !== \T_DECLARE && $tokens[$i]['code'] !== \T_ENDDECLARE) { + continue; + } + + if ($tokens[$i]['code'] === \T_ENDDECLARE) { + --$declareCount; + + if ($declareCount !== 0) { + continue; + } + + // OK, we reached the target enddeclare. + $closer = $i; + break; + } + + if ($tokens[$i]['code'] === \T_DECLARE) { + ++$declareCount; + + // Find the scope opener + if (isset($tokens[$i]['parenthesis_closer']) === false) { + // Parse error or live coding, nothing to do. + return false; + } + + $scopeOpener = $phpcsFile->findNext( + Tokens::$emptyTokens, + ($tokens[$i]['parenthesis_closer'] + 1), + null, + true + ); + + if ($scopeOpener === false) { + // Live coding, nothing to do. + return false; + } + + // Remember the scope opener for our target declare. + if ($declareCount === 1) { + $opener = $scopeOpener; + } + + $i = $scopeOpener; + + switch ($tokens[$scopeOpener]['code']) { + case \T_COLON: + // Nothing particular to do. Just continue the loop. + break; + + case \T_OPEN_CURLY_BRACKET: + /* + * Live coding or nested declare statement with curlies. + */ + + if (isset($tokens[$scopeOpener]['scope_closer']) === false) { + // Live coding, nothing to do. + return false; + } + + // Jump over the statement. + $i = $tokens[$scopeOpener]['scope_closer']; + --$declareCount; + + break; + + case \T_SEMICOLON: + // Nested single line declare statement. + --$declareCount; + break; + + default: + // This is an unexpected token. Most likely a parse error. Bow out. + return false; + } + } + + if ($declareCount === 0) { + break; + } + } + + if (isset($opener, $closer)) { + return [ + 'opener' => $opener, + 'closer' => $closer, + ]; + } + + return false; + } +} diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.inc b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.inc new file mode 100644 index 00000000..2578c24a --- /dev/null +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.inc @@ -0,0 +1,5 @@ +getTargetToken('/* testNoCloseParenthesis */', \T_DECLARE); + $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); + $this->assertFalse($result); + } +} diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.inc b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.inc new file mode 100644 index 00000000..275a9989 --- /dev/null +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.inc @@ -0,0 +1,5 @@ +getTargetToken('/* testNoScopeOpener */', \T_DECLARE); + $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); + $this->assertFalse($result); + } +} diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.inc b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.inc new file mode 100644 index 00000000..29348ff8 --- /dev/null +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.inc @@ -0,0 +1,5 @@ +getTargetToken('/* testNoScopeCloser */', \T_DECLARE); + $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); + $this->assertFalse($result); + } +} diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.inc b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.inc new file mode 100644 index 00000000..b05cccfa --- /dev/null +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.inc @@ -0,0 +1,5 @@ +getTargetToken('/* testUnexpectedToken */', \T_DECLARE); + $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); + $this->assertFalse($result); + } +} diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.inc b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.inc new file mode 100644 index 00000000..964e9b21 --- /dev/null +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.inc @@ -0,0 +1,53 @@ +assertFalse(ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, 10000)); + } + + /** + * Test that false is returned when a token other than `T_DECLARE` is passed. + * + * @return void + */ + public function testNotDeclare() + { + $target = $this->getTargetToken('/* testNotDeclare */', \T_ECHO); + $this->assertFalse(ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $target)); + } + + /** + * Test retrieving the scope open/close tokens for a `declare` statement. + * + * @dataProvider dataGetDeclareScopeOpenClose + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array|false $expected The expected return value. + * + * @return void + */ + public function testGetDeclareScopeOpenClose($testMarker, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, \T_DECLARE); + + // Translate offsets to absolute token positions. + if (isset($expected['opener'], $expected['closer']) === true) { + $expected['opener'] += $stackPtr; + $expected['closer'] += $stackPtr; + } + + $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetDeclareScopeOpenClose() For the array format. + * + * @return array + */ + public function dataGetDeclareScopeOpenClose() + { + return [ + 'file-scope' => [ + '/* testFileScope */', + false, + ], + + 'curlies' => [ + '/* testCurlies */', + [ + 'opener' => 7, + 'closer' => 11, + ], + ], + 'nested-curlies-outside' => [ + '/* testNestedCurliesOutside */', + [ + 'opener' => 7, + 'closer' => 32, + ], + ], + 'nested-curlies-inside' => [ + '/* testNestedCurliesInside */', + [ + 'opener' => 12, + 'closer' => 17, + ], + ], + + 'alternative-syntax' => [ + '/* testAlternativeSyntax */', + [ + 'opener' => 7, + 'closer' => 11, + ], + ], + 'alternative-syntax-nested-level-1' => [ + '/* testAlternativeSyntaxNestedLevel1 */', + [ + 'opener' => 7, + 'closer' => 50, + ], + ], + 'alternative-syntax-nested-level-2' => [ + '/* testAlternativeSyntaxNestedLevel2 */', + [ + 'opener' => 12, + 'closer' => 34, + ], + ], + 'alternative-syntax-nested-level-3' => [ + '/* testAlternativeSyntaxNestedLevel3 */', + [ + 'opener' => 7, + 'closer' => 12, + ], + ], + + 'mixed-nested-level-1' => [ + '/* testMixedNestedLevel1 */', + [ + 'opener' => 7, + 'closer' => 61, + ], + ], + 'mixed-nested-level-2' => [ + '/* testMixedNestedLevel2 */', + [ + 'opener' => 12, + 'closer' => 46, + ], + ], + 'mixed-nested-level-3' => [ + '/* testMixedNestedLevel3 */', + [ + 'opener' => 7, + 'closer' => 24, + ], + ], + 'mixed-nested-level-4' => [ + '/* testMixedNestedLevel4 */', + false, + ], + + 'live-coding' => [ + '/* testLiveCoding */', + false, + ], + ]; + } +} diff --git a/Tests/Utils/ControlStructures/HasBodyParseError1Test.inc b/Tests/Utils/ControlStructures/HasBodyParseError1Test.inc new file mode 100644 index 00000000..7eb8917c --- /dev/null +++ b/Tests/Utils/ControlStructures/HasBodyParseError1Test.inc @@ -0,0 +1,9 @@ +getTargetToken('/* testLiveCoding */', \T_ELSE); + + $result = ControlStructures::hasBody(self::$phpcsFile, $stackPtr); + $this->assertTrue($result, 'Failed hasBody check with $allowEmpty = true'); + + $result = ControlStructures::hasBody(self::$phpcsFile, $stackPtr, false); + $this->assertFalse($result, 'Failed hasBody check with $allowEmpty = false'); + } +} diff --git a/Tests/Utils/ControlStructures/HasBodyParseError2Test.inc b/Tests/Utils/ControlStructures/HasBodyParseError2Test.inc new file mode 100644 index 00000000..eba91210 --- /dev/null +++ b/Tests/Utils/ControlStructures/HasBodyParseError2Test.inc @@ -0,0 +1,9 @@ +getTargetToken('/* testLiveCoding */', \T_ELSE); + + $result = ControlStructures::hasBody(self::$phpcsFile, $stackPtr); + $this->assertTrue($result, 'Failed hasBody check with $allowEmpty = true'); + + $result = ControlStructures::hasBody(self::$phpcsFile, $stackPtr, false); + $this->assertTrue($result, 'Failed hasBody check with $allowEmpty = false'); + } +} diff --git a/Tests/Utils/ControlStructures/HasBodyTest.inc b/Tests/Utils/ControlStructures/HasBodyTest.inc new file mode 100644 index 00000000..e0363bb0 --- /dev/null +++ b/Tests/Utils/ControlStructures/HasBodyTest.inc @@ -0,0 +1,226 @@ + $c); // Surprisingly enough not a parse error. + +/* testForEachEmptyBody */ +foreach ($a as $k => $v) { + // phpcs:ignore Stnd.Cat.Sniff -- for reasons. +} + +/* testForEachWithCode */ +foreach ($a as $k => $v) { + echo "Key: $k; Current value of \$a: $v.\n"; +} + +/* testWhileWithoutBody */ +while (++$i <= 10) /*comment*/ ; + +/* testWhileEmptyBody */ +while (++$i <= 10) {} + +/* testWhileWithCode */ +while (++$i <= 10) { + echo $i; +} + +/* testDoWhileEmptyBody */ +do { +} while (++$i <= 10); + +/* testDoWhileWithCode */ +do { + echo $i; +} while (++$i <= 10); + +/* testSwitchWithoutBody */ +// Intentional parse error. +switch ($foo); + +/* testSwitchEmptyBody */ +switch ($foo) { + // Kind of useless, but not a parse error. +} + +/* testSwitchWithCode */ +switch ($foo) { + case 1: + echo '
something
'; + break; +} + +/* testDeclareWithoutBody */ +declare(ticks=1); + +/* testDeclareEmptyBody */ +declare(ticks=1) { + // Comment. +} + +/* testDeclareWithCode */ +declare(ticks=1) { + echo 'ticking'; +} + +/* + * Alternative control structure syntax. + */ + +/* testAlternativeIfEmptyBody */ +if (true): + // Code. + +/* testAlternativeElseIfWithCode */ +elseif (false): + echo 123; + +/* testAlternativeElseWithCode */ +else: + echo 123; +endif; + +/* testAlternativeForEmptyBody */ +for ($i = 1; $i <= 10; $i++) : + +endfor; + +/* testAlternativeForWithCode */ +for ($i = 1; $i <= 10; $i++) : + echo $i; +endfor; + +/* testAlternativeForeachEmptyBody */ +foreach ($a as $k => $v): + // Comment. +endforeach; + +/* testAlternativeForeachWithCode */ +foreach ($a as $k => $v): + echo "Key: $k; Current value of \$a: $v.\n"; +endforeach; + +/* testAlternativeWhileEmptyBody */ +while (++$i <= 10): + // phpcs:disable Stnd.Cat.Sniff -- for reasons. +endwhile; + +/* testAlternativeWhileWithCode */ +while (++$i <= 10): + echo $i; +endwhile; + +/* testAlternativeSwitchEmptyBody */ +switch ($foo) : +endswitch; + +/* testAlternativeSwitchWithCode */ +switch ($foo) : + case 1: + echo '
something
'; +endswitch; + +/* testAlternativeDeclareEmptyBody */ +declare (ticks = 1): + // comment +enddeclare; + +/* testAlternativeDeclareWithCode */ +declare (ticks = 1): + echo 'ticking'; +enddeclare; + +/* + * Control structures without braces. + * Without a body, these are a parse error straight away. + */ + +/* testInlineIfWithCode */ +if (true) + function_call($a); + +/* testInlineElseIfWithCode */ +elseif (false) + function_call($a); + +/* testInlineElseWithCode */ +else + function_call($a); + +/* testInlineForWithCode */ +for ($i = 1; $i <= 10; $i++) + echo $i; + +/* testInlineForEachWithCode */ +foreach ($a as $k => $v) + echo "Key: $k; Current value of \$a: $v.\n"; + +/* testInlineWhileWithCode */ +while (++$i <= 10) + echo $i; + +/* testInlineDoWhileWithCode */ +do + echo $i; +while (++$i <= 10); + +// Live coding. +// Intentional parse error. This test has to be the last in the file. + if ($a) { + // Code. + /* testElseLiveCoding */ + } else { + // Code. diff --git a/Tests/Utils/ControlStructures/HasBodyTest.php b/Tests/Utils/ControlStructures/HasBodyTest.php new file mode 100644 index 00000000..59c473ef --- /dev/null +++ b/Tests/Utils/ControlStructures/HasBodyTest.php @@ -0,0 +1,321 @@ +assertFalse(ControlStructures::hasBody(self::$phpcsFile, 10000)); + } + + /** + * Test that false is returned when a non-control structure token is passed. + * + * @return void + */ + public function testNotControlStructure() + { + $target = $this->getTargetToken('/* testNotControlStructure */', \T_ECHO); + $this->assertFalse(ControlStructures::hasBody(self::$phpcsFile, $target)); + } + + /** + * Test whether the function correctly identifies whether a control structure has a body. + * + * @dataProvider dataHasBody + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $hasBody The expected boolean return value when the function is called + * with `$allowEmpty = true`. + * @param bool $hasNonEmptyBody The expected boolean return value when the function is called + * with `$allowEmpty = false`. + * + * @return void + */ + public function testHasBody($testMarker, $hasBody, $hasNonEmptyBody) + { + $stackPtr = $this->getTargetToken($testMarker, Collections::$controlStructureTokens); + + $result = ControlStructures::hasBody(self::$phpcsFile, $stackPtr); + $this->assertSame($hasBody, $result, 'Failed hasBody check with $allowEmpty = true'); + + $result = ControlStructures::hasBody(self::$phpcsFile, $stackPtr, false); + $this->assertSame($hasNonEmptyBody, $result, 'Failed hasBody check with $allowEmpty = false'); + } + + /** + * Data provider. + * + * @see testHasBody() For the array format. + * + * @return array + */ + public function dataHasBody() + { + return [ + 'if-without-body' => [ + '/* testIfWithoutBody */', + false, + false, + ], + 'if-empty-body' => [ + '/* testIfEmptyBody */', + true, + false, + ], + 'elseif-empty-body' => [ + '/* testElseIfEmptyBody */', + true, + false, + ], + 'else-if-empty-body' => [ + '/* testElseSpaceIfEmptyBody */', + true, + false, + ], + 'else-empty-body' => [ + '/* testElseEmptyBody */', + true, + false, + ], + 'if-with-code' => [ + '/* testIfWithCode */', + true, + true, + ], + 'elseif-with-code' => [ + '/* testElseIfWithCode */', + true, + true, + ], + 'else-if-with-code' => [ + '/* testElseSpaceIfWithCode */', + true, + true, + ], + 'else-with-code' => [ + '/* testElseWithCode */', + true, + true, + ], + 'for-without-body' => [ + '/* testForWithoutBody */', + false, + false, + ], + 'for-empty-body' => [ + '/* testForEmptyBody */', + true, + false, + ], + 'for-with-code' => [ + '/* testForWithCode */', + true, + true, + ], + 'foreach-without-body' => [ + '/* testForEachWithoutBody */', + false, + false, + ], + 'foreach-empty-body' => [ + '/* testForEachEmptyBody */', + true, + false, + ], + 'foreach-with-code' => [ + '/* testForEachWithCode */', + true, + true, + ], + 'while-without-body' => [ + '/* testWhileWithoutBody */', + false, + false, + ], + 'while-empty-body' => [ + '/* testWhileEmptyBody */', + true, + false, + ], + 'while-with-code' => [ + '/* testWhileWithCode */', + true, + true, + ], + 'do-while-empty-body' => [ + '/* testDoWhileEmptyBody */', + true, + false, + ], + 'do-while-with-code' => [ + '/* testDoWhileWithCode */', + true, + true, + ], + 'switch-without-body' => [ + '/* testSwitchWithoutBody */', + false, + false, + ], + 'switch-empty-body' => [ + '/* testSwitchEmptyBody */', + true, + false, + ], + 'switch-with-code' => [ + '/* testSwitchWithCode */', + true, + true, + ], + 'declare-without-body' => [ + '/* testDeclareWithoutBody */', + false, + false, + ], + 'declare-empty-body' => [ + '/* testDeclareEmptyBody */', + true, + false, + ], + 'declare-with-code' => [ + '/* testDeclareWithCode */', + true, + true, + ], + 'alternative-syntax-if-empty-body' => [ + '/* testAlternativeIfEmptyBody */', + true, + false, + ], + 'alternative-syntax-elseif-with-code' => [ + '/* testAlternativeElseIfWithCode */', + true, + true, + ], + 'alternative-syntax-else-with-code' => [ + '/* testAlternativeElseWithCode */', + true, + true, + ], + 'alternative-syntax-for-empty-body' => [ + '/* testAlternativeForEmptyBody */', + true, + false, + ], + 'alternative-syntax-for-with-code' => [ + '/* testAlternativeForWithCode */', + true, + true, + ], + 'alternative-syntax-foreach-empty-body' => [ + '/* testAlternativeForeachEmptyBody */', + true, + false, + ], + 'alternative-syntax-foreach-with-code' => [ + '/* testAlternativeForeachWithCode */', + true, + true, + ], + 'alternative-syntax-while-empty-body' => [ + '/* testAlternativeWhileEmptyBody */', + true, + false, + ], + 'alternative-syntax-while-with-code' => [ + '/* testAlternativeWhileWithCode */', + true, + true, + ], + 'alternative-syntax-switch-empty-body' => [ + '/* testAlternativeSwitchEmptyBody */', + true, + false, + ], + 'alternative-syntax-switch-with-code' => [ + '/* testAlternativeSwitchWithCode */', + true, + true, + ], + 'alternative-syntax-declare-empty-body' => [ + '/* testAlternativeDeclareEmptyBody */', + true, + false, + ], + 'alternative-syntax-declare-with-code' => [ + '/* testAlternativeDeclareWithCode */', + true, + true, + ], + 'inline-if-with-code' => [ + '/* testInlineIfWithCode */', + true, + true, + ], + 'inline-elseif-with-code' => [ + '/* testInlineElseIfWithCode */', + true, + true, + ], + 'inline-else-with-code' => [ + '/* testInlineElseWithCode */', + true, + true, + ], + 'inline-for-with-code' => [ + '/* testInlineForWithCode */', + true, + true, + ], + 'inline-foreach-with-code' => [ + '/* testInlineForEachWithCode */', + true, + true, + ], + 'inline-while-with-code' => [ + '/* testInlineWhileWithCode */', + true, + true, + ], + 'inline-do-while-with-code' => [ + '/* testInlineDoWhileWithCode */', + true, + true, + ], + 'else-live-coding' => [ + '/* testElseLiveCoding */', + true, + false, + ], + ]; + } +} diff --git a/Tests/Utils/ControlStructures/IsElseIfTest.inc b/Tests/Utils/ControlStructures/IsElseIfTest.inc new file mode 100644 index 00000000..b7dd30ba --- /dev/null +++ b/Tests/Utils/ControlStructures/IsElseIfTest.inc @@ -0,0 +1,58 @@ +assertFalse(ControlStructures::isElseIf(self::$phpcsFile, 10000)); + } + + /** + * Test that false is returned when a token other than `T_IF`, `T_ELSE`, `T_ELSEIF` is passed. + * + * @return void + */ + public function testNotIfElseifOrElse() + { + $target = $this->getTargetToken('/* testNotIfElseifOrElse */', \T_ECHO); + $this->assertFalse(ControlStructures::isElseIf(self::$phpcsFile, $target)); + } + + /** + * Test whether a T_IF or T_ELSE token is correctly identified as either elseif or not. + * + * @dataProvider dataIsElseIf + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $expected The expected boolean return value. + * + * @return void + */ + public function testIsElseIf($testMarker, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, [\T_IF, \T_ELSEIF, \T_ELSE]); + $result = ControlStructures::isElseIf(self::$phpcsFile, $stackPtr); + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testIsElseIf() For the array format. + * + * @return array + */ + public function dataIsElseIf() + { + return [ + 'if' => [ + '/* testIf */', + false, + ], + 'elseif' => [ + '/* testElseIf */', + true, + ], + 'else-if' => [ + '/* testElseSpaceIf */', + true, + ], + 'else-if-with-comment-else' => [ + '/* testElseCommentIfElse */', + true, + ], + 'else-if-with-comment-if' => [ + '/* testElseCommentIfIf */', + true, + ], + 'else' => [ + '/* testElse */', + false, + ], + + 'alternative-syntax-if' => [ + '/* testAlternativeIf */', + false, + ], + 'alternative-syntax-elseif' => [ + '/* testAlternativeElseIf */', + true, + ], + 'alternative-syntax-else' => [ + '/* testAlternativeElse */', + false, + ], + + 'inline-if' => [ + '/* testAlternativeIf */', + false, + ], + 'inline-elseif' => [ + '/* testAlternativeElseIf */', + true, + ], + 'inline-else' => [ + '/* testAlternativeElse */', + false, + ], + + 'live-coding' => [ + '/* testLiveCoding */', + false, + ], + ]; + } +} From 0392f8f2b3e682f40cec4b16e38ad7c30e6c8a5b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Feb 2020 00:57:06 +0100 Subject: [PATCH 05/48] BCFile::getCondition()/Conditions::getCondition(): sync with PHPCS 3.5.4 / new $first parameter PHPCS 3.5.4 introduces a new `$first` parameter to the `File::getCondition()` function. The PHPCSUtils `Conditions::getCondition()` already had a parameter for the same - `$reverse`, though the boolean values used were also the reverse of how the new `$first` parameter is implemented. As PHPCSUtils is still in `alpha`, I'm making the executive decision to rename the parameter for the `Conditions::getCondition()` function to `$first`, including reversing the meaning of the boolean values, to stay in line with PHPCS itself. Includes adjusting any function calls in the existing codebase for the reversal of the meaning of the boolean. Includes moving the unit tests covering this parameter, which were already in place in the test file for the `Conditions::getCondition()` function, to the test file for the `BCFile::getCondition()` function. The actual tests will be run for both functions now. Refs: * https://github.com/squizlabs/PHP_CodeSniffer/commit/77c5fa2cd0b2ceca49d1610f8a30b857fe0f0fb9. --- PHPCSUtils/BackCompat/BCFile.php | 34 ++++++++++- PHPCSUtils/Utils/Conditions.php | 21 ++++--- Tests/BackCompat/BCFile/GetConditionTest.php | 63 ++++++++++++++++++++ Tests/Utils/Conditions/GetConditionTest.php | 62 ------------------- 4 files changed, 106 insertions(+), 74 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index c347e4e4..aaff0113 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -1311,7 +1311,8 @@ public static function hasCondition(File $phpcsFile, $stackPtr, $types) * * Changelog for the PHPCS native function: * - Introduced in PHPCS 1.3.0. - * - This method has received no significant code updates since PHPCS 2.6.0. + * - PHPCS 3.5.4: New `$first` parameter which allows for the closest matching token to be returned. + * By default, it continues to return the first matched token found from the top of the file. * * @see \PHP_CodeSniffer\Files\File::getCondition() Original source. * @see \PHPCSUtils\Utils\Conditions::getCondition() More versatile alternative. @@ -1321,13 +1322,40 @@ public static function hasCondition(File $phpcsFile, $stackPtr, $types) * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the token we are checking. * @param int|string $type The type of token to search for. + * @param bool $first If TRUE, will return the matched condition + * furthest away from the passed token. + * If FALSE, will return the matched condition + * closest to the passed token. * * @return int|false Integer stack pointer to the condition or FALSE if the token * does not have the condition. */ - public static function getCondition(File $phpcsFile, $stackPtr, $type) + public static function getCondition(File $phpcsFile, $stackPtr, $type, $first = true) { - return $phpcsFile->getCondition($stackPtr, $type); + $tokens = $phpcsFile->getTokens(); + + // Check for the existence of the token. + if (isset($tokens[$stackPtr]) === false) { + return false; + } + + // Make sure the token has conditions. + if (isset($tokens[$stackPtr]['conditions']) === false) { + return false; + } + + $conditions = $tokens[$stackPtr]['conditions']; + if ($first === false) { + $conditions = array_reverse($conditions, true); + } + + foreach ($conditions as $token => $condition) { + if ($condition === $type) { + return $token; + } + } + + return false; } /** diff --git a/PHPCSUtils/Utils/Conditions.php b/PHPCSUtils/Utils/Conditions.php index f998d7c9..edcfb3f3 100644 --- a/PHPCSUtils/Utils/Conditions.php +++ b/PHPCSUtils/Utils/Conditions.php @@ -26,31 +26,34 @@ class Conditions /** * Retrieve the position of a condition for the passed token. * - * If no types are specified, the first condition for the token - or if `$reverse=true`, + * If no types are specified, the first condition for the token - or if `$first=false`, * the last condition - will be returned. * * Main differences with the PHPCS version: * - The singular `$type` parameter has become the more flexible `$types` parameter allowing to * search for several types of conditions in one go. * - The `$types` parameter is now optional. - * - Addition of the `$reverse` parameter. * * @see \PHP_CodeSniffer\Files\File::getCondition() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getCondition() Cross-version compatible version of the original. * * @since 1.0.0 + * @since 1.0.0-alpha2 The `$reverse` parameter has been renamed to `$first` and the meaning of the + * boolean reversed (true = first, false = last, was: true = last, false = first) + * to be in line with PHPCS itself which added the `$first` parameter in v 3.5.4 + * to allow for the same/similar functionality as `$reverse` already offered. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the token we are checking. * @param int|string|array $types Optional. The type(s) of tokens to search for. - * @param bool $reverse Optional. Whether to search for the first (outermost) - * (false) or the last (innermost) condition (true) of + * @param bool $first Optional. Whether to search for the first (outermost) + * (true) or the last (innermost) condition (false) of * the specified type(s). * * @return int|false Integer stack pointer to the condition or FALSE if the token * does not have the condition. */ - public static function getCondition(File $phpcsFile, $stackPtr, $types = [], $reverse = false) + public static function getCondition(File $phpcsFile, $stackPtr, $types = [], $first = true) { $tokens = $phpcsFile->getTokens(); @@ -69,7 +72,7 @@ public static function getCondition(File $phpcsFile, $stackPtr, $types = [], $re if (empty($types) === true) { // No types specified, just return the first/last condition pointer. - if ($reverse === true) { + if ($first === false) { \end($conditions); } else { \reset($conditions); @@ -78,7 +81,7 @@ public static function getCondition(File $phpcsFile, $stackPtr, $types = [], $re return \key($conditions); } - if ($reverse === true) { + if ($first === false) { $conditions = \array_reverse($conditions, true); } @@ -131,7 +134,7 @@ public static function hasCondition(File $phpcsFile, $stackPtr, $types) */ public static function getFirstCondition(File $phpcsFile, $stackPtr, $types = []) { - return self::getCondition($phpcsFile, $stackPtr, $types, false); + return self::getCondition($phpcsFile, $stackPtr, $types, true); } /** @@ -150,6 +153,6 @@ public static function getFirstCondition(File $phpcsFile, $stackPtr, $types = [] */ public static function getLastCondition(File $phpcsFile, $stackPtr, $types = []) { - return self::getCondition($phpcsFile, $stackPtr, $types, true); + return self::getCondition($phpcsFile, $stackPtr, $types, false); } } diff --git a/Tests/BackCompat/BCFile/GetConditionTest.php b/Tests/BackCompat/BCFile/GetConditionTest.php index 9dfa77c9..844be4f9 100644 --- a/Tests/BackCompat/BCFile/GetConditionTest.php +++ b/Tests/BackCompat/BCFile/GetConditionTest.php @@ -304,6 +304,69 @@ public static function dataGetCondition() ]; } + /** + * Test retrieving a specific condition from a tokens "conditions" array. + * + * @dataProvider dataGetConditionReversed + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the marker for the expected stack pointer result as a value. + * + * @return void + */ + public function testGetConditionReversed($testMarker, $expectedResults) + { + $testClass = static::TEST_CLASS; + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + if ($expected !== false) { + $expected = self::$markerTokens[$expected]; + } + + $result = $testClass::getCondition(self::$phpcsFile, $stackPtr, \constant($conditionType), false); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType} (reversed)" + ); + } + } + + /** + * Data provider. + * + * Only the conditions which are expected to be *found* need to be listed here. + * All other potential conditions will automatically also be tested and will expect + * `false` as a result. + * + * @see testGetConditionReversed() For the array format. + * + * @return array + */ + public static function dataGetConditionReversed() + { + $data = self::dataGetCondition(); + + // Set up the data for the reversed results. + $data['testSeriouslyNestedMethod'][1]['T_IF'] = '/* condition 4: if */'; + + $data['testDeepestNested'][1]['T_FUNCTION'] = '/* condition 12: nested anonymous class method */'; + $data['testDeepestNested'][1]['T_IF'] = '/* condition 10-1: if */'; + + $data['testInException'][1]['T_FUNCTION'] = '/* condition 6: class method */'; + $data['testInException'][1]['T_IF'] = '/* condition 4: if */'; + + $data['testInDefault'][1]['T_FUNCTION'] = '/* condition 6: class method */'; + $data['testInDefault'][1]['T_IF'] = '/* condition 4: if */'; + + return $data; + } + /** * Test whether a token has a condition of a certain type. * diff --git a/Tests/Utils/Conditions/GetConditionTest.php b/Tests/Utils/Conditions/GetConditionTest.php index ebf8ffd1..74ece761 100644 --- a/Tests/Utils/Conditions/GetConditionTest.php +++ b/Tests/Utils/Conditions/GetConditionTest.php @@ -57,68 +57,6 @@ public static function setUpTestFile() parent::setUpTestFile(); } - /** - * Test retrieving a specific condition from a tokens "conditions" array. - * - * @dataProvider dataGetConditionReversed - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param array $expectedResults Array with the condition token type to search for as key - * and the marker for the expected stack pointer result as a value. - * - * @return void - */ - public function testGetConditionReversed($testMarker, $expectedResults) - { - $stackPtr = self::$testTokens[$testMarker]; - - // Add expected results for all test markers not listed in the data provider. - $expectedResults += $this->conditionDefaults; - - foreach ($expectedResults as $conditionType => $expected) { - if ($expected !== false) { - $expected = self::$markerTokens[$expected]; - } - - $result = Conditions::getCondition(self::$phpcsFile, $stackPtr, \constant($conditionType), true); - $this->assertSame( - $expected, - $result, - "Assertion failed for test marker '{$testMarker}' with condition {$conditionType} (reversed)" - ); - } - } - - /** - * Data provider. - * - * Only the conditions which are expected to be *found* need to be listed here. - * All other potential conditions will automatically also be tested and will expect - * `false` as a result. - * - * @see testGetConditionReversed() For the array format. - * - * @return array - */ - public static function dataGetConditionReversed() - { - $data = self::dataGetCondition(); - - // Set up the data for the reversed results. - $data['testSeriouslyNestedMethod'][1]['T_IF'] = '/* condition 4: if */'; - - $data['testDeepestNested'][1]['T_FUNCTION'] = '/* condition 12: nested anonymous class method */'; - $data['testDeepestNested'][1]['T_IF'] = '/* condition 10-1: if */'; - - $data['testInException'][1]['T_FUNCTION'] = '/* condition 6: class method */'; - $data['testInException'][1]['T_IF'] = '/* condition 4: if */'; - - $data['testInDefault'][1]['T_FUNCTION'] = '/* condition 6: class method */'; - $data['testInDefault'][1]['T_IF'] = '/* condition 4: if */'; - - return $data; - } - /** * Test retrieving a specific condition from a token's "conditions" array, * with multiple allowed possibilities. From 4ed622d143d48bb252b7e13793eb34f157026c97 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 4 Feb 2020 03:22:01 +0100 Subject: [PATCH 06/48] Travis: run sniff stage of PHP 7.4 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8e6be1d8..20b8b7a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ jobs: include: #### SNIFF STAGE #### - stage: sniff - php: 7.3 + php: 7.4 env: PHPCS_VERSION="dev-master" addons: apt: From b4443d902e4764477772392cd2f0ca72d156e497 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 4 Feb 2020 03:22:29 +0100 Subject: [PATCH 07/48] Build/PHPCS: remove temporary exclusion now PHPCS 3.5.4 has been released --- phpcs.xml.dist | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index b2cd4fab..50b9e1e8 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -95,19 +95,4 @@ /Tests/BackCompat/BCFile/*Test\.php$ - - - - - /PHPCSUtils/Utils/Namespaces\.php$ - - From 531c5b423140ab311e355ce8f08cedd66b512eac Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 4 Feb 2020 20:57:37 +0100 Subject: [PATCH 08/48] Documentation: update `@copyright` year --- PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php | 2 +- PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php | 2 +- PHPCSUtils/BackCompat/BCFile.php | 2 +- PHPCSUtils/BackCompat/BCTokens.php | 2 +- PHPCSUtils/BackCompat/Helper.php | 2 +- PHPCSUtils/Fixers/SpacesFixer.php | 2 +- PHPCSUtils/TestUtils/UtilityMethodTestCase.php | 2 +- PHPCSUtils/Tokens/Collections.php | 2 +- PHPCSUtils/Utils/Arrays.php | 2 +- PHPCSUtils/Utils/Conditions.php | 2 +- PHPCSUtils/Utils/ControlStructures.php | 2 +- PHPCSUtils/Utils/FunctionDeclarations.php | 2 +- PHPCSUtils/Utils/GetTokensAsString.php | 2 +- PHPCSUtils/Utils/Lists.php | 2 +- PHPCSUtils/Utils/Namespaces.php | 2 +- PHPCSUtils/Utils/Numbers.php | 2 +- PHPCSUtils/Utils/ObjectDeclarations.php | 2 +- PHPCSUtils/Utils/Operators.php | 2 +- PHPCSUtils/Utils/Orthography.php | 2 +- PHPCSUtils/Utils/Parentheses.php | 2 +- PHPCSUtils/Utils/PassedParameters.php | 2 +- PHPCSUtils/Utils/Scopes.php | 2 +- PHPCSUtils/Utils/TextStrings.php | 2 +- PHPCSUtils/Utils/UseStatements.php | 2 +- PHPCSUtils/Utils/Variables.php | 2 +- .../AbstractArrayDeclarationSniffTest.php | 2 +- .../ArrayDeclarationSniffTestDouble.php | 2 +- .../AbstractArrayDeclaration/GetActualArrayKeyTest.php | 2 +- Tests/BackCompat/BCFile/FindEndOfStatementTest.php | 2 +- Tests/BackCompat/BCFile/FindExtendedClassNameTest.php | 2 +- Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php | 2 +- Tests/BackCompat/BCFile/GetClassPropertiesTest.php | 2 +- Tests/BackCompat/BCFile/GetConditionTest.php | 2 +- Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php | 2 +- Tests/BackCompat/BCFile/GetDeclarationNameTest.php | 2 +- Tests/BackCompat/BCFile/GetMemberPropertiesTest.php | 2 +- Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php | 2 +- Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php | 2 +- Tests/BackCompat/BCFile/GetMethodParametersTest.php | 2 +- Tests/BackCompat/BCFile/GetMethodPropertiesTest.php | 2 +- Tests/BackCompat/BCFile/GetTokensAsStringTest.php | 2 +- Tests/BackCompat/BCFile/IsReferenceTest.php | 2 +- Tests/BackCompat/BCTokens/ArithmeticTokensTest.php | 2 +- Tests/BackCompat/BCTokens/AssignmentTokensTest.php | 2 +- Tests/BackCompat/BCTokens/ComparisonTokensTest.php | 2 +- Tests/BackCompat/BCTokens/EmptyTokensTest.php | 2 +- Tests/BackCompat/BCTokens/FunctionNameTokensTest.php | 2 +- Tests/BackCompat/BCTokens/OoScopeTokensTest.php | 2 +- Tests/BackCompat/BCTokens/OperatorsTest.php | 2 +- Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php | 2 +- Tests/BackCompat/BCTokens/TextStringTokensTest.php | 2 +- Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php | 2 +- Tests/BackCompat/Helper/ConfigDataTest.php | 2 +- Tests/BackCompat/Helper/GetCommandLineDataTest.php | 2 +- Tests/BackCompat/Helper/GetVersionTest.php | 2 +- Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php | 2 +- Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php | 2 +- Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php | 2 +- Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php | 2 +- Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php | 2 +- Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php | 2 +- Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php | 2 +- Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php | 2 +- .../UtilityMethodTestCase/UtilityMethodTestCaseTest.php | 2 +- Tests/Utils/Arrays/GetDoubleArrowPtrTest.php | 2 +- Tests/Utils/Arrays/GetOpenCloseTest.php | 2 +- Tests/Utils/Arrays/IsShortArrayTest.php | 2 +- Tests/Utils/Arrays/IsShortArrayTokenizerBC1Test.php | 2 +- Tests/Utils/Arrays/IsShortArrayTokenizerBC2Test.php | 2 +- Tests/Utils/Conditions/GetConditionTest.php | 2 +- .../GetDeclareScopeOpenCloseParseError1Test.php | 2 +- .../GetDeclareScopeOpenCloseParseError2Test.php | 2 +- .../GetDeclareScopeOpenCloseParseError3Test.php | 2 +- .../GetDeclareScopeOpenCloseParseError4Test.php | 2 +- Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.php | 2 +- Tests/Utils/ControlStructures/HasBodyParseError1Test.php | 2 +- Tests/Utils/ControlStructures/HasBodyParseError2Test.php | 2 +- Tests/Utils/ControlStructures/HasBodyTest.php | 2 +- Tests/Utils/ControlStructures/IsElseIfTest.php | 2 +- Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php | 2 +- .../Utils/FunctionDeclarations/GetParametersParseError1Test.php | 2 +- .../Utils/FunctionDeclarations/GetParametersParseError2Test.php | 2 +- Tests/Utils/FunctionDeclarations/GetParametersTest.php | 2 +- Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php | 2 +- Tests/Utils/FunctionDeclarations/GetPropertiesTest.php | 2 +- Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php | 2 +- Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php | 2 +- .../IsPHPDoubleUnderscoreMethodNameTest.php | 2 +- Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php | 2 +- Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php | 2 +- Tests/Utils/Lists/GetAssignmentsTest.php | 2 +- Tests/Utils/Lists/GetOpenCloseTest.php | 2 +- Tests/Utils/Lists/IsShortListTest.php | 2 +- Tests/Utils/Lists/IsShortListTokenizerBC1Test.php | 2 +- Tests/Utils/Lists/IsShortListTokenizerBC2Test.php | 2 +- Tests/Utils/Namespaces/DetermineNamespaceTest.php | 2 +- Tests/Utils/Namespaces/GetDeclaredNameTest.php | 2 +- Tests/Utils/Namespaces/NamespaceTypeTest.php | 2 +- Tests/Utils/Numbers/GetCompleteNumberTest.php | 2 +- Tests/Utils/Numbers/GetDecimalValueTest.php | 2 +- Tests/Utils/Numbers/NumberTypesTest.php | 2 +- .../Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php | 2 +- Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php | 2 +- .../Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php | 2 +- .../FindImplementedInterfaceNamesDiffTest.php | 2 +- .../ObjectDeclarations/FindImplementedInterfaceNamesTest.php | 2 +- Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php | 2 +- Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php | 2 +- Tests/Utils/ObjectDeclarations/GetNameDiffTest.php | 2 +- Tests/Utils/ObjectDeclarations/GetNameJSTest.php | 2 +- Tests/Utils/ObjectDeclarations/GetNameTest.php | 2 +- Tests/Utils/Operators/IsReferenceDiffTest.php | 2 +- Tests/Utils/Operators/IsReferenceTest.php | 2 +- Tests/Utils/Operators/IsShortTernaryTest.php | 2 +- Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php | 2 +- Tests/Utils/Operators/IsUnaryPlusMinusTest.php | 2 +- Tests/Utils/Orthography/FirstCharTest.php | 2 +- Tests/Utils/Orthography/IsLastCharPunctuationTest.php | 2 +- Tests/Utils/Parentheses/ParenthesesTest.php | 2 +- Tests/Utils/PassedParameters/GetParameterCountTest.php | 2 +- Tests/Utils/PassedParameters/GetParametersTest.php | 2 +- Tests/Utils/PassedParameters/HasParametersTest.php | 2 +- Tests/Utils/Scopes/IsOOConstantTest.php | 2 +- Tests/Utils/Scopes/IsOOMethodTest.php | 2 +- Tests/Utils/Scopes/IsOOPropertyTest.php | 2 +- Tests/Utils/TextStrings/GetCompleteTextStringTest.php | 2 +- Tests/Utils/TextStrings/StripQuotesTest.php | 2 +- Tests/Utils/UseStatements/SplitImportUseStatementTest.php | 2 +- Tests/Utils/UseStatements/UseTypeTest.php | 2 +- Tests/Utils/Variables/GetMemberPropertiesDiffTest.php | 2 +- Tests/Utils/Variables/GetMemberPropertiesTest.php | 2 +- Tests/Utils/Variables/IsPHPReservedVarNameTest.php | 2 +- Tests/Utils/Variables/IsSuperglobalTest.php | 2 +- Tests/bootstrap.php | 2 +- phpcsutils-autoload.php | 2 +- 135 files changed, 135 insertions(+), 135 deletions(-) diff --git a/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php b/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php index c0d18bcc..8d82c3f6 100644 --- a/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php +++ b/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php b/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php index 5646e450..0928f5a8 100644 --- a/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php +++ b/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index aaff0113..82de4b0d 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * diff --git a/PHPCSUtils/BackCompat/BCTokens.php b/PHPCSUtils/BackCompat/BCTokens.php index d06400ae..60514e01 100644 --- a/PHPCSUtils/BackCompat/BCTokens.php +++ b/PHPCSUtils/BackCompat/BCTokens.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/BackCompat/Helper.php b/PHPCSUtils/BackCompat/Helper.php index 11cfaf0b..5af02ca9 100644 --- a/PHPCSUtils/BackCompat/Helper.php +++ b/PHPCSUtils/BackCompat/Helper.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Fixers/SpacesFixer.php b/PHPCSUtils/Fixers/SpacesFixer.php index 557412a3..1dc777a1 100644 --- a/PHPCSUtils/Fixers/SpacesFixer.php +++ b/PHPCSUtils/Fixers/SpacesFixer.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php index 4928dcd2..7ad0e253 100644 --- a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 0558499e..754c31e8 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index 0e490479..889db186 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Conditions.php b/PHPCSUtils/Utils/Conditions.php index edcfb3f3..690e5906 100644 --- a/PHPCSUtils/Utils/Conditions.php +++ b/PHPCSUtils/Utils/Conditions.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/ControlStructures.php b/PHPCSUtils/Utils/ControlStructures.php index af3c2dfa..72ae2ca5 100644 --- a/PHPCSUtils/Utils/ControlStructures.php +++ b/PHPCSUtils/Utils/ControlStructures.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index ddf24ba2..b59dbda7 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/GetTokensAsString.php b/PHPCSUtils/Utils/GetTokensAsString.php index 043331f0..fc1fcf23 100644 --- a/PHPCSUtils/Utils/GetTokensAsString.php +++ b/PHPCSUtils/Utils/GetTokensAsString.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Lists.php b/PHPCSUtils/Utils/Lists.php index 0e50f091..af62a044 100644 --- a/PHPCSUtils/Utils/Lists.php +++ b/PHPCSUtils/Utils/Lists.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Namespaces.php b/PHPCSUtils/Utils/Namespaces.php index 253dbdc6..7d8c7c0f 100644 --- a/PHPCSUtils/Utils/Namespaces.php +++ b/PHPCSUtils/Utils/Namespaces.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Numbers.php b/PHPCSUtils/Utils/Numbers.php index a9acdc3b..22058831 100644 --- a/PHPCSUtils/Utils/Numbers.php +++ b/PHPCSUtils/Utils/Numbers.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/ObjectDeclarations.php b/PHPCSUtils/Utils/ObjectDeclarations.php index 45373b09..cc61128d 100644 --- a/PHPCSUtils/Utils/ObjectDeclarations.php +++ b/PHPCSUtils/Utils/ObjectDeclarations.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Operators.php b/PHPCSUtils/Utils/Operators.php index 29ad3226..ad0749f7 100644 --- a/PHPCSUtils/Utils/Operators.php +++ b/PHPCSUtils/Utils/Operators.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Orthography.php b/PHPCSUtils/Utils/Orthography.php index 4a6a706c..5e204e5e 100644 --- a/PHPCSUtils/Utils/Orthography.php +++ b/PHPCSUtils/Utils/Orthography.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Parentheses.php b/PHPCSUtils/Utils/Parentheses.php index 240905de..8c365540 100644 --- a/PHPCSUtils/Utils/Parentheses.php +++ b/PHPCSUtils/Utils/Parentheses.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/PassedParameters.php b/PHPCSUtils/Utils/PassedParameters.php index 2c0d5a1c..7b3e21af 100644 --- a/PHPCSUtils/Utils/PassedParameters.php +++ b/PHPCSUtils/Utils/PassedParameters.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Scopes.php b/PHPCSUtils/Utils/Scopes.php index 486fbe18..a85d9e82 100644 --- a/PHPCSUtils/Utils/Scopes.php +++ b/PHPCSUtils/Utils/Scopes.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/TextStrings.php b/PHPCSUtils/Utils/TextStrings.php index e89a268d..5b2a46e2 100644 --- a/PHPCSUtils/Utils/TextStrings.php +++ b/PHPCSUtils/Utils/TextStrings.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/UseStatements.php b/PHPCSUtils/Utils/UseStatements.php index 81d29731..9ebea8d2 100644 --- a/PHPCSUtils/Utils/UseStatements.php +++ b/PHPCSUtils/Utils/UseStatements.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/PHPCSUtils/Utils/Variables.php b/PHPCSUtils/Utils/Variables.php index b240f0b4..fee9b535 100644 --- a/PHPCSUtils/Utils/Variables.php +++ b/PHPCSUtils/Utils/Variables.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php index 274fc59f..04983eaf 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffTestDouble.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffTestDouble.php index 8d080703..207810a4 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffTestDouble.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffTestDouble.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.php index d552d34b..3e2390c8 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index 1dc32aea..4b157046 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils /** diff --git a/Tests/BackCompat/BCFile/FindExtendedClassNameTest.php b/Tests/BackCompat/BCFile/FindExtendedClassNameTest.php index c910345b..279b4404 100644 --- a/Tests/BackCompat/BCFile/FindExtendedClassNameTest.php +++ b/Tests/BackCompat/BCFile/FindExtendedClassNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * diff --git a/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php b/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php index d1871a8e..602aab86 100644 --- a/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php +++ b/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * diff --git a/Tests/BackCompat/BCFile/GetClassPropertiesTest.php b/Tests/BackCompat/BCFile/GetClassPropertiesTest.php index 98823221..f21dea86 100644 --- a/Tests/BackCompat/BCFile/GetClassPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetClassPropertiesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCFile/GetConditionTest.php b/Tests/BackCompat/BCFile/GetConditionTest.php index 844be4f9..e316eebf 100644 --- a/Tests/BackCompat/BCFile/GetConditionTest.php +++ b/Tests/BackCompat/BCFile/GetConditionTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php b/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php index bf97018f..32fec5ee 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php +++ b/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php index 0c401b7e..7c19e8e5 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php index 707afc7e..ce3d32bb 100644 --- a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * diff --git a/Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php b/Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php index afff5e57..cd86d071 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php b/Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php index 7db94106..08da2c2d 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index fe091d08..cd7486ca 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php index fd9d567c..c800f744 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * diff --git a/Tests/BackCompat/BCFile/GetTokensAsStringTest.php b/Tests/BackCompat/BCFile/GetTokensAsStringTest.php index ca061631..42611669 100644 --- a/Tests/BackCompat/BCFile/GetTokensAsStringTest.php +++ b/Tests/BackCompat/BCFile/GetTokensAsStringTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCFile/IsReferenceTest.php b/Tests/BackCompat/BCFile/IsReferenceTest.php index 67a28d57..aff6a9c6 100644 --- a/Tests/BackCompat/BCFile/IsReferenceTest.php +++ b/Tests/BackCompat/BCFile/IsReferenceTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * diff --git a/Tests/BackCompat/BCTokens/ArithmeticTokensTest.php b/Tests/BackCompat/BCTokens/ArithmeticTokensTest.php index 94360f03..9bd33a40 100644 --- a/Tests/BackCompat/BCTokens/ArithmeticTokensTest.php +++ b/Tests/BackCompat/BCTokens/ArithmeticTokensTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/AssignmentTokensTest.php b/Tests/BackCompat/BCTokens/AssignmentTokensTest.php index 88f2a38f..1d8f7394 100644 --- a/Tests/BackCompat/BCTokens/AssignmentTokensTest.php +++ b/Tests/BackCompat/BCTokens/AssignmentTokensTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/ComparisonTokensTest.php b/Tests/BackCompat/BCTokens/ComparisonTokensTest.php index f8a6edf5..a70afb6d 100644 --- a/Tests/BackCompat/BCTokens/ComparisonTokensTest.php +++ b/Tests/BackCompat/BCTokens/ComparisonTokensTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/EmptyTokensTest.php b/Tests/BackCompat/BCTokens/EmptyTokensTest.php index 2f915613..38dcff9b 100644 --- a/Tests/BackCompat/BCTokens/EmptyTokensTest.php +++ b/Tests/BackCompat/BCTokens/EmptyTokensTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/FunctionNameTokensTest.php b/Tests/BackCompat/BCTokens/FunctionNameTokensTest.php index 16bc277a..25f66316 100644 --- a/Tests/BackCompat/BCTokens/FunctionNameTokensTest.php +++ b/Tests/BackCompat/BCTokens/FunctionNameTokensTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/OoScopeTokensTest.php b/Tests/BackCompat/BCTokens/OoScopeTokensTest.php index 9db86945..9a63b8bb 100644 --- a/Tests/BackCompat/BCTokens/OoScopeTokensTest.php +++ b/Tests/BackCompat/BCTokens/OoScopeTokensTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/OperatorsTest.php b/Tests/BackCompat/BCTokens/OperatorsTest.php index b4a2c00d..cdabe140 100644 --- a/Tests/BackCompat/BCTokens/OperatorsTest.php +++ b/Tests/BackCompat/BCTokens/OperatorsTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php b/Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php index a2e8cd11..94e1ef01 100644 --- a/Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php +++ b/Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/TextStringTokensTest.php b/Tests/BackCompat/BCTokens/TextStringTokensTest.php index 24093f28..5cb44269 100644 --- a/Tests/BackCompat/BCTokens/TextStringTokensTest.php +++ b/Tests/BackCompat/BCTokens/TextStringTokensTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php b/Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php index ea2941eb..c179c949 100644 --- a/Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php +++ b/Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/Helper/ConfigDataTest.php b/Tests/BackCompat/Helper/ConfigDataTest.php index 09474246..f570e0f2 100644 --- a/Tests/BackCompat/Helper/ConfigDataTest.php +++ b/Tests/BackCompat/Helper/ConfigDataTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/Helper/GetCommandLineDataTest.php b/Tests/BackCompat/Helper/GetCommandLineDataTest.php index 8f0eb7b3..b37e1c83 100644 --- a/Tests/BackCompat/Helper/GetCommandLineDataTest.php +++ b/Tests/BackCompat/Helper/GetCommandLineDataTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/BackCompat/Helper/GetVersionTest.php b/Tests/BackCompat/Helper/GetVersionTest.php index 8f5c8c51..cc20e3b7 100644 --- a/Tests/BackCompat/Helper/GetVersionTest.php +++ b/Tests/BackCompat/Helper/GetVersionTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php index 6f61c989..1400c7cc 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php index 28bb577e..ce508d0d 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php index 5d69ce36..47e41207 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php index 861065a9..de3cff82 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php index 56b9c0ef..a76f59cd 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php b/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php index 157d6440..12329cf3 100644 --- a/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php +++ b/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php b/Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php index ad8a6de1..39a2af03 100644 --- a/Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php +++ b/Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php b/Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php index ca946fba..f53d4c87 100644 --- a/Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php +++ b/Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/TestUtils/UtilityMethodTestCase/UtilityMethodTestCaseTest.php b/Tests/TestUtils/UtilityMethodTestCase/UtilityMethodTestCaseTest.php index 8e83bc78..9a0ba793 100644 --- a/Tests/TestUtils/UtilityMethodTestCase/UtilityMethodTestCaseTest.php +++ b/Tests/TestUtils/UtilityMethodTestCase/UtilityMethodTestCaseTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php index b0c4de3d..286b3843 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Arrays/GetOpenCloseTest.php b/Tests/Utils/Arrays/GetOpenCloseTest.php index 6c1981e8..99445bb2 100644 --- a/Tests/Utils/Arrays/GetOpenCloseTest.php +++ b/Tests/Utils/Arrays/GetOpenCloseTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Arrays/IsShortArrayTest.php b/Tests/Utils/Arrays/IsShortArrayTest.php index c8a7ea37..fb9b3041 100644 --- a/Tests/Utils/Arrays/IsShortArrayTest.php +++ b/Tests/Utils/Arrays/IsShortArrayTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Arrays/IsShortArrayTokenizerBC1Test.php b/Tests/Utils/Arrays/IsShortArrayTokenizerBC1Test.php index 32b25289..4a649b94 100644 --- a/Tests/Utils/Arrays/IsShortArrayTokenizerBC1Test.php +++ b/Tests/Utils/Arrays/IsShortArrayTokenizerBC1Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Arrays/IsShortArrayTokenizerBC2Test.php b/Tests/Utils/Arrays/IsShortArrayTokenizerBC2Test.php index 907c6937..4b975324 100644 --- a/Tests/Utils/Arrays/IsShortArrayTokenizerBC2Test.php +++ b/Tests/Utils/Arrays/IsShortArrayTokenizerBC2Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Conditions/GetConditionTest.php b/Tests/Utils/Conditions/GetConditionTest.php index 74ece761..a3e6cb6b 100644 --- a/Tests/Utils/Conditions/GetConditionTest.php +++ b/Tests/Utils/Conditions/GetConditionTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php index 49886ac3..fb299040 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php index c831b9b8..791654c1 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php index 525cb12e..9c87aee0 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php index 668c3025..e72c1b3b 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.php index 0edb5eed..b72baefb 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/HasBodyParseError1Test.php b/Tests/Utils/ControlStructures/HasBodyParseError1Test.php index e677af6e..225343d0 100644 --- a/Tests/Utils/ControlStructures/HasBodyParseError1Test.php +++ b/Tests/Utils/ControlStructures/HasBodyParseError1Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/HasBodyParseError2Test.php b/Tests/Utils/ControlStructures/HasBodyParseError2Test.php index b3032195..1f8f4953 100644 --- a/Tests/Utils/ControlStructures/HasBodyParseError2Test.php +++ b/Tests/Utils/ControlStructures/HasBodyParseError2Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/HasBodyTest.php b/Tests/Utils/ControlStructures/HasBodyTest.php index 59c473ef..7182cc47 100644 --- a/Tests/Utils/ControlStructures/HasBodyTest.php +++ b/Tests/Utils/ControlStructures/HasBodyTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ControlStructures/IsElseIfTest.php b/Tests/Utils/ControlStructures/IsElseIfTest.php index d508c27a..d2a663d0 100644 --- a/Tests/Utils/ControlStructures/IsElseIfTest.php +++ b/Tests/Utils/ControlStructures/IsElseIfTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php index 575738f9..0dda94d5 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/GetParametersParseError1Test.php b/Tests/Utils/FunctionDeclarations/GetParametersParseError1Test.php index e77c489a..2efd50cc 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersParseError1Test.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersParseError1Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/GetParametersParseError2Test.php b/Tests/Utils/FunctionDeclarations/GetParametersParseError2Test.php index 7d856e90..ebefed1d 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersParseError2Test.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersParseError2Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/GetParametersTest.php b/Tests/Utils/FunctionDeclarations/GetParametersTest.php index d930296a..06e4fb84 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersTest.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php index 1be47ccf..3db7c90e 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php index d8e48c12..8f06561e 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php b/Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php index 34ee0e4a..03c267d0 100644 --- a/Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php +++ b/Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php b/Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php index 07b126c5..82a48a4b 100644 --- a/Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php +++ b/Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/IsPHPDoubleUnderscoreMethodNameTest.php b/Tests/Utils/FunctionDeclarations/IsPHPDoubleUnderscoreMethodNameTest.php index f29d2238..2feb771a 100644 --- a/Tests/Utils/FunctionDeclarations/IsPHPDoubleUnderscoreMethodNameTest.php +++ b/Tests/Utils/FunctionDeclarations/IsPHPDoubleUnderscoreMethodNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php index c401f27d..10adfcfe 100644 --- a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php +++ b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php b/Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php index 5dde8be1..d08560d4 100644 --- a/Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php +++ b/Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Lists/GetAssignmentsTest.php b/Tests/Utils/Lists/GetAssignmentsTest.php index 830b98b3..bc7f3213 100644 --- a/Tests/Utils/Lists/GetAssignmentsTest.php +++ b/Tests/Utils/Lists/GetAssignmentsTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Lists/GetOpenCloseTest.php b/Tests/Utils/Lists/GetOpenCloseTest.php index f2d0c0cb..e085dc0c 100644 --- a/Tests/Utils/Lists/GetOpenCloseTest.php +++ b/Tests/Utils/Lists/GetOpenCloseTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Lists/IsShortListTest.php b/Tests/Utils/Lists/IsShortListTest.php index 8e86d78b..4b74cecb 100644 --- a/Tests/Utils/Lists/IsShortListTest.php +++ b/Tests/Utils/Lists/IsShortListTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Lists/IsShortListTokenizerBC1Test.php b/Tests/Utils/Lists/IsShortListTokenizerBC1Test.php index 4dbbbc8c..2df3b7b8 100644 --- a/Tests/Utils/Lists/IsShortListTokenizerBC1Test.php +++ b/Tests/Utils/Lists/IsShortListTokenizerBC1Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Lists/IsShortListTokenizerBC2Test.php b/Tests/Utils/Lists/IsShortListTokenizerBC2Test.php index 019f2cda..47b6840b 100644 --- a/Tests/Utils/Lists/IsShortListTokenizerBC2Test.php +++ b/Tests/Utils/Lists/IsShortListTokenizerBC2Test.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Namespaces/DetermineNamespaceTest.php b/Tests/Utils/Namespaces/DetermineNamespaceTest.php index 3e6e67e5..774b9e16 100644 --- a/Tests/Utils/Namespaces/DetermineNamespaceTest.php +++ b/Tests/Utils/Namespaces/DetermineNamespaceTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Namespaces/GetDeclaredNameTest.php b/Tests/Utils/Namespaces/GetDeclaredNameTest.php index 3be47454..fe8c3c40 100644 --- a/Tests/Utils/Namespaces/GetDeclaredNameTest.php +++ b/Tests/Utils/Namespaces/GetDeclaredNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Namespaces/NamespaceTypeTest.php b/Tests/Utils/Namespaces/NamespaceTypeTest.php index a8fe0bef..23dffcdf 100644 --- a/Tests/Utils/Namespaces/NamespaceTypeTest.php +++ b/Tests/Utils/Namespaces/NamespaceTypeTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Numbers/GetCompleteNumberTest.php b/Tests/Utils/Numbers/GetCompleteNumberTest.php index 6c6899bb..4a15c03c 100644 --- a/Tests/Utils/Numbers/GetCompleteNumberTest.php +++ b/Tests/Utils/Numbers/GetCompleteNumberTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Numbers/GetDecimalValueTest.php b/Tests/Utils/Numbers/GetDecimalValueTest.php index 95109c19..f404a6ae 100644 --- a/Tests/Utils/Numbers/GetDecimalValueTest.php +++ b/Tests/Utils/Numbers/GetDecimalValueTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Numbers/NumberTypesTest.php b/Tests/Utils/Numbers/NumberTypesTest.php index cd6a368c..242c8155 100644 --- a/Tests/Utils/Numbers/NumberTypesTest.php +++ b/Tests/Utils/Numbers/NumberTypesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php index 4fdb49bd..d07ddd92 100644 --- a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php index a1bcd212..04bb95e0 100644 --- a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php +++ b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php b/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php index c9e216e6..e4d57b12 100644 --- a/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php +++ b/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.php b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.php index 9149fedb..1f8f07b8 100644 --- a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesTest.php b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesTest.php index a6117555..fe6bc029 100644 --- a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesTest.php +++ b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php b/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php index aabe6abb..3ff4fcbb 100644 --- a/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php b/Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php index 602d4fb9..05f271f5 100644 --- a/Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php +++ b/Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php b/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php index 7ec5026e..e29d9b9d 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/GetNameJSTest.php b/Tests/Utils/ObjectDeclarations/GetNameJSTest.php index 1bbf64a4..85d9ea9a 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameJSTest.php +++ b/Tests/Utils/ObjectDeclarations/GetNameJSTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/ObjectDeclarations/GetNameTest.php b/Tests/Utils/ObjectDeclarations/GetNameTest.php index cddf96c2..b41e849f 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameTest.php +++ b/Tests/Utils/ObjectDeclarations/GetNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Operators/IsReferenceDiffTest.php b/Tests/Utils/Operators/IsReferenceDiffTest.php index 0702824e..86bf7c01 100644 --- a/Tests/Utils/Operators/IsReferenceDiffTest.php +++ b/Tests/Utils/Operators/IsReferenceDiffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Operators/IsReferenceTest.php b/Tests/Utils/Operators/IsReferenceTest.php index 75de2671..fbbce68a 100644 --- a/Tests/Utils/Operators/IsReferenceTest.php +++ b/Tests/Utils/Operators/IsReferenceTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Operators/IsShortTernaryTest.php b/Tests/Utils/Operators/IsShortTernaryTest.php index abf71cb7..c5a66c60 100644 --- a/Tests/Utils/Operators/IsShortTernaryTest.php +++ b/Tests/Utils/Operators/IsShortTernaryTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php b/Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php index c09388c8..86c0af65 100644 --- a/Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php +++ b/Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Operators/IsUnaryPlusMinusTest.php b/Tests/Utils/Operators/IsUnaryPlusMinusTest.php index 76190e0e..2addb23e 100644 --- a/Tests/Utils/Operators/IsUnaryPlusMinusTest.php +++ b/Tests/Utils/Operators/IsUnaryPlusMinusTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Orthography/FirstCharTest.php b/Tests/Utils/Orthography/FirstCharTest.php index 6c0b437c..53f00584 100644 --- a/Tests/Utils/Orthography/FirstCharTest.php +++ b/Tests/Utils/Orthography/FirstCharTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Orthography/IsLastCharPunctuationTest.php b/Tests/Utils/Orthography/IsLastCharPunctuationTest.php index a6921402..55b74f60 100644 --- a/Tests/Utils/Orthography/IsLastCharPunctuationTest.php +++ b/Tests/Utils/Orthography/IsLastCharPunctuationTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Parentheses/ParenthesesTest.php b/Tests/Utils/Parentheses/ParenthesesTest.php index 0f99cf84..9f564ff3 100644 --- a/Tests/Utils/Parentheses/ParenthesesTest.php +++ b/Tests/Utils/Parentheses/ParenthesesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/PassedParameters/GetParameterCountTest.php b/Tests/Utils/PassedParameters/GetParameterCountTest.php index 844c556d..be03c7e6 100644 --- a/Tests/Utils/PassedParameters/GetParameterCountTest.php +++ b/Tests/Utils/PassedParameters/GetParameterCountTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/PassedParameters/GetParametersTest.php b/Tests/Utils/PassedParameters/GetParametersTest.php index 88353977..1e963b7c 100644 --- a/Tests/Utils/PassedParameters/GetParametersTest.php +++ b/Tests/Utils/PassedParameters/GetParametersTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/PassedParameters/HasParametersTest.php b/Tests/Utils/PassedParameters/HasParametersTest.php index b78d9c6b..36290a5e 100644 --- a/Tests/Utils/PassedParameters/HasParametersTest.php +++ b/Tests/Utils/PassedParameters/HasParametersTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Scopes/IsOOConstantTest.php b/Tests/Utils/Scopes/IsOOConstantTest.php index 8e9b6129..4f898b40 100644 --- a/Tests/Utils/Scopes/IsOOConstantTest.php +++ b/Tests/Utils/Scopes/IsOOConstantTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Scopes/IsOOMethodTest.php b/Tests/Utils/Scopes/IsOOMethodTest.php index 742522b0..877bdf4f 100644 --- a/Tests/Utils/Scopes/IsOOMethodTest.php +++ b/Tests/Utils/Scopes/IsOOMethodTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Scopes/IsOOPropertyTest.php b/Tests/Utils/Scopes/IsOOPropertyTest.php index f4081806..566d6640 100644 --- a/Tests/Utils/Scopes/IsOOPropertyTest.php +++ b/Tests/Utils/Scopes/IsOOPropertyTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/TextStrings/GetCompleteTextStringTest.php b/Tests/Utils/TextStrings/GetCompleteTextStringTest.php index 5766189b..f31193bd 100644 --- a/Tests/Utils/TextStrings/GetCompleteTextStringTest.php +++ b/Tests/Utils/TextStrings/GetCompleteTextStringTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/TextStrings/StripQuotesTest.php b/Tests/Utils/TextStrings/StripQuotesTest.php index 9623b609..51c34d28 100644 --- a/Tests/Utils/TextStrings/StripQuotesTest.php +++ b/Tests/Utils/TextStrings/StripQuotesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/UseStatements/SplitImportUseStatementTest.php b/Tests/Utils/UseStatements/SplitImportUseStatementTest.php index 71239ed8..28f7edf6 100644 --- a/Tests/Utils/UseStatements/SplitImportUseStatementTest.php +++ b/Tests/Utils/UseStatements/SplitImportUseStatementTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/UseStatements/UseTypeTest.php b/Tests/Utils/UseStatements/UseTypeTest.php index ec19b2b2..d58f179e 100644 --- a/Tests/Utils/UseStatements/UseTypeTest.php +++ b/Tests/Utils/UseStatements/UseTypeTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php index fbf9614a..2dfa66bb 100644 --- a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php +++ b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Variables/GetMemberPropertiesTest.php b/Tests/Utils/Variables/GetMemberPropertiesTest.php index 21e5fb4c..d4d4c34e 100644 --- a/Tests/Utils/Variables/GetMemberPropertiesTest.php +++ b/Tests/Utils/Variables/GetMemberPropertiesTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Variables/IsPHPReservedVarNameTest.php b/Tests/Utils/Variables/IsPHPReservedVarNameTest.php index 3257f84a..ed310da1 100644 --- a/Tests/Utils/Variables/IsPHPReservedVarNameTest.php +++ b/Tests/Utils/Variables/IsPHPReservedVarNameTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/Utils/Variables/IsSuperglobalTest.php b/Tests/Utils/Variables/IsSuperglobalTest.php index d882334c..cb5cf3f6 100644 --- a/Tests/Utils/Variables/IsSuperglobalTest.php +++ b/Tests/Utils/Variables/IsSuperglobalTest.php @@ -3,7 +3,7 @@ * PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils */ diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php index 80b00d3c..6812f447 100644 --- a/Tests/bootstrap.php +++ b/Tests/bootstrap.php @@ -5,7 +5,7 @@ * Bootstrap file for the unit tests. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * diff --git a/phpcsutils-autoload.php b/phpcsutils-autoload.php index db48196c..d9cd9349 100644 --- a/phpcsutils-autoload.php +++ b/phpcsutils-autoload.php @@ -22,7 +22,7 @@ * the unit test bootstrap file. * * @package PHPCSUtils - * @copyright 2019 PHPCSUtils Contributors + * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils * From 05464c7beb790089b07c483e742ea3573698229a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:29:35 +0100 Subject: [PATCH 09/48] Tokens\Collections: add `T_ARRAY` to $returnTypeTokens PHPCS does not adjust the return type token for arrow functions to `T_STRING` until PHPCS 3.5.3/4. Depening on the PHPCS version and the specific code, an `array` return type token for an arrow function may be tokenized as `T_ARRAY_HINT` or `T_ARRAY`. --- PHPCSUtils/Tokens/Collections.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 754c31e8..d8d034af 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -308,7 +308,8 @@ class Collections \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. + \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. ]; /** From c22a30a7ab18511609aa440378423ebddb3cc4ca Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:30:14 +0100 Subject: [PATCH 10/48] Utils\FunctionDeclarations: new arrow function helper utilities This introduces two new utilities to allow for detecting and analyzing PHP 7.4 arrow functions. The arrow function tokens - the PHP native `T_FN` and the PHPCS native `T_FN_ARROW` - where backfilled/introduced in PHPCS 3.5.3/4, including assigning parentheses owner/opener/closer and scope owner/opener/closer tokens to the relevant related tokens. The utility functions in this commit back-fills this functionality for use with older PHPCS versions. **Note**: this does mean that sniffs which target functions, will need to add both the `T_FN`, as well as the `T_STRING` token to their `register()` method and need to pass any `T_STRING` tokens onto these utility functions before processing the token. Functions: * `isArrowFunction()` to detect whether an arbitrary (`T_FN`/`T_STRING`) token is in actual fact an arrow function keyword. * `getArrowFunctionOpenClose()` to retrieve the token pointers to the open parenthesis, close parenthesis, scope opener and scope closer for arrow functions. Generally speaking, a sniff should only need to call one of these functions depending on what information is needed. Includes dedicated unit tests. The tests are loosely based on the `Tokenizer/BackfillFnTokenTest` file in PHPCS itself. Note: in a limited set of very specific circumstances, the backfill in PHPCS 3.5.3 is broken. While the `isArrowFunction()` will still give correct results in that case, the `getArrowFunctionOpenClose()` function will not. As PHPCS 3.5.3 is explicitly not supported due to the broken backfill of PHP 7.4 numeric literals, no fixes will be added to work-around the broken backfill for arrow functions in PHPCS 3.5.3. Related ticket in PHPCS itself: * squizlabs/PHP_CodeSniffer 2523 Related commits in PHPCS itself: * https://github.com/squizlabs/PHP_CodeSniffer/commit/8fedf8c449ba95a8dcd82a51cbe377bf2a03aea2 * https://github.com/squizlabs/PHP_CodeSniffer/commit/51afb54b674ace643ea726bfe52796187d62d55e * https://github.com/squizlabs/PHP_CodeSniffer/commit/ae3ffc721d32e03e6f6815bba6704f5588d428c6 * https://github.com/squizlabs/PHP_CodeSniffer/commit/0b498ad5a6325c55d85838505da3fc488c9c9d2f * https://github.com/squizlabs/PHP_CodeSniffer/commit/30b545728c2c273eb39277f51da43ef1265ac0e8 * https://github.com/squizlabs/PHP_CodeSniffer/commit/0e4fe7404d19701687c27a2991feae9641fa7359 Co-authored-by: Greg Sherwood --- PHPCSUtils/Utils/FunctionDeclarations.php | 258 ++++++++++ .../IsArrowFunctionTest.inc | 85 ++++ .../IsArrowFunctionTest.php | 467 ++++++++++++++++++ 3 files changed, 810 insertions(+) create mode 100644 Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc create mode 100644 Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index b59dbda7..4975dac1 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -532,6 +532,264 @@ public static function getParameters(File $phpcsFile, $stackPtr) return $vars; } + /** + * Check if an arbitrary token is a PHP 7.4 arrow function keyword token. + * + * Helper function for backward-compatibility with PHP < 7.4 in combination with PHPCS < 3.5.3/4 + * in which the `T_FN` token is not yet backfilled. + * + * Note: While this function can determine whether a token should be regarded as `T_FN`, if the + * token isn't a PHP native `T_FN` or backfilled `T_FN` token, the token will still not have + * the `parenthesis_owner`, `parenthesis_opener`, `parenthesis_closer`, `scope_owner` + * `scope_opener` or `scope_closer` keys assigned in the tokens array. + * Use the `FunctionDeclarations::getArrowFunctionOpenClose()` utility method to retrieve + * these when they're needed. + * + * @see \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose() + * + * @since 1.0.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. + * @param int $stackPtr The token to check. Typically a T_FN or + * T_STRING token as those are the only two + * tokens which can be the arrow function keyword. + * + * @return bool + */ + public static function isArrowFunction(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + if (isset($tokens[$stackPtr]) === false) { + return false; + } + + if ($tokens[$stackPtr]['type'] === 'T_FN') { + // Either PHP 7.4 or PHPCS 3.5.3+. Check if this is not a real function called "fn". + $prevNonEmpty = $phpcsFile->findPrevious( + Tokens::$emptyTokens + [\T_BITWISE_AND], + ($stackPtr - 1), + null, + true + ); + if ($tokens[$prevNonEmpty]['code'] === \T_FUNCTION) { + return false; + } + + return true; + } + + if (\defined('T_FN') === true) { + // If the token exists and isn't used, it's not an arrow function. + return false; + } + + if ($tokens[$stackPtr]['code'] !== \T_STRING + || \strtolower($tokens[$stackPtr]['content']) !== 'fn' + ) { + return false; + } + + $nextNonEmpty = $phpcsFile->findNext((Tokens::$emptyTokens + [\T_BITWISE_AND]), ($stackPtr + 1), null, true); + if ($nextNonEmpty === false + || ($tokens[$nextNonEmpty]['code'] === \T_OPEN_PARENTHESIS + // Make sure it is not a real function called "fn". + && (isset($tokens[$nextNonEmpty]['parenthesis_owner']) === false + || $tokens[$tokens[$nextNonEmpty]['parenthesis_owner']]['code'] !== \T_FUNCTION)) + ) { + return true; + } + + return false; + } + + /** + * Retrieve the parenthesis opener, parenthesis closer, the scope opener and the scope closer + * for an arrow function. + * + * Helper function for backward-compatibility with PHP < 7.4 in combination with PHPCS < 3.5.3/4 + * in which the `T_FN` token is not yet backfilled and does not have parenthesis opener/closer + * nor scope opener/closer indexes assigned in the `$tokens` array. + * + * Note: The backfill in PHPCS 3.5.3 is incomplete and this function will - in a limited set of + * circumstances - not work on PHPCS 3.5.3. + * As PHPCS 3.5.3 is not supported by PHPCSUtils due to the broken PHP 7.4 numeric literals backfill + * anyway, this will not be fixed. + * + * @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() + * + * @since 1.0.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. + * @param int $stackPtr The token to retrieve the opener/closers for. + * Typically a T_FN or T_STRING token as those are the + * only two tokens which can be the arrow function keyword. + * + * @return array An array with the token pointers or an empty array if this is not an arrow function. + * The format of the return value is: + * + * array( + * 'parenthesis_opener' => integer|false, // Stack pointer or false if undetermined. + * 'parenthesis_closer' => integer|false, // Stack pointer or false if undetermined. + * 'scope_opener' => integer|false, // Stack pointer or false if undetermined. + * 'scope_closer' => integer|false, // Stack pointer or false if undetermined. + * ) + * + */ + public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) + { + if (self::isArrowFunction($phpcsFile, $stackPtr) === false) { + return []; + } + + $returnValue = [ + 'parenthesis_opener' => false, + 'parenthesis_closer' => false, + 'scope_opener' => false, + 'scope_closer' => false, + ]; + + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['type'] === 'T_FN' + && \version_compare(Helper::getVersion(), '3.5.3', '>=') === true + ) { + if (isset($tokens[$stackPtr]['parenthesis_opener']) === true) { + $returnValue['parenthesis_opener'] = $tokens[$stackPtr]['parenthesis_opener']; + } + + if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { + $returnValue['parenthesis_closer'] = $tokens[$stackPtr]['parenthesis_closer']; + } + + if (isset($tokens[$stackPtr]['scope_opener']) === true) { + $returnValue['scope_opener'] = $tokens[$stackPtr]['scope_opener']; + } + + if (isset($tokens[$stackPtr]['scope_closer']) === true) { + $returnValue['scope_closer'] = $tokens[$stackPtr]['scope_closer']; + } + + return $returnValue; + } + + /* + * Either a T_STRING token pre-PHP 7.4, or T_FN on PHP 7.4, in combination with PHPCS < 3.5.3. + * Now see about finding the relevant arrow function tokens. + */ + $nextNonEmpty = $phpcsFile->findNext( + (Tokens::$emptyTokens + [\T_BITWISE_AND]), + ($stackPtr + 1), + null, + true + ); + if ($nextNonEmpty === false || $tokens[$nextNonEmpty]['code'] !== \T_OPEN_PARENTHESIS) { + return $returnValue; + } + + $returnValue['parenthesis_opener'] = $nextNonEmpty; + if (isset($tokens[$nextNonEmpty]['parenthesis_closer']) === false) { + return $returnValue; + } + + $returnValue['parenthesis_closer'] = $tokens[$nextNonEmpty]['parenthesis_closer']; + + $ignore = Tokens::$emptyTokens; + $ignore += Collections::$returnTypeTokens; + $ignore[\T_COLON] = \T_COLON; + $ignore[\T_INLINE_ELSE] = \T_INLINE_ELSE; // PHPCS < 2.9.1. + $ignore[\T_INLINE_THEN] = \T_INLINE_THEN; // PHPCS < 2.9.1. + + if (\defined('T_NULLABLE') === true) { + $ignore[\T_NULLABLE] = \T_NULLABLE; + } + + $arrow = $phpcsFile->findNext( + $ignore, + ($tokens[$nextNonEmpty]['parenthesis_closer'] + 1), + null, + true + ); + + if ($arrow === false + || $tokens[$arrow]['code'] !== \T_DOUBLE_ARROW + ) { + return $returnValue; + } + + $returnValue['scope_opener'] = $arrow; + + $endTokens = [ + \T_COLON => true, + \T_COMMA => true, + \T_SEMICOLON => true, + \T_CLOSE_PARENTHESIS => true, + \T_CLOSE_SQUARE_BRACKET => true, + \T_CLOSE_CURLY_BRACKET => true, + \T_CLOSE_SHORT_ARRAY => true, + \T_OPEN_TAG => true, + \T_CLOSE_TAG => true, + ]; + + $inTernary = false; + + for ($scopeCloser = ($arrow + 1); $scopeCloser < $phpcsFile->numTokens; $scopeCloser++) { + if (isset($endTokens[$tokens[$scopeCloser]['code']]) === true + && ($tokens[$scopeCloser]['code'] !== \T_COLON || $inTernary === false) + ) { + break; + } + + if ($tokens[$scopeCloser]['type'] === 'T_FN' + || ($tokens[$scopeCloser]['code'] === \T_STRING + && $tokens[$scopeCloser]['content'] === 'fn') + ) { + $nested = self::getArrowFunctionOpenClose($phpcsFile, $scopeCloser); + if (isset($nested['scope_closer']) && $nested['scope_closer'] !== false) { + // We minus 1 here in case the closer can be shared with us. + $scopeCloser = ($nested['scope_closer'] - 1); + continue; + } + } + + if (isset($tokens[$scopeCloser]['scope_closer']) === true + && $tokens[$scopeCloser]['code'] !== \T_INLINE_ELSE + ) { + // We minus 1 here in case the closer can be shared with us. + $scopeCloser = ($tokens[$scopeCloser]['scope_closer'] - 1); + continue; + } + + if (isset($tokens[$scopeCloser]['parenthesis_closer']) === true) { + $scopeCloser = $tokens[$scopeCloser]['parenthesis_closer']; + continue; + } + + if (isset($tokens[$scopeCloser]['bracket_closer']) === true) { + $scopeCloser = $tokens[$scopeCloser]['bracket_closer']; + continue; + } + + if ($tokens[$scopeCloser]['code'] === \T_INLINE_THEN) { + $inTernary = true; + continue; + } + + if ($tokens[$scopeCloser]['code'] === \T_INLINE_ELSE) { + if ($inTernary === false) { + break; + } + + $inTernary = false; + } + } + + if ($scopeCloser !== $phpcsFile->numTokens) { + $returnValue['scope_closer'] = $scopeCloser; + } + + return $returnValue; + } + /** * Checks if a given function is a PHP magic function. * diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc new file mode 100644 index 00000000..d48ab6b2 --- /dev/null +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc @@ -0,0 +1,85 @@ + $x + $y; + +/* testMixedCase */ +$fn1 = Fn($x) => $x + $y; + +/* testWhitespace */ +$fn1 = fn ($x) => $x + $y; + +/* testComment */ +$fn1 = fn /* comment here */ ($x) => $x + $y; + +/* testFunctionName */ +function &fn() {} + +/* testNestedOuter */ +$fn = fn($x) => /* testNestedInner */ fn($y) => $x * $y + $z; + +/* testFunctionCall */ +$extended = fn($c) => $callable($factory($c), $c); + +/* testChainedFunctionCall */ +$result = Collection::from([1, 2]) + ->map(fn($v) => $v * 2) + ->reduce(/* testFunctionArgument */ fn($tmp, $v) => $tmp + $v, 0); + +/* testClosure */ +$extended = fn($c) => $callable(function() { + for ($x = 1; $x < 10; $x++) { + echo $x; + } + + echo 'done'; +}, $c); + +$result = array_map( + /* testReturnTypeNullableInt */ + static fn(int $number) : ?int => $number + 1, + $numbers +); + +/* testReturnTypeNamespacedClass */ +$fn = fn($x) : ?\My\NS\ClassName => $x; + +/* testReturnTypeArray */ +$fn = fn($x) : array => $x; + +/* testReturnTypeArrayBug2773 */ +$fn = fn(): array => [a($a, $b)]; + +array_map( + /* testMoreArrayTypeDeclarations */ + static fn (array $value): array => array_filter($value), + [] +); + +/* testReturnTypeCallable */ +$fn = fn($x) : callable => $x; + +/* testReturnTypeSelf */ +$fn = fn($x) : ?self => $x; + +/* testReference */ +fn&($x) => $x; + +/* testGrouped */ +(fn($x) => $x) + $y; + +/* testYield */ +$a = fn($x) => yield 'k' => $x; + +/* testTernary */ +$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b'; + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php new file mode 100644 index 00000000..0511f922 --- /dev/null +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php @@ -0,0 +1,467 @@ +assertFalse($result); + } + + /** + * Test that the function returns false when passed a token which definitely is not an arrow function. + * + * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction + * + * @return void + */ + public function testUnsupportedToken() + { + $stackPtr = $this->getTargetToken('/* testNotAnArrowFunction */', \T_CONST); + + $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); + $this->assertFalse($result); + } + + /** + * Test that the function returns false when passed a T_STRING token without `fn` as content. + * + * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction + * + * @return void + */ + public function testTStringNotFn() + { + $stackPtr = $this->getTargetToken('/* testNotTheRightContent */', \T_STRING); + + $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); + $this->assertFalse($result); + } + + /** + * Test correctly detecting arrow functions. + * + * @dataProvider dataArrowFunction + * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction + * + * @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 = [\T_STRING]; + if (\defined('T_FN') === true) { + $targets[] = \T_FN; + } + + $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); + $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); + $this->assertSame($expected['is'], $result); + } + + /** + * Test correctly detecting arrow functions. + * + * @dataProvider dataArrowFunction + * @covers \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose + * + * @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. + * @param bool $maybeSkip Whether the test should be skipped on PHPCS 3.5.3 due to a broken + * upstream backfill. + * + * @return void + */ + public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetContent = null, $maybeSkip = false) + { + // Skip specific test(s) on unsupported PHPCS versions. + if ($maybeSkip === true && \version_compare(Helper::getVersion(), '3.5.3', '==') === true) { + $this->markTestSkipped( + 'PHPCS 3.5.3 is not supported for this specific test due to a buggy arrow functions backfill.' + ); + } + + $targets = [\T_STRING]; + if (\defined('T_FN') === true) { + $targets[] = \T_FN; + } + + $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); + + // Change from offsets to absolute token positions. + foreach ($expected['get'] as $key => $value) { + if ($value === false) { + continue; + } + + $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 [ + /* + * This particular case tests the "no open parenthesis after" condition in PHPCS < 3.5.3 + * and the "fn defined but not used" condition in PHPCS 3.5.3+. + */ + 'const-declaration-not-an-arrow-function' => [ + '/* testNotAnArrowFunction */', + [ + 'is' => false, + 'get' => [], + ], + ], + 'arrow-function-standard' => [ + '/* testStandard */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 12, + ], + ], + ], + 'arrow-function-mixed-case' => [ + '/* testMixedCase */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 12, + ], + ], + ], + 'arrow-function-with-whitespace' => [ + '/* testWhitespace */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 2, + 'parenthesis_closer' => 4, + 'scope_opener' => 6, + 'scope_closer' => 13, + ], + ], + ], + 'arrow-function-with-comment' => [ + '/* testComment */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 4, + 'parenthesis_closer' => 6, + 'scope_opener' => 8, + 'scope_closer' => 15, + ], + ], + ], + 'real-function-called-fn' => [ + '/* testFunctionName */', + [ + 'is' => false, + 'get' => [], + ], + ], + 'arrow-function-nested-outer' => [ + '/* testNestedOuter */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 25, + ], + ], + ], + 'arrow-function-nested-inner' => [ + '/* testNestedInner */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 16, + ], + ], + ], + 'arrow-function-function-call' => [ + '/* testFunctionCall */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 17, + ], + ], + ], + 'arrow-function-chained-function-call' => [ + '/* testChainedFunctionCall */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 12, + ], + ], + 'fn', + ], + 'arrow-function-as-function-argument' => [ + '/* testFunctionArgument */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 6, + 'scope_opener' => 8, + 'scope_closer' => 15, + ], + ], + ], + 'arrow-function-nested-closure' => [ + '/* testClosure */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 60, + ], + ], + ], + 'arrow-function-with-return-type-nullable-int' => [ + '/* testReturnTypeNullableInt */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 5, + 'scope_opener' => 12, + 'scope_closer' => 19, + ], + ], + ], + 'arrow-function-with-return-type-nullable-namespaced-class' => [ + '/* testReturnTypeNamespacedClass */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 15, + 'scope_closer' => 18, + ], + ], + ], + 'arrow-function-with-return-type-array' => [ + '/* testReturnTypeArray */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 9, + 'scope_closer' => 12, + ], + ], + ], + 'arrow-function-with-return-type-array-bug-2773' => [ + '/* testReturnTypeArrayBug2773 */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 7, + 'scope_closer' => 18, + ], + ], + null, + true, + ], + 'arrow-function-with-array-param-and-return-type' => [ + '/* testMoreArrayTypeDeclarations */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 2, + 'parenthesis_closer' => 6, + 'scope_opener' => 11, + 'scope_closer' => 17, + ], + ], + null, + true, + ], + 'arrow-function-with-return-type-callable' => [ + '/* testReturnTypeCallable */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 9, + 'scope_closer' => 12, + ], + ], + ], + 'arrow-function-with-return-type-nullable-self' => [ + '/* testReturnTypeSelf */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 10, + 'scope_closer' => 13, + ], + ], + ], + 'arrow-function-with-reference' => [ + '/* testReference */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 2, + 'parenthesis_closer' => 4, + 'scope_opener' => 6, + 'scope_closer' => 9, + ], + ], + ], + 'arrow-function-within-parenthesis' => [ + '/* testGrouped */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 8, + ], + ], + ], + 'arrow-function-with-yield-in-value' => [ + '/* testYield */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 14, + ], + ], + ], + 'arrow-function-with-ternary-content' => [ + '/* testTernary */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 40, + ], + ], + ], + 'arrow-function-with-ternary-content-after-then' => [ + '/* testTernaryThen */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 8, + 'scope_closer' => 12, + ], + ], + ], + 'arrow-function-with-ternary-content-after-else' => [ + '/* testTernaryElse */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 8, + 'scope_closer' => 11, + ], + ], + ], + + 'live-coding' => [ + '/* testLiveCoding */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => false, + 'parenthesis_closer' => false, + 'scope_opener' => false, + 'scope_closer' => false, + ], + ], + ], + ]; + } +} From f2ebedb5f5277542bfac85f443a5c5bf750fdc76 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:30:56 +0100 Subject: [PATCH 11/48] BCFile/Operators::isReference(): allow for arrow functions returning by reference ... for backwards compatibility to the `BCFile::isReference()` and the sister-method `Operators::isReference()` as per upstream commit squizlabs/PHP_CodeSniffer@96e69bbb3fad479602aa315bb520ff1739aa6d1a which was included in PHPCS 3.5.3. Also see: squizlabs/PHP_CodeSniffer 2523 Co-authored-by: Greg Sherwood --- PHPCSUtils/BackCompat/BCFile.php | 5 ++++- PHPCSUtils/Utils/Operators.php | 4 +++- Tests/BackCompat/BCFile/IsReferenceTest.inc | 3 +++ Tests/BackCompat/BCFile/IsReferenceTest.php | 4 ++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 82de4b0d..6d86ee35 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -923,6 +923,7 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) * - New by reference was not recognized as a reference. * - References to class properties with `self::`, `parent::`, `static::`, * `namespace\ClassName::`, `classname::` were not recognized as references. + * - PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions returning by reference. * * @see \PHP_CodeSniffer\Files\File::isReference() Original source. * @see \PHPCSUtils\Utils\Operators::isReference() PHPCSUtils native improved version. @@ -945,7 +946,9 @@ public static function isReference(File $phpcsFile, $stackPtr) $tokenBefore = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$tokenBefore]['code'] === T_FUNCTION) { + if ($tokens[$tokenBefore]['code'] === T_FUNCTION + || $tokens[$tokenBefore]['code'] === T_FN + ) { // Function returns a reference. return true; } diff --git a/PHPCSUtils/Utils/Operators.php b/PHPCSUtils/Utils/Operators.php index ad0749f7..29f0bd37 100644 --- a/PHPCSUtils/Utils/Operators.php +++ b/PHPCSUtils/Utils/Operators.php @@ -80,7 +80,9 @@ public static function isReference(File $phpcsFile, $stackPtr) $tokenBefore = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$tokenBefore]['code'] === \T_FUNCTION) { + if ($tokens[$tokenBefore]['code'] === \T_FUNCTION + || $tokens[$tokenBefore]['code'] === \T_FN + ) { // Function returns a reference. return true; } diff --git a/Tests/BackCompat/BCFile/IsReferenceTest.inc b/Tests/BackCompat/BCFile/IsReferenceTest.inc index 1c95480e..b7e34252 100644 --- a/Tests/BackCompat/BCFile/IsReferenceTest.inc +++ b/Tests/BackCompat/BCFile/IsReferenceTest.inc @@ -162,3 +162,6 @@ functionCall( $something , &new Foobar() ); /* testUseByReference */ $closure = function() use (&$var){}; + +/* testArrowFunctionReturnByReference */ +fn&($x) => $x; diff --git a/Tests/BackCompat/BCFile/IsReferenceTest.php b/Tests/BackCompat/BCFile/IsReferenceTest.php index aff6a9c6..aa1b0db8 100644 --- a/Tests/BackCompat/BCFile/IsReferenceTest.php +++ b/Tests/BackCompat/BCFile/IsReferenceTest.php @@ -308,6 +308,10 @@ public function dataIsReference() '/* testUseByReference */', true, ], + [ + '/* testArrowFunctionReturnByReference */', + true, + ], ]; } } From d6ddf4e728cd919f3b34d4726a171c0a3d9f7b29 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:32:32 +0100 Subject: [PATCH 12/48] BCFile/Operators::isReference(): fix backward compatibility with PHPCS < 3.5.3 --- PHPCSUtils/BackCompat/BCFile.php | 3 ++- PHPCSUtils/Utils/Operators.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 6d86ee35..7c45bd8f 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -929,6 +929,7 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) * @see \PHPCSUtils\Utils\Operators::isReference() PHPCSUtils native improved version. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the T_BITWISE_AND token. @@ -947,7 +948,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_FN + || FunctionDeclarations::isArrowFunction($phpcsFile, $tokenBefore) === true ) { // Function returns a reference. return true; diff --git a/PHPCSUtils/Utils/Operators.php b/PHPCSUtils/Utils/Operators.php index 29f0bd37..ff4ac3b9 100644 --- a/PHPCSUtils/Utils/Operators.php +++ b/PHPCSUtils/Utils/Operators.php @@ -63,6 +63,7 @@ class Operators * @see \PHPCSUtils\BackCompat\BCFile::isReference() Cross-version compatible version of the original. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the T_BITWISE_AND token. @@ -81,7 +82,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_FN + || FunctionDeclarations::isArrowFunction($phpcsFile, $tokenBefore) === true ) { // Function returns a reference. return true; From defe04f3c122ad051dc6451646730cca43ae2c07 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:33:42 +0100 Subject: [PATCH 13/48] BCFile/FunctionDeclarations::get[Method]Parameters(): add support for arrow functions Add support for arrow functions to the `BCFile::getMethodParameters()` and the sister-method `FunctionDeclarations::getParameters()` as per upstream commit squizlabs/PHP_CodeSniffer@b74e813245148402c79a4fc074bb9e68044eb734 which was included in PHPCS 3.5.3. Also see: squizlabs/PHP_CodeSniffer 2523 Co-authored-by: Greg Sherwood --- PHPCSUtils/BackCompat/BCFile.php | 7 ++- PHPCSUtils/Utils/FunctionDeclarations.php | 8 +-- .../BCFile/GetMethodParametersTest.inc | 3 ++ .../BCFile/GetMethodParametersTest.php | 52 +++++++++++++++++-- .../GetParametersTest.php | 11 ++-- 5 files changed, 68 insertions(+), 13 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 7c45bd8f..62dbb6d1 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -238,6 +238,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * be set in a "variadic_token" array index. * - PHPCS 3.5.3: Fixed a bug where the "type_hint_end_token" array index for a type hinted * parameter would bleed through to the next (non-type hinted) parameter. + * - PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions. * * @see \PHP_CodeSniffer\Files\File::getMethodParameters() Original source. * @see \PHPCSUtils\Utils\FunctionDeclarations::getParameters() PHPCSUtils native improved version. @@ -251,7 +252,8 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * @return array * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified $stackPtr is not of - * type T_FUNCTION, T_CLOSURE, or T_USE. + * type T_FUNCTION, T_CLOSURE, T_USE, + * or T_FN. */ public static function getMethodParameters(File $phpcsFile, $stackPtr) { @@ -260,8 +262,9 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) if ($tokens[$stackPtr]['code'] !== T_FUNCTION && $tokens[$stackPtr]['code'] !== T_CLOSURE && $tokens[$stackPtr]['code'] !== T_USE + && $tokens[$stackPtr]['code'] !== T_FN ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE'); + throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); } if ($tokens[$stackPtr]['code'] === T_USE) { diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 4975dac1..b2732cf3 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -348,7 +348,8 @@ public static function getProperties(File $phpcsFile, $stackPtr) * @return array * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified $stackPtr is not of - * type T_FUNCTION, T_CLOSURE, or T_USE. + * type T_FUNCTION, T_CLOSURE, T_USE, + * or T_FN. */ public static function getParameters(File $phpcsFile, $stackPtr) { @@ -357,9 +358,10 @@ public static function getParameters(File $phpcsFile, $stackPtr) if (isset($tokens[$stackPtr]) === false || ($tokens[$stackPtr]['code'] !== \T_FUNCTION && $tokens[$stackPtr]['code'] !== \T_CLOSURE - && $tokens[$stackPtr]['code'] !== \T_USE) + && $tokens[$stackPtr]['code'] !== \T_USE + && $tokens[$stackPtr]['code'] !== \T_FN) ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE'); + throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); } if ($tokens[$stackPtr]['code'] === \T_USE) { diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc index e539d5be..404da716 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc @@ -53,6 +53,9 @@ function defaultValues($var1=1, $var2='value') {} /* testBitwiseAndConstantExpressionDefaultValue */ function myFunction($a = 10 & 20) {} +/* testArrowFunction */ +fn(int $a, ...$b) => $b; + /* testArrayDefaultValues */ function arrayDefaultValues($var1 = [], $var2 = array(1, 2, 3) ) {} diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index cd7486ca..dfe39295 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -45,7 +45,7 @@ class GetMethodParametersTest extends UtilityMethodTestCase */ public function testUnexpectedTokenException() { - $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE'); + $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); $next = $this->getTargetToken('/* testNotAFunction */', [T_INTERFACE]); BCFile::getMethodParameters(self::$phpcsFile, $next); @@ -96,7 +96,7 @@ public function dataInvalidUse() * * @return void */ - public function testNoParams($commentString, $targetTokenType = [T_FUNCTION, T_CLOSURE]) + public function testNoParams($commentString, $targetTokenType = [T_FUNCTION, T_CLOSURE, T_FN]) { $target = $this->getTargetToken($commentString, $targetTokenType); $result = BCFile::getMethodParameters(self::$phpcsFile, $target); @@ -410,6 +410,47 @@ public function testBitwiseAndConstantExpressionDefaultValue() $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Verify that arrow functions are supported. + * + * @return void + */ + public function testArrowFunction() + { + $expected = []; + $expected[0] = [ + 'token' => 4, // Offset from the T_FN token. + 'name' => '$a', + 'content' => 'int $a', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 2, // Offset from the T_FN token. + 'type_hint_end_token' => 2, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 5, // Offset from the T_FN token. + ]; + + $expected[1] = [ + 'token' => 8, // Offset from the T_FN token. + 'name' => '$b', + 'content' => '...$b', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 7, // Offset from the T_FN token. + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Verify default value parsing with array values. * @@ -991,8 +1032,11 @@ public function testClosureUse() * * @return void */ - protected function getMethodParametersTestHelper($commentString, $expected, $targetType = [T_FUNCTION, T_CLOSURE]) - { + protected function getMethodParametersTestHelper( + $commentString, + $expected, + $targetType = [T_FUNCTION, T_CLOSURE, T_FN] + ) { $target = $this->getTargetToken($commentString, $targetType); $found = BCFile::getMethodParameters(self::$phpcsFile, $target); diff --git a/Tests/Utils/FunctionDeclarations/GetParametersTest.php b/Tests/Utils/FunctionDeclarations/GetParametersTest.php index 06e4fb84..57cccc7a 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersTest.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersTest.php @@ -54,7 +54,7 @@ public static function setUpTestFile() */ public function testUnexpectedTokenException() { - $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE'); + $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); $next = $this->getTargetToken('/* testNotAFunction */', [\T_INTERFACE]); FunctionDeclarations::getParameters(self::$phpcsFile, $next); @@ -88,7 +88,7 @@ public function testInvalidUse($identifier) * * @return void */ - public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T_CLOSURE]) + public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T_CLOSURE, \T_FN]) { $target = $this->getTargetToken($commentString, $targetTokenType); $result = FunctionDeclarations::getParameters(self::$phpcsFile, $target); @@ -106,8 +106,11 @@ public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T * * @return void */ - protected function getMethodParametersTestHelper($commentString, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE]) - { + protected function getMethodParametersTestHelper( + $commentString, + $expected, + $targetType = [\T_FUNCTION, \T_CLOSURE, \T_FN] + ) { $target = $this->getTargetToken($commentString, $targetType); $found = FunctionDeclarations::getParameters(self::$phpcsFile, $target); From 2cd5342eff2c7623f13ab8c2dfc2e2b2b3715b74 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:33:59 +0100 Subject: [PATCH 14/48] BCFile/FunctionDeclarations::get[Method]Parameters(): fix backward compatibility with PHPCS < 3.5.3 * Use the `FunctionDeclarations::isArrowFunction()` utility to determine whether a token is an arrow function, rather than relying on the existence of a token which wasn't backfilled until PHPCS 3.5.3. * Stabilize the unit test for when the `T_FN` token is not yet backfilled. * Add a unit test covering all supported parameter types. * Add a unit test covering arrow functions returning by reference. * Add a unit test for handling of live coding/parse errors. --- PHPCSUtils/BackCompat/BCFile.php | 13 +- PHPCSUtils/Utils/FunctionDeclarations.php | 14 +- .../BCFile/GetMethodParametersTest.inc | 22 ++ .../BCFile/GetMethodParametersTest.php | 235 +++++++++++++++++- .../GetParametersTest.php | 9 +- 5 files changed, 277 insertions(+), 16 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 62dbb6d1..d688642e 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -39,6 +39,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCTokens; use PHPCSUtils\Tokens\Collections; +use PHPCSUtils\Utils\FunctionDeclarations; /** * PHPCS native utility functions. @@ -244,6 +245,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * @see \PHPCSUtils\Utils\FunctionDeclarations::getParameters() PHPCSUtils native improved version. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token @@ -262,7 +264,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) if ($tokens[$stackPtr]['code'] !== T_FUNCTION && $tokens[$stackPtr]['code'] !== T_CLOSURE && $tokens[$stackPtr]['code'] !== T_USE - && $tokens[$stackPtr]['code'] !== T_FN + && FunctionDeclarations::isArrowFunction($phpcsFile, $stackPtr) === false ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); } @@ -272,6 +274,15 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) if ($opener === false || isset($tokens[$opener]['parenthesis_owner']) === true) { throw new RuntimeException('$stackPtr was not a valid T_USE'); } + } elseif ($tokens[$stackPtr]['code'] === \T_STRING || $tokens[$stackPtr]['type'] === 'T_FN') { + /* + * Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. + */ + $opener = $phpcsFile->findNext((Tokens::$emptyTokens + [\T_BITWISE_AND]), ($stackPtr + 1), null, true); + if ($opener === false || $tokens[$opener]['code'] !== T_OPEN_PARENTHESIS) { + // Live coding or syntax error, so no params to find. + return []; + } } else { if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) { // Live coding or syntax error, so no params to find. diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index b2732cf3..86a6ecbe 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -335,11 +335,14 @@ public static function getProperties(File $phpcsFile, $stackPtr) * - More efficient and more stable checking whether a T_USE token is a closure use. * - More efficient and more stable looping of the default value. * - Clearer exception message when a non-closure use token was passed to the function. + * - To allow for backward compatible handling of arrow functions, this method will also accept + * `T_STRING` tokens and examine them to check if these are arrow functions. * * @see \PHP_CodeSniffer\Files\File::getMethodParameters() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getMethodParameters() Cross-version compatible version of the original. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token @@ -359,7 +362,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) || ($tokens[$stackPtr]['code'] !== \T_FUNCTION && $tokens[$stackPtr]['code'] !== \T_CLOSURE && $tokens[$stackPtr]['code'] !== \T_USE - && $tokens[$stackPtr]['code'] !== \T_FN) + && self::isArrowFunction($phpcsFile, $stackPtr) === false) ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); } @@ -372,6 +375,15 @@ public static function getParameters(File $phpcsFile, $stackPtr) ) { throw new RuntimeException('$stackPtr was not a valid closure T_USE'); } + } elseif ($tokens[$stackPtr]['code'] === \T_STRING || $tokens[$stackPtr]['type'] === 'T_FN') { + /* + * Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. + */ + $opener = $phpcsFile->findNext((Tokens::$emptyTokens + [\T_BITWISE_AND]), ($stackPtr + 1), null, true); + if ($opener === false || $tokens[$opener]['code'] !== \T_OPEN_PARENTHESIS) { + // Live coding or syntax error, so no params to find. + return []; + } } else { if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) { // Live coding or syntax error, so no params to find. diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc index 404da716..d3daca2a 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc @@ -56,6 +56,9 @@ function myFunction($a = 10 & 20) {} /* testArrowFunction */ fn(int $a, ...$b) => $b; +/* testArrowFunctionReturnByRef */ +fn&(?string $a) => $b; + /* testArrayDefaultValues */ function arrayDefaultValues($var1 = [], $var2 = array(1, 2, 3) ) {} @@ -94,6 +97,21 @@ class testAllTypes { ) {} } +/* testArrowFunctionWithAllTypes */ +$fn = fn( + ?ClassName $a, + self $b, + parent $c, + object $d, + ?int $e, + string &$f, + iterable $g, + bool $h = true, + callable $i = 'is_null', + float $j = 1.1, + array ...$k +) => $something; + /* testMessyDeclaration */ function messyDeclaration( // comment @@ -121,3 +139,7 @@ function() use( $foo, $bar ) {} /* testInvalidUse */ function() use {} // Intentional parse error. + +/* testArrowFunctionLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index dfe39295..3a248cd8 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -96,7 +96,7 @@ public function dataInvalidUse() * * @return void */ - public function testNoParams($commentString, $targetTokenType = [T_FUNCTION, T_CLOSURE, T_FN]) + public function testNoParams($commentString, $targetTokenType = [T_FUNCTION, T_CLOSURE]) { $target = $this->getTargetToken($commentString, $targetTokenType); $result = BCFile::getMethodParameters(self::$phpcsFile, $target); @@ -113,11 +113,20 @@ public function testNoParams($commentString, $targetTokenType = [T_FUNCTION, T_C */ public function dataNoParams() { - return [ + $data = [ 'FunctionNoParams' => ['/* testFunctionNoParams */'], 'ClosureNoParams' => ['/* testClosureNoParams */'], 'ClosureUseNoParams' => ['/* testClosureUseNoParams */', T_USE], ]; + + $arrowTokenType = T_STRING; + if (defined('T_FN') === true) { + $arrowTokenType = T_FN; + } + + $data['ArrowFunctionLiveCoding'] = ['/* testArrowFunctionLiveCoding */', $arrowTokenType]; + + return $data; } /** @@ -448,7 +457,41 @@ public function testArrowFunction() 'comma_token' => false, ]; - $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + $arrowTokenType = T_STRING; + if (defined('T_FN') === true) { + $arrowTokenType = T_FN; + } + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + } + + /** + * Verify that arrow functions are supported. + * + * @return void + */ + public function testArrowFunctionReturnByRef() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FN token. + 'name' => '$a', + 'content' => '?string $a', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 4, // Offset from the T_FN token. + 'type_hint_end_token' => 4, // Offset from the T_FN token. + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $arrowTokenType = T_STRING; + if (defined('T_FN') === true) { + $arrowTokenType = T_FN; + } + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); } /** @@ -890,6 +933,185 @@ public function testWithAllTypes() $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Verify correctly recognizing all type declarations supported by PHP when used with an arrow function. + * + * @return void + */ + public function testArrowFunctionWithAllTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 7, // Offset from the T_FN token. + 'name' => '$a', + 'content' => '?ClassName $a', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?ClassName', + 'type_hint_token' => 5, // Offset from the T_FN token. + 'type_hint_end_token' => 5, // Offset from the T_FN token. + 'nullable_type' => true, + 'comma_token' => 8, // Offset from the T_FN token. + ]; + $expected[1] = [ + 'token' => 13, // Offset from the T_FN token. + 'name' => '$b', + 'content' => 'self $b', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 11, // Offset from the T_FN token. + 'type_hint_end_token' => 11, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 14, // Offset from the T_FN token. + ]; + $expected[2] = [ + 'token' => 19, // Offset from the T_FN token. + 'name' => '$c', + 'content' => 'parent $c', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'parent', + 'type_hint_token' => 17, // Offset from the T_FN token. + 'type_hint_end_token' => 17, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 20, // Offset from the T_FN token. + ]; + $expected[3] = [ + 'token' => 25, // Offset from the T_FN token. + 'name' => '$d', + 'content' => 'object $d', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object', + 'type_hint_token' => 23, // Offset from the T_FN token. + 'type_hint_end_token' => 23, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 26, // Offset from the T_FN token. + ]; + $expected[4] = [ + 'token' => 32, // Offset from the T_FN token. + 'name' => '$e', + 'content' => '?int $e', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 30, // Offset from the T_FN token. + 'type_hint_end_token' => 30, // Offset from the T_FN token. + 'nullable_type' => true, + 'comma_token' => 33, // Offset from the T_FN token. + ]; + $expected[5] = [ + 'token' => 39, // Offset from the T_FN token. + 'name' => '$f', + 'content' => 'string &$f', + 'pass_by_reference' => true, + 'reference_token' => 38, // Offset from the T_FN token. + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 36, // Offset from the T_FN token. + 'type_hint_end_token' => 36, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 40, // Offset from the T_FN token. + ]; + $expected[6] = [ + 'token' => 45, // Offset from the T_FN token. + 'name' => '$g', + 'content' => 'iterable $g', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable', + 'type_hint_token' => 43, // Offset from the T_FN token. + 'type_hint_end_token' => 43, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 46, // Offset from the T_FN token. + ]; + $expected[7] = [ + 'token' => 51, // Offset from the T_FN token. + 'name' => '$h', + 'content' => 'bool $h = true', + 'default' => 'true', + 'default_token' => 55, // Offset from the T_FN token. + 'default_equal_token' => 53, // Offset from the T_FN token. + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool', + 'type_hint_token' => 49, // Offset from the T_FN token. + 'type_hint_end_token' => 49, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 56, // Offset from the T_FN token. + ]; + $expected[8] = [ + 'token' => 61, // Offset from the T_FN token. + 'name' => '$i', + 'content' => 'callable $i = \'is_null\'', + 'default' => "'is_null'", + 'default_token' => 65, // Offset from the T_FN token. + 'default_equal_token' => 63, // Offset from the T_FN token. + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 59, // Offset from the T_FN token. + 'type_hint_end_token' => 59, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 66, // Offset from the T_FN token. + ]; + $expected[9] = [ + 'token' => 71, // Offset from the T_FN token. + 'name' => '$j', + 'content' => 'float $j = 1.1', + 'default' => '1.1', + 'default_token' => 75, // Offset from the T_FN token. + 'default_equal_token' => 73, // Offset from the T_FN token. + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float', + 'type_hint_token' => 69, // Offset from the T_FN token. + 'type_hint_end_token' => 69, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => 76, // Offset from the T_FN token. + ]; + $expected[10] = [ + 'token' => 82, // Offset from the T_FN token. + 'name' => '$k', + 'content' => 'array ...$k', + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 81, // Offset from the T_FN token. + 'type_hint' => 'array', + 'type_hint_token' => 79, // Offset from the T_FN token. + 'type_hint_end_token' => 79, // Offset from the T_FN token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $arrowTokenType = T_STRING; + if (defined('T_FN') === true) { + $arrowTokenType = T_FN; + } + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + } + /** * Verify handling of a declaration interlaced with whitespace and comments. * @@ -1032,11 +1254,8 @@ public function testClosureUse() * * @return void */ - protected function getMethodParametersTestHelper( - $commentString, - $expected, - $targetType = [T_FUNCTION, T_CLOSURE, T_FN] - ) { + protected function getMethodParametersTestHelper($commentString, $expected, $targetType = [T_FUNCTION, T_CLOSURE]) + { $target = $this->getTargetToken($commentString, $targetType); $found = BCFile::getMethodParameters(self::$phpcsFile, $target); diff --git a/Tests/Utils/FunctionDeclarations/GetParametersTest.php b/Tests/Utils/FunctionDeclarations/GetParametersTest.php index 57cccc7a..679b0e6c 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersTest.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersTest.php @@ -88,7 +88,7 @@ public function testInvalidUse($identifier) * * @return void */ - public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T_CLOSURE, \T_FN]) + public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T_CLOSURE]) { $target = $this->getTargetToken($commentString, $targetTokenType); $result = FunctionDeclarations::getParameters(self::$phpcsFile, $target); @@ -106,11 +106,8 @@ public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T * * @return void */ - protected function getMethodParametersTestHelper( - $commentString, - $expected, - $targetType = [\T_FUNCTION, \T_CLOSURE, \T_FN] - ) { + protected function getMethodParametersTestHelper($commentString, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE]) + { $target = $this->getTargetToken($commentString, $targetType); $found = FunctionDeclarations::getParameters(self::$phpcsFile, $target); From 10f0daeb5a6d289ada0216519635c4ca6dbf37cf Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:34:18 +0100 Subject: [PATCH 15/48] BCFile/FunctionDeclarations::get[Method]Properties(): add support for arrow functions Add support for arrow functions to the `BCFile::getMethodProperties()` and the sister-method `FunctionDeclarations::getProperties()` as per upstream commit squizlabs/PHP_CodeSniffer@c8fca563139bf217b5306191b9b5bb13d07f92f1 which was included in PHPCS 3.5.3. Also see: squizlabs/PHP_CodeSniffer 2523 Co-authored-by: Greg Sherwood --- PHPCSUtils/BackCompat/BCFile.php | 16 +++++++++--- PHPCSUtils/Utils/FunctionDeclarations.php | 7 ++--- .../BCFile/GetMethodPropertiesTest.inc | 6 +++++ .../BCFile/GetMethodPropertiesTest.php | 26 +++++++++++++++++-- .../GetPropertiesTest.php | 4 +-- 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index d688642e..3712197d 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -522,6 +522,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) * or `true` otherwise. * - PHPCS 3.5.0: The Exception thrown changed from a `TokenizerException` to * `\PHP_CodeSniffer\Exceptions\RuntimeException`. + * - PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions. * * @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source. * @see \PHPCSUtils\Utils\FunctionDeclarations::getProperties() PHPCSUtils native improved version. @@ -535,7 +536,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) * @return array * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a - * T_FUNCTION or a T_CLOSURE token. + * T_FUNCTION, T_CLOSURE, or T_FN token. */ public static function getMethodProperties(File $phpcsFile, $stackPtr) { @@ -543,8 +544,9 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) if ($tokens[$stackPtr]['code'] !== T_FUNCTION && $tokens[$stackPtr]['code'] !== T_CLOSURE + && $tokens[$stackPtr]['code'] !== T_FN ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE'); + throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); } if ($tokens[$stackPtr]['code'] === T_FUNCTION) { @@ -639,8 +641,14 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) } } - $end = $phpcsFile->findNext([T_OPEN_CURLY_BRACKET, T_SEMICOLON], $tokens[$stackPtr]['parenthesis_closer']); - $hasBody = $tokens[$end]['code'] === T_OPEN_CURLY_BRACKET; + if ($tokens[$stackPtr]['code'] === T_FN) { + $bodyToken = T_DOUBLE_ARROW; + } else { + $bodyToken = T_OPEN_CURLY_BRACKET; + } + + $end = $phpcsFile->findNext([$bodyToken, T_SEMICOLON], $tokens[$stackPtr]['parenthesis_closer']); + $hasBody = $tokens[$end]['code'] === $bodyToken; } if ($returnType !== '' && $nullableReturnType === true) { diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 86a6ecbe..4f2e2c5d 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -179,7 +179,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 a T_CLOSURE token. + * T_FUNCTION, T_CLOSURE, or T_FN token. */ public static function getProperties(File $phpcsFile, $stackPtr) { @@ -187,9 +187,10 @@ public static function getProperties(File $phpcsFile, $stackPtr) if (isset($tokens[$stackPtr]) === false || ($tokens[$stackPtr]['code'] !== \T_FUNCTION - && $tokens[$stackPtr]['code'] !== \T_CLOSURE) + && $tokens[$stackPtr]['code'] !== \T_CLOSURE + && $tokens[$stackPtr]['code'] !== \T_FN) ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE'); + throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); } if ($tokens[$stackPtr]['code'] === \T_FUNCTION) { diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc index 2139fb23..895b11c9 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc @@ -61,6 +61,12 @@ interface MyInterface function myFunction(); } +$result = array_map( + /* testArrowFunction */ + static fn(int $number) : int => $number + 1, + $numbers +); + /* testNotAFunction */ return true; diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php index c800f744..639ac997 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php @@ -42,7 +42,7 @@ class GetMethodPropertiesTest extends UtilityMethodTestCase */ public function testNotAFunctionException() { - $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE'); + $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); $next = $this->getTargetToken('/* testNotAFunction */', T_RETURN); BCFile::getMethodProperties(self::$phpcsFile, $next); @@ -378,6 +378,28 @@ public function testInterfaceMethod() $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Test a static arrow function. + * + * @return void + */ + public function testArrowFunction() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 9, // Offset from the T_FN token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0. * @@ -412,7 +434,7 @@ public function testPhpcsIssue1264() */ protected function getMethodPropertiesTestHelper($commentString, $expected) { - $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE]); + $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]); $found = BCFile::getMethodProperties(self::$phpcsFile, $function); if ($expected['return_type_token'] !== false) { diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php index 8f06561e..6a84d92f 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php @@ -54,7 +54,7 @@ public static function setUpTestFile() */ public function testNotAFunctionException() { - $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE'); + $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); $next = $this->getTargetToken('/* testNotAFunction */', \T_RETURN); FunctionDeclarations::getProperties(self::$phpcsFile, $next); @@ -70,7 +70,7 @@ public function testNotAFunctionException() */ protected function getMethodPropertiesTestHelper($commentString, $expected) { - $function = $this->getTargetToken($commentString, [\T_FUNCTION, \T_CLOSURE]); + $function = $this->getTargetToken($commentString, [\T_FUNCTION, \T_CLOSURE, \T_FN]); $found = FunctionDeclarations::getProperties(self::$phpcsFile, $function); if ($expected['return_type_token'] !== false) { From a4abd344a396c18c15186463b93e2a1289a723dc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:34:34 +0100 Subject: [PATCH 16/48] BCFile/FunctionDeclarations::get[Method]Properties(): fix backward compatibility with PHPCS < 3.5.3 * Use the `FunctionDeclarations::getArrowFunctionOpenClose()` utility to determine whether a token is an arrow function and what the relevant opener/closer tokens are, rather than relying on the existence of a token which wasn't backfilled until PHPCS 3.5.3/4. * Stabilize the unit test for when the `T_FN` token is not yet backfilled. * Add a unit test covering arrow functions returning by reference. * Add a unit test for upstream issue squizlabs/PHP_CodeSniffer 2773. This particular test will be skipped on PHPCS 3.5.3 as it won't pass due to the incomplete backfill in PHPCS 3.5.3. As PHPCS 3.5.3 is not supported by PHPCSUtils, this will not be fixed. * Add a unit test for handling of live coding/parse errors. * Add toggle for the double arrow token to use depending on the PHPCS version as per upstream commit squizlabs/PHP_CodeSniffer@bbd6f6308bd15f457d49ec0fde30b08609dae9e5. --- PHPCSUtils/BackCompat/BCFile.php | 38 +++++-- PHPCSUtils/Utils/FunctionDeclarations.php | 25 ++++- .../BCFile/GetMethodPropertiesTest.inc | 10 ++ .../BCFile/GetMethodPropertiesTest.php | 105 +++++++++++++++++- .../GetPropertiesTest.php | 6 +- 5 files changed, 167 insertions(+), 17 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 3712197d..491691f8 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -38,6 +38,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCTokens; +use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; @@ -528,6 +529,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) * @see \PHPCSUtils\Utils\FunctionDeclarations::getProperties() PHPCSUtils native improved version. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token to @@ -540,11 +542,12 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) */ public static function getMethodProperties(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); + $tokens = $phpcsFile->getTokens(); + $arrowOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $stackPtr); if ($tokens[$stackPtr]['code'] !== T_FUNCTION && $tokens[$stackPtr]['code'] !== T_CLOSURE - && $tokens[$stackPtr]['code'] !== T_FN + && $arrowOpenClose === [] ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); } @@ -611,13 +614,24 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) $nullableReturnType = false; $hasBody = true; + $parenthesisCloser = null; if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { + $parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer']; + } elseif ($arrowOpenClose !== [] && $arrowOpenClose['parenthesis_closer'] !== false) { + // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. + $parenthesisCloser = $arrowOpenClose['parenthesis_closer']; + } + + if (isset($parenthesisCloser) === true) { $scopeOpener = null; if (isset($tokens[$stackPtr]['scope_opener']) === true) { $scopeOpener = $tokens[$stackPtr]['scope_opener']; + } elseif ($arrowOpenClose !== [] && $arrowOpenClose['scope_opener'] !== false) { + // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. + $scopeOpener = $arrowOpenClose['scope_opener']; } - for ($i = $tokens[$stackPtr]['parenthesis_closer']; $i < $phpcsFile->numTokens; $i++) { + for ($i = $parenthesisCloser; $i < $phpcsFile->numTokens; $i++) { if (($scopeOpener === null && $tokens[$i]['code'] === T_SEMICOLON) || ($scopeOpener !== null && $i === $scopeOpener) ) { @@ -628,6 +642,9 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) if ($tokens[$i]['type'] === 'T_NULLABLE' // Handle nullable tokens in PHPCS < 2.8.0. || (defined('T_NULLABLE') === false && $tokens[$i]['code'] === T_INLINE_THEN) + // Handle nullable tokens with arrow functions in PHPCS 2.8.0 - 2.9.0. + || ($arrowOpenClose !== [] && $tokens[$i]['code'] === T_INLINE_THEN + && version_compare(Helper::getVersion(), '2.9.1', '<') === true) ) { $nullableReturnType = true; } @@ -641,14 +658,17 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) } } - if ($tokens[$stackPtr]['code'] === T_FN) { - $bodyToken = T_DOUBLE_ARROW; - } else { - $bodyToken = T_OPEN_CURLY_BRACKET; + $bodyTokens = [T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET]; + if ($arrowOpenClose !== []) { + $bodyTokens = [T_DOUBLE_ARROW => T_DOUBLE_ARROW]; + if (defined('T_FN_ARROW') === true) { + // PHPCS 3.5.3+. + $bodyTokens = [T_FN_ARROW => T_FN_ARROW]; + } } - $end = $phpcsFile->findNext([$bodyToken, T_SEMICOLON], $tokens[$stackPtr]['parenthesis_closer']); - $hasBody = $tokens[$end]['code'] === $bodyToken; + $end = $phpcsFile->findNext(($bodyTokens + [T_SEMICOLON]), $parenthesisCloser); + $hasBody = isset($bodyTokens[$tokens[$end]['code']]); } if ($returnType !== '' && $nullableReturnType === true) { diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 4f2e2c5d..a824497c 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -14,6 +14,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCTokens; +use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Conditions; use PHPCSUtils\Utils\GetTokensAsString; @@ -166,11 +167,14 @@ public static function getName(File $phpcsFile, $stackPtr) * - Defensive coding against incorrect calls to this method. * - More efficient checking whether a function has a body. * - New `return_type_end_token` (int|false) array index. + * - To allow for backward compatible handling of arrow functions, this method will also accept + * `T_STRING` tokens and examine them to check if these are arrow functions. * * @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getMethodProperties() Cross-version compatible version of the original. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token to @@ -183,12 +187,13 @@ public static function getName(File $phpcsFile, $stackPtr) */ public static function getProperties(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); + $tokens = $phpcsFile->getTokens(); + $arrowOpenClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); if (isset($tokens[$stackPtr]) === false || ($tokens[$stackPtr]['code'] !== \T_FUNCTION && $tokens[$stackPtr]['code'] !== \T_CLOSURE - && $tokens[$stackPtr]['code'] !== \T_FN) + && $arrowOpenClose === []) ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); } @@ -243,13 +248,24 @@ public static function getProperties(File $phpcsFile, $stackPtr) $nullableReturnType = false; $hasBody = false; + $parenthesisCloser = null; if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { + $parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer']; + } elseif ($arrowOpenClose !== [] && $arrowOpenClose['parenthesis_closer'] !== false) { + // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. + $parenthesisCloser = $arrowOpenClose['parenthesis_closer']; + } + + if (isset($parenthesisCloser) === true) { $scopeOpener = null; if (isset($tokens[$stackPtr]['scope_opener']) === true) { $scopeOpener = $tokens[$stackPtr]['scope_opener']; + } elseif ($arrowOpenClose !== [] && $arrowOpenClose['scope_opener'] !== false) { + // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. + $scopeOpener = $arrowOpenClose['scope_opener']; } - for ($i = $tokens[$stackPtr]['parenthesis_closer']; $i < $phpcsFile->numTokens; $i++) { + for ($i = $parenthesisCloser; $i < $phpcsFile->numTokens; $i++) { if ($i === $scopeOpener) { // End of function definition. $hasBody = true; @@ -264,6 +280,9 @@ public static function getProperties(File $phpcsFile, $stackPtr) if ($tokens[$i]['type'] === 'T_NULLABLE' // Handle nullable tokens in PHPCS < 2.8.0. || (\defined('T_NULLABLE') === false && $tokens[$i]['code'] === \T_INLINE_THEN) + // Handle nullable tokens with arrow functions in PHPCS 2.8.0 - 2.9.0. + || ($arrowOpenClose !== [] && $tokens[$i]['code'] === \T_INLINE_THEN + && \version_compare(Helper::getVersion(), '2.9.1', '<') === true) ) { $nullableReturnType = true; } diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc index 895b11c9..815456ce 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc @@ -74,3 +74,13 @@ return true; function foo() : array { echo $foo; } + +/* testArrowFunctionArrayReturnValue */ +$fn = fn(): array => [a($a, $b)]; + +/* testArrowFunctionReturnByRef */ +fn&(?string $a) : ?string => $b; + +/* testArrowFunctionLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php index 639ac997..4475df3c 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php @@ -21,6 +21,7 @@ namespace PHPCSUtils\Tests\BackCompat\BCFile; use PHPCSUtils\BackCompat\BCFile; +use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; /** @@ -397,7 +398,12 @@ public function testArrowFunction() 'has_body' => true, ]; - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + $arrowTokenType = T_STRING; + if (defined('T_FN') === true) { + $arrowTokenType = T_FN; + } + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); } /** @@ -424,17 +430,110 @@ public function testPhpcsIssue1264() $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Test handling of incorrect tokenization of array return type declarations for arrow functions + * in a very specific code sample in PHPCS < 3.5.4. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2773 + * + * @return void + */ + public function testArrowFunctionArrayReturnValue() + { + // Skip this test on unsupported PHPCS versions. + if (\version_compare(Helper::getVersion(), '3.5.3', '==') === true) { + $this->markTestSkipped( + 'PHPCS 3.5.3 is not supported for this specific test due to a buggy arrow functions backfill.' + ); + } + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 5, // Offset from the T_FN token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $arrowTokenType = T_STRING; + if (defined('T_FN') === true) { + $arrowTokenType = T_FN; + } + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + } + + /** + * Test handling of an arrow function returning by reference. + * + * @return void + */ + public function testArrowFunctionReturnByRef() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?string', + 'return_type_token' => 12, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $arrowTokenType = T_STRING; + if (defined('T_FN') === true) { + $arrowTokenType = T_FN; + } + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + } + + /** + * Test an arrow function live coding/parse error. + * + * @return void + */ + public function testArrowFunctionLiveCoding() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $arrowTokenType = T_STRING; + if (defined('T_FN') === true) { + $arrowTokenType = T_FN; + } + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + } + /** * Test helper. * * @param string $commentString The comment which preceeds the test. * @param array $expected The expected function output. + * @param array $targetType Optional. The token type to search for after $commentString. + * Defaults to the function/closure tokens. * * @return void */ - protected function getMethodPropertiesTestHelper($commentString, $expected) + protected function getMethodPropertiesTestHelper($commentString, $expected, $targetType = [T_FUNCTION, T_CLOSURE]) { - $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]); + $function = $this->getTargetToken($commentString, $targetType); $found = BCFile::getMethodProperties(self::$phpcsFile, $function); if ($expected['return_type_token'] !== false) { diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php index 6a84d92f..8339bdd8 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php @@ -65,12 +65,14 @@ public function testNotAFunctionException() * * @param string $commentString The comment which preceeds the test. * @param array $expected The expected function output. + * @param array $targetType Optional. The token type to search for after $commentString. + * Defaults to the function/closure tokens. * * @return void */ - protected function getMethodPropertiesTestHelper($commentString, $expected) + protected function getMethodPropertiesTestHelper($commentString, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE]) { - $function = $this->getTargetToken($commentString, [\T_FUNCTION, \T_CLOSURE, \T_FN]); + $function = $this->getTargetToken($commentString, $targetType); $found = FunctionDeclarations::getProperties(self::$phpcsFile, $function); if ($expected['return_type_token'] !== false) { From ce476a40b7ec02705a76e5c4123f9dae70113d2b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:34:53 +0100 Subject: [PATCH 17/48] FunctionDeclaration::getProperties(): document bug fix - 'has_body' = `false` for unfinished arrow functions The `fn` for a potential arrow function will be tokenized as `T_FN`, even when there are no parenthesis and there is no function body, like during live coding or in case of a parse error. In that case, IMO, the `has_body` index key should be set to `false`. This is in line with the behaviour of the `FunctionDeclaration::getProperties()` function for other function constructs (and in contrast to the behaviour of the `BCFile::getMethodProperties()` function). Also see: PHPCSStandards/PHPCSUtils@198371590e10d7064ae2e19715285a1ed6201896 --- .../GetPropertiesTest.php | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php index 8339bdd8..9519ecea 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php @@ -60,6 +60,33 @@ public function testNotAFunctionException() FunctionDeclarations::getProperties(self::$phpcsFile, $next); } + /** + * Test a arrow function live coding/parse error. + * + * @return void + */ + public function testArrowFunctionLiveCoding() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, // Different from original. + ]; + + $arrowTokenType = \T_STRING; + if (\defined('T_FN') === true) { + $arrowTokenType = \T_FN; + } + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + } + /** * Test helper. * From 5d50b94a5336b3ce209aa1f52fe59044bffc7b7c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:36:17 +0100 Subject: [PATCH 18/48] BCFile::getDeclarationName(): allow functions to be called "fn" ... for backwards compatibility. As per upstream commit squizlabs/PHP_CodeSniffer@37dda44ed3bf34dbaad6e0dd1e9e10b03d67ed00 which was included in PHPCS 3.5.3. Includes new unit test. Also see: squizlabs/PHP_CodeSniffer 2523 Co-authored-by: Greg Sherwood --- PHPCSUtils/BackCompat/BCFile.php | 6 +++++- Tests/BackCompat/BCFile/GetDeclarationNameTest.inc | 3 +++ Tests/BackCompat/BCFile/GetDeclarationNameTest.php | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 491691f8..5d0a4699 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -96,6 +96,8 @@ class BCFile * - PHPCS 3.0.0: Added support for ES6 class/method syntax. * - PHPCS 3.0.0: The Exception thrown changed from a `PHP_CodeSniffer_Exception` to * `\PHP_CodeSniffer\Exceptions\RuntimeException`. + * - PHPCS 3.5.3: Allow for functions to be called `fn` for backwards compatibility. + * Related to PHP 7.4 T_FN arrow functions. * * Note: For ES6 classes in combination with PHPCS 2.x, passing a `T_STRING` token to * this method will be accepted for JS files. @@ -155,7 +157,9 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) $content = null; for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { - if ($tokens[$i]['code'] === T_STRING) { + if ($tokens[$i]['code'] === T_STRING + || $tokens[$i]['code'] === T_FN + ) { /* * BC: In PHPCS 2.6.0, in case of live coding, the last token in a file will be tokenized * as T_STRING, but won't have the `content` index set. diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc b/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc index b7ebb056..466f07df 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc @@ -60,6 +60,9 @@ class /* comment */ // phpcs:ignore Standard.Cat.SniffName -- for reasons ClassWithCommentsAndNewLines {} +/* testFunctionFn */ +function fn() {} + /* testLiveCoding */ // Intentional parse error. This has to be the last test in the file. function // Comment. diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php index 7c19e8e5..e8a5cb37 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php @@ -173,6 +173,10 @@ public function dataGetDeclarationName() '/* testClassWithCommentsAndNewLines */', 'ClassWithCommentsAndNewLines', ], + 'function-named-fn' => [ + '/* testFunctionFn */', + 'fn', + ], ]; } } From 087409092b64325fcb5f3d6b52ee2e8621ec3142 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:36:37 +0100 Subject: [PATCH 19/48] BCFile::getDeclarationName(): fix backward compatibility with PHPCS < 3.5.3 --- PHPCSUtils/BackCompat/BCFile.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 5d0a4699..3440aeef 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -107,6 +107,7 @@ class BCFile * @see \PHPCSUtils\Utils\ObjectDeclarations::getName() PHPCSUtils native improved version. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the declaration token @@ -158,7 +159,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) $content = null; for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { if ($tokens[$i]['code'] === T_STRING - || $tokens[$i]['code'] === T_FN + || $tokens[$i]['type'] === 'T_FN' ) { /* * BC: In PHPCS 2.6.0, in case of live coding, the last token in a file will be tokenized From 23c5d8984d921ad5e17858ff73781e0c0e8a2aba Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:36:57 +0100 Subject: [PATCH 20/48] BCFile::findEndOfStatement(): add support for arrow functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add support for arrow functions to the `BCFile::findEndOfStatement()` method as per upstream commit squizlabs/PHP_CodeSniffer@bf642b2a244acdb26681d0f4f3f275d5c8125468 which was included in PHPCS 3.5.3. * Improve support for arrow functions in the `BCFile::findEndOfStatement()` method as per upstream commit squizlabs/PHP_CodeSniffer@1be4196e5219e1f4e3dabe2100cb8c7344aec1b8 which was included in PHPCS 3.5.4. * Add additional unit test as per upstream commit squizlabs/PHP_CodeSniffer@30b545728c2c273eb39277f51da43ef1265ac0e8 which was included in PHPCS 3.5.4. Also see: squizlabs/PHP_CodeSniffer 2523 Co-authored-by: Greg Sherwood Co-authored-by: Michał Bundyra --- PHPCSUtils/BackCompat/BCFile.php | 7 +++ .../BCFile/FindEndOfStatementTest.inc | 14 ++++++ .../BCFile/FindEndOfStatementTest.php | 44 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 3440aeef..f2d33092 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -1244,6 +1244,8 @@ public static function findStartOfStatement(File $phpcsFile, $start, $ignore = n * - PHPCS 2.7.1: Improved handling of short arrays, PHPCS #1203. * - PHPCS 3.3.0: Bug fix: end of statement detection when passed a scope opener, PHPCS #1863. * - 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. * * @see \PHP_CodeSniffer\Files\File::findEndOfStatement() Original source. * @@ -1302,6 +1304,11 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul && ($i === $tokens[$i]['scope_opener'] || $i === $tokens[$i]['scope_condition']) ) { + if ($tokens[$i]['code'] === T_FN) { + $i = ($tokens[$i]['scope_closer'] - 1); + continue; + } + if ($i === $start && isset(Tokens::$scopeOpeners[$tokens[$i]['code']]) === true) { return $tokens[$i]['scope_closer']; } diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc b/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc index f8763c6a..a86ed250 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc @@ -29,3 +29,17 @@ $a = new Datetime; /* testUseGroup */ use Vendor\Package\{ClassA as A, ClassB, ClassC as C}; + +$a = [ + /* testArrowFunctionArrayValue */ + 'a' => fn() => return 1, + 'b' => fn() => return 1, +]; + +/* testStaticArrowFunction */ +static fn ($a) => $a; + +/* testArrowFunctionReturnValue */ +fn(): array => [a($a, $b)]; + +return 0; diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index 4b157046..99e279c8 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -179,4 +179,48 @@ public function testUseGroup() $tokens = self::$phpcsFile->getTokens(); $this->assertSame($tokens[($start + 23)], $tokens[$found]); } + + /** + * Test arrow function as array value. + * + * @return void + */ + public function testArrowFunctionArrayValue() + { + $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testArrowFunctionArrayValue */') + 7); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $tokens = self::$phpcsFile->getTokens(); + $this->assertSame($tokens[($start + 9)], $tokens[$found]); + } + + /** + * Test static arrow function. + * + * @return void + */ + public function testStaticArrowFunction() + { + $static = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testStaticArrowFunction */') + 2); + $fn = self::$phpcsFile->findNext(T_FN, ($static + 1)); + + $endOfStatementStatic = BCFile::findEndOfStatement(self::$phpcsFile, $static); + $endOfStatementFn = BCFile::findEndOfStatement(self::$phpcsFile, $fn); + + $this->assertSame($endOfStatementFn, $endOfStatementStatic); + } + + /** + * Test arrow function with return value. + * + * @return void + */ + public function testArrowFunctionReturnValue() + { + $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testArrowFunctionReturnValue */') + 2); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $tokens = self::$phpcsFile->getTokens(); + $this->assertSame(($start + 18), $found); + } } From 10cf39d24ca81811aeb308fe3c9418dbe281ca66 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:37:39 +0100 Subject: [PATCH 21/48] BCFile::findEndOfStatement(): fix backward compatibility with PHPCS < 3.5.3/3.5.4 --- PHPCSUtils/BackCompat/BCFile.php | 17 ++++++++++++++++- .../BCFile/FindEndOfStatementTest.php | 14 +++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index f2d33092..2e45fc48 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -1250,6 +1250,7 @@ public static function findStartOfStatement(File $phpcsFile, $start, $ignore = n * @see \PHP_CodeSniffer\Files\File::findEndOfStatement() Original source. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $start The position to start searching from in the token stack. @@ -1304,7 +1305,8 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul && ($i === $tokens[$i]['scope_opener'] || $i === $tokens[$i]['scope_condition']) ) { - if ($tokens[$i]['code'] === T_FN) { + if ($tokens[$i]['type'] === 'T_FN') { + // Minus 1 as the closer can be shared. $i = ($tokens[$i]['scope_closer'] - 1); continue; } @@ -1327,6 +1329,19 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul if ($end !== false) { $i = $end; } + } elseif ($tokens[$i]['code'] === T_STRING || $tokens[$i]['type'] === 'T_FN') { + // Potentially a PHP 7.4 arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/3.5.4. + $arrowFunctionOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $i); + if ($arrowFunctionOpenClose !== [] + && $arrowFunctionOpenClose['scope_closer'] !== false + ) { + if ($i === $start) { + return $arrowFunctionOpenClose['scope_closer']; + } + + // Minus 1 as the closer can be shared. + $i = ($arrowFunctionOpenClose['scope_closer'] - 1); + } } if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false) { diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index 99e279c8..13ca6805 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -25,6 +25,7 @@ namespace PHPCSUtils\Tests\BackCompat\BCFile; use PHPCSUtils\BackCompat\BCFile; +use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; /** @@ -201,8 +202,13 @@ public function testArrowFunctionArrayValue() */ public function testStaticArrowFunction() { + $fnTargets = [\T_STRING]; + if (\defined('T_FN') === true) { + $fnTargets[] = \T_FN; + } + $static = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testStaticArrowFunction */') + 2); - $fn = self::$phpcsFile->findNext(T_FN, ($static + 1)); + $fn = self::$phpcsFile->findNext($fnTargets, ($static + 1)); $endOfStatementStatic = BCFile::findEndOfStatement(self::$phpcsFile, $static); $endOfStatementFn = BCFile::findEndOfStatement(self::$phpcsFile, $fn); @@ -217,6 +223,12 @@ public function testStaticArrowFunction() */ public function testArrowFunctionReturnValue() { + // Skip this test on unsupported PHPCS version. + if (\version_compare(Helper::getVersion(), '3.5.3', '==') === true) { + $this->markTestSkipped( + 'PHPCS 3.5.3 is not supported for this specific test due to a buggy arrow functions backfill.' + ); + } $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testArrowFunctionReturnValue */') + 2); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); From 6179eb0782bf06a21a71a7c3d7fc46944a798c8d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:38:04 +0100 Subject: [PATCH 22/48] BCFile::findStartOfStatement(): add support for arrow functions * Add support for arrow functions to the `BCFile::findStartOfStatement()` method as per upstream commit squizlabs/PHP_CodeSniffer@fbf67efc3fc0c2a355f5585d49f4f6fe160ff2f9 which will be included in PHPCS 3.5.5. Also see: squizlabs/PHP_CodeSniffer 2523 and squizlabs/PHP_CodeSniffer 2849 Includes adding an initial unit test file for the `BCFile::findStartOfStatement()` method which was, so far, untested. The initial unit test only (intentionally) covers the current change. Co-authored-by: Greg Sherwood --- PHPCSUtils/BackCompat/BCFile.php | 3 ++ .../BCFile/FindStartOfStatementTest.inc | 12 ++++++ .../BCFile/FindStartOfStatementTest.php | 43 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 Tests/BackCompat/BCFile/FindStartOfStatementTest.inc create mode 100644 Tests/BackCompat/BCFile/FindStartOfStatementTest.php diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 2e45fc48..7267c3a0 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -1167,10 +1167,12 @@ public static function getTokensAsString(File $phpcsFile, $start, $length, $orig * Changelog for the PHPCS native function: * - Introduced in PHPCS 2.1.0. * - PHPCS 2.6.2: New optional `$ignore` parameter to selectively ignore stop points. + * - PHPCS 3.5.5: Added support for PHP 7.4 T_FN arrow functions. * * @see \PHP_CodeSniffer\Files\File::findStartOfStatement() Original source. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $start The position to start searching from in the token stack. @@ -1209,6 +1211,7 @@ public static function findStartOfStatement(File $phpcsFile, $start, $ignore = n if (isset($tokens[$i]['scope_opener']) === true && $i === $tokens[$i]['scope_closer'] + && $tokens[$i]['code'] !== T_CLOSE_PARENTHESIS ) { // Found the end of the previous scope block. return $lastNotEmpty; diff --git a/Tests/BackCompat/BCFile/FindStartOfStatementTest.inc b/Tests/BackCompat/BCFile/FindStartOfStatementTest.inc new file mode 100644 index 00000000..366047b6 --- /dev/null +++ b/Tests/BackCompat/BCFile/FindStartOfStatementTest.inc @@ -0,0 +1,12 @@ + $song->url()) + /* testPrecededByArrowFunctionInArray */ + ->onlyOnDetail(), + + new Panel('Information', [ + Text::make('Title') + ]), +]; diff --git a/Tests/BackCompat/BCFile/FindStartOfStatementTest.php b/Tests/BackCompat/BCFile/FindStartOfStatementTest.php new file mode 100644 index 00000000..966d5ec5 --- /dev/null +++ b/Tests/BackCompat/BCFile/FindStartOfStatementTest.php @@ -0,0 +1,43 @@ +getTargetToken('/* testPrecededByArrowFunctionInArray - Expected */', \T_STRING, 'Url'); + + $start = $this->getTargetToken('/* testPrecededByArrowFunctionInArray */', \T_STRING, 'onlyOnDetail'); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame($expected, $found); + } +} From 090c56682c16c61476c4690c95e7c2c85f6ce85b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:40:28 +0100 Subject: [PATCH 23/48] Arrays::getDoubleArrowPtr(): handle arrow functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In PHPCS 3.5.3+, the double arrow for arrow functions is tokenized as `T_FN_ARROW` and will not confuse this utility method anymore. However, for PHPCS < 3.5.3 in combination with PHP 7.4, the `fn` keyword will be tokenized as `T_FN`, however, the double arrow will still tokenize as `T_DOUBLE_ARROW`. And for PHPCS < 3.5.3 in combination with PHP 7.4, the `fn` keyword will be tokenized as `T_STRING` and the double arrow will tokenize as `T_DOUBLE_ARROW`. Both of these would cause incorrect results for this function. As far as I can see, arrow functions are not usable in an array key, so basically, we know that there will be no (array) arrow as soon as we encounter a `T_FN` token of a `T_STRING` token which is an arrow function. Includes unit tests. Related: squizlabs/PHP_CodeSniffer 2703 Co-authored-by: Michał Bundyra --- PHPCSUtils/Utils/Arrays.php | 21 +++++++++++++++++++- Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc | 9 +++++++++ Tests/Utils/Arrays/GetDoubleArrowPtrTest.php | 12 +++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index 889db186..98ea54fc 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -15,6 +15,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; +use PHPCSUtils\Utils\FunctionDeclarations; use PHPCSUtils\Utils\Lists; /** @@ -28,12 +29,16 @@ class Arrays /** * The tokens to target to find the double arrow in an array item. * + * Note: this array does not contain the `T_FN` token as it may or may not exist. + * If it exists, it will be added in the `getDoubleArrowPtr()` function. + * * @var array => */ private static $doubleArrowTargets = [ \T_DOUBLE_ARROW => \T_DOUBLE_ARROW, \T_ARRAY => \T_ARRAY, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, + \T_STRING => \T_STRING, // BC for T_FN token in PHPCS < 3.5.3 icw PHP < 7.4. ]; /** @@ -236,6 +241,9 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortArray = * Expects to be passed the array item start and end tokens as retrieved via * {@see \PHPCSUtils\Utils\PassedParameters::getParameters()}. * + * @since 1.0.0 + * @since 1.0.0-alpha2 Now allows for arrow functions in arrays. + * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being examined. * @param int $start Stack pointer to the start of the array item. * @param int $end Stack pointer to the end of the array item (inclusive). @@ -256,6 +264,9 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) } $targets = self::$doubleArrowTargets + Collections::$closedScopes; + if (\defined('T_FN') === true) { + $targets[\T_FN] = \T_FN; + } $doubleArrow = ($start - 1); ++$end; @@ -282,7 +293,15 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) continue; } - // Start of nested long/short array. + // BC for PHP 7.4 arrow functions with PHPCS < 3.5.3. + if ($tokens[$doubleArrow]['code'] === \T_STRING + && FunctionDeclarations::isArrowFunction($phpcsFile, $doubleArrow) === false + ) { + // Not an arrow function, continue looking. + continue; + } + + // Start of nested long/short array or arrow function. break; } while ($doubleArrow < $end); diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc index e2dd831f..c54b98d9 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc @@ -71,4 +71,13 @@ $array = [ /* testArrowKeyClosureYieldWithKey */ function() { yield 'k' => $x }() => 'value', + + /* testFnFunctionWithKey */ + 'fn' => fn ($x) => yield 'k' => $x, + + /* testNoArrowValueFnFunction */ + fn ($x) => yield 'k' => $x, + + /* testTstringKeyNotFnFunction */ + CONSTANT_NAME => 'value', ]; diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php index 286b3843..85040dd4 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php @@ -196,6 +196,18 @@ public function dataGetDoubleArrowPtr() '/* testArrowKeyClosureYieldWithKey */', 24, ], + 'test-arrow-value-fn-function' => [ + '/* testFnFunctionWithKey */', + 8, + ], + 'test-no-arrow-value-fn-function' => [ + '/* testNoArrowValueFnFunction */', + false, + ], + 'test-arrow-tstring-key-not-fn-function' => [ + '/* testTstringKeyNotFnFunction */', + 8, + ], ]; } } From dfdaccb0ee9cdd4e6783da1a4dac5dc534c68868 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 00:39:40 +0100 Subject: [PATCH 24/48] PassedParameters: add unit test with arrow function --- .../PassedParameters/GetParametersTest.inc | 7 ++++++ .../PassedParameters/GetParametersTest.php | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Tests/Utils/PassedParameters/GetParametersTest.inc b/Tests/Utils/PassedParameters/GetParametersTest.inc index c5f3a326..594156fa 100644 --- a/Tests/Utils/PassedParameters/GetParametersTest.inc +++ b/Tests/Utils/PassedParameters/GetParametersTest.inc @@ -96,6 +96,13 @@ $array = [ }, ]; +/* testLongArrayArrowFunctionWithYield */ +$array = array( + 1 => '1', + 2 => fn ($x) => yield 'a' => $x, + 3 => '3', + ); + /* testVariableFunctionCall */ $closure($a, (1 + 20), $a & $b ); diff --git a/Tests/Utils/PassedParameters/GetParametersTest.php b/Tests/Utils/PassedParameters/GetParametersTest.php index 1e963b7c..15c67af1 100644 --- a/Tests/Utils/PassedParameters/GetParametersTest.php +++ b/Tests/Utils/PassedParameters/GetParametersTest.php @@ -411,6 +411,29 @@ public function test( $foo, $bar ) { ], ], + // Array arrow function and yield. + 'long-array-nested-arrow-function-with-yield' => [ + '/* testLongArrayArrowFunctionWithYield */', + \T_ARRAY, + [ + 1 => [ + 'start' => 2, + 'end' => 8, + 'raw' => '1 => \'1\'', + ], + 2 => [ + 'start' => 10, + 'end' => 30, + 'raw' => '2 => fn ($x) => yield \'a\' => $x', + ], + 3 => [ + 'start' => 32, + 'end' => 38, + 'raw' => '3 => \'3\'', + ], + ], + ], + // Function calling closure in variable. 'variable-function-call' => [ '/* testVariableFunctionCall */', From 020627d0a950da599ffdd302401c318b7dea4109 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 5 Feb 2020 02:57:45 +0100 Subject: [PATCH 25/48] Parentheses::getOwner()/isOwnerIn(): add support for arrow functions Allow for the `PHPCSUtils\Utils\Parentheses::getOwner()` and `PHPCSUtils\Utils\Parentheses::isOwnerIn()` methods to recognize arrow functions as parentheses owners in PHP < 7.4 and PHPCS < 3.5.3/4. Includes unit tests. --- PHPCSUtils/Utils/Parentheses.php | 19 ++++- Tests/Utils/Parentheses/ParenthesesTest.inc | 6 ++ Tests/Utils/Parentheses/ParenthesesTest.php | 83 +++++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/Utils/Parentheses.php b/PHPCSUtils/Utils/Parentheses.php index 8c365540..7455956a 100644 --- a/PHPCSUtils/Utils/Parentheses.php +++ b/PHPCSUtils/Utils/Parentheses.php @@ -13,6 +13,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Utils\FunctionDeclarations; /** * Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped in @@ -27,6 +28,7 @@ class Parentheses * Get the pointer to the parentheses owner of an open/close parenthesis. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The position of `T_OPEN/CLOSE_PARENTHESIS` token. @@ -45,11 +47,14 @@ public static function getOwner(File $phpcsFile, $stackPtr) /* * `T_LIST` and `T_ANON_CLASS` only became parentheses owners in PHPCS 3.5.0. + * `T_FN` was only backfilled in PHPCS 3.5.3/4. + * - On PHP 7.4 with PHPCS < 3.5.3, T_FN will not yet be a parentheses owner. + * - On PHP < 7.4 with PHPCS < 3.5.3, T_FN will be tokenized as T_STRING and not yet be a parentheses owner. * * {@internal As the 'parenthesis_owner' index is only set on parentheses, we didn't need to do any * input validation before, but now we do.} */ - if (\version_compare(Helper::getVersion(), '3.5.0', '>=') === true) { + if (\version_compare(Helper::getVersion(), '3.5.4', '>=') === true) { return false; } @@ -69,7 +74,9 @@ public static function getOwner(File $phpcsFile, $stackPtr) && ($tokens[$prevNonEmpty]['code'] === \T_LIST || $tokens[$prevNonEmpty]['code'] === \T_ANON_CLASS // Work-around: anon classes were, in certain circumstances, tokenized as T_CLASS prior to PHPCS 3.4.0. - || $tokens[$prevNonEmpty]['code'] === \T_CLASS) + || $tokens[$prevNonEmpty]['code'] === \T_CLASS + // Possibly an arrow function. + || FunctionDeclarations::isArrowFunction($phpcsFile, $prevNonEmpty) === true) ) { return $prevNonEmpty; } @@ -82,6 +89,7 @@ public static function getOwner(File $phpcsFile, $stackPtr) * set of valid owners. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The position of `T_OPEN/CLOSE_PARENTHESIS` token. @@ -111,6 +119,13 @@ public static function isOwnerIn(File $phpcsFile, $stackPtr, $validOwners) $validOwners[] = \T_CLASS; } + /* + * Allow for T_FN token being tokenized as T_STRING before PHPCS 3.5.3. + */ + if (\defined('T_FN') && \in_array(\T_FN, $validOwners, true)) { + $validOwners[] = \T_STRING; + } + return \in_array($tokens[$owner]['code'], $validOwners, true); } diff --git a/Tests/Utils/Parentheses/ParenthesesTest.inc b/Tests/Utils/Parentheses/ParenthesesTest.inc index e868076e..fda84f68 100644 --- a/Tests/Utils/Parentheses/ParenthesesTest.inc +++ b/Tests/Utils/Parentheses/ParenthesesTest.inc @@ -38,6 +38,12 @@ $anonClass = new class( /* testListOnCloseParens */ list($a, $b) = $array; +/* testArrayFunctionCallWithArrowFunctionParam */ +$value = array(ClassName::functionCall('Text', fn($param) => $param->get())); + +/* testFunctionNamedFn */ +function fn() {} + /* testNoOwnerOnCloseParens */ $a = ($b + $c); diff --git a/Tests/Utils/Parentheses/ParenthesesTest.php b/Tests/Utils/Parentheses/ParenthesesTest.php index 9f564ff3..bfce6242 100644 --- a/Tests/Utils/Parentheses/ParenthesesTest.php +++ b/Tests/Utils/Parentheses/ParenthesesTest.php @@ -134,6 +134,16 @@ class ParenthesesTest extends UtilityMethodTestCase 'code' => \T_VARIABLE, 'content' => '$a', ], + 'testArrowFunction-$param' => [ + 'marker' => '/* testArrayFunctionCallWithArrowFunctionParam */', + 'code' => \T_VARIABLE, + 'content' => '$param', + ], + 'testArrowFunction-get' => [ + 'marker' => '/* testArrayFunctionCallWithArrowFunctionParam */', + 'code' => \T_STRING, + 'content' => 'get', + ], 'testParseError-1' => [ 'marker' => '/* testParseError */', 'code' => \T_LNUMBER, @@ -174,6 +184,7 @@ class ParenthesesTest extends UtilityMethodTestCase 'T_ELSEIF' => false, 'T_CATCH' => false, 'T_DECLARE' => false, + 'T_FN' => false, ]; /** @@ -349,6 +360,21 @@ public function testPassingParenthesisCloseHandlinginBCLayer() $this->assertFalse($result); } + /** + * Test that a function named fn sees the T_FUNCTION token as owner, not the T_FN token. + * + * This specifically tests the BC-layer for arrow functions. + * + * @return void + */ + public function testFunctionNamedFnKeywordNotParenthesesOwner() + { + $stackPtr = $this->getTargetToken('/* testFunctionNamedFn */', \T_OPEN_PARENTHESIS); + + $result = Parentheses::getOwner(self::$phpcsFile, $stackPtr); + $this->assertSame(($stackPtr - 3), $result); + } + /** * Test correctly retrieving the first parenthesis opener for an arbitrary token. * @@ -652,6 +678,40 @@ public function dataWalkParentheses() 'lastIfElseOwner' => false, ], ], + 'testArrowFunction-$param' => [ + 'testArrowFunction-$param', + [ + 'firstOpener' => -10, + 'firstCloser' => 11, + 'firstOwner' => -11, + 'firstScopeOwnerOpener' => false, + 'firstScopeOwnerCloser' => false, + 'firstScopeOwnerOwner' => false, + 'lastOpener' => -1, + 'lastCloser' => 1, + 'lastOwner' => -2, + 'lastArrayOpener' => -10, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => false, + ], + ], + 'testArrowFunction-get' => [ + 'testArrowFunction-get', + [ + 'firstOpener' => -17, + 'firstCloser' => 4, + 'firstOwner' => -18, + 'firstScopeOwnerOpener' => false, + 'firstScopeOwnerCloser' => false, + 'firstScopeOwnerOwner' => false, + 'lastOpener' => -13, + 'lastCloser' => 3, + 'lastOwner' => false, + 'lastArrayOpener' => -17, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => false, + ], + ], 'testParseError-1' => [ 'testParseError-1', [ @@ -692,6 +752,11 @@ public function testHasOwner($testName, $expectedResults) // Add expected results for all owner types not listed in the data provider. $expectedResults += $this->ownerDefaults; + if (\defined('T_FN') === false) { + $expectedResults['T_STRING'] = $expectedResults['T_FN']; + unset($expectedResults['T_FN']); + } + foreach ($expectedResults as $ownerType => $expected) { $result = Parentheses::hasOwner(self::$phpcsFile, $stackPtr, \constant($ownerType)); $this->assertSame( @@ -831,6 +896,13 @@ public function dataHasOwner() 'T_WHILE' => true, ], ], + 'testArrowFunction-$param' => [ + 'testArrowFunction-$param', + [ + 'T_ARRAY' => true, + 'T_FN' => true, + ], + ], 'testParseError-1' => [ 'testParseError-1', [], @@ -998,6 +1070,11 @@ public function testLastOwnerIn($testName, $validOwners, $expected) */ public function dataLastOwnerIn() { + $arrowFunctionOwners = [\T_STRING]; + if (\defined('T_FN') === true) { + $arrowFunctionOwners = [\T_FN]; + } + return [ 'testElseIfWithClosure-$a-closure' => [ 'testElseIfWithClosure-$a', @@ -1049,6 +1126,12 @@ public function dataLastOwnerIn() [\T_FUNCTION], false, ], + 'testArrowFunction-$param' => [ + 'testArrowFunction-$param', + $arrowFunctionOwners, + -2, + ], + 'testAnonClass-$e-catch' => [ 'testAnonClass-$e', [\T_CATCH], From e2f17bd2ca5aab49b1c6f4f72be322609a203a51 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 10 Feb 2020 15:02:54 +0100 Subject: [PATCH 26/48] Tokens\Collections: add new `arrowFunctionTokensBC()` method ... to retrieve the tokens which can represent the arrow function keyword. Includes unit tests. --- PHPCSUtils/Tokens/Collections.php | 23 +++++++++ .../Collections/ArrowFunctionTokensBCTest.php | 49 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index d8d034af..a03bceb2 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -393,4 +393,27 @@ class Collections \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING, ]; + + /** + * Tokens which can represent the arrow function keyword. + * + * Note: this is a method, not a property as the `T_FN` token may not exist. + * + * @since 1.0.0 + * + * @return array => + */ + public static function arrowFunctionTokensBC() + { + $tokens = [ + \T_STRING => \T_STRING, + ]; + + if (\defined('T_FN') === true) { + // PHP 7.4 or PHPCS 3.5.3+. + $tokens[\T_FN] = \T_FN; + } + + return $tokens; + } } diff --git a/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php b/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php new file mode 100644 index 00000000..c0c0767c --- /dev/null +++ b/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php @@ -0,0 +1,49 @@ + \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::ArrowFunctionTokensBC()); + } +} From d5b33dba789b28a1f46bb84ba1ecc4a6756a5abc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 10 Feb 2020 15:42:09 +0100 Subject: [PATCH 27/48] Implement use of the new `Collections::arrowFunctionTokensBC()` method ... in all applicable places. --- PHPCSUtils/BackCompat/BCFile.php | 2 +- PHPCSUtils/Utils/Arrays.php | 6 ++-- PHPCSUtils/Utils/FunctionDeclarations.php | 2 +- PHPCSUtils/Utils/Parentheses.php | 3 +- .../BCFile/FindEndOfStatementTest.php | 6 ++-- .../BCFile/GetMethodParametersTest.php | 32 +++++++------------ .../BCFile/GetMethodPropertiesTest.php | 29 ++++++----------- .../GetPropertiesTest.php | 8 ++--- .../IsArrowFunctionTest.php | 13 ++------ Tests/Utils/Parentheses/ParenthesesTest.php | 6 ++-- 10 files changed, 37 insertions(+), 70 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 7267c3a0..1955072f 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -1332,7 +1332,7 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul if ($end !== false) { $i = $end; } - } elseif ($tokens[$i]['code'] === T_STRING || $tokens[$i]['type'] === 'T_FN') { + } elseif (isset(Collections::arrowFunctionTokensBC()[$tokens[$i]['code']]) === true) { // Potentially a PHP 7.4 arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/3.5.4. $arrowFunctionOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $i); if ($arrowFunctionOpenClose !== [] diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index 98ea54fc..515fbfa8 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -263,10 +263,8 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) ); } - $targets = self::$doubleArrowTargets + Collections::$closedScopes; - if (\defined('T_FN') === true) { - $targets[\T_FN] = \T_FN; - } + $targets = self::$doubleArrowTargets + Collections::$closedScopes; + $targets += Collections::arrowFunctionTokensBC(); $doubleArrow = ($start - 1); ++$end; diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index a824497c..d4191d29 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -395,7 +395,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) ) { throw new RuntimeException('$stackPtr was not a valid closure T_USE'); } - } elseif ($tokens[$stackPtr]['code'] === \T_STRING || $tokens[$stackPtr]['type'] === 'T_FN') { + } elseif (isset(Collections::arrowFunctionTokensBC()[$tokens[$stackPtr]['code']]) === true) { /* * Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. */ diff --git a/PHPCSUtils/Utils/Parentheses.php b/PHPCSUtils/Utils/Parentheses.php index 7455956a..63e0dce5 100644 --- a/PHPCSUtils/Utils/Parentheses.php +++ b/PHPCSUtils/Utils/Parentheses.php @@ -13,6 +13,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -123,7 +124,7 @@ public static function isOwnerIn(File $phpcsFile, $stackPtr, $validOwners) * Allow for T_FN token being tokenized as T_STRING before PHPCS 3.5.3. */ if (\defined('T_FN') && \in_array(\T_FN, $validOwners, true)) { - $validOwners[] = \T_STRING; + $validOwners += Collections::arrowFunctionTokensBC(); } return \in_array($tokens[$owner]['code'], $validOwners, true); diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index 13ca6805..2b0d1452 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -27,6 +27,7 @@ use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\BackCompat\BCFile::findEndOfStatement method. @@ -202,10 +203,7 @@ public function testArrowFunctionArrayValue() */ public function testStaticArrowFunction() { - $fnTargets = [\T_STRING]; - if (\defined('T_FN') === true) { - $fnTargets[] = \T_FN; - } + $fnTargets = Collections::arrowFunctionTokensBC(); $static = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testStaticArrowFunction */') + 2); $fn = self::$phpcsFile->findNext($fnTargets, ($static + 1)); diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index 3a248cd8..01c6bf64 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -25,6 +25,7 @@ use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\BackCompat\BCFile::getMethodParameters method. @@ -119,12 +120,9 @@ public function dataNoParams() 'ClosureUseNoParams' => ['/* testClosureUseNoParams */', T_USE], ]; - $arrowTokenType = T_STRING; - if (defined('T_FN') === true) { - $arrowTokenType = T_FN; - } + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - $data['ArrowFunctionLiveCoding'] = ['/* testArrowFunctionLiveCoding */', $arrowTokenType]; + $data['ArrowFunctionLiveCoding'] = ['/* testArrowFunctionLiveCoding */', $arrowTokenTypes]; return $data; } @@ -457,11 +455,9 @@ public function testArrowFunction() 'comma_token' => false, ]; - $arrowTokenType = T_STRING; - if (defined('T_FN') === true) { - $arrowTokenType = T_FN; - } - $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } /** @@ -487,11 +483,9 @@ public function testArrowFunctionReturnByRef() 'comma_token' => false, ]; - $arrowTokenType = T_STRING; - if (defined('T_FN') === true) { - $arrowTokenType = T_FN; - } - $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } /** @@ -1105,11 +1099,9 @@ public function testArrowFunctionWithAllTypes() 'comma_token' => false, ]; - $arrowTokenType = T_STRING; - if (defined('T_FN') === true) { - $arrowTokenType = T_FN; - } - $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } /** diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php index 4475df3c..d05d295e 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php @@ -23,6 +23,7 @@ use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\BackCompat\BCFile::getMethodProperties method. @@ -398,12 +399,9 @@ public function testArrowFunction() 'has_body' => true, ]; - $arrowTokenType = T_STRING; - if (defined('T_FN') === true) { - $arrowTokenType = T_FN; - } + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } /** @@ -459,12 +457,9 @@ public function testArrowFunctionArrayReturnValue() 'has_body' => true, ]; - $arrowTokenType = T_STRING; - if (defined('T_FN') === true) { - $arrowTokenType = T_FN; - } + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } /** @@ -486,12 +481,9 @@ public function testArrowFunctionReturnByRef() 'has_body' => true, ]; - $arrowTokenType = T_STRING; - if (defined('T_FN') === true) { - $arrowTokenType = T_FN; - } + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } /** @@ -513,12 +505,9 @@ public function testArrowFunctionLiveCoding() 'has_body' => true, ]; - $arrowTokenType = T_STRING; - if (defined('T_FN') === true) { - $arrowTokenType = T_FN; - } + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } /** diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php index 9519ecea..9d4758e8 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; use PHPCSUtils\Tests\BackCompat\BCFile\GetMethodPropertiesTest as BCFile_GetMethodPropertiesTest; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -79,12 +80,9 @@ public function testArrowFunctionLiveCoding() 'has_body' => false, // Different from original. ]; - $arrowTokenType = \T_STRING; - if (\defined('T_FN') === true) { - $arrowTokenType = \T_FN; - } + $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenType); + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } /** diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php index 0511f922..c2879d1b 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php @@ -12,6 +12,7 @@ use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -85,11 +86,7 @@ public function testTStringNotFn() */ public function testIsArrowFunction($testMarker, $expected, $targetContent = null) { - $targets = [\T_STRING]; - if (\defined('T_FN') === true) { - $targets[] = \T_FN; - } - + $targets = Collections::arrowFunctionTokensBC(); $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); $this->assertSame($expected['is'], $result); @@ -119,11 +116,7 @@ public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetCon ); } - $targets = [\T_STRING]; - if (\defined('T_FN') === true) { - $targets[] = \T_FN; - } - + $targets = Collections::arrowFunctionTokensBC(); $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); // Change from offsets to absolute token positions. diff --git a/Tests/Utils/Parentheses/ParenthesesTest.php b/Tests/Utils/Parentheses/ParenthesesTest.php index bfce6242..7a8e36ed 100644 --- a/Tests/Utils/Parentheses/ParenthesesTest.php +++ b/Tests/Utils/Parentheses/ParenthesesTest.php @@ -12,6 +12,7 @@ use PHPCSUtils\BackCompat\BCTokens; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Parentheses; /** @@ -1070,10 +1071,7 @@ public function testLastOwnerIn($testName, $validOwners, $expected) */ public function dataLastOwnerIn() { - $arrowFunctionOwners = [\T_STRING]; - if (\defined('T_FN') === true) { - $arrowFunctionOwners = [\T_FN]; - } + $arrowFunctionOwners = Collections::arrowFunctionTokensBC(); return [ 'testElseIfWithClosure-$a-closure' => [ From 5ecdf04b5be12d084d972184f14dd0211cf57cd6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 10 Feb 2020 15:59:26 +0100 Subject: [PATCH 28/48] FunctionDeclarations::getArrowFunctionOpenClose(): move fixed array to property --- PHPCSUtils/Utils/FunctionDeclarations.php | 36 +++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index d4191d29..e079b844 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -111,6 +111,25 @@ class FunctionDeclarations '__soapcall' => 'SOAPClient', ]; + /** + * Tokens which can be the end token of an arrow function. + * + * @since 1.0.0 + * + * @var array => + */ + private static $arrowFunctionEndTokens = [ + \T_COLON => true, + \T_COMMA => true, + \T_SEMICOLON => true, + \T_CLOSE_PARENTHESIS => true, + \T_CLOSE_SQUARE_BRACKET => true, + \T_CLOSE_CURLY_BRACKET => true, + \T_CLOSE_SHORT_ARRAY => true, + \T_OPEN_TAG => true, + \T_CLOSE_TAG => true, + ]; + /** * Returns the declaration name for a function. * @@ -751,23 +770,10 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) } $returnValue['scope_opener'] = $arrow; - - $endTokens = [ - \T_COLON => true, - \T_COMMA => true, - \T_SEMICOLON => true, - \T_CLOSE_PARENTHESIS => true, - \T_CLOSE_SQUARE_BRACKET => true, - \T_CLOSE_CURLY_BRACKET => true, - \T_CLOSE_SHORT_ARRAY => true, - \T_OPEN_TAG => true, - \T_CLOSE_TAG => true, - ]; - - $inTernary = false; + $inTernary = false; for ($scopeCloser = ($arrow + 1); $scopeCloser < $phpcsFile->numTokens; $scopeCloser++) { - if (isset($endTokens[$tokens[$scopeCloser]['code']]) === true + if (isset(self::$arrowFunctionEndTokens[$tokens[$scopeCloser]['code']]) === true && ($tokens[$scopeCloser]['code'] !== \T_COLON || $inTernary === false) ) { break; From ef96ac4d79a18723094989e71bfa2b6e7b28f1e8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 11 Feb 2020 02:46:55 +0100 Subject: [PATCH 29/48] FunctionDeclarations::isArrowFunction()/getArrowFunctionOpenClose(): sync with PHPCS 3.5.5 This brings the `FunctionDeclarations::isArrowFunction()` and `FunctionDeclarations::getArrowFunctionOpenClose()` functions in line with the changes in PHPCS which will be released in PHPCS 3.5.5. Note: the return value for the `FunctionDeclarations::getArrowFunctionOpenClose()` function has changed from `array` to `array|false`. Previously, the function may return an empty array or an array with only some of the indexes set to `false`. Now it will return `false` when this is not an arrow function or an array with all the indexes set to the relevant stack pointers when it _is_ an arrow function. This should make the function return value easier to work with. Includes extensive additional unit tests, as well as some changed unit tests, similar to the additional unit tests as pulled to PHPCS itself for these changes. Related upstream commits: * squizlabs/PHP_CodeSniffer@2e3a01035f267bd299cf8ef6fed4b1f19cc2f1dc * squizlabs/PHP_CodeSniffer@ea810a235ab6865f2355d97b221c068d65820818 * squizlabs/PHP_CodeSniffer@2adcb64a2de94d3993a97e285314c923d6fe7db1 * squizlabs/PHP_CodeSniffer@3a62dd4aa8429821b3f5a9b88852f0e1b854fccb * squizlabs/PHP_CodeSniffer@6070b6083e0ab6cd3de43dea69ec820884836aac Related upstream issues/PRs: * squizlabs/PHP_CodeSniffer 2523 * squizlabs/PHP_CodeSniffer 2859 * squizlabs/PHP_CodeSniffer 2860 * squizlabs/PHP_CodeSniffer 2863 --- PHPCSUtils/BackCompat/BCFile.php | 1 + PHPCSUtils/Utils/FunctionDeclarations.php | 168 ++++------ .../IsArrowFunctionTest.inc | 86 ++++- .../IsArrowFunctionTest.php | 303 ++++++++++++------ 4 files changed, 349 insertions(+), 209 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 1955072f..ec6fcede 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -159,6 +159,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) $content = null; for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { if ($tokens[$i]['code'] === T_STRING + // BC: PHPCS 3.5.3/3.5.4. || $tokens[$i]['type'] === 'T_FN' ) { /* diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index e079b844..5ed6d203 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -586,19 +586,21 @@ public static function getParameters(File $phpcsFile, $stackPtr) } /** - * Check if an arbitrary token is a PHP 7.4 arrow function keyword token. + * Check if an arbitrary token is the "fn" keyword for a PHP 7.4 arrow function. * - * Helper function for backward-compatibility with PHP < 7.4 in combination with PHPCS < 3.5.3/4 - * in which the `T_FN` token is not yet backfilled. + * Helper function for cross-version compatibility with both PHP as well as PHPCS. + * - PHP 7.4+ will tokenize most tokens with the content "fn" as T_FN, even when it isn't an arrow function. + * - PHPCS < 3.5.3 will tokenize arrow functions keywords as T_STRING. + * - PHPCS 3.5.3/3.5.4 will tokenize the keyword differently depending on which PHP version is used + * and similar to PHP will tokenize most tokens with the content "fn" as T_FN, even when it's not an + * arrow function. + * Note: the tokens tokenized by PHPCS 3.5.3 - 3.5.4 as T_FN are not 100% the same as those tokenized + * by PHP 7.4+ as T_FN. * - * Note: While this function can determine whether a token should be regarded as `T_FN`, if the - * token isn't a PHP native `T_FN` or backfilled `T_FN` token, the token will still not have - * the `parenthesis_owner`, `parenthesis_opener`, `parenthesis_closer`, `scope_owner` - * `scope_opener` or `scope_closer` keys assigned in the tokens array. - * Use the `FunctionDeclarations::getArrowFunctionOpenClose()` utility method to retrieve - * these when they're needed. + * Either way, the T_FN token is not a reliable indicator that something is in actual fact an arrow function. + * This function solves that and will give reliable results in the same way as this is now solved in PHPCS 3.5.5. * - * @see \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose() + * @see \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose() Related function. * * @since 1.0.0 * @@ -607,7 +609,8 @@ 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 + * @return bool TRUE is 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) { @@ -616,39 +619,20 @@ public static function isArrowFunction(File $phpcsFile, $stackPtr) return false; } - if ($tokens[$stackPtr]['type'] === 'T_FN') { - // Either PHP 7.4 or PHPCS 3.5.3+. Check if this is not a real function called "fn". - $prevNonEmpty = $phpcsFile->findPrevious( - Tokens::$emptyTokens + [\T_BITWISE_AND], - ($stackPtr - 1), - null, - true - ); - if ($tokens[$prevNonEmpty]['code'] === \T_FUNCTION) { - return false; - } - + if ($tokens[$stackPtr]['type'] === 'T_FN' + && isset($tokens[$stackPtr]['scope_closer']) === true + ) { return true; } - if (\defined('T_FN') === true) { - // If the token exists and isn't used, it's not an arrow function. - return false; - } - - if ($tokens[$stackPtr]['code'] !== \T_STRING + if (isset(Collections::arrowFunctionTokensBC()[$tokens[$stackPtr]['code']]) === false || \strtolower($tokens[$stackPtr]['content']) !== 'fn' ) { return false; } - $nextNonEmpty = $phpcsFile->findNext((Tokens::$emptyTokens + [\T_BITWISE_AND]), ($stackPtr + 1), null, true); - if ($nextNonEmpty === false - || ($tokens[$nextNonEmpty]['code'] === \T_OPEN_PARENTHESIS - // Make sure it is not a real function called "fn". - && (isset($tokens[$nextNonEmpty]['parenthesis_owner']) === false - || $tokens[$tokens[$nextNonEmpty]['parenthesis_owner']]['code'] !== \T_FUNCTION)) - ) { + $openClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); + if ($openClose !== false && isset($openClose['scope_closer'])) { return true; } @@ -659,76 +643,62 @@ public static function isArrowFunction(File $phpcsFile, $stackPtr) * Retrieve the parenthesis opener, parenthesis closer, the scope opener and the scope closer * for an arrow function. * - * Helper function for backward-compatibility with PHP < 7.4 in combination with PHPCS < 3.5.3/4 - * in which the `T_FN` token is not yet backfilled and does not have parenthesis opener/closer - * nor scope opener/closer indexes assigned in the `$tokens` array. + * Helper function for cross-version compatibility with both PHP as well as PHPCS. + * In PHPCS versions prior to PHPCS 3.5.3/3.5.4, the `T_FN` token is not yet backfilled + * and does not have parenthesis opener/closer nor scope opener/closer indexes assigned + * in the `$tokens` array. * - * Note: The backfill in PHPCS 3.5.3 is incomplete and this function will - in a limited set of - * circumstances - not work on PHPCS 3.5.3. - * As PHPCS 3.5.3 is not supported by PHPCSUtils due to the broken PHP 7.4 numeric literals backfill - * anyway, this will not be fixed. - * - * @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() + * @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() Related function. * * @since 1.0.0 * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The token to retrieve the opener/closers for. + * @param int $stackPtr The token to retrieve the openers/closers for. * Typically a T_FN or T_STRING token as those are the * only two tokens which can be the arrow function keyword. * - * @return array An array with the token pointers or an empty array if this is not an arrow function. - * The format of the return value is: - * - * array( - * 'parenthesis_opener' => integer|false, // Stack pointer or false if undetermined. - * 'parenthesis_closer' => integer|false, // Stack pointer or false if undetermined. - * 'scope_opener' => integer|false, // Stack pointer or false if undetermined. - * 'scope_closer' => integer|false, // Stack pointer or false if undetermined. - * ) - * + * @return array|false An array with the token pointers or FALSE if this is not an arrow function. + * The format of the return value is: + * + * array( + * 'parenthesis_opener' => integer, // Stack pointer to the parenthesis opener. + * 'parenthesis_closer' => integer, // Stack pointer to the parenthesis closer. + * 'scope_opener' => integer, // Stack pointer to the scope opener (arrow). + * 'scope_closer' => integer, // Stack pointer to the scope closer. + * ) + * */ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) { - if (self::isArrowFunction($phpcsFile, $stackPtr) === false) { - return []; - } - - $returnValue = [ - 'parenthesis_opener' => false, - 'parenthesis_closer' => false, - 'scope_opener' => false, - 'scope_closer' => false, - ]; - $tokens = $phpcsFile->getTokens(); - if ($tokens[$stackPtr]['type'] === 'T_FN' - && \version_compare(Helper::getVersion(), '3.5.3', '>=') === true + if (isset($tokens[$stackPtr]) === false + || isset(Collections::arrowFunctionTokensBC()[$tokens[$stackPtr]['code']]) === false + || \strtolower($tokens[$stackPtr]['content']) !== 'fn' ) { - if (isset($tokens[$stackPtr]['parenthesis_opener']) === true) { - $returnValue['parenthesis_opener'] = $tokens[$stackPtr]['parenthesis_opener']; - } - - if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { - $returnValue['parenthesis_closer'] = $tokens[$stackPtr]['parenthesis_closer']; - } - - if (isset($tokens[$stackPtr]['scope_opener']) === true) { - $returnValue['scope_opener'] = $tokens[$stackPtr]['scope_opener']; - } - - if (isset($tokens[$stackPtr]['scope_closer']) === true) { - $returnValue['scope_closer'] = $tokens[$stackPtr]['scope_closer']; - } + return false; + } - return $returnValue; + if ($tokens[$stackPtr]['type'] === 'T_FN' + && isset($tokens[$stackPtr]['scope_closer']) === true + ) { + // The keys will either all be set or none will be set, so no additional checks needed. + return [ + 'parenthesis_opener' => $tokens[$stackPtr]['parenthesis_opener'], + 'parenthesis_closer' => $tokens[$stackPtr]['parenthesis_closer'], + 'scope_opener' => $tokens[$stackPtr]['scope_opener'], + 'scope_closer' => $tokens[$stackPtr]['scope_closer'], + ]; } /* - * Either a T_STRING token pre-PHP 7.4, or T_FN on PHP 7.4, in combination with PHPCS < 3.5.3. + * This is either a T_STRING token pre-PHP 7.4, or T_FN on PHP 7.4 in combination + * with PHPCS < 3.5.3/4/5. + * * Now see about finding the relevant arrow function tokens. */ + $returnValue = []; + $nextNonEmpty = $phpcsFile->findNext( (Tokens::$emptyTokens + [\T_BITWISE_AND]), ($stackPtr + 1), @@ -736,12 +706,12 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) true ); if ($nextNonEmpty === false || $tokens[$nextNonEmpty]['code'] !== \T_OPEN_PARENTHESIS) { - return $returnValue; + return false; } $returnValue['parenthesis_opener'] = $nextNonEmpty; if (isset($tokens[$nextNonEmpty]['parenthesis_closer']) === false) { - return $returnValue; + return false; } $returnValue['parenthesis_closer'] = $tokens[$nextNonEmpty]['parenthesis_closer']; @@ -749,8 +719,8 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) $ignore = Tokens::$emptyTokens; $ignore += Collections::$returnTypeTokens; $ignore[\T_COLON] = \T_COLON; - $ignore[\T_INLINE_ELSE] = \T_INLINE_ELSE; // PHPCS < 2.9.1. - $ignore[\T_INLINE_THEN] = \T_INLINE_THEN; // PHPCS < 2.9.1. + $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. if (\defined('T_NULLABLE') === true) { $ignore[\T_NULLABLE] = \T_NULLABLE; @@ -764,9 +734,9 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) ); if ($arrow === false - || $tokens[$arrow]['code'] !== \T_DOUBLE_ARROW + || ($tokens[$arrow]['code'] !== \T_DOUBLE_ARROW && $tokens[$arrow]['type'] !== 'T_FN_ARROW') ) { - return $returnValue; + return false; } $returnValue['scope_opener'] = $arrow; @@ -774,17 +744,15 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) 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) ) { break; } - if ($tokens[$scopeCloser]['type'] === 'T_FN' - || ($tokens[$scopeCloser]['code'] === \T_STRING - && $tokens[$scopeCloser]['content'] === 'fn') - ) { + if (isset(Collections::arrowFunctionTokensBC()[$tokens[$scopeCloser]['code']]) === true) { $nested = self::getArrowFunctionOpenClose($phpcsFile, $scopeCloser); - if (isset($nested['scope_closer']) && $nested['scope_closer'] !== false) { + if ($nested !== false && isset($nested['scope_closer'])) { // We minus 1 here in case the closer can be shared with us. $scopeCloser = ($nested['scope_closer'] - 1); continue; @@ -823,10 +791,12 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) } } - if ($scopeCloser !== $phpcsFile->numTokens) { - $returnValue['scope_closer'] = $scopeCloser; + if ($scopeCloser === $phpcsFile->numTokens) { + return false; } + $returnValue['scope_closer'] = $scopeCloser; + return $returnValue; } diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc index d48ab6b2..65d80aaf 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc @@ -3,9 +3,6 @@ /* testNotTheRightContent */ function_call(); -/* testNotAnArrowFunction */ -const FN = true; - /* testStandard */ $fn1 = fn($x) => $x + $y; @@ -47,11 +44,37 @@ $result = array_map( $numbers ); +/* testReference */ +fn&($x) => $x; + +/* testGrouped */ +(fn($x) => $x) + $y; + +/* testArrayValue */ +$a = [ + 'a' => fn() => return 1, +]; + +/* testYield */ +$a = fn($x) => yield 'k' => $x; + /* testReturnTypeNamespacedClass */ $fn = fn($x) : ?\My\NS\ClassName => $x; +/* testReturnTypeNullableFQNClass */ +$a = fn(?\DateTime $x) : ?\DateTime => $x; + +/* testReturnTypeSelf */ +$fn = fn(self $a) : ?self => $a; + +/* testReturnTypeParent */ +$fn = fn(parent $a) : parent => $a; + +/* testReturnTypeCallable */ +$fn = fn(callable $a) : callable => $a; + /* testReturnTypeArray */ -$fn = fn($x) : array => $x; +$fn = fn(array $a) : array => $a; /* testReturnTypeArrayBug2773 */ $fn = fn(): array => [a($a, $b)]; @@ -62,23 +85,54 @@ array_map( [] ); -/* testReturnTypeCallable */ -$fn = fn($x) : callable => $x; +/* testTernary */ +$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b'; -/* testReturnTypeSelf */ -$fn = fn($x) : ?self => $x; +/* testConstantDeclaration */ +const FN = 'a'; -/* testReference */ -fn&($x) => $x; +/* testConstantDeclarationLower */ +const fn = 'a'; -/* testGrouped */ -(fn($x) => $x) + $y; +class Foo { + /* testStaticMethodName */ + public static function fn($param) { + /* testNestedInMethod */ + $fn = fn($c) => $callable($factory($c), $c); + } -/* testYield */ -$a = fn($x) => yield 'k' => $x; + public function foo() { + /* testPropertyAssignment */ + $this->fn = 'a'; + } +} -/* testTernary */ -$fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b'; +$anon = new class() { + /* testAnonClassMethodName */ + protected function fN($param) { + } +} + +/* testNonArrowStaticMethodCall */ +$a = Foo::fn($param); + +/* testNonArrowConstantAccess */ +$a = MyClass::FN; + +/* testNonArrowConstantAccessDeref */ +$a = MyClass::Fn[$a]; + +/* testNonArrowObjectMethodCall */ +$a = $obj->fn($param); + +/* testNonArrowObjectMethodCallUpper */ +$a = $obj->FN($param); + +/* testNonArrowNamespacedFunctionCall */ +$a = MyNS\Sub\Fn($param); + +/* testNonArrowNamespaceOperatorFunctionCall */ +$a = namespace\fn($param); /* testLiveCoding */ // Intentional parse error. This has to be the last test in the file. diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php index c2879d1b..369a1651 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php @@ -10,7 +10,6 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; @@ -21,6 +20,9 @@ * * These tests are loosely based on the `Tokenizer/BackfillFnTokenTest` file in PHPCS itself. * + * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction + * @covers \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose + * * @group functiondeclarations * * @since 1.0.0 @@ -31,36 +33,36 @@ class IsArrowFunctionTest extends UtilityMethodTestCase /** * Test that the function returns false when passed a non-existent token. * - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction - * * @return void */ public function testNonExistentToken() { $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, 10000); - $this->assertFalse($result); + $this->assertFalse($result, 'Failed isArrowFunction() test'); + + $result = FunctionDeclarations::getArrowFunctionOpenClose(self::$phpcsFile, 10000); + $this->assertFalse($result, 'Failed getArrowFunctionOpenClose() test'); } /** * Test that the function returns false when passed a token which definitely is not an arrow function. * - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction - * * @return void */ public function testUnsupportedToken() { - $stackPtr = $this->getTargetToken('/* testNotAnArrowFunction */', \T_CONST); + $stackPtr = $this->getTargetToken('/* testConstantDeclaration */', \T_CONST); $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); - $this->assertFalse($result); + $this->assertFalse($result, 'Failed isArrowFunction() test'); + + $result = FunctionDeclarations::getArrowFunctionOpenClose(self::$phpcsFile, $stackPtr); + $this->assertFalse($result, 'Failed getArrowFunctionOpenClose() test'); } /** * Test that the function returns false when passed a T_STRING token without `fn` as content. * - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction - * * @return void */ public function testTStringNotFn() @@ -68,14 +70,16 @@ public function testTStringNotFn() $stackPtr = $this->getTargetToken('/* testNotTheRightContent */', \T_STRING); $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); - $this->assertFalse($result); + $this->assertFalse($result, 'Failed isArrowFunction() test'); + + $result = FunctionDeclarations::getArrowFunctionOpenClose(self::$phpcsFile, $stackPtr); + $this->assertFalse($result, 'Failed getArrowFunctionOpenClose() test'); } /** * Test correctly detecting arrow functions. * * @dataProvider dataArrowFunction - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction * * @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. @@ -96,36 +100,24 @@ public function testIsArrowFunction($testMarker, $expected, $targetContent = nul * Test correctly detecting arrow functions. * * @dataProvider dataArrowFunction - * @covers \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose * * @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. - * @param bool $maybeSkip Whether the test should be skipped on PHPCS 3.5.3 due to a broken - * upstream backfill. * * @return void */ - public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetContent = null, $maybeSkip = false) + public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetContent = 'fn') { - // Skip specific test(s) on unsupported PHPCS versions. - if ($maybeSkip === true && \version_compare(Helper::getVersion(), '3.5.3', '==') === true) { - $this->markTestSkipped( - 'PHPCS 3.5.3 is not supported for this specific test due to a buggy arrow functions backfill.' - ); - } - $targets = Collections::arrowFunctionTokensBC(); $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); // Change from offsets to absolute token positions. - foreach ($expected['get'] as $key => $value) { - if ($value === false) { - continue; + if ($expected['get'] != false) { + foreach ($expected['get'] as $key => $value) { + $expected['get'][$key] += $stackPtr; } - - $expected['get'][$key] += $stackPtr; } $result = FunctionDeclarations::getArrowFunctionOpenClose(self::$phpcsFile, $stackPtr); @@ -143,17 +135,6 @@ public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetCon public function dataArrowFunction() { return [ - /* - * This particular case tests the "no open parenthesis after" condition in PHPCS < 3.5.3 - * and the "fn defined but not used" condition in PHPCS 3.5.3+. - */ - 'const-declaration-not-an-arrow-function' => [ - '/* testNotAnArrowFunction */', - [ - 'is' => false, - 'get' => [], - ], - ], 'arrow-function-standard' => [ '/* testStandard */', [ @@ -177,6 +158,7 @@ public function dataArrowFunction() 'scope_closer' => 12, ], ], + 'Fn', ], 'arrow-function-with-whitespace' => [ '/* testWhitespace */', @@ -202,11 +184,11 @@ public function dataArrowFunction() ], ], ], - 'real-function-called-fn' => [ + 'non-arrow-function-global-function-declaration' => [ '/* testFunctionName */', [ 'is' => false, - 'get' => [], + 'get' => false, ], ], 'arrow-function-nested-outer' => [ @@ -294,67 +276,75 @@ public function dataArrowFunction() ], ], ], - 'arrow-function-with-return-type-nullable-namespaced-class' => [ - '/* testReturnTypeNamespacedClass */', + 'arrow-function-with-reference' => [ + '/* testReference */', [ 'is' => true, 'get' => [ - 'parenthesis_opener' => 1, - 'parenthesis_closer' => 3, - 'scope_opener' => 15, - 'scope_closer' => 18, + 'parenthesis_opener' => 2, + 'parenthesis_closer' => 4, + 'scope_opener' => 6, + 'scope_closer' => 9, ], ], ], - 'arrow-function-with-return-type-array' => [ - '/* testReturnTypeArray */', + 'arrow-function-grouped-within-parenthesis' => [ + '/* testGrouped */', [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, 'parenthesis_closer' => 3, - 'scope_opener' => 9, - 'scope_closer' => 12, + 'scope_opener' => 5, + 'scope_closer' => 8, ], ], ], - 'arrow-function-with-return-type-array-bug-2773' => [ - '/* testReturnTypeArrayBug2773 */', + 'arrow-function-as-array-value' => [ + '/* testArrayValue */', [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, 'parenthesis_closer' => 2, - 'scope_opener' => 7, - 'scope_closer' => 18, + 'scope_opener' => 4, + 'scope_closer' => 9, ], ], - null, - true, ], - 'arrow-function-with-array-param-and-return-type' => [ - '/* testMoreArrayTypeDeclarations */', + 'arrow-function-with-yield-in-value' => [ + '/* testYield */', [ 'is' => true, 'get' => [ - 'parenthesis_opener' => 2, - 'parenthesis_closer' => 6, - 'scope_opener' => 11, - 'scope_closer' => 17, + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 14, ], ], - null, - true, ], - 'arrow-function-with-return-type-callable' => [ - '/* testReturnTypeCallable */', + 'arrow-function-with-return-type-nullable-namespaced-class' => [ + '/* testReturnTypeNamespacedClass */', [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, 'parenthesis_closer' => 3, - 'scope_opener' => 9, - 'scope_closer' => 12, + 'scope_opener' => 15, + 'scope_closer' => 18, + ], + ], + ], + 'arrow-function-with-fqn-class' => [ + '/* testReturnTypeNullableFQNClass */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 7, + 'scope_opener' => 15, + 'scope_closer' => 18, ], ], ], @@ -364,48 +354,72 @@ public function dataArrowFunction() 'is' => true, 'get' => [ 'parenthesis_opener' => 1, - 'parenthesis_closer' => 3, - 'scope_opener' => 10, - 'scope_closer' => 13, + 'parenthesis_closer' => 5, + 'scope_opener' => 12, + 'scope_closer' => 15, ], ], ], - 'arrow-function-with-reference' => [ - '/* testReference */', + 'arrow-function-with-return-type-parent' => [ + '/* testReturnTypeParent */', [ 'is' => true, 'get' => [ - 'parenthesis_opener' => 2, - 'parenthesis_closer' => 4, - 'scope_opener' => 6, - 'scope_closer' => 9, + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 5, + 'scope_opener' => 11, + 'scope_closer' => 14, ], ], ], - 'arrow-function-within-parenthesis' => [ - '/* testGrouped */', + 'arrow-function-with-return-type-callable' => [ + '/* testReturnTypeCallable */', [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, - 'parenthesis_closer' => 3, - 'scope_opener' => 5, - 'scope_closer' => 8, + 'parenthesis_closer' => 5, + 'scope_opener' => 11, + 'scope_closer' => 14, ], ], ], - 'arrow-function-with-yield-in-value' => [ - '/* testYield */', + 'arrow-function-with-return-type-array' => [ + '/* testReturnTypeArray */', [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, - 'parenthesis_closer' => 3, - 'scope_opener' => 5, + 'parenthesis_closer' => 5, + 'scope_opener' => 11, 'scope_closer' => 14, ], ], ], + 'arrow-function-with-return-type-array-bug-2773' => [ + '/* testReturnTypeArrayBug2773 */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 7, + 'scope_closer' => 18, + ], + ], + ], + 'arrow-function-with-array-param-and-return-type' => [ + '/* testMoreArrayTypeDeclarations */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 2, + 'parenthesis_closer' => 6, + 'scope_opener' => 11, + 'scope_closer' => 17, + ], + ], + ], 'arrow-function-with-ternary-content' => [ '/* testTernary */', [ @@ -442,19 +456,120 @@ public function dataArrowFunction() ], ], ], - - 'live-coding' => [ - '/* testLiveCoding */', + 'arrow-function-nested-in-method' => [ + '/* testNestedInMethod */', [ 'is' => true, 'get' => [ - 'parenthesis_opener' => false, - 'parenthesis_closer' => false, - 'scope_opener' => false, - 'scope_closer' => false, + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 5, + 'scope_closer' => 17, ], ], ], + + /* + * Use of the "fn" keyword when not an arrow function. + */ + 'non-arrow-function-const-declaration' => [ + '/* testConstantDeclaration */', + [ + 'is' => false, + 'get' => false, + ], + 'FN', + ], + 'non-arrow-function-const-declaration-lowercase' => [ + '/* testConstantDeclarationLower */', + [ + 'is' => false, + 'get' => false, + ], + ], + 'non-arrow-function-static-method-declaration' => [ + '/* testStaticMethodName */', + [ + 'is' => false, + 'get' => false, + ], + ], + 'non-arrow-function-assignment-to-property' => [ + '/* testPropertyAssignment */', + [ + 'is' => false, + 'get' => false, + ], + ], + 'non-arrow-function-anon-class-method-declaration' => [ + '/* testAnonClassMethodName */', + [ + 'is' => false, + 'get' => false, + ], + 'fN', + ], + 'non-arrow-function-call-to-static-method' => [ + '/* testNonArrowStaticMethodCall */', + [ + 'is' => false, + 'get' => false, + ], + ], + 'non-arrow-function-class-constant-access' => [ + '/* testNonArrowConstantAccess */', + [ + 'is' => false, + 'get' => false, + ], + 'FN', + ], + 'non-arrow-function-class-constant-access-with-deref' => [ + '/* testNonArrowConstantAccessDeref */', + [ + 'is' => false, + 'get' => false, + ], + 'Fn', + ], + 'non-arrow-function-call-to-object-method' => [ + '/* testNonArrowObjectMethodCall */', + [ + 'is' => false, + 'get' => false, + ], + ], + 'non-arrow-function-call-to-object-method-uppercase' => [ + '/* testNonArrowObjectMethodCallUpper */', + [ + 'is' => false, + 'get' => false, + ], + 'FN', + ], + 'non-arrow-function-call-to-namespaced-function' => [ + '/* testNonArrowNamespacedFunctionCall */', + [ + 'is' => false, + 'get' => false, + ], + 'Fn', + ], + 'non-arrow-function-call-to-namespaced-function-using-namespace-operator' => [ + '/* testNonArrowNamespaceOperatorFunctionCall */', + [ + 'is' => false, + 'get' => false, + ], + ], + + 'live-coding' => [ + '/* testLiveCoding */', + [ + 'is' => false, + 'get' => false, + ], + ], ]; } } From 37440af5171d44619b8009302a59b58b65f815e2 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 11 Feb 2020 04:03:14 +0100 Subject: [PATCH 30/48] Improve on previous arrow function implementation in various utilities * Change checking of the return value of the `FunctionDeclarations::getArrowFunctionOpenClose()` function. - This function now either returns `false` or a array with all indexes set to the relevant stack pointers. * Improved the message of the `RuntimeException` for the `FunctionDeclarations::getParameters()` and the `FunctionDeclarations::getProperties()` methods. * Update unit tests to reflect the change in tokenization of "fn" tokens. * Remove test skipping for select arrow function related tests on select PHP/PHPCS versions. This is no longer needed. * Add/improve documentation about arrow function support. Includes a few additional unit tests to safeguard cross-version compatibility with PHPCS 3.5.3 and 3.5.4. --- PHPCSUtils/BackCompat/BCFile.php | 34 +++++----- PHPCSUtils/Utils/Arrays.php | 2 +- PHPCSUtils/Utils/FunctionDeclarations.php | 37 +++++------ PHPCSUtils/Utils/Parentheses.php | 2 +- .../BCFile/FindEndOfStatementTest.php | 7 -- .../BCFile/GetMethodParametersTest.inc | 3 + .../BCFile/GetMethodParametersTest.php | 44 ++++++++++--- .../BCFile/GetMethodPropertiesTest.inc | 3 + .../BCFile/GetMethodPropertiesTest.php | 66 +++++++++---------- Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc | 3 + Tests/Utils/Arrays/GetDoubleArrowPtrTest.php | 5 ++ .../GetParametersDiffTest.php | 2 +- .../GetParametersTest.php | 11 +++- .../GetPropertiesDiffTest.php | 2 +- .../GetPropertiesTest.php | 36 +++------- Tests/Utils/Parentheses/ParenthesesTest.inc | 3 + Tests/Utils/Parentheses/ParenthesesTest.php | 25 +++++++ 17 files changed, 159 insertions(+), 126 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index ec6fcede..d10171f5 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -63,6 +63,7 @@ * array return type declarations. * - Typed properties were not recognized prior to PHPCS 3.5.0, including the * `?` nullability token not being converted to `T_NULLABLE`. + * - Arrow functions were not recognized properly until PHPCS 3.5.3. * - General PHP cross-version incompatibilities. * * Most functions in this class will have a related twin-function in the relevant @@ -98,6 +99,8 @@ class BCFile * `\PHP_CodeSniffer\Exceptions\RuntimeException`. * - PHPCS 3.5.3: Allow for functions to be called `fn` for backwards compatibility. * Related to PHP 7.4 T_FN arrow functions. + * - PHPCS 3.5.5: Remove arrow function work-around which is no longer needed due to + * a change in the tokenization of arrow functions. * * Note: For ES6 classes in combination with PHPCS 2.x, passing a `T_STRING` token to * this method will be accepted for JS files. @@ -266,12 +269,13 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) */ public static function getMethodParameters(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); + $tokens = $phpcsFile->getTokens(); + $arrowOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $stackPtr); if ($tokens[$stackPtr]['code'] !== T_FUNCTION && $tokens[$stackPtr]['code'] !== T_CLOSURE && $tokens[$stackPtr]['code'] !== T_USE - && FunctionDeclarations::isArrowFunction($phpcsFile, $stackPtr) === false + && $arrowOpenClose === false ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); } @@ -281,15 +285,9 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) if ($opener === false || isset($tokens[$opener]['parenthesis_owner']) === true) { throw new RuntimeException('$stackPtr was not a valid T_USE'); } - } elseif ($tokens[$stackPtr]['code'] === \T_STRING || $tokens[$stackPtr]['type'] === 'T_FN') { - /* - * Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. - */ - $opener = $phpcsFile->findNext((Tokens::$emptyTokens + [\T_BITWISE_AND]), ($stackPtr + 1), null, true); - if ($opener === false || $tokens[$opener]['code'] !== T_OPEN_PARENTHESIS) { - // Live coding or syntax error, so no params to find. - return []; - } + } elseif ($arrowOpenClose !== false) { + // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/4/5. + $opener = $arrowOpenClose['parenthesis_opener']; } else { if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) { // Live coding or syntax error, so no params to find. @@ -553,7 +551,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) if ($tokens[$stackPtr]['code'] !== T_FUNCTION && $tokens[$stackPtr]['code'] !== T_CLOSURE - && $arrowOpenClose === [] + && $arrowOpenClose === false ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); } @@ -623,7 +621,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) $parenthesisCloser = null; if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { $parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer']; - } elseif ($arrowOpenClose !== [] && $arrowOpenClose['parenthesis_closer'] !== false) { + } elseif ($arrowOpenClose !== false) { // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. $parenthesisCloser = $arrowOpenClose['parenthesis_closer']; } @@ -632,7 +630,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) $scopeOpener = null; if (isset($tokens[$stackPtr]['scope_opener']) === true) { $scopeOpener = $tokens[$stackPtr]['scope_opener']; - } elseif ($arrowOpenClose !== [] && $arrowOpenClose['scope_opener'] !== false) { + } elseif ($arrowOpenClose !== false) { // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. $scopeOpener = $arrowOpenClose['scope_opener']; } @@ -649,7 +647,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) // Handle nullable tokens in PHPCS < 2.8.0. || (defined('T_NULLABLE') === false && $tokens[$i]['code'] === T_INLINE_THEN) // Handle nullable tokens with arrow functions in PHPCS 2.8.0 - 2.9.0. - || ($arrowOpenClose !== [] && $tokens[$i]['code'] === T_INLINE_THEN + || ($arrowOpenClose !== false && $tokens[$i]['code'] === T_INLINE_THEN && version_compare(Helper::getVersion(), '2.9.1', '<') === true) ) { $nullableReturnType = true; @@ -665,7 +663,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) } $bodyTokens = [T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET]; - if ($arrowOpenClose !== []) { + if ($arrowOpenClose !== false) { $bodyTokens = [T_DOUBLE_ARROW => T_DOUBLE_ARROW]; if (defined('T_FN_ARROW') === true) { // PHPCS 3.5.3+. @@ -1336,9 +1334,7 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul } elseif (isset(Collections::arrowFunctionTokensBC()[$tokens[$i]['code']]) === true) { // Potentially a PHP 7.4 arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/3.5.4. $arrowFunctionOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $i); - if ($arrowFunctionOpenClose !== [] - && $arrowFunctionOpenClose['scope_closer'] !== false - ) { + if ($arrowFunctionOpenClose !== false) { if ($i === $start) { return $arrowFunctionOpenClose['scope_closer']; } diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index 515fbfa8..5f66a122 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -292,7 +292,7 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) } // BC for PHP 7.4 arrow functions with PHPCS < 3.5.3. - if ($tokens[$doubleArrow]['code'] === \T_STRING + if (isset(Collections::arrowFunctionTokensBC()[$tokens[$doubleArrow]['code']]) === true && FunctionDeclarations::isArrowFunction($phpcsFile, $doubleArrow) === false ) { // Not an arrow function, continue looking. diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 5ed6d203..e6e397bf 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -201,8 +201,8 @@ public static function getName(File $phpcsFile, $stackPtr) * * @return array * - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a - * T_FUNCTION, T_CLOSURE, or T_FN token. + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a T_FUNCTION + * or T_CLOSURE token nor an arrow function. */ public static function getProperties(File $phpcsFile, $stackPtr) { @@ -212,9 +212,9 @@ public static function getProperties(File $phpcsFile, $stackPtr) if (isset($tokens[$stackPtr]) === false || ($tokens[$stackPtr]['code'] !== \T_FUNCTION && $tokens[$stackPtr]['code'] !== \T_CLOSURE - && $arrowOpenClose === []) + && $arrowOpenClose === false) ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); + throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or an arrow function'); } if ($tokens[$stackPtr]['code'] === \T_FUNCTION) { @@ -270,7 +270,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) $parenthesisCloser = null; if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { $parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer']; - } elseif ($arrowOpenClose !== [] && $arrowOpenClose['parenthesis_closer'] !== false) { + } elseif ($arrowOpenClose !== false) { // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. $parenthesisCloser = $arrowOpenClose['parenthesis_closer']; } @@ -279,7 +279,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) $scopeOpener = null; if (isset($tokens[$stackPtr]['scope_opener']) === true) { $scopeOpener = $tokens[$stackPtr]['scope_opener']; - } elseif ($arrowOpenClose !== [] && $arrowOpenClose['scope_opener'] !== false) { + } elseif ($arrowOpenClose !== false) { // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. $scopeOpener = $arrowOpenClose['scope_opener']; } @@ -300,7 +300,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) // Handle nullable tokens in PHPCS < 2.8.0. || (\defined('T_NULLABLE') === false && $tokens[$i]['code'] === \T_INLINE_THEN) // Handle nullable tokens with arrow functions in PHPCS 2.8.0 - 2.9.0. - || ($arrowOpenClose !== [] && $tokens[$i]['code'] === \T_INLINE_THEN + || ($arrowOpenClose !== false && $tokens[$i]['code'] === \T_INLINE_THEN && \version_compare(Helper::getVersion(), '2.9.1', '<') === true) ) { $nullableReturnType = true; @@ -390,20 +390,21 @@ public static function getProperties(File $phpcsFile, $stackPtr) * @return array * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified $stackPtr is not of - * type T_FUNCTION, T_CLOSURE, T_USE, - * or T_FN. + * type T_FUNCTION, T_CLOSURE or T_USE, + * nor an arrow function. */ public static function getParameters(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); + $tokens = $phpcsFile->getTokens(); + $arrowOpenClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); if (isset($tokens[$stackPtr]) === false || ($tokens[$stackPtr]['code'] !== \T_FUNCTION && $tokens[$stackPtr]['code'] !== \T_CLOSURE && $tokens[$stackPtr]['code'] !== \T_USE - && self::isArrowFunction($phpcsFile, $stackPtr) === false) + && $arrowOpenClose === false) ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); + throw new RuntimeException('$stackPtr must be of type T_FUNCTION, T_CLOSURE or T_USE or an arrow function'); } if ($tokens[$stackPtr]['code'] === \T_USE) { @@ -414,15 +415,9 @@ public static function getParameters(File $phpcsFile, $stackPtr) ) { throw new RuntimeException('$stackPtr was not a valid closure T_USE'); } - } elseif (isset(Collections::arrowFunctionTokensBC()[$tokens[$stackPtr]['code']]) === true) { - /* - * Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. - */ - $opener = $phpcsFile->findNext((Tokens::$emptyTokens + [\T_BITWISE_AND]), ($stackPtr + 1), null, true); - if ($opener === false || $tokens[$opener]['code'] !== \T_OPEN_PARENTHESIS) { - // Live coding or syntax error, so no params to find. - return []; - } + } elseif ($arrowOpenClose !== false) { + // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/4/5. + $opener = $arrowOpenClose['parenthesis_opener']; } else { if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) { // Live coding or syntax error, so no params to find. diff --git a/PHPCSUtils/Utils/Parentheses.php b/PHPCSUtils/Utils/Parentheses.php index 63e0dce5..bd5a6126 100644 --- a/PHPCSUtils/Utils/Parentheses.php +++ b/PHPCSUtils/Utils/Parentheses.php @@ -48,7 +48,7 @@ public static function getOwner(File $phpcsFile, $stackPtr) /* * `T_LIST` and `T_ANON_CLASS` only became parentheses owners in PHPCS 3.5.0. - * `T_FN` was only backfilled in PHPCS 3.5.3/4. + * `T_FN` was only backfilled in PHPCS 3.5.3/4/5. * - On PHP 7.4 with PHPCS < 3.5.3, T_FN will not yet be a parentheses owner. * - On PHP < 7.4 with PHPCS < 3.5.3, T_FN will be tokenized as T_STRING and not yet be a parentheses owner. * diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index 2b0d1452..ab38f0d4 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -25,7 +25,6 @@ namespace PHPCSUtils\Tests\BackCompat\BCFile; use PHPCSUtils\BackCompat\BCFile; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Tokens\Collections; @@ -221,12 +220,6 @@ public function testStaticArrowFunction() */ public function testArrowFunctionReturnValue() { - // Skip this test on unsupported PHPCS version. - if (\version_compare(Helper::getVersion(), '3.5.3', '==') === true) { - $this->markTestSkipped( - 'PHPCS 3.5.3 is not supported for this specific test due to a buggy arrow functions backfill.' - ); - } $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testArrowFunctionReturnValue */') + 2); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc index d3daca2a..922c59fd 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc @@ -125,6 +125,9 @@ function messyDeclaration( & /*test*/ ... /* phpcs:ignore */ $c ) {} +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + /* testClosureNoParams */ function() {} diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index 01c6bf64..302403fa 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -42,14 +42,44 @@ class GetMethodParametersTest extends UtilityMethodTestCase /** * Test receiving an expected exception when a non function/use token is passed. * + * @dataProvider dataUnexpectedTokenException + * + * @param string $commentString The comment which preceeds the test. + * @param array $targetTokenType The token type to search for after $commentString. + * * @return void */ - public function testUnexpectedTokenException() + public function testUnexpectedTokenException($commentString, $targetTokenType) { $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); - $next = $this->getTargetToken('/* testNotAFunction */', [T_INTERFACE]); - BCFile::getMethodParameters(self::$phpcsFile, $next); + $target = $this->getTargetToken($commentString, $targetTokenType); + BCFile::getMethodParameters(self::$phpcsFile, $target); + } + + /** + * Data Provider. + * + * @see testUnexpectedTokenException() For the array format. + * + * @return array + */ + public function dataUnexpectedTokenException() + { + return [ + 'interface' => [ + '/* testNotAFunction */', + T_INTERFACE, + ], + 'function-call-fn-phpcs-3.5.3-3.5.4' => [ + '/* testFunctionCallFnPHPCS353-354 */', + Collections::arrowFunctionTokensBC(), + ], + 'fn-live-coding' => [ + '/* testArrowFunctionLiveCoding */', + Collections::arrowFunctionTokensBC(), + ], + ]; } /** @@ -114,17 +144,11 @@ public function testNoParams($commentString, $targetTokenType = [T_FUNCTION, T_C */ public function dataNoParams() { - $data = [ + return [ 'FunctionNoParams' => ['/* testFunctionNoParams */'], 'ClosureNoParams' => ['/* testClosureNoParams */'], 'ClosureUseNoParams' => ['/* testClosureUseNoParams */', T_USE], ]; - - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - - $data['ArrowFunctionLiveCoding'] = ['/* testArrowFunctionLiveCoding */', $arrowTokenTypes]; - - return $data; } /** diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc index 815456ce..f21ecdb3 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc @@ -81,6 +81,9 @@ $fn = fn(): array => [a($a, $b)]; /* testArrowFunctionReturnByRef */ fn&(?string $a) : ?string => $b; +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + /* testArrowFunctionLiveCoding */ // Intentional parse error. This has to be the last test in the file. $fn = fn diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php index d05d295e..97649bc3 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php @@ -21,7 +21,6 @@ namespace PHPCSUtils\Tests\BackCompat\BCFile; use PHPCSUtils\BackCompat\BCFile; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Tokens\Collections; @@ -40,16 +39,46 @@ class GetMethodPropertiesTest extends UtilityMethodTestCase /** * Test receiving an expected exception when a non function token is passed. * + * @dataProvider dataNotAFunctionException + * + * @param string $commentString The comment which preceeds the test. + * @param array $targetTokenType The token type to search for after $commentString. + * * @return void */ - public function testNotAFunctionException() + public function testNotAFunctionException($commentString, $targetTokenType) { $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); - $next = $this->getTargetToken('/* testNotAFunction */', T_RETURN); + $next = $this->getTargetToken($commentString, $targetTokenType); BCFile::getMethodProperties(self::$phpcsFile, $next); } + /** + * Data Provider. + * + * @see testNotAFunctionException() For the array format. + * + * @return array + */ + public function dataNotAFunctionException() + { + return [ + 'return' => [ + '/* testNotAFunction */', + T_RETURN, + ], + 'function-call-fn-phpcs-3.5.3-3.5.4' => [ + '/* testFunctionCallFnPHPCS353-354 */', + Collections::arrowFunctionTokensBC(), + ], + 'fn-live-coding' => [ + '/* testArrowFunctionLiveCoding */', + Collections::arrowFunctionTokensBC(), + ], + ]; + } + /** * Test a basic function. * @@ -438,13 +467,6 @@ public function testPhpcsIssue1264() */ public function testArrowFunctionArrayReturnValue() { - // Skip this test on unsupported PHPCS versions. - if (\version_compare(Helper::getVersion(), '3.5.3', '==') === true) { - $this->markTestSkipped( - 'PHPCS 3.5.3 is not supported for this specific test due to a buggy arrow functions backfill.' - ); - } - $expected = [ 'scope' => 'public', 'scope_specified' => false, @@ -486,30 +508,6 @@ public function testArrowFunctionReturnByRef() $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); } - /** - * Test an arrow function live coding/parse error. - * - * @return void - */ - public function testArrowFunctionLiveCoding() - { - $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'return_type_token' => false, - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, - ]; - - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); - } - /** * Test helper. * diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc index c54b98d9..f732d5dd 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc @@ -80,4 +80,7 @@ $array = [ /* testTstringKeyNotFnFunction */ CONSTANT_NAME => 'value', + + /* testPropertyAccessPHPCS353-354 */ + ($obj->fn) => 'value', ]; diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php index 85040dd4..e5dc28d9 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php @@ -208,6 +208,11 @@ public function dataGetDoubleArrowPtr() '/* testTstringKeyNotFnFunction */', 8, ], + // Test specifically for PHPCS 3.5.3 and 3.5.4 in which all "fn" tokens were tokenized as T_FN. + 'test-arrow-access-to-property-named-fn-as-key-phpcs-3.5.3-3.5.4' => [ + '/* testPropertyAccessPHPCS353-354 */', + 12, + ], ]; } } diff --git a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php index 0dda94d5..66235ace 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.php @@ -35,7 +35,7 @@ class GetParametersDiffTest extends UtilityMethodTestCase */ public function testNonExistentToken() { - $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE'); + $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION, T_CLOSURE or T_USE or an arrow function'); FunctionDeclarations::getParameters(self::$phpcsFile, 10000); } diff --git a/Tests/Utils/FunctionDeclarations/GetParametersTest.php b/Tests/Utils/FunctionDeclarations/GetParametersTest.php index 679b0e6c..ff5e7b8d 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersTest.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersTest.php @@ -50,13 +50,18 @@ public static function setUpTestFile() /** * Test receiving an expected exception when a non function/use token is passed. * + * @dataProvider dataUnexpectedTokenException + * + * @param string $commentString The comment which preceeds the test. + * @param array $targetTokenType The token type to search for after $commentString. + * * @return void */ - public function testUnexpectedTokenException() + public function testUnexpectedTokenException($commentString, $targetTokenType) { - $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); + $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION, T_CLOSURE or T_USE or an arrow function'); - $next = $this->getTargetToken('/* testNotAFunction */', [\T_INTERFACE]); + $next = $this->getTargetToken($commentString, $targetTokenType); FunctionDeclarations::getParameters(self::$phpcsFile, $next); } diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php index 3db7c90e..8fee9566 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php @@ -35,7 +35,7 @@ class GetPropertiesDiffTest extends UtilityMethodTestCase */ public function testNonExistentToken() { - $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE'); + $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or an arrow function'); FunctionDeclarations::getProperties(self::$phpcsFile, 10000); } diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php index 9d4758e8..83bafbad 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php @@ -11,7 +11,6 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; use PHPCSUtils\Tests\BackCompat\BCFile\GetMethodPropertiesTest as BCFile_GetMethodPropertiesTest; -use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -51,38 +50,19 @@ public static function setUpTestFile() /** * Test receiving an expected exception when a non function token is passed. * - * @return void - */ - public function testNotAFunctionException() - { - $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); - - $next = $this->getTargetToken('/* testNotAFunction */', \T_RETURN); - FunctionDeclarations::getProperties(self::$phpcsFile, $next); - } - - /** - * Test a arrow function live coding/parse error. + * @dataProvider dataNotAFunctionException + * + * @param string $commentString The comment which preceeds the test. + * @param array $targetTokenType The token type to search for after $commentString. * * @return void */ - public function testArrowFunctionLiveCoding() + public function testNotAFunctionException($commentString, $targetTokenType) { - $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'return_type_token' => false, - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, // Different from original. - ]; + $this->expectPhpcsException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or an arrow function'); - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + $next = $this->getTargetToken($commentString, $targetTokenType); + FunctionDeclarations::getProperties(self::$phpcsFile, $next); } /** diff --git a/Tests/Utils/Parentheses/ParenthesesTest.inc b/Tests/Utils/Parentheses/ParenthesesTest.inc index fda84f68..62522c4d 100644 --- a/Tests/Utils/Parentheses/ParenthesesTest.inc +++ b/Tests/Utils/Parentheses/ParenthesesTest.inc @@ -47,6 +47,9 @@ function fn() {} /* testNoOwnerOnCloseParens */ $a = ($b + $c); +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + // Intentional parse error. This has to be the last test in the file. /* testParseError */ declare(ticks=1 diff --git a/Tests/Utils/Parentheses/ParenthesesTest.php b/Tests/Utils/Parentheses/ParenthesesTest.php index 7a8e36ed..6cbd3efb 100644 --- a/Tests/Utils/Parentheses/ParenthesesTest.php +++ b/Tests/Utils/Parentheses/ParenthesesTest.php @@ -145,6 +145,10 @@ class ParenthesesTest extends UtilityMethodTestCase 'code' => \T_STRING, 'content' => 'get', ], + 'testMethodCalledFn-true' => [ + 'marker' => '/* testFunctionCallFnPHPCS353-354 */', + 'code' => \T_TRUE, + ], 'testParseError-1' => [ 'marker' => '/* testParseError */', 'code' => \T_LNUMBER, @@ -713,6 +717,23 @@ public function dataWalkParentheses() 'lastIfElseOwner' => false, ], ], + 'testMethodCalledFn-true' => [ + 'testMethodCalledFn-true', + [ + 'firstOpener' => -1, + 'firstCloser' => 1, + 'firstOwner' => false, + 'firstScopeOwnerOpener' => false, + 'firstScopeOwnerCloser' => false, + 'firstScopeOwnerOwner' => false, + 'lastOpener' => -1, + 'lastCloser' => 1, + 'lastOwner' => false, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => false, + ], + ], 'testParseError-1' => [ 'testParseError-1', [ @@ -904,6 +925,10 @@ public function dataHasOwner() 'T_FN' => true, ], ], + 'testMethodCalledFn-true' => [ + 'testMethodCalledFn-true', + [], + ], 'testParseError-1' => [ 'testParseError-1', [], From 878561f62bf3d9dfbe8bdf181410da573fee5cc4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 4 Feb 2020 03:09:46 +0100 Subject: [PATCH 31/48] Documentation: various minor fixes --- PHPCSUtils/BackCompat/BCFile.php | 3 ++- PHPCSUtils/Utils/Arrays.php | 2 ++ PHPCSUtils/Utils/ControlStructures.php | 2 +- Tests/BackCompat/BCFile/FindEndOfStatementTest.php | 2 -- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index d10171f5..18e88dd8 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -208,7 +208,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * ) * * - * Parameters with default values have an additional array indexs of: + * Parameters with default values have the following additional array indexes: * 'default' => string, // The full content of the default value. * 'default_token' => integer, // The stack pointer to the start of the default value. * 'default_equal_token' => integer, // The stack pointer to the equals sign. @@ -1391,6 +1391,7 @@ public static function hasCondition(File $phpcsFile, $stackPtr, $types) * @see \PHPCSUtils\Utils\Conditions::getCondition() More versatile alternative. * * @since 1.0.0 + * @since 1.0.0-alpha2 Added support for the PHPCS 3.5.4 $first parameter. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the token we are checking. diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index 5f66a122..e1940b9f 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -32,6 +32,8 @@ class Arrays * Note: this array does not contain the `T_FN` token as it may or may not exist. * If it exists, it will be added in the `getDoubleArrowPtr()` function. * + * @since 1.0.0 + * * @var array => */ private static $doubleArrowTargets = [ diff --git a/PHPCSUtils/Utils/ControlStructures.php b/PHPCSUtils/Utils/ControlStructures.php index 72ae2ca5..df36f5e3 100644 --- a/PHPCSUtils/Utils/ControlStructures.php +++ b/PHPCSUtils/Utils/ControlStructures.php @@ -206,7 +206,7 @@ public static function isElseIf(File $phpcsFile, $stackPtr) * In the first case, the statement - correctly - won't have a scope opener/closer. * In the second case, the statement will have the scope opener/closer indexes. * In the last case, due to a bug in the PHPCS Tokenizer, it won't have the scope opener/closer indexes, - * while it really should. This bug is expected to be fixed in PHPCS 3.5.4. + * while it really should. This bug is fixed in PHPCS 3.5.4. * * In other words, if a sniff needs to support PHPCS < 3.5.4 and needs to take the alternative * control structure syntax into account, this method can be used to retrieve the diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index ab38f0d4..97d574d8 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -6,8 +6,6 @@ * @copyright 2019-2020 PHPCSUtils Contributors * @license https://opensource.org/licenses/LGPL-3.0 LGPL3 * @link https://github.com/PHPCSStandards/PHPCSUtils -/** - * Tests for the \PHP_CodeSniffer\Files\File:findEndOfStatement method. * * This class is imported from the PHP_CodeSniffer project. * From 80c736d4ec3020efd7ff23108b4f27c4f183b1c5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 11 Feb 2020 04:31:32 +0100 Subject: [PATCH 32/48] Various minor tidying up --- PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php | 2 -- PHPCSUtils/Utils/Lists.php | 1 + PHPCSUtils/Utils/Namespaces.php | 3 +-- Tests/BackCompat/BCFile/FindEndOfStatementTest.php | 1 - Tests/Utils/UseStatements/UseTypeTest.php | 2 +- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php b/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php index 0928f5a8..9d8eedc4 100644 --- a/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php +++ b/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php @@ -483,8 +483,6 @@ public function getActualArrayKey(File $phpcsFile, $startPtr, $endPtr) * an acceptable index key for an array and if not, what it would turn into. */ - $integerKey = false; - switch (\gettype($key)) { case 'NULL': // An array key of `null` will become an empty string. diff --git a/PHPCSUtils/Utils/Lists.php b/PHPCSUtils/Utils/Lists.php index af62a044..368caef4 100644 --- a/PHPCSUtils/Utils/Lists.php +++ b/PHPCSUtils/Utils/Lists.php @@ -15,6 +15,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\GetTokensAsString; +use PHPCSUtils\Utils\Parentheses; /** * Utility functions to retrieve information when working with lists. diff --git a/PHPCSUtils/Utils/Namespaces.php b/PHPCSUtils/Utils/Namespaces.php index 7d8c7c0f..68009e3a 100644 --- a/PHPCSUtils/Utils/Namespaces.php +++ b/PHPCSUtils/Utils/Namespaces.php @@ -164,8 +164,7 @@ public static function getDeclaredName(File $phpcsFile, $stackPtr, $clean = true return false; } - $tokens = $phpcsFile->getTokens(); - $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), ($endOfStatement + 1), true); + $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), ($endOfStatement + 1), true); if ($next === $endOfStatement) { // Declaration of global namespace. I.e.: namespace {}. // If not a scoped {} namespace declaration, no name/global declarations are invalid diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index ab38f0d4..4eb22cf7 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -223,7 +223,6 @@ public function testArrowFunctionReturnValue() $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testArrowFunctionReturnValue */') + 2); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); $this->assertSame(($start + 18), $found); } } diff --git a/Tests/Utils/UseStatements/UseTypeTest.php b/Tests/Utils/UseStatements/UseTypeTest.php index d58f179e..4faef85f 100644 --- a/Tests/Utils/UseStatements/UseTypeTest.php +++ b/Tests/Utils/UseStatements/UseTypeTest.php @@ -52,7 +52,7 @@ public function testNonUseToken() { $this->expectPhpcsException('$stackPtr must be of type T_USE'); - $result = UseStatements::getType(self::$phpcsFile, 0); + UseStatements::getType(self::$phpcsFile, 0); } /** From 6a4b4fdad03c53c46569cf3ccda26048fd605095 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 11 Feb 2020 16:20:36 +0100 Subject: [PATCH 33/48] ControlStructures/IsElseIfTest: bug fix Three tests were using the wrong test markers. In effect these three cases were therefore not being tested. Fixed now. --- Tests/Utils/ControlStructures/IsElseIfTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Utils/ControlStructures/IsElseIfTest.php b/Tests/Utils/ControlStructures/IsElseIfTest.php index d2a663d0..d25dfb2a 100644 --- a/Tests/Utils/ControlStructures/IsElseIfTest.php +++ b/Tests/Utils/ControlStructures/IsElseIfTest.php @@ -112,15 +112,15 @@ public function dataIsElseIf() ], 'inline-if' => [ - '/* testAlternativeIf */', + '/* testInlineIf */', false, ], 'inline-elseif' => [ - '/* testAlternativeElseIf */', + '/* testInlineElseIf */', true, ], 'inline-else' => [ - '/* testAlternativeElse */', + '/* testInlineElse */', false, ], From b133843232590e13e003af8bb01d7b50371294a3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 11 Feb 2020 16:12:33 +0100 Subject: [PATCH 34/48] FindEndOfStatementTest: simplify the tests These are the same changes as pulled upstream in squizlabs/PHP_CodeSniffer 2866 * Use the `AbstractMethodUnitTest::getTargetToken()` method instead of doing a `findNext()` with a calculation. This makes the `$start` token retrieval more descriptive. * Assert based on the token pointers, not the sub-array value. As for both the "expected" as well as "found" values, the token sub-array is retrieved from the same `$tokens` variable, if the token pointers are the same, the sub-arrays will be too, so doing the comparison based on the sub-array doesn't add any extra value to the test. Also: doing an array assertion is more expensive than doing a simple integer based assertion. * Remove redundant calls to the `getTokens()` method. --- .../BCFile/FindEndOfStatementTest.php | 66 +++++++------------ 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index b93d21c8..bccaa733 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -43,11 +43,10 @@ class FindEndOfStatementTest extends UtilityMethodTestCase */ public function testSimpleAssignment() { - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testSimpleAssignment */') + 2); + $start = $this->getTargetToken('/* testSimpleAssignment */', T_VARIABLE); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 5)], $tokens[$found]); + $this->assertSame(($start + 5), $found); } /** @@ -57,11 +56,10 @@ public function testSimpleAssignment() */ public function testControlStructure() { - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testControlStructure */') + 2); + $start = $this->getTargetToken('/* testControlStructure */', T_WHILE); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 6)], $tokens[$found]); + $this->assertSame(($start + 6), $found); } /** @@ -71,11 +69,10 @@ public function testControlStructure() */ public function testClosureAssignment() { - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testClosureAssignment */') + 2); + $start = $this->getTargetToken('/* testClosureAssignment */', T_VARIABLE, '$a'); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 13)], $tokens[$found]); + $this->assertSame(($start + 13), $found); } /** @@ -86,25 +83,22 @@ public function testClosureAssignment() public function testHeredocFunctionArg() { // Find the end of the function. - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testHeredocFunctionArg */') + 2); + $start = $this->getTargetToken('/* testHeredocFunctionArg */', T_STRING, 'myFunction'); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 10)], $tokens[$found]); + $this->assertSame(($start + 10), $found); // Find the end of the heredoc. $start += 2; $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 4)], $tokens[$found]); + $this->assertSame(($start + 4), $found); // Find the end of the last arg. $start = ($found + 2); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[$start], $tokens[$found]); + $this->assertSame($start, $found); } /** @@ -115,25 +109,22 @@ public function testHeredocFunctionArg() public function testSwitch() { // Find the end of the switch. - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testSwitch */') + 2); + $start = $this->getTargetToken('/* testSwitch */', T_SWITCH); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 28)], $tokens[$found]); + $this->assertSame(($start + 28), $found); // Find the end of the case. $start += 9; $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 8)], $tokens[$found]); + $this->assertSame(($start + 8), $found); // Find the end of default case. $start += 11; $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 6)], $tokens[$found]); + $this->assertSame(($start + 6), $found); } /** @@ -144,25 +135,22 @@ public function testSwitch() public function testStatementAsArrayValue() { // Test short array syntax. - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testStatementAsArrayValue */') + 7); + $start = $this->getTargetToken('/* testStatementAsArrayValue */', T_NEW); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 2)], $tokens[$found]); + $this->assertSame(($start + 2), $found); // Test long array syntax. $start += 12; $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 2)], $tokens[$found]); + $this->assertSame(($start + 2), $found); // Test same statement outside of array. $start += 10; $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 3)], $tokens[$found]); + $this->assertSame(($start + 3), $found); } /** @@ -172,11 +160,10 @@ public function testStatementAsArrayValue() */ public function testUseGroup() { - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testUseGroup */') + 2); + $start = $this->getTargetToken('/* testUseGroup */', T_USE); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 23)], $tokens[$found]); + $this->assertSame(($start + 23), $found); } /** @@ -186,11 +173,10 @@ public function testUseGroup() */ public function testArrowFunctionArrayValue() { - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testArrowFunctionArrayValue */') + 7); + $start = $this->getTargetToken('/* testArrowFunctionArrayValue */', Collections::arrowFunctionTokensBC()); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $tokens = self::$phpcsFile->getTokens(); - $this->assertSame($tokens[($start + 9)], $tokens[$found]); + $this->assertSame(($start + 9), $found); } /** @@ -200,10 +186,8 @@ public function testArrowFunctionArrayValue() */ public function testStaticArrowFunction() { - $fnTargets = Collections::arrowFunctionTokensBC(); - - $static = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testStaticArrowFunction */') + 2); - $fn = self::$phpcsFile->findNext($fnTargets, ($static + 1)); + $static = $this->getTargetToken('/* testStaticArrowFunction */', T_STATIC); + $fn = $this->getTargetToken('/* testStaticArrowFunction */', Collections::arrowFunctionTokensBC()); $endOfStatementStatic = BCFile::findEndOfStatement(self::$phpcsFile, $static); $endOfStatementFn = BCFile::findEndOfStatement(self::$phpcsFile, $fn); @@ -218,7 +202,7 @@ public function testStaticArrowFunction() */ public function testArrowFunctionReturnValue() { - $start = (self::$phpcsFile->findNext(T_COMMENT, 0, null, false, '/* testArrowFunctionReturnValue */') + 2); + $start = $this->getTargetToken('/* testArrowFunctionReturnValue */', Collections::arrowFunctionTokensBC()); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); $this->assertSame(($start + 18), $found); From eb2c9b7e430aaf3b21132160e6da5b7d0cf79d4d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 12 Feb 2020 23:40:07 +0100 Subject: [PATCH 35/48] Composer: add PHPCSDevCS dependency The `PHPCSDev` ruleset has been split off from PHPCSDevTools to its own package. Refs: * https://github.com/PHPCSStandards/PHPCSDevCS * PHPCSStandards/PHPCSDevTools 29 --- composer.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index eb348945..06d1d94a 100644 --- a/composer.json +++ b/composer.json @@ -46,24 +46,24 @@ "lint": [ "@php ./vendor/jakub-onderka/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git" ], - "install-devtools": [ - "composer require phpcsstandards/phpcsdevtools:\"^1.0 || dev-develop\" --no-suggest --update-no-dev" + "install-devcs": [ + "composer require phpcsstandards/phpcsdevcs:\"^1.0\" --no-suggest --update-no-dev" ], - "remove-devtools": [ - "composer remove phpcsstandards/phpcsdevtools --update-no-dev" + "remove-devcs": [ + "composer remove phpcsstandards/phpcsdevcs --update-no-dev" ], "checkcs": [ - "@install-devtools", + "@install-devcs", "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs", - "@remove-devtools" + "@remove-devcs" ], "fixcs": [ - "@install-devtools", + "@install-devcs", "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf", - "@remove-devtools" + "@remove-devcs" ], "travis-checkcs": [ - "@install-devtools", + "@install-devcs", "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs" ], "test": [ From ad74f77de0d31c83431f620e4924356dbf4c4be0 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 13 Feb 2020 08:44:35 +0100 Subject: [PATCH 36/48] Arrays::getDoubleArrowPtr(): work around tokenizer bug in PHPCS 3.5.4 The double arrow directly after a `fn` would be tokenized as `T_STRING` in PHPCS 3.5.4. Fixed now. Includes unit test. Ref: squizlabs/PHP_CodeSniffer 2865 --- PHPCSUtils/Utils/Arrays.php | 11 ++++++++++- Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc | 5 ++++- Tests/Utils/Arrays/GetDoubleArrowPtrTest.php | 6 +++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index e1940b9f..a6466f7d 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -265,7 +265,8 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) ); } - $targets = self::$doubleArrowTargets + Collections::$closedScopes; + $targets = self::$doubleArrowTargets; + $targets += Collections::$closedScopes; $targets += Collections::arrowFunctionTokensBC(); $doubleArrow = ($start - 1); @@ -285,6 +286,14 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) return $doubleArrow; } + /* + * 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'] === '=>') { + return $doubleArrow; + } + // Skip over closed scopes which may contain foreach structures or generators. if (isset(Collections::$closedScopes[$tokens[$doubleArrow]['code']]) === true && isset($tokens[$doubleArrow]['scope_closer']) === true diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc index f732d5dd..231ecece 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc @@ -81,6 +81,9 @@ $array = [ /* testTstringKeyNotFnFunction */ CONSTANT_NAME => 'value', - /* testPropertyAccessPHPCS353-354 */ + /* testKeyPropertyAccessFnPHPCS353-354 */ ($obj->fn) => 'value', + + /* testDoubleArrowTokenizedAsTstring-PHPCS2865 */ + $obj->fn => 'value', ]; diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php index e5dc28d9..c1ca43c0 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php @@ -210,9 +210,13 @@ public function dataGetDoubleArrowPtr() ], // Test specifically for PHPCS 3.5.3 and 3.5.4 in which all "fn" tokens were tokenized as T_FN. 'test-arrow-access-to-property-named-fn-as-key-phpcs-3.5.3-3.5.4' => [ - '/* testPropertyAccessPHPCS353-354 */', + '/* testKeyPropertyAccessFnPHPCS353-354 */', 12, ], + 'test-double-arrow-incorrectly-tokenized-phpcs-issue-2865' => [ + '/* testDoubleArrowTokenizedAsTstring-PHPCS2865 */', + 10, + ], ]; } } From 5238b8dbbe5907fce2a9836203edec48a6148bcb Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 12 Feb 2020 04:53:23 +0100 Subject: [PATCH 37/48] QA: Various minor tweaks --- PHPCSUtils/BackCompat/BCTokens.php | 2 +- PHPCSUtils/BackCompat/Helper.php | 2 +- PHPCSUtils/TestUtils/UtilityMethodTestCase.php | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCTokens.php b/PHPCSUtils/BackCompat/BCTokens.php index 60514e01..26d2829a 100644 --- a/PHPCSUtils/BackCompat/BCTokens.php +++ b/PHPCSUtils/BackCompat/BCTokens.php @@ -189,7 +189,7 @@ public static function comparisonTokens() */ public static function arithmeticTokens() { - return Tokens::$arithmeticTokens + [ \T_POW => \T_POW ]; + return Tokens::$arithmeticTokens + [\T_POW => \T_POW]; } /** diff --git a/PHPCSUtils/BackCompat/Helper.php b/PHPCSUtils/BackCompat/Helper.php index 5af02ca9..cdc6edf5 100644 --- a/PHPCSUtils/BackCompat/Helper.php +++ b/PHPCSUtils/BackCompat/Helper.php @@ -145,7 +145,7 @@ public static function getTabWidth(File $phpcsFile) { $tabWidth = self::getCommandLineData($phpcsFile, 'tabWidth'); if ($tabWidth > 0) { - return $tabWidth; + return (int) $tabWidth; } return self::DEFAULT_TABWIDTH; diff --git a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php index 7ad0e253..f92c7581 100644 --- a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php @@ -177,14 +177,14 @@ public static function setUpTestFile() } if (\is_readable($caseFile) === false) { - self::fail("Test case file missing. Expected case file location: $caseFile"); + parent::fail("Test case file missing. Expected case file location: $caseFile"); } $contents = \file_get_contents($caseFile); if (\version_compare(Helper::getVersion(), '2.99.99', '>')) { // PHPCS 3.x. - $config = new \PHP_Codesniffer\Config(); + $config = new \PHP_CodeSniffer\Config(); /* * We just need to provide a standard so PHPCS will tokenize the file. @@ -239,7 +239,7 @@ public static function setUpTestFile() // Fail the test if the case file failed to tokenize. if (self::$phpcsFile->numTokens === 0) { - self::fail("Tokenizing of the test case file failed for case file: $caseFile"); + parent::fail("Tokenizing of the test case file failed for case file: $caseFile"); } } From d8e4a0a3af0536e5ce472247b53dd7e7d7cb8b65 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 12 Feb 2020 04:54:02 +0100 Subject: [PATCH 38/48] Various minor documentation fixes --- PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php | 2 +- PHPCSUtils/Fixers/SpacesFixer.php | 2 +- PHPCSUtils/Utils/Arrays.php | 18 +++++++++--------- PHPCSUtils/Utils/Lists.php | 18 +++++++++--------- PHPCSUtils/Utils/Operators.php | 6 +++--- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php b/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php index 8d82c3f6..6d50c9df 100644 --- a/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php +++ b/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php @@ -13,7 +13,7 @@ /* * Here be magic. * - * This include allows for the Utility functions to work PHPCS cross-version. + * This `include` allows for the Utility functions to work in both PHPCS 2.x as well as PHPCS 3.x. */ require_once \dirname(\dirname(\dirname(__DIR__))) . '/phpcsutils-autoload.php'; diff --git a/PHPCSUtils/Fixers/SpacesFixer.php b/PHPCSUtils/Fixers/SpacesFixer.php index 1dc777a1..ac22cbc2 100644 --- a/PHPCSUtils/Fixers/SpacesFixer.php +++ b/PHPCSUtils/Fixers/SpacesFixer.php @@ -70,7 +70,7 @@ class SpacesFixer * same sniff. * @param string $errorType Optional. Whether to report the issue as a * `warning` or an `error`. Defaults to `error`. - * @param string $errorSeverity Optional. The severity level for this message. + * @param int $errorSeverity Optional. The severity level for this message. * A value of 0 will be converted into the default * severity level. * @param string $metricName Optional. The name of the metric to record. diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index a6466f7d..750da555 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -182,15 +182,15 @@ public static function isShortArray(File $phpcsFile, $stackPtr) * * @since 1.0.0 * - * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the T_ARRAY or T_OPEN_SHORT_ARRAY - * token in the stack. - * @param true|null $isShortArray Short-circuit the short array check for T_OPEN_SHORT_ARRAY - * tokens if it isn't necessary. - * Efficiency tweak for when this has already been established, - * i.e. when encountering a nested array while walking the - * tokens in an array. - * Use with care. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the T_ARRAY or T_OPEN_SHORT_ARRAY + * token in the stack. + * @param true|null $isShortArray Short-circuit the short array check for T_OPEN_SHORT_ARRAY + * tokens if it isn't necessary. + * Efficiency tweak for when this has already been established, + * i.e. when encountering a nested array while walking the + * tokens in an array. + * Use with care. * * @return array|false Array with two keys `opener`, `closer` or false if * not a (short) array token or if the opener/closer diff --git a/PHPCSUtils/Utils/Lists.php b/PHPCSUtils/Utils/Lists.php index 368caef4..0623722f 100644 --- a/PHPCSUtils/Utils/Lists.php +++ b/PHPCSUtils/Utils/Lists.php @@ -154,15 +154,15 @@ public static function isShortList(File $phpcsFile, $stackPtr) * * @since 1.0.0 * - * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the T_LIST or T_OPEN_SHORT_ARRAY - * token in the stack. - * @param true|null $isShortList Short-circuit the short list check for T_OPEN_SHORT_ARRAY - * tokens if it isn't necessary. - * Efficiency tweak for when this has already been established, - * i.e. when encountering a nested list while walking the - * tokens in a list. - * Use with care. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the T_LIST or T_OPEN_SHORT_ARRAY + * token in the stack. + * @param true|null $isShortList Short-circuit the short list check for T_OPEN_SHORT_ARRAY + * tokens if it isn't necessary. + * Efficiency tweak for when this has already been established, + * i.e. when encountering a nested list while walking the + * tokens in a list. + * Use with care. * * @return array|false Array with two keys `opener`, `closer` or false if * not a (short) list token or if the opener/closer diff --git a/PHPCSUtils/Utils/Operators.php b/PHPCSUtils/Utils/Operators.php index ff4ac3b9..272b4c8d 100644 --- a/PHPCSUtils/Utils/Operators.php +++ b/PHPCSUtils/Utils/Operators.php @@ -234,9 +234,9 @@ public static function isUnaryPlusMinus(File $phpcsFile, $stackPtr) * * @since 1.0.0 * - * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the ternary then/else - * operator in the stack. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the ternary then/else + * operator in the stack. * * @return bool True if short ternary, or false otherwise. */ From 0bce0fb627de4ce1edfa010edbc629ca9031526d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 14 Feb 2020 22:49:59 +0100 Subject: [PATCH 39/48] Docs: add some missing `@since` tags --- PHPCSUtils/TestUtils/UtilityMethodTestCase.php | 6 ++++++ PHPCSUtils/Tokens/Collections.php | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php index f92c7581..8949855e 100644 --- a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php @@ -117,6 +117,8 @@ abstract class UtilityMethodTestCase extends TestCase * the same directory and named the same as the test class, but with an * `inc` file extension. * + * @since 1.0.0 + * * @var string */ protected static $caseFile = ''; @@ -126,6 +128,8 @@ abstract class UtilityMethodTestCase extends TestCase * * This allows for test case files to use a different tab width than the default. * + * @since 1.0.0 + * * @var int */ protected static $tabWidth = 4; @@ -321,6 +325,8 @@ public function getTargetToken($commentString, $tokenType, $tokenContent = null) * Helper method to tell PHPUnit to expect a PHPCS Exception in a PHPUnit cross-version * compatible manner. * + * @since 1.0.0 + * * @param string $msg The expected exception message. * @param string $type The exception type to expect. Either 'runtime' or 'tokenizer'. * Defaults to 'runtime'. diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index a03bceb2..8c41bcfe 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -27,6 +27,8 @@ class Collections /** * Control structures which can use the alternative control structure syntax. * + * @since 1.0.0-alpha2 + * * @var array => */ public static $alternativeControlStructureSyntaxTokens = [ @@ -43,6 +45,8 @@ class Collections /** * Alternative control structure syntax closer keyword tokens. * + * @since 1.0.0-alpha2 + * * @var array => */ public static $alternativeControlStructureSyntaxCloserTokens = [ @@ -128,6 +132,8 @@ class Collections /** * Control structure tokens. * + * @since 1.0.0-alpha2 + * * @var array => */ public static $controlStructureTokens = [ From b0301661378481bb925d877b0a8900e7639a6a7b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 15 Feb 2020 00:17:08 +0100 Subject: [PATCH 40/48] BCFile::getMethodProperties(): minor code tweak --- PHPCSUtils/BackCompat/BCFile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 18e88dd8..d1cfc680 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -667,12 +667,12 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) $bodyTokens = [T_DOUBLE_ARROW => T_DOUBLE_ARROW]; if (defined('T_FN_ARROW') === true) { // PHPCS 3.5.3+. - $bodyTokens = [T_FN_ARROW => T_FN_ARROW]; + $bodyTokens[T_FN_ARROW] = T_FN_ARROW; } } $end = $phpcsFile->findNext(($bodyTokens + [T_SEMICOLON]), $parenthesisCloser); - $hasBody = isset($bodyTokens[$tokens[$end]['code']]); + $hasBody = ($end !== false && isset($bodyTokens[$tokens[$end]['code']])); } if ($returnType !== '' && $nullableReturnType === true) { From 379013fb144d82f0eac16076d4ba306c17d07de9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 14 Feb 2020 23:58:51 +0100 Subject: [PATCH 41/48] Utils\Numbers: replace `$unsupportedPHPCSVersions` with `UNSUPPORTED_PHPCS_VERSION` As the fix for the broken backfill in PHPCS 3.5.3 was released in PHPCS 3.5.4, there is only one PHPCS version which is unsupported. This negates the need for an array, making it possible to use a class constant instead which should be less risky as it cannot be overloaded. Includes adjusting all places in the code base which were using the property to use the constant instead. --- PHPCSUtils/Utils/Numbers.php | 14 ++++++-------- Tests/Utils/Numbers/GetCompleteNumberTest.php | 7 +++---- Tests/Utils/Operators/IsUnaryPlusMinusTest.php | 4 +--- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/PHPCSUtils/Utils/Numbers.php b/PHPCSUtils/Utils/Numbers.php index 22058831..c05788f9 100644 --- a/PHPCSUtils/Utils/Numbers.php +++ b/PHPCSUtils/Utils/Numbers.php @@ -120,12 +120,12 @@ class Numbers * PHPCS versions in which the backfill for PHP 7.4 numeric literal separators is broken. * * @since 1.0.0 + * @since 1.0.0-alpha2 Changed from a property to a class constant. + * Changed from an array to a string. * - * @var array + * @var string */ - public static $unsupportedPHPCSVersions = [ - '3.5.3' => true, - ]; + const UNSUPPORTED_PHPCS_VERSION = '3.5.3'; /** * Valid tokens which could be part of a numeric literal sequence in PHP < 7.4. @@ -177,7 +177,6 @@ class Numbers */ public static function getCompleteNumber(File $phpcsFile, $stackPtr) { - static $php74, $phpcsVersion, $phpcsWithBackfill; $tokens = $phpcsFile->getTokens(); @@ -193,8 +192,7 @@ public static function getCompleteNumber(File $phpcsFile, $stackPtr) if (isset($php74, $phpcsVersion, $phpcsWithBackfill) === false) { $php74 = \version_compare(\PHP_VERSION_ID, '70399', '>'); $phpcsVersion = Helper::getVersion(); - $maxUnsupported = \max(\array_keys(self::$unsupportedPHPCSVersions)); - $phpcsWithBackfill = \version_compare($phpcsVersion, $maxUnsupported, '>'); + $phpcsWithBackfill = \version_compare($phpcsVersion, self::UNSUPPORTED_PHPCS_VERSION, '>'); } /* @@ -203,7 +201,7 @@ public static function getCompleteNumber(File $phpcsFile, $stackPtr) * * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2546 */ - if (isset(self::$unsupportedPHPCSVersions[$phpcsVersion]) === true) { + if (\version_compare($phpcsVersion, self::UNSUPPORTED_PHPCS_VERSION, '==') === true) { throw new RuntimeException('The ' . __METHOD__ . '() method does not support PHPCS ' . $phpcsVersion); } diff --git a/Tests/Utils/Numbers/GetCompleteNumberTest.php b/Tests/Utils/Numbers/GetCompleteNumberTest.php index 4a15c03c..4b69becb 100644 --- a/Tests/Utils/Numbers/GetCompleteNumberTest.php +++ b/Tests/Utils/Numbers/GetCompleteNumberTest.php @@ -60,8 +60,7 @@ public static function setUpStaticProperties() self::$phpcsVersion = Helper::getVersion(); self::$php74OrHigher = \version_compare(\PHP_VERSION_ID, '70399', '>'); - $maxUnsupported = \max(\array_keys(Numbers::$unsupportedPHPCSVersions)); - self::$usableBackfill = \version_compare(self::$phpcsVersion, $maxUnsupported, '>'); + self::$usableBackfill = \version_compare(self::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '>'); } /** @@ -85,7 +84,7 @@ public function testNotANumberException() public function testUnsupportedPhpcsException() { self::setUpStaticProperties(); - if (isset(Numbers::$unsupportedPHPCSVersions[self::$phpcsVersion]) === false) { + if (\version_compare(self::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '!=') === true) { $this->markTestSkipped('Test specific to a limited set of PHPCS versions'); } @@ -111,7 +110,7 @@ public function testGetCompleteNumber($testMarker, $expected) { // Skip the test(s) on unsupported PHPCS versions. self::setUpStaticProperties(); - if (isset(Numbers::$unsupportedPHPCSVersions[self::$phpcsVersion]) === true) { + if (\version_compare(self::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '==') === true) { $this->markTestSkipped( 'PHPCS ' . self::$phpcsVersion . ' is not supported due to buggy numeric string literal backfill.' ); diff --git a/Tests/Utils/Operators/IsUnaryPlusMinusTest.php b/Tests/Utils/Operators/IsUnaryPlusMinusTest.php index 2addb23e..77d7bd0d 100644 --- a/Tests/Utils/Operators/IsUnaryPlusMinusTest.php +++ b/Tests/Utils/Operators/IsUnaryPlusMinusTest.php @@ -72,9 +72,7 @@ public function testIsUnaryPlusMinus($testMarker, $expected, $maybeSkip = false) $this->markTestSkipped($skipMessage); } - $phpcsVersion = Helper::getVersion(); - $minVersionWithBackfill = \min(\array_keys(Numbers::$unsupportedPHPCSVersions)); - if (\version_compare($phpcsVersion, $minVersionWithBackfill, '>=') === true) { + if (\version_compare(Helper::getVersion(), Numbers::UNSUPPORTED_PHPCS_VERSION, '>=') === true) { $this->markTestSkipped($skipMessage); } } From efe38d3c46797af36a22c033c2befaf84971bc7f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 28 Aug 2019 03:29:49 +0200 Subject: [PATCH 42/48] :books: Readme: add installation instructions Add badges, feature description, installation instructions, a contributing section and license information to the Readme. --- README.md | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 244 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1e7a4380..d7ab40b3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,244 @@ -# PHPCSUtils -A suite of utility functions for use with PHP_CodeSniffer +PHPCSUtils: A suite of utility functions for use with PHP_CodeSniffer +===================================================== + +[![Latest Stable Version](https://poser.pugx.org/phpcsstandards/phpcsutils/v/stable)](https://packagist.org/packages/phpcsstandards/phpcsutils) +[![Travis Build Status](https://travis-ci.com/PHPCSStandards/PHPCSUtils.svg?branch=master)](https://travis-ci.com/PHPCSStandards/PHPCSUtils/branches) +[![Release Date of the Latest Version](https://img.shields.io/github/release-date/PHPCSStandards/PHPCSUtils.svg?maxAge=1800)](https://github.com/PHPCSStandards/PHPCSUtils/releases) +:construction: +[![Latest Unstable Version](https://img.shields.io/badge/unstable-dev--develop-e68718.svg?maxAge=2419200)](https://packagist.org/packages/phpcsstandards/phpcsutils#dev-develop) +[![Travis Build Status](https://travis-ci.com/PHPCSStandards/PHPCSUtils.svg?branch=develop)](https://travis-ci.com/PHPCSStandards/PHPCSUtils/branches) +[![Last Commit to Unstable](https://img.shields.io/github/last-commit/PHPCSStandards/PHPCSUtils/develop.svg)](https://github.com/PHPCSStandards/PHPCSUtils/commits/develop) + +[![Minimum PHP Version](https://img.shields.io/packagist/php-v/phpcsstandards/phpcsutils.svg?maxAge=3600)](https://packagist.org/packages/phpcsstandards/phpcsutils) +[![Tested on PHP 5.4 to 7.4](https://img.shields.io/badge/tested%20on-PHP%205.4%20|%205.5%20|%205.6%20|%207.0%20|%207.1%20|%207.2%20|%207.3%20|%207.4-brightgreen.svg?maxAge=2419200)](https://travis-ci.com/PHPCSStandards/PHPCSUtils) +[![Coverage Status](https://coveralls.io/repos/github/PHPCSStandards/PHPCSUtils/badge.svg)](https://coveralls.io/github/PHPCSStandards/PHPCSUtils) + +[![License: LGPLv3](https://poser.pugx.org/phpcsstandards/phpcsutils/license)](https://github.com/PHPCSStandards/PHPCSUtils/blob/master/LICENSE) +![Awesome](https://img.shields.io/badge/awesome%3F-yes!-brightgreen.svg) + + +* [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) + + [Non-Composer based integration](#non-composer-based-integration) +* [Frequently Asked Questions](#frequently-asked-questions) +* [Contributing](#contributing) +* [License](#license) + + +Features +------------------------------------------- + +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: + +### 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. + +### A number of 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. + +### A collection of static properties for often used token groups. + +Collections of related tokens as 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 got you covered! + +Includes improved versions of the PHPCS native utility functions and plenty 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. +Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 8.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. + +### 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/). + + +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: +```bash +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. + +> :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 may want to 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. + + +### Non-Composer based integration + +In this case, more than anything, you will need to update the non-Composer installation instructions for your end-users. + +To use a non-Composer based installation for your sniff development environment, the same instructions would apply. + +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). +> * 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: +> ```bash +> phpcs --config-set installed_paths /path/to/YourStandardName +> ``` +> **Warning**: :warning: The `installed_paths` command overwrites any previously set `installed_paths`. If you have previously set `installed_paths` for other external standards, run `phpcs --config-show` first and then run the `installed_paths` command with all the paths you need separated by comma's, i.e.: +> ```bash +> phpcs --config-set installed_paths /path/1,/path/2,/path/3 +> ``` + +For things to continue working when you add PHPCSUtils to your standard, you need to replace the last bullet with this: + +> * **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: +> ```bash +> phpcs --config-set installed_paths /path/to/YourStandardName,/path/to/PHPCSUtils +> ``` +> **Warning**: :warning: The `installed_paths` command overwrites any previously set `installed_paths`. If you have previously set `installed_paths` for other external standards, run `phpcs --config-show` first and then run the `installed_paths` command with all the paths you need separated by comma's, i.e.: +> ```bash +> phpcs --config-set installed_paths /path/1,/path/2,/path/3 +> ``` + +#### Running your unit tests + +To support non-Composer based installs for running your sniff unit tests, you will need to adjust the PHPUnit `bootstrap.php` file to allow for passing an environment variable pointing to your PHPCSUtils installation. + +
+ Example bootstrap code using a PHPCSUTILS_DIR environment variable + +```php +// Get the PHPCS dir from an environment variable. +$phpcsUtilDir = getenv('PHPCSUTILS_DIR'); + +// This may be a Composer install. +if ($phpcsUtilDir === false && file_exists(__DIR__ . '/vendor/autoload.php')) { + $vendorDir = __DIR__ . '/vendor'; + $phpcsUtilDir = $vendorDir . '/phpcsstandards/phpcsutils'; + + // Load the Composer autoload file. + require_once $vendorDir . '/autoload.php'; + + // This snippet is only needed when you use the PHPCSUtils TestUtils or if your standard still supports PHPCS 2.x. + if (file_exists($phpcsUtilDir . '/phpcsutils-autoload.php')) { + require_once $phpcsUtilDir . '/phpcsutils-autoload.php'; + } + +} elseif ($phpcsUtilDir !== false) { + $phpcsUtilDir = realpath($phpcsUtilDir); + + require_once $phpcsUtilDir . '/phpcsutils-autoload.php'; +} else { + echo 'Uh oh... can\'t find PHPCSUtils. + +If you use Composer, please run `composer install`. +Otherwise, make sure you set a `PHPCSUTILS_DIR` environment variable in your phpunit.xml file +pointing to the PHPCS directory. +'; + + die(1); +} +``` + +
+ +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 + + + + ``` + + +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 ? + +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. Just 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. + +License +------- +This code is released under the GNU Lesser General Public License (LGPLv3). For more information, visit http://www.gnu.org/copyleft/lesser.html From 274d18adee282a9f6da31db3fd56ea0e0bf3c448 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 8 Nov 2019 08:35:55 +0100 Subject: [PATCH 43/48] Set up PHPDocumentor This adds the configuration for running [PHPDocumentor](https://github.com/phpDocumentor/phpDocumentor) for PHPCSUtils. The documentation can be generated with PHPDocumentor 3.x by running the `phpdoc` command from the root of the project. PHPDocumentor has _not_ been added to the project dependencies as it is only needed intermittely - once for each release - when generating the documentation and doing so with a phar install is recommended by the developers of PHPDocumentor. The documentation will be published as a [GitHub Pages](https://pages.github.com/) website at the webaddress https://phpcsutils.com/ . --- .gitattributes | 2 ++ .gitignore | 1 + composer.json | 4 +++- phpcs.xml.dist | 3 +++ phpdoc.xml.dist | 22 ++++++++++++++++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 phpdoc.xml.dist diff --git a/.gitattributes b/.gitattributes index 2ce6c7da..05317e78 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10,7 +10,9 @@ /.gitignore export-ignore /.travis.yml export-ignore /phpcs.xml.dist export-ignore +/phpdoc.xml.dist export-ignore /phpunit.xml.dist export-ignore +/docs/ export-ignore /Tests/ export-ignore # diff --git a/.gitignore b/.gitignore index de278d07..d1df7be2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ vendor/ /composer.lock /.phpcs.xml /phpcs.xml +/phpdoc.xml /phpunit.xml /.phpunit.result.cache diff --git a/composer.json b/composer.json index 06d1d94a..a8d5b380 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,7 @@ "type" : "phpcodesniffer-standard", "keywords" : [ "phpcs", "standards", "php_codesniffer", "phpcs2", "phpcs3", "tokens", "utility" ], "license" : "LGPL-3.0-or-later", + "homepage": "https://phpcsutils.com/", "authors" : [ { "name" : "Juliette Reinders Folmer", @@ -17,7 +18,8 @@ ], "support" : { "issues" : "https://github.com/PHPCSStandards/PHPCSUtils/issues", - "source" : "https://github.com/PHPCSStandards/PHPCSUtils" + "source" : "https://github.com/PHPCSStandards/PHPCSUtils", + "docs" : "https://phpcsutils.com/" }, "require" : { "php" : ">=5.4", diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 50b9e1e8..fea3a4bd 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -11,6 +11,9 @@ . + + */build/* + */vendor/* diff --git a/phpdoc.xml.dist b/phpdoc.xml.dist new file mode 100644 index 00000000..91b6cffd --- /dev/null +++ b/phpdoc.xml.dist @@ -0,0 +1,22 @@ + + + PHPCSUtils + + + phpcsutils-autoload.php + PHPCSUtils + + + + build/docs/structure/ + + + + docs/phpdoc/ + + + + info + + + From 4213746a1d5595514c44fc1437007bda5b17e083 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 14 Feb 2020 23:20:33 +0100 Subject: [PATCH 44/48] Initial documentation generated by PHPDocumentor --- ...tSniffs-AbstractArrayDeclarationSniff.html | 1087 +++++++++++++ .../classes/PHPCSUtils-BackCompat-BCFile.html | 1420 +++++++++++++++++ .../PHPCSUtils-BackCompat-BCTokens.html | 721 +++++++++ .../classes/PHPCSUtils-BackCompat-Helper.html | 469 ++++++ .../PHPCSUtils-Fixers-SpacesFixer.html | 277 ++++ ...Utils-TestUtils-UtilityMethodTestCase.html | 523 ++++++ .../PHPCSUtils-Tokens-Collections.html | 761 +++++++++ .../classes/PHPCSUtils-Utils-Arrays.html | 360 +++++ .../classes/PHPCSUtils-Utils-Conditions.html | 429 +++++ .../PHPCSUtils-Utils-ControlStructures.html | 320 ++++ ...PHPCSUtils-Utils-FunctionDeclarations.html | 1189 ++++++++++++++ .../PHPCSUtils-Utils-GetTokensAsString.html | 730 +++++++++ .../classes/PHPCSUtils-Utils-Lists.html | 351 ++++ .../classes/PHPCSUtils-Utils-Namespaces.html | 518 ++++++ .../classes/PHPCSUtils-Utils-Numbers.html | 802 ++++++++++ .../PHPCSUtils-Utils-ObjectDeclarations.html | 609 +++++++ .../classes/PHPCSUtils-Utils-Operators.html | 332 ++++ .../classes/PHPCSUtils-Utils-Orthography.html | 320 ++++ .../classes/PHPCSUtils-Utils-Parentheses.html | 1028 ++++++++++++ .../PHPCSUtils-Utils-PassedParameters.html | 467 ++++++ .../classes/PHPCSUtils-Utils-Scopes.html | 360 +++++ .../classes/PHPCSUtils-Utils-TextStrings.html | 234 +++ .../PHPCSUtils-Utils-UseStatements.html | 449 ++++++ .../classes/PHPCSUtils-Utils-Variables.html | 431 +++++ docs/phpdoc/css/normalize.css | 427 +++++ docs/phpdoc/css/template.css | 915 +++++++++++ ...tsniffs-abstractarraydeclarationsniff.html | 85 + docs/phpdoc/files/phpcsutils-autoload.html | 78 + .../files/phpcsutils-backcompat-bcfile.html | 85 + .../files/phpcsutils-backcompat-bctokens.html | 85 + .../files/phpcsutils-backcompat-helper.html | 85 + .../files/phpcsutils-fixers-spacesfixer.html | 85 + ...utils-testutils-utilitymethodtestcase.html | 85 + .../files/phpcsutils-tokens-collections.html | 85 + .../phpdoc/files/phpcsutils-utils-arrays.html | 85 + .../files/phpcsutils-utils-conditions.html | 85 + .../phpcsutils-utils-controlstructures.html | 85 + ...phpcsutils-utils-functiondeclarations.html | 85 + .../phpcsutils-utils-gettokensasstring.html | 85 + docs/phpdoc/files/phpcsutils-utils-lists.html | 85 + .../files/phpcsutils-utils-namespaces.html | 86 + .../files/phpcsutils-utils-numbers.html | 85 + .../phpcsutils-utils-objectdeclarations.html | 85 + .../files/phpcsutils-utils-operators.html | 85 + .../files/phpcsutils-utils-orthography.html | 85 + .../files/phpcsutils-utils-parentheses.html | 86 + .../phpcsutils-utils-passedparameters.html | 86 + .../phpdoc/files/phpcsutils-utils-scopes.html | 85 + .../files/phpcsutils-utils-textstrings.html | 85 + .../files/phpcsutils-utils-usestatements.html | 85 + .../files/phpcsutils-utils-variables.html | 85 + docs/phpdoc/graphs/classes.html | 81 + docs/phpdoc/index.html | 80 + docs/phpdoc/js/search.js | 150 ++ docs/phpdoc/js/searchIndex.js | 1124 +++++++++++++ docs/phpdoc/namespaces/default.html | 83 + .../namespaces/phpcsutils-abstractsniffs.html | 87 + .../namespaces/phpcsutils-backcompat.html | 91 ++ docs/phpdoc/namespaces/phpcsutils-fixers.html | 87 + .../namespaces/phpcsutils-testutils.html | 87 + docs/phpdoc/namespaces/phpcsutils-tokens.html | 87 + docs/phpdoc/namespaces/phpcsutils-utils.html | 122 ++ docs/phpdoc/namespaces/phpcsutils.html | 88 + docs/phpdoc/packages/PHPCSUtils.html | 135 ++ docs/phpdoc/packages/default.html | 83 + docs/phpdoc/reports/deprecated.html | 82 + docs/phpdoc/reports/errors.html | 107 ++ docs/phpdoc/reports/markers.html | 104 ++ 68 files changed, 20328 insertions(+) create mode 100644 docs/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Tokens-Collections.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Arrays.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Conditions.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Lists.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Numbers.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Operators.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Orthography.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Scopes.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html create mode 100644 docs/phpdoc/classes/PHPCSUtils-Utils-Variables.html create mode 100644 docs/phpdoc/css/normalize.css create mode 100644 docs/phpdoc/css/template.css create mode 100644 docs/phpdoc/files/phpcsutils-abstractsniffs-abstractarraydeclarationsniff.html create mode 100644 docs/phpdoc/files/phpcsutils-autoload.html create mode 100644 docs/phpdoc/files/phpcsutils-backcompat-bcfile.html create mode 100644 docs/phpdoc/files/phpcsutils-backcompat-bctokens.html create mode 100644 docs/phpdoc/files/phpcsutils-backcompat-helper.html create mode 100644 docs/phpdoc/files/phpcsutils-fixers-spacesfixer.html create mode 100644 docs/phpdoc/files/phpcsutils-testutils-utilitymethodtestcase.html create mode 100644 docs/phpdoc/files/phpcsutils-tokens-collections.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-arrays.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-conditions.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-controlstructures.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-functiondeclarations.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-gettokensasstring.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-lists.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-namespaces.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-numbers.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-objectdeclarations.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-operators.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-orthography.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-parentheses.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-passedparameters.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-scopes.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-textstrings.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-usestatements.html create mode 100644 docs/phpdoc/files/phpcsutils-utils-variables.html create mode 100644 docs/phpdoc/graphs/classes.html create mode 100644 docs/phpdoc/index.html create mode 100644 docs/phpdoc/js/search.js create mode 100644 docs/phpdoc/js/searchIndex.js create mode 100644 docs/phpdoc/namespaces/default.html create mode 100644 docs/phpdoc/namespaces/phpcsutils-abstractsniffs.html create mode 100644 docs/phpdoc/namespaces/phpcsutils-backcompat.html create mode 100644 docs/phpdoc/namespaces/phpcsutils-fixers.html create mode 100644 docs/phpdoc/namespaces/phpcsutils-testutils.html create mode 100644 docs/phpdoc/namespaces/phpcsutils-tokens.html create mode 100644 docs/phpdoc/namespaces/phpcsutils-utils.html create mode 100644 docs/phpdoc/namespaces/phpcsutils.html create mode 100644 docs/phpdoc/packages/PHPCSUtils.html create mode 100644 docs/phpdoc/packages/default.html create mode 100644 docs/phpdoc/reports/deprecated.html create mode 100644 docs/phpdoc/reports/errors.html create mode 100644 docs/phpdoc/reports/markers.html diff --git a/docs/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html b/docs/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html new file mode 100644 index 00000000..6842e98d --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html @@ -0,0 +1,1087 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ AbstractArrayDeclarationSniff + + implements + Sniff +

+ + +

Abstract sniff to easily examine all parts of an array declaration.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
$stackPtrThe stack pointer to the array keyword or the short array open token.int
$tokensThe token stack for the current file being examined.array
$arrayOpenerThe stack pointer to the array opener.int
$arrayCloserThe stack pointer to the array closer.int
$arrayItemsA multi-dimentional array with information on each array item.array
$itemCountHow many items are in the array.int
$singleLineWhether or not the array is single line.bool
$acceptedTokensList of tokens which can safely be used with an eval() expression.array
__construct()Set up this class.void
register()Returns an array of tokens this test wants to listen for.array
process()Processes this test when one of its tokens is encountered.void
processArray()Process every part of the array declaration.void
processOpenClose()Process the array opener and closer.bool|void
processKey()Process the tokens in an array key.bool|void
processNoKey()Process an array item without an array key.bool|void
processArrow()Process the double arrow.bool|void
processValue()Process the tokens in an array value.bool|void
processComma()Process the comma after an array item.bool|void
getActualArrayKey()Determine what the actual array key would be.string|int|void
+ + +
+

Properties

+ +
+

$stackPtr

+ +

The stack pointer to the array keyword or the short array open token.

+ + protected + int + $stackPtr + +
+ + + + + + + +
+

$arrayItems

+ +

A multi-dimentional array with information on each array item.

+ + protected + array + $arrayItems + +
The array index is 1-based and contains the following information on each array item: +- 'start' : The stack pointer to the first token in the array item. +- 'end' : The stack pointer to the first token in the array item. +- 'raw' : A string with the contents of all tokens between `start` and `end`. +- 'clean' : Same as `raw`, but all comment tokens have been stripped out.
+
+ + + + + +
+

$acceptedTokens

+ +

List of tokens which can safely be used with an eval() expression.

+ + private + array + $acceptedTokens + = [\T_NULL => \T_NULL, \T_TRUE => \T_TRUE, \T_FALSE => \T_FALSE, \T_LNUMBER => \T_LNUMBER, \T_DNUMBER => \T_DNUMBER, \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, \T_STRING_CONCAT => \T_STRING_CONCAT, \T_INLINE_THEN => \T_INLINE_THEN, \T_INLINE_ELSE => \T_INLINE_ELSE, \T_BOOLEAN_NOT => \T_BOOLEAN_NOT] +
+
+ +
+

Methods

+ +
+

__construct()

+ +

Set up this class.

+ + public + final __construct( + ) + : void + + + + +
Tags
+
+
+ since +
+
+
+ codeCoverageIgnore +
+
+
+ + +
+ +
+

register()

+ +

Returns an array of tokens this test wants to listen for.

+ + public + register( + ) + : array + + + + +
Tags
+
+
+ since +
+
+
+ codeCoverageIgnore +
+
+
+ +
Return values
+ array + +
+ +
+

process()

+ +

Processes this test when one of its tokens is encountered.

+ + public + final process( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : void + + +

This method fills the properties with relevant information for examining the array +and then passes off to the processArray() method.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ $stackPtr + : int +
+

The position in the PHP_CodeSniffer +file's token stack where the token +was found.

+
+ +
Tags
+
+
+ since +
+
+
+ + +
+ +
+

processArray()

+ +

Process every part of the array declaration.

+ + public + processArray( + + $phpcsFile : + File + + ) + : void + + +

This contains the default logic for the sniff, but can be overloaded in a concrete child class +if needed.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ +
Tags
+
+
+ since +
+
+
+ + +
+ +
+

processOpenClose()

+ +

Process the array opener and closer.

+ + public + processOpenClose( + + $phpcsFile : + File + + + , $openPtr : + int + + + , $closePtr : + int + + ) + : bool|void + + +

Optional method to be implemented in concrete child classes.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ $openPtr + : int +
+

The position of the array opener token in the token stack.

+
+ $closePtr + : int +
+

The position of the array closer token in the token stack.

+
+ +
Tags
+
+
+ since +
+
+
+ codeCoverageIgnore +
+
+
+ +
Return values
+ bool|void + —

Returning true will short-circuit the sniff and stop processing.

+ +
+ +
+

processKey()

+ +

Process the tokens in an array key.

+ + public + processKey( + + $phpcsFile : + File + + + , $startPtr : + int + + + , $endPtr : + int + + + , $itemNr : + int + + ) + : bool|void + + +

Optional method to be implemented in concrete child classes.

+

The $startPtr and $endPtr do not discount whitespace or comments, but are all inclusive to +allow examining all tokens in an array key.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ $startPtr + : int +
+

The stack pointer to the first token in the "key" part of +an array item.

+
+ $endPtr + : int +
+

The stack pointer to the last token in the "key" part of +an array item.

+
+ $itemNr + : int +
+

Which item in the array is being handled. +1-based, i.e. the first item is item 1, the second 2 etc.

+
+ +
Tags
+
+
+ since +
+
+
+ codeCoverageIgnore +
+
+
+ see +
+

Optional helper function.

+
+ +
Return values
+ bool|void + —

Returning true will short-circuit the array item loop and stop processing.

+ +
+ +
+

processNoKey()

+ +

Process an array item without an array key.

+ + public + processNoKey( + + $phpcsFile : + File + + + , $startPtr : + int + + + , $itemNr : + int + + ) + : bool|void + + +

Optional method to be implemented in concrete child classes.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ $startPtr + : int +
+

The stack pointer to the first token in the array item, +which in this case will be the first token of the array +value part of the array item.

+
+ $itemNr + : int +
+

Which item in the array is being handled. +1-based, i.e. the first item is item 1, the second 2 etc.

+
+ +
Tags
+
+
+ since +
+
+
+ codeCoverageIgnore +
+
+
+ +
Return values
+ bool|void + —

Returning true will short-circuit the array item loop and stop processing.

+ +
+ +
+

processArrow()

+ +

Process the double arrow.

+ + public + processArrow( + + $phpcsFile : + File + + + , $arrowPtr : + int + + + , $itemNr : + int + + ) + : bool|void + + +

Optional method to be implemented in concrete child classes.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ $arrowPtr + : int +
+

The stack pointer to the double arrow for the array item.

+
+ $itemNr + : int +
+

Which item in the array is being handled. +1-based, i.e. the first item is item 1, the second 2 etc.

+
+ +
Tags
+
+
+ since +
+
+
+ codeCoverageIgnore +
+
+
+ +
Return values
+ bool|void + —

Returning true will short-circuit the array item loop and stop processing.

+ +
+ +
+

processValue()

+ +

Process the tokens in an array value.

+ + public + processValue( + + $phpcsFile : + File + + + , $startPtr : + int + + + , $endPtr : + int + + + , $itemNr : + int + + ) + : bool|void + + +

Optional method to be implemented in concrete child classes.

+

The $startPtr and $endPtr do not discount whitespace or comments, but are all inclusive to +allow examining all tokens in an array value.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ $startPtr + : int +
+

The stack pointer to the first token in the "value" part of +an array item.

+
+ $endPtr + : int +
+

The stack pointer to the last token in the "value" part of +an array item.

+
+ $itemNr + : int +
+

Which item in the array is being handled. +1-based, i.e. the first item is item 1, the second 2 etc.

+
+ +
Tags
+
+
+ since +
+
+
+ codeCoverageIgnore +
+
+
+ +
Return values
+ bool|void + —

Returning true will short-circuit the array item loop and stop processing.

+ +
+ +
+

processComma()

+ +

Process the comma after an array item.

+ + public + processComma( + + $phpcsFile : + File + + + , $commaPtr : + int + + + , $itemNr : + int + + ) + : bool|void + + +

Optional method to be implemented in concrete child classes.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ $commaPtr + : int +
+

The stack pointer to the comma.

+
+ $itemNr + : int +
+

Which item in the array is being handled. +1-based, i.e. the first item is item 1, the second 2 etc.

+
+ +
Tags
+
+
+ since +
+
+
+ codeCoverageIgnore +
+
+
+ +
Return values
+ bool|void + —

Returning true will short-circuit the array item loop and stop processing.

+ +
+ +
+

getActualArrayKey()

+ +

Determine what the actual array key would be.

+ + public + getActualArrayKey( + + $phpcsFile : + File + + + , $startPtr : + int + + + , $endPtr : + int + + ) + : string|int|void + + +

Optional helper function for processsing array keys in the processKey() function.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The PHP_CodeSniffer file where the +token was found.

+
+ $startPtr + : int +
+

The stack pointer to the first token in the "key" part of +an array item.

+
+ $endPtr + : int +
+

The stack pointer to the last token in the "key" part of +an array item.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ string|int|void + —

The string or integer array key or void if the array key could not +reliably be determined.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html b/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html new file mode 100644 index 00000000..4cedbeb9 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html @@ -0,0 +1,1420 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ BCFile +

+ + +

PHPCS native utility functions.

+

Backport of the latest versions of PHPCS native utility functions to make them +available in older PHPCS versions without the bugs and other quirks that the +older versions of the native functions had.

+

Additionally, this class works round the following tokenizer issues for +any affected utility functions:

+
    +
  • Array return type declarations were incorrectly tokenized to T_ARRAY_HINT +instead of T_RETURN_TYPE in some circumstances prior to PHPCS 2.8.0.
  • +
  • T_NULLABLE was not available prior to PHPCS 2.8.0 and utility functions did +not take nullability of types into account.
  • +
  • The PHPCS native ignore annotations were not available prior to PHPCS 3.2.0.
  • +
  • The way return types were tokenized has changed in PHPCS 3.3.0. +Previously a lot of them were tokenized as T_RETURN_HINT. For namespaced +classnames this only tokenized the classname, not the whole return type. +Now tokenization is "normalized" with most tokens being T_STRING, including +array return type declarations.
  • +
  • Typed properties were not recognized prior to PHPCS 3.5.0, including the +? nullability token not being converted to T_NULLABLE.
  • +
  • Arrow functions were not recognized properly until PHPCS 3.5.3.
  • +
  • General PHP cross-version incompatibilities.
  • +
+

Most functions in this class will have a related twin-function in the relevant +class in the PHPCSUtils\Utils namespace. +These will be indicated with @see tags in the docblock of the function.

+

The PHPCSUtils native twin-functions will often have additional features and/or +improved functionality, but will generally be fully compatible with the PHPCS +native functions. +The differences between the functions here and the twin functions are documented +in the docblock of the respective twin-function.

+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
getDeclarationName()Returns the declaration names for classes, interfaces, traits, and functions.string|null
getMethodParameters()Returns the method parameters for the specified function token.array
getMethodProperties()Returns the visibility and implementation properties of a method.array
getMemberProperties()Returns the visibility and implementation properties of a class member var.array
getClassProperties()Returns the implementation properties of a class.array
isReference()Determine if the passed token is a reference operator.bool
getTokensAsString()Returns the content of the tokens from the specified start position in +the token stack for the specified length.string
findStartOfStatement()Returns the position of the first non-whitespace token in a statement.int
findEndOfStatement()Returns the position of the last non-whitespace token in a statement.int
hasCondition()Determine if the passed token has a condition of one of the passed types.bool
getCondition()Return the position of the condition for the passed token.int|bool
findExtendedClassName()Returns the name of the class that the specified class extends.string|bool
findImplementedInterfaceNames()Returns the names of the interfaces that the specified class implements.array|bool
+ + + +
+

Methods

+ +
+

getDeclarationName()

+ +

Returns the declaration names for classes, interfaces, traits, and functions.

+ + public + static getDeclarationName( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : string|null + + +

PHPCS cross-version compatible version of the File::getDeclarationName() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 2.8.0: Returns null when passed an anonymous class. Previously, the method +would throw a "token not of an accepted type" exception.
  • +
  • PHPCS 2.9.0: Returns null when passed a PHP closure. Previously, the method +would throw a "token not of an accepted type" exception.
  • +
  • PHPCS 3.0.0: Added support for ES6 class/method syntax.
  • +
  • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to +\PHP_CodeSniffer\Exceptions\RuntimeException.
  • +
  • PHPCS 3.5.3: Allow for functions to be called fn for backwards compatibility. +Related to PHP 7.4 T_FN arrow functions.
  • +
  • PHPCS 3.5.5: Remove arrow function work-around which is no longer needed due to +a change in the tokenization of arrow functions.
  • +
+

Note: For ES6 classes in combination with PHPCS 2.x, passing a T_STRING token to +this method will be accepted for JS files. +Note: support for JS ES6 method syntax has not been back-filled for PHPCS < 3.0.0.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the declaration token +which declared the class, interface, +trait, or function.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ throws +
+

If the specified token is not of type +T_FUNCTION, T_CLASS, T_TRAIT, or T_INTERFACE.

+
+ +
Return values
+ string|null + —

The name of the class, interface, trait, or function; +or NULL if the function or class is anonymous or +in case of a parse error/live coding.

+ +
+ +
+

getMethodParameters()

+ +

Returns the method parameters for the specified function token.

+ + public + static getMethodParameters( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

Also supports passing in a USE token for a closure use group.

+

Each parameter is in the following format:

+

+0 => array( +'name' => '$var', // The variable name. +'token' => integer, // The stack pointer to the variable name. +'content' => string, // The full content of the variable definition. +'pass_by_reference' => boolean, // Is the variable passed by reference? +'reference_token' => integer, // The stack pointer to the reference operator +// or FALSE if the param is not passed by reference. +'variable_length' => boolean, // Is the param of variable length through use of ... ? +'variadic_token' => integer, // The stack pointer to the ... operator +// or FALSE if the param is not variable length. +'type_hint' => string, // The type hint for the variable. +'type_hint_token' => integer, // The stack pointer to the start of the type hint +// or FALSE if there is no type hint. +'type_hint_end_token' => integer, // The stack pointer to the end of the type hint +// or FALSE if there is no type hint. +'nullable_type' => boolean, // TRUE if the var type is nullable. +'comma_token' => integer, // The stack pointer to the comma after the param +// or FALSE if this is the last param. +) +

+

Parameters with default values have the following additional array indexes: +'default' => string, // The full content of the default value. +'default_token' => integer, // The stack pointer to the start of the default value. +'default_equal_token' => integer, // The stack pointer to the equals sign.

+

PHPCS cross-version compatible version of the File::getMethodParameters() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 2.8.0: Now recognises self as a valid type declaration.
  • +
  • PHPCS 2.8.0: The return array now contains a new "token" index containing the stack pointer +to the variable.
  • +
  • PHPCS 2.8.0: The return array now contains a new "content" index containing the raw content +of the param definition.
  • +
  • PHPCS 2.8.0: Added support for nullable types. +
      +
    • The return array now contains a new "nullable_type" index set to true or false +for each method parameter.
    • +
  • +
  • PHPCS 2.8.0: Added support for closures.
  • +
  • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to +\PHP_CodeSniffer\Exceptions\TokenizerException.
  • +
  • PHPCS 3.3.0: The return array now contains a new "type_hint_token" array index. +
      +
    • Provides the position in the token stack of the first token in the type declaration.
    • +
  • +
  • PHPCS 3.3.1: Fixed incompatibility with PHP 7.3.
  • +
  • PHPCS 3.5.0: The Exception thrown changed from a TokenizerException to +\PHP_CodeSniffer\Exceptions\RuntimeException.
  • +
  • PHPCS 3.5.0: Added support for closure USE groups.
  • +
  • PHPCS 3.5.0: The return array now contains yet more more information. +
      +
    • If a type hint is specified, the position of the last token in the hint will be +set in a "type_hint_end_token" array index.
    • +
    • If a default is specified, the position of the first token in the default value +will be set in a "default_token" array index.
    • +
    • If a default is specified, the position of the equals sign will be set in a +"default_equal_token" array index.
    • +
    • If the param is not the last, the position of the comma will be set in a +"comma_token" array index.
    • +
    • If the param is passed by reference, the position of the reference operator +will be set in a "reference_token" array index.
    • +
    • If the param is variable length, the position of the variadic operator will +be set in a "variadic_token" array index.
    • +
  • +
  • PHPCS 3.5.3: Fixed a bug where the "type_hint_end_token" array index for a type hinted +parameter would bleed through to the next (non-type hinted) parameter.
  • +
  • PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the function token +to acquire the parameters for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ throws +
+

If the specified $stackPtr is not of +type T_FUNCTION, T_CLOSURE, T_USE, +or T_FN.

+
+ +
Return values
+ array + +
+ +
+

getMethodProperties()

+ +

Returns the visibility and implementation properties of a method.

+ + public + static getMethodProperties( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

The format of the return value is: + +array( +'scope' => 'public', // Public, private, or protected +'scope_specified' => true, // TRUE if the scope keyword was found. +'return_type' => '', // The return type of the method. +'return_type_token' => integer, // The stack pointer to the start of the return type +// or FALSE if there is no return type. +'nullable_return_type' => false, // TRUE if the return type is nullable. +'is_abstract' => false, // TRUE if the abstract keyword was found. +'is_final' => false, // TRUE if the final keyword was found. +'is_static' => false, // TRUE if the static keyword was found. +'has_body' => false, // TRUE if the method has a body +); +

+

PHPCS cross-version compatible version of the File::getMethodProperties() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 3.0.0: Removed the is_closure array index which was always false anyway.
  • +
  • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to +\PHP_CodeSniffer\Exceptions\TokenizerException.
  • +
  • PHPCS 3.3.0: New return_type, return_type_token and nullable_return_type array indexes. +
      +
    • The return_type index contains the return type of the function or closer, +or a blank string if not specified.
    • +
    • If the return type is nullable, the return type will contain the leading ?.
    • +
    • A nullable_return_type array index in the return value will also be set to true.
    • +
    • If the return type contains namespace information, it will be cleaned of +whitespace and comments.
    • +
    • To access the original return value string, use the main tokens array.
    • +
  • +
  • PHPCS 3.4.0: New has_body array index. +
      +
    • false if the method has no body (as with abstract and interface methods) +or true otherwise.
    • +
  • +
  • PHPCS 3.5.0: The Exception thrown changed from a TokenizerException to +\PHP_CodeSniffer\Exceptions\RuntimeException.
  • +
  • PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the function token to +acquire the properties for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ throws +
+

If the specified position is not a +T_FUNCTION, T_CLOSURE, or T_FN token.

+
+ +
Return values
+ array + +
+ +
+

getMemberProperties()

+ +

Returns the visibility and implementation properties of a class member var.

+ + public + static getMemberProperties( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

The format of the return value is:

+

+array( +'scope' => string, // Public, private, or protected. +'scope_specified' => boolean, // TRUE if the scope was explicitly specified. +'is_static' => boolean, // TRUE if the static keyword was found. +'type' => string, // The type of the var (empty if no type specified). +'type_token' => integer, // The stack pointer to the start of the type +// or FALSE if there is no type. +'type_end_token' => integer, // The stack pointer to the end of the type +// or FALSE if there is no type. +'nullable_type' => boolean, // TRUE if the type is nullable. +); +

+

PHPCS cross-version compatible version of the File::getMemberProperties() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to +\PHP_CodeSniffer\Exceptions\TokenizerException.
  • +
  • PHPCS 3.4.0: Fixed method params being recognized as properties, PHPCS#2214.
  • +
  • PHPCS 3.5.0: New type, type_token, type_end_token and nullable_type array indexes. +
      +
    • The type index contains the type of the member var, or a blank string +if not specified.
    • +
    • If the type is nullable, type will contain the leading ?.
    • +
    • If a type is specified, the position of the first token in the type will +be set in a type_token array index.
    • +
    • If a type is specified, the position of the last token in the type will +be set in a type_end_token array index.
    • +
    • If the type is nullable, a nullable_type array index will also be set to TRUE.
    • +
    • If the type contains namespace information, it will be cleaned of whitespace +and comments in the type value.
    • +
  • +
  • PHPCS 3.5.0: The Exception thrown changed from a TokenizerException to +\PHP_CodeSniffer\Exceptions\RuntimeException.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the T_VARIABLE token to +acquire the properties for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_VARIABLE token, or if the position is not +a class member variable.

+
+ +
Return values
+ array + +
+ +
+

getClassProperties()

+ +

Returns the implementation properties of a class.

+ + public + static getClassProperties( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

The format of the return value is: + +array( +'is_abstract' => false, // true if the abstract keyword was found. +'is_final' => false, // true if the final keyword was found. +); +

+

PHPCS cross-version compatible version of the File::getClassProperties() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 1.3.0.
  • +
  • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to +\PHP_CodeSniffer\Exceptions\TokenizerException.
  • +
  • PHPCS 3.5.0: The Exception thrown changed from a TokenizerException to +\PHP_CodeSniffer\Exceptions\RuntimeException.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the T_CLASS +token to acquire the properties for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_CLASS token.

+
+ +
Return values
+ array + +
+ +
+

isReference()

+ +

Determine if the passed token is a reference operator.

+ + public + static isReference( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + +

PHPCS cross-version compatible version of the File::isReference() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 3.1.1: Bug fix: misidentification of reference vs bitwise operator, PHPCS#1604/#1609. +
      +
    • An array assignment of a calculated value with a bitwise and operator in it, +was being misidentified as a reference.
    • +
    • A calculated default value for a function parameter with a bitwise and operator +in it, was being misidentified as a reference.
    • +
    • New by reference was not recognized as a reference.
    • +
    • References to class properties with self::, parent::, static::, +namespace\ClassName::, classname:: were not recognized as references.
    • +
  • +
  • PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions returning by reference.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_BITWISE_AND token.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ +
Return values
+ bool + —

TRUE if the specified token position represents a reference. +FALSE if the token represents a bitwise operator.

+ +
+ +
+

getTokensAsString()

+ +

Returns the content of the tokens from the specified start position in +the token stack for the specified length.

+ + public + static getTokensAsString( + + $phpcsFile : + File + + + , $start : + int + + + , $length : + int + + + [, $origContent : + bool + = false ] + ) + : string + + +

PHPCS cross-version compatible version of the File::getTokensAsString() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 3.3.0: New $origContent parameter to optionally return original +(non tab-replaced) content.
  • +
  • PHPCS 3.4.0: - Now throws a RuntimeException if the $start param is invalid. +This stops an infinite loop when the function is passed invalid data. +
      +
    • If the $length param is invalid, an empty string will be returned.
    • +
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start from in the token stack.

+
+ $length + : int +
+

The length of tokens to traverse from the start pos.

+
+ $origContent + : bool + = false
+

Whether the original content or the tab replaced +content should be used.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Related set of functions.

+
+ since +
+
+
+ throws +
+

If the specified start position does not exist.

+
+ +
Return values
+ string + —

The token contents.

+ +
+ +
+

findStartOfStatement()

+ +

Returns the position of the first non-whitespace token in a statement.

+ + public + static findStartOfStatement( + + $phpcsFile : + File + + + , $start : + int + + + [, $ignore : + int|string|array + = null ] + ) + : int + + +

PHPCS cross-version compatible version of the File::findStartOfStatement() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 2.1.0.
  • +
  • PHPCS 2.6.2: New optional $ignore parameter to selectively ignore stop points.
  • +
  • PHPCS 3.5.5: Added support for PHP 7.4 T_FN arrow functions.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start searching from in the token stack.

+
+ $ignore + : int|string|array + = null
+

Token types that should not be considered stop points.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ +
Return values
+ int + +
+ +
+

findEndOfStatement()

+ +

Returns the position of the last non-whitespace token in a statement.

+ + public + static findEndOfStatement( + + $phpcsFile : + File + + + , $start : + int + + + [, $ignore : + int|string|array + = null ] + ) + : int + + +

PHPCS cross-version compatible version of the File::findEndOfStatement() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 2.1.0.
  • +
  • PHPCS 2.6.2: New optional $ignore parameter to selectively ignore stop points.
  • +
  • PHPCS 2.7.1: Improved handling of short arrays, PHPCS #1203.
  • +
  • PHPCS 3.3.0: Bug fix: end of statement detection when passed a scope opener, PHPCS #1863.
  • +
  • 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.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start searching from in the token stack.

+
+ $ignore + : int|string|array + = null
+

Token types that should not be considered stop points.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ +
Return values
+ int + +
+ +
+

hasCondition()

+ +

Determine if the passed token has a condition of one of the passed types.

+ + public + static hasCondition( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $types : + int|string|array + + ) + : bool + + +

PHPCS cross-version compatible version of the File::hasCondition() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • This method has received no significant code updates since PHPCS 2.6.0.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $types + : int|string|array +
+

The type(s) of tokens to search for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native alternative.

+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

getCondition()

+ +

Return the position of the condition for the passed token.

+ + public + static getCondition( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $type : + int|string + + + [, $first : + bool + = true ] + ) + : int|bool + + +

PHPCS cross-version compatible version of the File::getCondition() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 1.3.0.
  • +
  • PHPCS 3.5.4: New $first parameter which allows for the closest matching token to be returned. +By default, it continues to return the first matched token found from the top of the file.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $type + : int|string +
+

The type of token to search for.

+
+ $first + : bool + = true
+

If TRUE, will return the matched condition +furthest away from the passed token. +If FALSE, will return the matched condition +closest to the passed token.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

More versatile alternative.

+
+ since +
+
+
+ since +
+

Added support for the PHPCS 3.5.4 $first parameter.

+
+ +
Return values
+ int|bool + —

Integer stack pointer to the condition or FALSE if the token +does not have the condition.

+ +
+ +
+

findExtendedClassName()

+ +

Returns the name of the class that the specified class extends.

+ + public + static findExtendedClassName( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : string|bool + + +

(works for classes, anonymous classes and interfaces)

+

PHPCS cross-version compatible version of the File::findExtendedClassName() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 1.2.0.
  • +
  • PHPCS 2.8.0: Now supports anonymous classes.
  • +
  • PHPCS 3.1.0: Now supports interfaces extending interfaces (incorrectly, only supporting +single interface extension).
  • +
  • PHPCS 3.3.2: Fixed bug causing bleed through with nested classes, PHPCS#2127.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The stack position of the class or interface.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ +
Return values
+ string|bool + —

The extended class name or FALSE on error or if there +is no extended class name.

+ +
+ +
+

findImplementedInterfaceNames()

+ +

Returns the names of the interfaces that the specified class implements.

+ + public + static findImplementedInterfaceNames( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array|bool + + +

PHPCS cross-version compatible version of the File::findImplementedInterfaceNames() method.

+

Changelog for the PHPCS native function:

+
    +
  • Introduced in PHPCS 2.7.0.
  • +
  • PHPCS 2.8.0: Now supports anonymous classes.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The stack position of the class.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ +
Return values
+ array|bool + —

Array with names of the implemented interfaces or FALSE on +error or if there are no implemented interface names.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html b/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html new file mode 100644 index 00000000..42aba896 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html @@ -0,0 +1,721 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ BCTokens +

+ + +

Token arrays related utility methods.

+

PHPCS provides a number of static token arrays in the \PHP_CodeSniffer\Util\Tokens +class. +Some of these token arrays will not be available in older PHPCS versions. +Some will not contain the same set of tokens across PHPCS versions.

+

This class is a compatibility layer to allow for retrieving these token arrays +with a consistent token content across PHPCS versions. +The one caveat is that the token constants do need to be available.

+

Recommended usage: +Only use the methods in this class when needed. I.e. when your sniff unit tests indicate +a PHPCS cross-version compatibility issue related to inconsistent token arrays.

+

All PHPCS token arrays are supported, though only a limited number of them are different +across PHPCS versions.

+

The names of the PHPCS native token arrays translate one-on-one to the methods in this class: +PHP_CodeSniffer\Util\Tokens::$emptyTokens => PHPCSUtils\BackCompat\BCTokens::emptyTokens() +PHP_CodeSniffer\Util\Tokens::$operators => PHPCSUtils\BackCompat\BCTokens::operators() +... etc

+

The order of the tokens in the arrays may differ between the PHPCS native token arrays and +the token arrays returned by this class.

+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
$phpcsCommentTokensTypesToken types that are comments containing PHPCS instructions.string[]
$ooScopeTokensTokens that open class and object scopes.array
$textStringTokensTokens that represent text strings.array
__callStatic()Handle calls to (undeclared) methods for token arrays which haven't received any +changes since PHPCS 2.6.0.array
assignmentTokens()Retrieve the PHPCS assignment tokens array in a cross-version compatible manner.array
comparisonTokens()Retrieve the PHPCS comparison tokens array in a cross-version compatible manner.array
arithmeticTokens()Retrieve the PHPCS arithmetic tokens array in a cross-version compatible manner.array
operators()Retrieve the PHPCS operator tokens array in a cross-version compatible manner.array
parenthesisOpeners()Retrieve the PHPCS parenthesis openers tokens array in a cross-version compatible manner.array
phpcsCommentTokens()Retrieve the PHPCS comment tokens array in a cross-version compatible manner.array
textStringTokens()Retrieve the PHPCS text string tokens array in a cross-version compatible manner.array
functionNameTokens()Retrieve the PHPCS function name tokens array in a cross-version compatible manner.array
ooScopeTokens()Retrieve the OO scope tokens array in a cross-version compatible manner.array
+ + +
+

Properties

+ +
+

$phpcsCommentTokensTypes

+ +

Token types that are comments containing PHPCS instructions.

+ + protected + static string[] + $phpcsCommentTokensTypes + = ['T_PHPCS_ENABLE', 'T_PHPCS_DISABLE', 'T_PHPCS_SET', 'T_PHPCS_IGNORE', 'T_PHPCS_IGNORE_FILE'] +
+ +
+

$ooScopeTokens

+ +

Tokens that open class and object scopes.

+ + protected + static array + $ooScopeTokens + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE, \T_TRAIT => \T_TRAIT] +
+ +
+

$textStringTokens

+ +

Tokens that represent text strings.

+ + protected + static array + $textStringTokens + = [\T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING, \T_INLINE_HTML => \T_INLINE_HTML, \T_HEREDOC => \T_HEREDOC, \T_NOWDOC => \T_NOWDOC] +
+
+ +
+

Methods

+ +
+

__callStatic()

+ +

Handle calls to (undeclared) methods for token arrays which haven't received any +changes since PHPCS 2.6.0.

+ + public + static __callStatic( + + $name : + string + + + , $args : + array + + ) + : array + + + +
Parameters
+
+
+ $name + : string +
+

The name of the method which has been called.

+
+ $args + : array +
+

Any arguments passed to the method. +Unused as none of the methods take arguments.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array

+ +
+ +
+

assignmentTokens()

+ +

Retrieve the PHPCS assignment tokens array in a cross-version compatible manner.

+ + public + static assignmentTokens( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 2.9.0: The PHP 7.4 T_COALESCE_EQUAL token was added to the array. +The T_COALESCE_EQUAL token was introduced in PHPCS 2.8.1.
  • +
  • PHPCS 3.2.0: The JS T_ZSR_EQUAL token was added to the array. +The T_ZSR_EQUAL token was introduced in PHPCS 2.8.0.
  • +
+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array.

+ +
+ +
+

comparisonTokens()

+ +

Retrieve the PHPCS comparison tokens array in a cross-version compatible manner.

+ + public + static comparisonTokens( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 0.5.0.
  • +
  • PHPCS 2.9.0: The PHP 7.0 T_COALESCE token was added to the array. +The T_COALESCE token was introduced in PHPCS 2.6.1.
  • +
  • PHPCS 2.9.0: The PHP 7.0 T_SPACESHIP token was added to the array. +The T_SPACESHIP token was introduced in PHPCS 2.5.1.
  • +
+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array.

+ +
+ +
+

arithmeticTokens()

+ +

Retrieve the PHPCS arithmetic tokens array in a cross-version compatible manner.

+ + public + static arithmeticTokens( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 0.5.0.
  • +
  • PHPCS 2.9.0: The PHP 5.6 T_POW token was added to the array. +The T_POW token was introduced in PHPCS 2.4.0.
  • +
+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array or an empty array for PHPCS versions in +which the PHPCS native comment tokens did not exist yet.

+ +
+ +
+

operators()

+ +

Retrieve the PHPCS operator tokens array in a cross-version compatible manner.

+ + public + static operators( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 2.6.1: The PHP 7.0 T_COALESCE token was backfilled and added to the array.
  • +
  • PHPCS 2.8.1: The PHP 7.4 T_COALESCE_EQUAL token was backfilled and (incorrectly) +added to the array.
  • +
  • PHPCS 2.9.0: The T_COALESCE_EQUAL token was removed from the array.
  • +
+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array.

+ +
+ +
+

parenthesisOpeners()

+ +

Retrieve the PHPCS parenthesis openers tokens array in a cross-version compatible manner.

+ + public + static parenthesisOpeners( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 0.0.5.
  • +
  • PHPCS 3.5.0: T_LIST and T_ANON_CLASS added to the array.
  • +
+

Note: While T_LIST and T_ANON_CLASS will be included in the return value for this +method, the associated parentheses will not have the 'parenthesis_owner' index set +until PHPCS 3.5.0.

+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array.

+ +
+ +
+

phpcsCommentTokens()

+ +

Retrieve the PHPCS comment tokens array in a cross-version compatible manner.

+ + public + static phpcsCommentTokens( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 3.2.3.
  • +
+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + — => Token array or an empty array for PHPCS +versions in which the PHPCS native annotation +tokens did not exist yet. + +
+ +
+

textStringTokens()

+ +

Retrieve the PHPCS text string tokens array in a cross-version compatible manner.

+ + public + static textStringTokens( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 2.9.0.
  • +
+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array.

+ +
+ +
+

functionNameTokens()

+ +

Retrieve the PHPCS function name tokens array in a cross-version compatible manner.

+ + public + static functionNameTokens( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 2.3.3.
  • +
  • PHPCS 3.1.0: T_SELF and T_STATIC added to the array.
  • +
+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array.

+ +
+ +
+

ooScopeTokens()

+ +

Retrieve the OO scope tokens array in a cross-version compatible manner.

+ + public + static ooScopeTokens( + ) + : array + + +

Changelog for the PHPCS native array:

+
    +
  • Introduced in PHPCS 3.1.0.
  • +
+ + +
Tags
+
+
+ see +
+

Original array.

+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string> Token array.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html b/docs/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html new file mode 100644 index 00000000..e6f91761 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html @@ -0,0 +1,469 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Helper +

+ + +

Utility methods to retrieve (configuration) information from PHP_CodeSniffer.

+

PHP_CodeSniffer cross-version compatibility helper for PHPCS 2.x vs PHPCS 3.x.

+

A number of PHPCS classes were split up into several classes in PHPCS 3.x +Those classes cannot be aliased as they don't represent the same object. +This class provides helper methods for functions which were contained in +one of these classes and which are commonly used by external standards.

+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DEFAULT_TABWIDTHThe default tab width used by PHP_CodeSniffer.4
getVersion()Get the PHP_CodeSniffer version number.string
setConfigData()Pass config data to PHP_CodeSniffer.bool
getConfigData()Get the value of a single PHP_CodeSniffer config key.string|null
getCommandLineData()Get the value of a CLI overrulable single PHP_CodeSniffer config key.string|null
getTabWidth()Get the applicable tab width as passed to PHP_CodeSniffer from the +command-line or the ruleset.int
ignoreAnnotations()Check whether the `--ignore-annotations` option has been used.bool
+ +
+

Constants

+ +
+

DEFAULT_TABWIDTH

+ +

The default tab width used by PHP_CodeSniffer.

+ + + int + $DEFAULT_TABWIDTH + = 4 + +
+
+ + +
+

Methods

+ +
+

getVersion()

+ +

Get the PHP_CodeSniffer version number.

+ + public + static getVersion( + ) + : string + + + + +
Tags
+
+
+ since +
+
+
+ +
Return values
+ string + +
+ +
+

setConfigData()

+ +

Pass config data to PHP_CodeSniffer.

+ + public + static setConfigData( + + $key : + string + + + , $value : + string|null + + + [, $temp : + bool + = false ] + ) + : bool + + + +
Parameters
+
+
+ $key + : string +
+

The name of the config value.

+
+ $value + : string|null +
+

The value to set. If null, the config entry +is deleted, reverting it to the default value.

+
+ $temp + : bool + = false
+

Set this config data temporarily for this script run. +This will not write the config data to the config file.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

Whether the setting of the data was successfull.

+ +
+ +
+

getConfigData()

+ +

Get the value of a single PHP_CodeSniffer config key.

+ + public + static getConfigData( + + $key : + string + + ) + : string|null + + + +
Parameters
+
+
+ $key + : string +
+

The name of the config value.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ string|null + +
+ +
+

getCommandLineData()

+ +

Get the value of a CLI overrulable single PHP_CodeSniffer config key.

+ + public + static getCommandLineData( + + $phpcsFile : + File + + + , $key : + string + + ) + : string|null + + +

Use this for config keys which can be set in the CodeSniffer.conf file, +on the command-line or in a ruleset.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being processed.

+
+ $key + : string +
+

The name of the config value.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ string|null + +
+ +
+

getTabWidth()

+ +

Get the applicable tab width as passed to PHP_CodeSniffer from the +command-line or the ruleset.

+ + public + static getTabWidth( + + $phpcsFile : + File + + ) + : int + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being processed.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int + —

Tab width. Defaults to the PHPCS native default of 4.

+ +
+ +
+

ignoreAnnotations()

+ +

Check whether the `--ignore-annotations` option has been used.

+ + public + static ignoreAnnotations( + + [ $phpcsFile : + File + = null ] + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File + = null
+

Optional. The current file +being processed.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True if annotations should be ignored, false otherwise.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html b/docs/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html new file mode 100644 index 00000000..051e8de4 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html @@ -0,0 +1,277 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ SpacesFixer +

+ + +

Utility to check and, if necessary, fix the whitespace between two tokens.

+
+ +

Table of Contents

+ + + + + + +
checkAndFix()Check the whitespace between two tokens, throw an error if it doesn't match the +expected whitespace and if relevant, fix it.void
+ + + +
+

Methods

+ +
+

checkAndFix()

+ +

Check the whitespace between two tokens, throw an error if it doesn't match the +expected whitespace and if relevant, fix it.

+ + public + static checkAndFix( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $secondPtr : + int + + + , $expectedSpaces : + string|int + + + , $errorTemplate : + string + + + [, $errorCode : + string + = 'Found' ] + + [, $errorType : + string + = 'error' ] + + , $errorSeverity : + int + + + [, $metricName : + string + = '' ] + ) + : void + + +

Note:

+
    +
  • This method will not auto-fix if there is anything but whitespace between the two +tokens. In that case, it will throw a non-fixable error/warning.
  • +
  • If 'newline' is expected and no new line is encountered, a new line will be added, +but no assumptions will be made about the intended indentation of the code. +This should be handled by a (separate) indentation sniff.
  • +
  • If 'newline' is expected and multiple new lines are encountered, this will be accepted +as valid. +No assumptions are made about whether additional blank lines are allowed or not. +If exactly one line is desired, combine this Fixer with the BlankLineFixer.
  • +
  • The fixer will not leave behind any trailing spaces on the original line when fixing +to 'newline', but it will not correct existing trailing spaces when there already +is a new line in place.
  • +
  • This method can optionally record a metric for this check which will be displayed +when the end-user requests the info report.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the token which should be used +when reporting an issue.

+
+ $secondPtr + : int +
+

The stack pointer to the second token. +This token can be before or after the $stackPtr, +but should only be seperated from the $stackPtr +by whitespace and/or comments/annotations.

+
+ $expectedSpaces + : string|int +
+

Number of spaces to enforce. +Valid values:

+
    +
  • (int) Number of spaces. Must be 0 or more.
  • +
  • (string) 'newline'.
  • +
+
+ $errorTemplate + : string +
+

Error message template. This string should contain +two placeholders: +%1$s = expected spaces phrase. +%2$s = found spaces phrase. +Note: The replacement phrase will be in human +readable English and include "spaces"/"new line", +so no need to include that in the template.

+
+ $errorCode + : string + = 'Found'
+

A violation code unique to the sniff message. +Defaults to Found. +It is strongly recommended to change this if +this fixer is used for different errors in the +same sniff.

+
+ $errorType + : string + = 'error'
+

Optional. Whether to report the issue as a +warning or an error. Defaults to error.

+
+ $errorSeverity + : int +
+

Optional. The severity level for this message. +A value of 0 will be converted into the default +severity level.

+
+ $metricName + : string + = ''
+

Optional. The name of the metric to record. +This can be a short description phrase. +Leave empty to not record metrics.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the tokens passed do not exist or are whitespace +tokens.

+
+ throws +
+

If $expectedSpaces is not a valid value.

+
+ throws +
+

If the tokens passed are separated by more than just +empty (whitespace + comments/annotations) tokens.

+
+ + +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html b/docs/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html new file mode 100644 index 00000000..83032600 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html @@ -0,0 +1,523 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ UtilityMethodTestCase + + extends TestCase + +

+ + +

Base class for use when testing utility methods for PHP_CodeSniffer.

+

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 +file is included in the test bootstrap.

+

To allow for testing of tab vs space content, the tabWidth is set to 4 by default.

+

Typical usage:

+

Test case file path/to/ClassUnderTestUnitTest.inc:

+
<?php
+
+/* testTestCaseDescription * /
+const BAR = false;
+

Test file path/to/ClassUnderTestUnitTest.php:

+
<?php
+
+use PHPCSUtils\TestUtils\UtilityMethodTestCase;
+use YourStandard\ClassUnderTest;
+
+class ClassUnderTestUnitTest extends UtilityMethodTestCase {
+
+    /**
+     * Testing utility method MyMethod.
+     *
+     * @dataProvider dataMyMethod
+     *
+     * @covers \YourStandard\ClassUnderTest::MyMethod
+     *
+     * @param string $commentString The comment which prefaces the target token in the test file.
+     * @param string $expected      The expected return value.
+     *
+     * @return void
+     * /
+   public function testMyMethod($commentString, $expected)
+   {
+       $stackPtr = $this->getTargetToken($commentString, [\T_TOKEN_CONSTANT, \T_ANOTHER_TOKEN]);
+       $class    = new ClassUnderTest();
+       $result   = $class->MyMethod(self::$phpcsFile, $stackPtr);
+       // Or for static utility methods:
+       $result   = ClassUnderTest::MyMethod(self::$phpcsFile, $stackPtr);
+
+       $this->assertSame($expected, $result);
+   }
+
+   /**
+    * Data Provider.
+    *
+    * @see testMyMethod() For the array format.
+    *
+    * @return array
+    * /
+   public function dataMyMethod()
+   {
+       return array(
+           array('/* testTestCaseDescription * /', false),
+       );
+   }
+}
+

Note:

+
    +
  • Remove the space between the comment closers * / for a working example.
  • +
  • Each test case separator comment MUST start with /* test. +This is to allow the getTargetToken() method to distinquish between the +test separation comments and comments which may be part of the test case.
  • +
  • The test case file and unit test file should be placed in the same directory.
  • +
  • For working examples using this abstract class, have a look at the unit tests +for the PHPCSUtils utility functions themselves.
  • +
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
$fileExtensionThe file extension of the test case file (without leading dot).string
$caseFileFull path to the test case file associated with the concrete test class.string
$tabWidthThe tab width setting to use when tokenizing the file.int
$phpcsFileThe {@see \PHP_CodeSniffer\Files\File} object containing the parsed contents of the test case file.File
$selectedSniffSet the name of a sniff to pass to PHPCS to limit the run (and force it to record errors).array
setUpTestFile()Initialize PHPCS & tokenize the test case file.void
resetTestFile()Clean up after finished test.void
getTargetToken()Get the token pointer for a target token based on a specific comment found on the line before.int
expectPhpcsException()Helper method to tell PHPUnit to expect a PHPCS Exception in a PHPUnit cross-version +compatible manner.void
+ + +
+

Properties

+ +
+

$fileExtension

+ +

The file extension of the test case file (without leading dot).

+ + protected + static string + $fileExtension + = 'inc' +
This allows concrete test classes to overrule the default `inc` with, for instance, +`js` or `css` when applicable.
+
+ +
+

$caseFile

+ +

Full path to the test case file associated with the concrete test class.

+ + protected + static string + $caseFile + = '' +
Optional. If left empty, the case file will be presumed to be in +the same directory and named the same as the test class, but with an +`inc` file extension.
+
+ +
+

$tabWidth

+ +

The tab width setting to use when tokenizing the file.

+ + protected + static int + $tabWidth + = 4 +
This allows for test case files to use a different tab width than the default.
+
+ +
+

$phpcsFile

+ +

The {@see \PHP_CodeSniffer\Files\File} object containing the parsed contents of the test case file.

+ + protected + static File + $phpcsFile + +
+ +
+

$selectedSniff

+ +

Set the name of a sniff to pass to PHPCS to limit the run (and force it to record errors).

+ + protected + static array + $selectedSniff + = ['Dummy.Dummy.Dummy'] +
Normally, this propery won't need to be overloaded, but for utility methods which record +violations and contain fixers, setting a dummy sniff name equal to the sniff name passed +in the error code for `addError()`/`addWarning()` during the test, will allow for testing +the recording of these violations, as well as testing the fixer.
+
+
+ +
+

Methods

+ +
+

setUpTestFile()

+ +

Initialize PHPCS & tokenize the test case file.

+ + public + static setUpTestFile( + ) + : void + + +

The test case file for a unit test class has to be in the same directory +directory and use the same file name as the test class, using the .inc extension.

+ + +
Tags
+
+
+ since +
+
+
+ beforeClass +
+
+
+ + +
+ +
+

resetTestFile()

+ +

Clean up after finished test.

+ + public + static resetTestFile( + ) + : void + + + + +
Tags
+
+
+ since +
+
+
+ afterClass +
+
+
+ + +
+ +
+

getTargetToken()

+ +

Get the token pointer for a target token based on a specific comment found on the line before.

+ + public + getTargetToken( + + $commentString : + string + + + , $tokenType : + int|string|array + + + [, $tokenContent : + string + = null ] + ) + : int + + +

Note: the test delimiter comment MUST start with "/ test" to allow this function to +distinguish between comments used in* a test and test delimiters.

+ +
Parameters
+
+
+ $commentString + : string +
+

The delimiter comment to look for.

+
+ $tokenType + : int|string|array +
+

The type of token(s) to look for.

+
+ $tokenContent + : string + = null
+

Optional. The token content for the target token.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int + +
+ +
+

expectPhpcsException()

+ +

Helper method to tell PHPUnit to expect a PHPCS Exception in a PHPUnit cross-version +compatible manner.

+ + public + expectPhpcsException( + + $msg : + string + + + [, $type : + string + = 'runtime' ] + ) + : void + + + +
Parameters
+
+
+ $msg + : string +
+

The expected exception message.

+
+ $type + : string + = 'runtime'
+

The exception type to expect. Either 'runtime' or 'tokenizer'. +Defaults to 'runtime'.

+
+ +
Tags
+
+
+ since +
+
+
+ + +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Tokens-Collections.html b/docs/phpdoc/classes/PHPCSUtils-Tokens-Collections.html new file mode 100644 index 00000000..c70fe7c4 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Tokens-Collections.html @@ -0,0 +1,761 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Collections +

+ + +

Collections of related tokens as 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.

+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
$alternativeControlStructureSyntaxTokensControl structures which can use the alternative control structure syntax.array
$alternativeControlStructureSyntaxCloserTokensAlternative control structure syntax closer keyword tokens.array
$arrayTokensTokens which are used to create arrays.array
$arrayTokensBCTokens which are used to create arrays.array
$classModifierKeywordsModifier keywords which can be used for a class declaration.array
$closedScopesList of tokens which represent "closed" scopes.array
$controlStructureTokensControl structure tokens.array
$listTokensTokens which are used to create lists.array
$listTokensBCTokens which are used to create lists.array
$namespaceDeclarationClosersList of tokens which can end a namespace declaration statement.array
$OOCanExtendOO structures which can use the `extends` keyword.array
$OOCanImplementOO structures which can use the `implements` keyword.array
$OOConstantScopesOO scopes in which constants can be declared.array
$OOPropertyScopesOO scopes in which properties can be declared.array
$parameterTypeTokensToken types which can be encountered in a parameter type declaration.array
$propertyModifierKeywordsModifier keywords which can be used for a property declaration.array
$propertyTypeTokensToken types which can be encountered in a property type declaration.array
$returnTypeTokensToken types which can be encountered in a return type declaration.array
$shortArrayTokensTokens which are used for short arrays.array
$shortArrayTokensBCTokens which are used for short arrays.array
$shortListTokensTokens which are used for short lists.array
$shortListTokensBCTokens which are used for short lists.array
$textStingStartTokensTokens which can start a - potentially multi-line - text string.array
arrowFunctionTokensBC()Tokens which can represent the arrow function keyword.array
+ + +
+

Properties

+ +
+

$alternativeControlStructureSyntaxTokens

+ +

Control structures which can use the alternative control structure syntax.

+ + public + static array + $alternativeControlStructureSyntaxTokens + = [\T_IF => \T_IF, \T_ELSEIF => \T_ELSEIF, \T_ELSE => \T_ELSE, \T_FOR => \T_FOR, \T_FOREACH => \T_FOREACH, \T_SWITCH => \T_SWITCH, \T_WHILE => \T_WHILE, \T_DECLARE => \T_DECLARE] +
+ +
+

$alternativeControlStructureSyntaxCloserTokens

+ +

Alternative control structure syntax closer keyword tokens.

+ + public + static array + $alternativeControlStructureSyntaxCloserTokens + = [\T_ENDIF => \T_ENDIF, \T_ENDFOR => \T_ENDFOR, \T_ENDFOREACH => \T_ENDFOREACH, \T_ENDWHILE => \T_ENDWHILE, \T_ENDSWITCH => \T_ENDSWITCH, \T_ENDDECLARE => \T_ENDDECLARE] +
+ +
+

$arrayTokens

+ +

Tokens which are used to create arrays.

+ + public + static array + $arrayTokens + = [\T_ARRAY => \T_ARRAY, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY] +
+ +
+

$arrayTokensBC

+ +

Tokens which are used to create arrays.

+ + public + static array + $arrayTokensBC + = [\T_ARRAY => \T_ARRAY, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET] +
List which is backward-compatible with PHPCS < 3.3.0. +Should only be used selectively.
+
+ +
+

$classModifierKeywords

+ +

Modifier keywords which can be used for a class declaration.

+ + public + static array + $classModifierKeywords + = [\T_FINAL => \T_FINAL, \T_ABSTRACT => \T_ABSTRACT] +
+ +
+

$closedScopes

+ +

List of tokens which represent "closed" scopes.

+ + public + static array + $closedScopes + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE, \T_TRAIT => \T_TRAIT, \T_FUNCTION => \T_FUNCTION, \T_CLOSURE => \T_CLOSURE] +
I.e. anything declared within that scope - except for other closed scopes - is +outside of the global namespace. + +This list doesn't contain `T_NAMESPACE` on purpose as variables declared +within a namespace scope are still global and not limited to that namespace.
+
+ +
+

$controlStructureTokens

+ +

Control structure tokens.

+ + public + static array + $controlStructureTokens + = [\T_IF => \T_IF, \T_ELSEIF => \T_ELSEIF, \T_ELSE => \T_ELSE, \T_FOR => \T_FOR, \T_FOREACH => \T_FOREACH, \T_SWITCH => \T_SWITCH, \T_DO => \T_DO, \T_WHILE => \T_WHILE, \T_DECLARE => \T_DECLARE] +
+ +
+

$listTokens

+ +

Tokens which are used to create lists.

+ + public + static array + $listTokens + = [\T_LIST => \T_LIST, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY] +
+ +
+

$listTokensBC

+ +

Tokens which are used to create lists.

+ + public + static array + $listTokensBC + = [\T_LIST => \T_LIST, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET] +
List which is backward-compatible with PHPCS < 3.3.0. +Should only be used selectively.
+
+ +
+

$namespaceDeclarationClosers

+ +

List of tokens which can end a namespace declaration statement.

+ + public + static array + $namespaceDeclarationClosers + = [\T_SEMICOLON => \T_SEMICOLON, \T_OPEN_CURLY_BRACKET => \T_OPEN_CURLY_BRACKET, \T_CLOSE_TAG => \T_CLOSE_TAG] +
+ +
+

$OOCanExtend

+ +

OO structures which can use the `extends` keyword.

+ + public + static array + $OOCanExtend + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE] +
+ +
+

$OOCanImplement

+ +

OO structures which can use the `implements` keyword.

+ + public + static array + $OOCanImplement + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS] +
+ +
+

$OOConstantScopes

+ +

OO scopes in which constants can be declared.

+ + public + static array + $OOConstantScopes + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE] +
Note: traits can not declare constants.
+
+ +
+

$OOPropertyScopes

+ +

OO scopes in which properties can be declared.

+ + public + static array + $OOPropertyScopes + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_TRAIT => \T_TRAIT] +
Note: interfaces can not declare properties.
+
+ +
+

$parameterTypeTokens

+ +

Token types which can be encountered in a parameter type declaration.

+ + public + static array + $parameterTypeTokens + = [ + \T_ARRAY_HINT => \T_ARRAY_HINT, + // PHPCS < 3.3.0. + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, +] +
+ +
+

$propertyModifierKeywords

+ +

Modifier keywords which can be used for a property declaration.

+ + public + static array + $propertyModifierKeywords + = [\T_PUBLIC => \T_PUBLIC, \T_PRIVATE => \T_PRIVATE, \T_PROTECTED => \T_PROTECTED, \T_STATIC => \T_STATIC, \T_VAR => \T_VAR] +
+ +
+

$propertyTypeTokens

+ +

Token types which can be encountered in a property type declaration.

+ + public + static array + $propertyTypeTokens + = [ + \T_ARRAY_HINT => \T_ARRAY_HINT, + // PHPCS < 3.3.0. + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, +] +
+ +
+

$returnTypeTokens

+ +

Token types which can be encountered in a return type declaration.

+ + public + static array + $returnTypeTokens + = [ + \T_STRING => \T_STRING, + \T_CALLABLE => \T_CALLABLE, + \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, +] +
+ +
+

$shortArrayTokens

+ +

Tokens which are used for short arrays.

+ + public + static array + $shortArrayTokens + = [\T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY] +
+ +
+

$shortArrayTokensBC

+ +

Tokens which are used for short arrays.

+ + public + static array + $shortArrayTokensBC + = [\T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET] +
List which is backward-compatible with PHPCS < 3.3.0. +Should only be used selectively.
+
+ +
+

$shortListTokens

+ +

Tokens which are used for short lists.

+ + public + static array + $shortListTokens + = [\T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY] +
+ +
+

$shortListTokensBC

+ +

Tokens which are used for short lists.

+ + public + static array + $shortListTokensBC + = [\T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET] +
List which is backward-compatible with PHPCS < 3.3.0. +Should only be used selectively.
+
+ +
+

$textStingStartTokens

+ +

Tokens which can start a - potentially multi-line - text string.

+ + public + static array + $textStingStartTokens + = [\T_START_HEREDOC => \T_START_HEREDOC, \T_START_NOWDOC => \T_START_NOWDOC, \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING] +
+
+ +
+

Methods

+ +
+

arrowFunctionTokensBC()

+ +

Tokens which can represent the arrow function keyword.

+ + public + static arrowFunctionTokensBC( + ) + : array + + +

Note: this is a method, not a property as the T_FN token may not exist.

+ + +
Tags
+
+
+ since +
+
+
+ +
Return values
+ array + —

<int|string> => <int|string>

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Arrays.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Arrays.html new file mode 100644 index 00000000..28a8f33a --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Arrays.html @@ -0,0 +1,360 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Arrays +

+ + +

Utility functions for use when examining arrays.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + +
$doubleArrowTargetsThe tokens to target to find the double arrow in an array item.array
isShortArray()Determine whether a `T_OPEN/CLOSE_SHORT_ARRAY` token is a short array() construct +and not a short list.bool
getOpenClose()Find the array opener & closer based on a T_ARRAY or T_OPEN_SHORT_ARRAY token.array|bool
getDoubleArrowPtr()Get the stack pointer position of the double arrow within an array item.int|bool
+ + +
+

Properties

+ +
+

$doubleArrowTargets

+ +

The tokens to target to find the double arrow in an array item.

+ + private + static array + $doubleArrowTargets + = [\T_DOUBLE_ARROW => \T_DOUBLE_ARROW, \T_ARRAY => \T_ARRAY, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_STRING => \T_STRING] +
Note: this array does not contain the `T_FN` token as it may or may not exist. +If it exists, it will be added in the `getDoubleArrowPtr()` function.
+
+
+ +
+

Methods

+ +
+

isShortArray()

+ +

Determine whether a `T_OPEN/CLOSE_SHORT_ARRAY` token is a short array() construct +and not a short list.

+ + public + static isShortArray( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + +

This method also accepts T_OPEN/CLOSE_SQUARE_BRACKET tokens to allow it to be +PHPCS cross-version compatible as the short array tokenizing has been plagued by +a number of bugs over time.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the short array bracket token.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True if the token passed is the open/close bracket of a short array. +False if the token is a short list bracket, a plain square bracket +or not one of the accepted tokens.

+ +
+ +
+

getOpenClose()

+ +

Find the array opener & closer based on a T_ARRAY or T_OPEN_SHORT_ARRAY token.

+ + public + static getOpenClose( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $isShortArray : + bool|null + = null ] + ) + : array|bool + + +

This method also accepts T_OPEN_SQUARE_BRACKET tokens to allow it to be +PHPCS cross-version compatible as the short array tokenizing has been plagued by +a number of bugs over time, which affects the short array determination.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_ARRAY or T_OPEN_SHORT_ARRAY +token in the stack.

+
+ $isShortArray + : bool|null + = null
+

Short-circuit the short array check for T_OPEN_SHORT_ARRAY +tokens if it isn't necessary. +Efficiency tweak for when this has already been established, +i.e. when encountering a nested array while walking the +tokens in an array. +Use with care.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ array|bool + —

Array with two keys opener, closer or false if +not a (short) array token or if the opener/closer +could not be determined.

+ +
+ +
+

getDoubleArrowPtr()

+ +

Get the stack pointer position of the double arrow within an array item.

+ + public + static getDoubleArrowPtr( + + $phpcsFile : + File + + + , $start : + int + + + , $end : + int + + ) + : int|bool + + +

Expects to be passed the array item start and end tokens as retrieved via +\PHPCSUtils\Utils\PassedParameters::getParameters().

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being examined.

+
+ $start + : int +
+

Stack pointer to the start of the array item.

+
+ $end + : int +
+

Stack pointer to the end of the array item (inclusive).

+
+ +
Tags
+
+
+ since +
+
+
+ since +
+

Now allows for arrow functions in arrays.

+
+ throws +
+

If the start or end positions are invalid.

+
+ +
Return values
+ int|bool + —

Stack pointer to the double arrow if this array item has a key or false otherwise.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Conditions.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Conditions.html new file mode 100644 index 00000000..6c861c17 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Conditions.html @@ -0,0 +1,429 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Conditions +

+ + +

Utility functions for use when examining token conditions.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + +
getCondition()Retrieve the position of a condition for the passed token.int|bool
hasCondition()Determine if the passed token has a condition of one of the passed types.bool
getFirstCondition()Return the position of the first (outermost) condition of a certain type for the passed token.int|bool
getLastCondition()Return the position of the last (innermost) condition of a certain type for the passed token.int|bool
+ + + +
+

Methods

+ +
+

getCondition()

+ +

Retrieve the position of a condition for the passed token.

+ + public + static getCondition( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $types : + int|string|array + = [] ] + + [, $first : + bool + = true ] + ) + : int|bool + + +

If no types are specified, the first condition for the token - or if $first=false, +the last condition - will be returned.

+

Main differences with the PHPCS version:

+
    +
  • The singular $type parameter has become the more flexible $types parameter allowing to +search for several types of conditions in one go.
  • +
  • The $types parameter is now optional.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $types + : int|string|array + = []
+

Optional. The type(s) of tokens to search for.

+
+ $first + : bool + = true
+

Optional. Whether to search for the first (outermost) +(true) or the last (innermost) condition (false) of +the specified type(s).

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ since +
+

The $reverse parameter has been renamed to $first and the meaning of the +boolean reversed (true = first, false = last, was: true = last, false = first) +to be in line with PHPCS itself which added the $first parameter in v 3.5.4 +to allow for the same/similar functionality as $reverse already offered.

+
+ +
Return values
+ int|bool + —

Integer stack pointer to the condition or FALSE if the token +does not have the condition.

+ +
+ +
+

hasCondition()

+ +

Determine if the passed token has a condition of one of the passed types.

+ + public + static hasCondition( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $types : + int|string|array + + ) + : bool + + +

This method is not significantly different from the PHPCS native version.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $types + : int|string|array +
+

The type(s) of tokens to search for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

getFirstCondition()

+ +

Return the position of the first (outermost) condition of a certain type for the passed token.

+ + public + static getFirstCondition( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $types : + int|string|array + = [] ] + ) + : int|bool + + +

If no types are specified, the first condition for the token, independently of type, +will be returned.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $types + : int|string|array + = []
+

Optional. The type(s) of tokens to search for.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

StackPtr to the condition or false if the token does not have the condition.

+ +
+ +
+

getLastCondition()

+ +

Return the position of the last (innermost) condition of a certain type for the passed token.

+ + public + static getLastCondition( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $types : + int|string|array + = [] ] + ) + : int|bool + + +

If no types are specified, the last condition for the token, independently of type, +will be returned.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $types + : int|string|array + = []
+

Optional. The type(s) of tokens to search for.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

StackPtr to the condition or false if the token does not have the condition.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html b/docs/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html new file mode 100644 index 00000000..3e40c94b --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html @@ -0,0 +1,320 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ ControlStructures +

+ + +

Utility functions for use when examining control structures.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + +
hasBody()Check whether a control structure has a body.bool
isElseIf()Check whether an IF or ELSE token is part of an `else if`.bool
getDeclareScopeOpenClose()Get the scope opener and closer for a `declare` statement.array|bool
+ + + +
+

Methods

+ +
+

hasBody()

+ +

Check whether a control structure has a body.

+ + public + static hasBody( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $allowEmpty : + bool + = true ] + ) + : bool + + +

Some control structures - while, for and declare - can be declared without a body, like +while (++$i < 10);.

+

All other control structures will always have a body, though the body may be empty, where "empty" means: +no code is found in the body. If a control structure body only contains a comment, it will be +regarded as empty.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $allowEmpty + : bool + = true
+

Whether a control structure with an empty body should +still be considered as having a body. +Defaults to true.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True when the control structure has a body, or when $allowEmpty is set to false +when it has a non-empty body. +False in all other cases, including when a non-control structure token has been passed.

+ +
+ +
+

isElseIf()

+ +

Check whether an IF or ELSE token is part of an `else if`.

+ + public + static isElseIf( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

getDeclareScopeOpenClose()

+ +

Get the scope opener and closer for a `declare` statement.

+ + public + static getDeclareScopeOpenClose( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array|bool + + +

A declare statement can be:

+
    +
  • 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.
  • +
+

In the first case, the statement - correctly - won't have a scope opener/closer. +In the second case, the statement will have the scope opener/closer indexes. +In the last case, due to a bug in the PHPCS Tokenizer, it won't have the scope opener/closer indexes, +while it really should. This bug is fixed in PHPCS 3.5.4.

+

In other words, if a sniff needs to support PHPCS < 3.5.4 and needs to take the alternative +control structure syntax into account, this method can be used to retrieve the +scope opener/closer for the declare statement.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ +
Tags
+
+
+ link +
+
+
+ since +
+
+
+ +
Return values
+ array|bool + —

Array with two keys opener, closer or false if +not a declare token or if the opener/closer +could not be determined.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html b/docs/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html new file mode 100644 index 00000000..eea96ebb --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html @@ -0,0 +1,1189 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ FunctionDeclarations +

+ + +

Utility functions for use when examining function declaration statements.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
$magicFunctionsA list of all PHP magic functions.array
$magicMethodsA list of all PHP magic methods.array
$methodsDoubleUnderscoreA list of all PHP native non-magic methods starting with a double underscore.array
$arrowFunctionEndTokensTokens which can be the end token of an arrow function.array
getName()Returns the declaration name for a function.string|null
getProperties()Retrieves the visibility and implementation properties of a method.array
getParameters()Retrieves the method parameters for the specified function token.array
isArrowFunction()Check if an arbitrary token is the "fn" keyword for a PHP 7.4 arrow function.bool
getArrowFunctionOpenClose()Retrieve the parenthesis opener, parenthesis closer, the scope opener and the scope closer +for an arrow function.array|bool
isMagicFunction()Checks if a given function is a PHP magic function.bool
isMagicFunctionName()Verify if a given function name is the name of a PHP magic function.bool
isMagicMethod()Checks if a given function is a PHP magic method.bool
isMagicMethodName()Verify if a given function name is the name of a PHP magic method.bool
isPHPDoubleUnderscoreMethod()Checks if a given function is a PHP native double underscore method.bool
isPHPDoubleUnderscoreMethodName()Verify if a given function name is the name of a PHP native double underscore method.bool
isSpecialMethod()Checks if a given function is a magic method or a PHP native double underscore method.bool
isSpecialMethodName()Verify if a given function name is the name of a magic method or a PHP native double underscore method.bool
+ + +
+

Properties

+ +
+

$magicFunctions

+ +

A list of all PHP magic functions.

+ + public + static array + $magicFunctions + = ['__autoload' => 'autoload'] +
The array keys are the function names, the values as well, but without the double underscore. + +The function names are listed in lowercase as function names in PHP are case-insensitive +and comparisons against this list should therefore always be done in a case-insensitive manner.
+
+ +
+

$magicMethods

+ +

A list of all PHP magic methods.

+ + public + static array + $magicMethods + = [ + '__construct' => 'construct', + '__destruct' => 'destruct', + '__call' => 'call', + '__callstatic' => 'callstatic', + '__get' => 'get', + '__set' => 'set', + '__isset' => 'isset', + '__unset' => 'unset', + '__sleep' => 'sleep', + '__wakeup' => 'wakeup', + '__tostring' => 'tostring', + '__set_state' => 'set_state', + '__clone' => 'clone', + '__invoke' => 'invoke', + '__debuginfo' => 'debuginfo', + // PHP 5.6. + '__serialize' => 'serialize', + // PHP 7.4. + '__unserialize' => 'unserialize', +] +
The array keys are the method names, the values as well, but without the double underscore. + +The method names are listed in lowercase as function names in PHP are case-insensitive +and comparisons against this list should therefore always be done in a case-insensitive manner.
+
+ +
+

$methodsDoubleUnderscore

+ +

A list of all PHP native non-magic methods starting with a double underscore.

+ + public + static array + $methodsDoubleUnderscore + = ['__dorequest' => 'SOAPClient', '__getcookies' => 'SOAPClient', '__getfunctions' => 'SOAPClient', '__getlastrequest' => 'SOAPClient', '__getlastrequestheaders' => 'SOAPClient', '__getlastresponse' => 'SOAPClient', '__getlastresponseheaders' => 'SOAPClient', '__gettypes' => 'SOAPClient', '__setcookie' => 'SOAPClient', '__setlocation' => 'SOAPClient', '__setsoapheaders' => 'SOAPClient', '__soapcall' => 'SOAPClient'] +
These come from PHP modules such as SOAPClient. + +The array keys are the method names, the values the name of the PHP extension containing +the function. + +The method names are listed in lowercase as function names in PHP are case-insensitive +and comparisons against this list should therefore always be done in a case-insensitive manner.
+
+ +
+

$arrowFunctionEndTokens

+ +

Tokens which can be the end token of an arrow function.

+ + private + static array + $arrowFunctionEndTokens + = [\T_COLON => true, \T_COMMA => true, \T_SEMICOLON => true, \T_CLOSE_PARENTHESIS => true, \T_CLOSE_SQUARE_BRACKET => true, \T_CLOSE_CURLY_BRACKET => true, \T_CLOSE_SHORT_ARRAY => true, \T_OPEN_TAG => true, \T_CLOSE_TAG => true] +
+
+ +
+

Methods

+ +
+

getName()

+ +

Returns the declaration name for a function.

+ + public + static getName( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : string|null + + +

Alias for the \PHPCSUtils\Utils\ObjectDeclarations::getName() method.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the declaration token +which declared the function.

+
+ +
Tags
+
+
+ codeCoverageIgnore +
+
+
+ see +
+

Original function.

+
+ see +
+

PHPCSUtils native improved version.

+
+ since +
+
+
+ throws +
+

If the specified token is not of type +T_FUNCTION, T_CLASS, T_TRAIT, or T_INTERFACE.

+
+ +
Return values
+ string|null + —

The name of the function; or NULL if the passed token doesn't exist, +the function is anonymous or in case of a parse error/live coding.

+ +
+ +
+

getProperties()

+ +

Retrieves the visibility and implementation properties of a method.

+ + public + static getProperties( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

The format of the return value is: + +array( +'scope' => 'public', // Public, private, or protected +'scope_specified' => true, // TRUE if the scope keyword was found. +'return_type' => '', // The return type of the method. +'return_type_token' => integer, // The stack pointer to the start of the return type +// or FALSE if there is no return type. +'return_type_end_token' => integer, // The stack pointer to the end of the return type +// or FALSE if there is no return type. +'nullable_return_type' => false, // TRUE if the return type is nullable. +'is_abstract' => false, // TRUE if the abstract keyword was found. +'is_final' => false, // TRUE if the final keyword was found. +'is_static' => false, // TRUE if the static keyword was found. +'has_body' => false, // TRUE if the method has a body +); +

+

Main differences with the PHPCS version:

+
    +
  • Bugs fixed: +
      +
    • Handling of PHPCS annotations.
    • +
    • has_body index could be set to true for functions without body in the case of +parse errors or live coding.
    • +
  • +
  • Defensive coding against incorrect calls to this method.
  • +
  • More efficient checking whether a function has a body.
  • +
  • New return_type_end_token (int|false) array index.
  • +
  • To allow for backward compatible handling of arrow functions, this method will also accept +T_STRING tokens and examine them to check if these are arrow functions.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the function token to +acquire the properties for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ throws +
+

If the specified position is not a T_FUNCTION +or T_CLOSURE token nor an arrow function.

+
+ +
Return values
+ array + +
+ +
+

getParameters()

+ +

Retrieves the method parameters for the specified function token.

+ + public + static getParameters( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

Also supports passing in a USE token for a closure use group.

+

The returned array will contain the following information for each parameter:

+

+0 => array( +'name' => '$var', // The variable name. +'token' => integer, // The stack pointer to the variable name. +'content' => string, // The full content of the variable definition. +'pass_by_reference' => boolean, // Is the variable passed by reference? +'reference_token' => integer, // The stack pointer to the reference operator +// or FALSE if the param is not passed by reference. +'variable_length' => boolean, // Is the param of variable length through use of ... ? +'variadic_token' => integer, // The stack pointer to the ... operator +// or FALSE if the param is not variable length. +'type_hint' => string, // The type hint for the variable. +'type_hint_token' => integer, // The stack pointer to the start of the type hint +// or FALSE if there is no type hint. +'type_hint_end_token' => integer, // The stack pointer to the end of the type hint +// or FALSE if there is no type hint. +'nullable_type' => boolean, // TRUE if the var type is nullable. +'comma_token' => integer, // The stack pointer to the comma after the param +// or FALSE if this is the last param. +) +

+

Parameters with default values have the following additional array indexes: +'default' => string, // The full content of the default value. +'default_token' => integer, // The stack pointer to the start of the default value. +'default_equal_token' => integer, // The stack pointer to the equals sign.

+

Main differences with the PHPCS version:

+
    +
  • Defensive coding against incorrect calls to this method.
  • +
  • More efficient and more stable checking whether a T_USE token is a closure use.
  • +
  • More efficient and more stable looping of the default value.
  • +
  • Clearer exception message when a non-closure use token was passed to the function.
  • +
  • To allow for backward compatible handling of arrow functions, this method will also accept +T_STRING tokens and examine them to check if these are arrow functions.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the function token +to acquire the parameters for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ throws +
+

If the specified $stackPtr is not of +type T_FUNCTION, T_CLOSURE or T_USE, +nor an arrow function.

+
+ +
Return values
+ array + +
+ +
+

isArrowFunction()

+ +

Check if an arbitrary token is the "fn" keyword for a PHP 7.4 arrow function.

+ + public + static isArrowFunction( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + +

Helper function for cross-version compatibility with both PHP as well as PHPCS.

+
    +
  • PHP 7.4+ will tokenize most tokens with the content "fn" as T_FN, even when it isn't an arrow function.
  • +
  • PHPCS < 3.5.3 will tokenize arrow functions keywords as T_STRING.
  • +
  • PHPCS 3.5.3/3.5.4 will tokenize the keyword differently depending on which PHP version is used +and similar to PHP will tokenize most tokens with the content "fn" as T_FN, even when it's not an +arrow function. +Note: the tokens tokenized by PHPCS 3.5.3 - 3.5.4 as T_FN are not 100% the same as those tokenized +by PHP 7.4+ as T_FN.
  • +
+

Either way, the T_FN token is not a reliable indicator that something is in actual fact an arrow function. +This function solves that and will give reliable results in the same way as this is now solved in PHPCS 3.5.5.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The token to check. Typically a T_FN or +T_STRING token as those are the only two +tokens which can be the arrow function keyword.

+
+ +
Tags
+
+
+ see +
+

Related function.

+
+ since +
+
+
+ +
Return values
+ bool + —

TRUE is the token is the "fn" keyword for an arrow function. FALSE when not or +in case of live coding/parse error.

+ +
+ +
+

getArrowFunctionOpenClose()

+ +

Retrieve the parenthesis opener, parenthesis closer, the scope opener and the scope closer +for an arrow function.

+ + public + static getArrowFunctionOpenClose( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array|bool + + +

Helper function for cross-version compatibility with both PHP as well as PHPCS. +In PHPCS versions prior to PHPCS 3.5.3/3.5.4, the T_FN token is not yet backfilled +and does not have parenthesis opener/closer nor scope opener/closer indexes assigned +in the $tokens array.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The token to retrieve the openers/closers for. +Typically a T_FN or T_STRING token as those are the +only two tokens which can be the arrow function keyword.

+
+ +
Tags
+
+
+ see +
+

Related function.

+
+ since +
+
+
+ +
Return values
+ array|bool + —

An array with the token pointers or FALSE if this is not an arrow function. +The format of the return value is: + +array( +'parenthesis_opener' => integer, // Stack pointer to the parenthesis opener. +'parenthesis_closer' => integer, // Stack pointer to the parenthesis closer. +'scope_opener' => integer, // Stack pointer to the scope opener (arrow). +'scope_closer' => integer, // Stack pointer to the scope closer. +) +

+ +
+ +
+

isMagicFunction()

+ +

Checks if a given function is a PHP magic function.

+ + public + static isMagicFunction( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The T_FUNCTION token to check.

+
+ +
Tags
+
+
+ todo +
+

Add check for the function declaration being namespaced!

+
+ see +
+

For when you already know the name of the +function and scope checking is done in the +sniff.

+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isMagicFunctionName()

+ +

Verify if a given function name is the name of a PHP magic function.

+ + public + static isMagicFunctionName( + + $name : + string + + ) + : bool + + + +
Parameters
+
+
+ $name + : string +
+

The full function name.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isMagicMethod()

+ +

Checks if a given function is a PHP magic method.

+ + public + static isMagicMethod( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The T_FUNCTION token to check.

+
+ +
Tags
+
+
+ see +
+

For when you already know the name of the +method and scope checking is done in the +sniff.

+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isMagicMethodName()

+ +

Verify if a given function name is the name of a PHP magic method.

+ + public + static isMagicMethodName( + + $name : + string + + ) + : bool + + + +
Parameters
+
+
+ $name + : string +
+

The full function name.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isPHPDoubleUnderscoreMethod()

+ +

Checks if a given function is a PHP native double underscore method.

+ + public + static isPHPDoubleUnderscoreMethod( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The T_FUNCTION token to check.

+
+ +
Tags
+
+
+ see +
+

For when you already know the +name of the method and scope +checking is done in the sniff.

+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isPHPDoubleUnderscoreMethodName()

+ +

Verify if a given function name is the name of a PHP native double underscore method.

+ + public + static isPHPDoubleUnderscoreMethodName( + + $name : + string + + ) + : bool + + + +
Parameters
+
+
+ $name + : string +
+

The full function name.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isSpecialMethod()

+ +

Checks if a given function is a magic method or a PHP native double underscore method.

+ + public + static isSpecialMethod( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The T_FUNCTION token to check.

+
+ +
Tags
+
+
+ see +
+

For when you already know the name of the +method and scope checking is done in the +sniff.

+
+ since +
+

{@internal Not the most efficient way of checking this, but less efficient ways will get +less reliable results or introduce a lot of code duplication.}

+
+ +
Return values
+ bool + +
+ +
+

isSpecialMethodName()

+ +

Verify if a given function name is the name of a magic method or a PHP native double underscore method.

+ + public + static isSpecialMethodName( + + $name : + string + + ) + : bool + + + +
Parameters
+
+
+ $name + : string +
+

The full function name.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html b/docs/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html new file mode 100644 index 00000000..22bcc84d --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html @@ -0,0 +1,730 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ GetTokensAsString +

+ + +

Utility functions to retrieve the content of a set of tokens as a string.

+

In contrast to the PHPCS native \PHP_CodeSniffer\Files\File::getTokensAsString() method, +which has $length as the third parameter, all methods in this class expect a stack pointer to +an $end token (inclusive) as the third parameter.

+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
normal()Retrieve the tab-replaced content of the tokens from the specified start position in +the token stack to the specified end position (inclusive).string
tabReplaced()Retrieve the tab-replaced content of the tokens from the specified start position in +the token stack to the specified end position (inclusive).string
origContent()Retrieve the original content of the tokens from the specified start position in +the token stack to the specified end position (inclusive).string
noComments()Retrieve the content of the tokens from the specified start position in the token +stack to the specified end position (inclusive) without comments.string
noEmpties()Retrieve the code-tokens only content of the tokens from the specified start position +in the token stack to the specified end position (inclusive) without whitespace or comments.string
compact()Retrieve the content of the tokens from the specified start position in the token +stack to the specified end position (inclusive) with all whitespace tokens - tabs, +new lines, multiple spaces - replaced by a single space and optionally without comments.string
getString()Retrieve the content of the tokens from the specified start position in the token stack +to the specified end position (inclusive).string
+ + + +
+

Methods

+ +
+

normal()

+ +

Retrieve the tab-replaced content of the tokens from the specified start position in +the token stack to the specified end position (inclusive).

+ + public + static normal( + + $phpcsFile : + File + + + , $start : + int + + + , $end : + int + + ) + : string + + +

This is the default behaviour for PHPCS.

+

If the tab width is set, either via a (custom) ruleset, the config file or by passing it +on the command-line, PHPCS will automatically replace tabs with spaces. +The 'content' index key in the $tokens array will contain the tab-replaced content. +The 'orig_content' index key in the $tokens array will contain the original content.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start from in the token stack.

+
+ $end + : int +
+

The position to end at in the token stack (inclusive).

+
+ +
Tags
+
+
+ see +
+

Similar length-based function.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ throws +
+

If the specified start position does not exist.

+
+ +
Return values
+ string + —

The token contents.

+ +
+ +
+

tabReplaced()

+ +

Retrieve the tab-replaced content of the tokens from the specified start position in +the token stack to the specified end position (inclusive).

+ + public + static tabReplaced( + + $phpcsFile : + File + + + , $start : + int + + + , $end : + int + + ) + : string + + +

Alias for the \PHPCSUtils\Utils\GetTokensAsString::normal() method.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start from in the token stack.

+
+ $end + : int +
+

The position to end at in the token stack (inclusive).

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified start position does not exist.

+
+ +
Return values
+ string + —

The token contents.

+ +
+ +
+

origContent()

+ +

Retrieve the original content of the tokens from the specified start position in +the token stack to the specified end position (inclusive).

+ + public + static origContent( + + $phpcsFile : + File + + + , $start : + int + + + , $end : + int + + ) + : string + + +

If the original content contained tabs, the return value of this function will +also contain tabs.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start from in the token stack.

+
+ $end + : int +
+

The position to end at in the token stack (inclusive).

+
+ +
Tags
+
+
+ see +
+

Similar length-based function.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ throws +
+

If the specified start position does not exist.

+
+ +
Return values
+ string + —

The token contents.

+ +
+ +
+

noComments()

+ +

Retrieve the content of the tokens from the specified start position in the token +stack to the specified end position (inclusive) without comments.

+ + public + static noComments( + + $phpcsFile : + File + + + , $start : + int + + + , $end : + int + + ) + : string + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start from in the token stack.

+
+ $end + : int +
+

The position to end at in the token stack (inclusive).

+
+ +
Tags
+
+
+ see +
+

Loosely related function.

+
+ since +
+
+
+ throws +
+

If the specified start position does not exist.

+
+ +
Return values
+ string + —

The token contents.

+ +
+ +
+

noEmpties()

+ +

Retrieve the code-tokens only content of the tokens from the specified start position +in the token stack to the specified end position (inclusive) without whitespace or comments.

+ + public + static noEmpties( + + $phpcsFile : + File + + + , $start : + int + + + , $end : + int + + ) + : string + + +

This is, for instance, useful to retrieve a namespace name without stray whitespace or comments. +Use this function selectively and with care!

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start from in the token stack.

+
+ $end + : int +
+

The position to end at in the token stack (inclusive).

+
+ +
Tags
+
+
+ see +
+

Loosely related function.

+
+ since +
+
+
+ throws +
+

If the specified start position does not exist.

+
+ +
Return values
+ string + —

The token contents.

+ +
+ +
+

compact()

+ +

Retrieve the content of the tokens from the specified start position in the token +stack to the specified end position (inclusive) with all whitespace tokens - tabs, +new lines, multiple spaces - replaced by a single space and optionally without comments.

+ + public + static compact( + + $phpcsFile : + File + + + , $start : + int + + + , $end : + int + + + [, $stripComments : + bool + = false ] + ) + : string + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start from in the token stack.

+
+ $end + : int +
+

The position to end at in the token stack (inclusive).

+
+ $stripComments + : bool + = false
+

Whether comments should be stripped from the contents. +Defaults to false.

+
+ +
Tags
+
+
+ see +
+

Loosely related function.

+
+ since +
+
+
+ throws +
+

If the specified start position does not exist.

+
+ +
Return values
+ string + —

The token contents.

+ +
+ +
+

getString()

+ +

Retrieve the content of the tokens from the specified start position in the token stack +to the specified end position (inclusive).

+ + protected + static getString( + + $phpcsFile : + File + + + , $start : + int + + + , $end : + int + + + [, $origContent : + bool + = false ] + + [, $stripComments : + bool + = false ] + + [, $stripWhitespace : + bool + = false ] + + [, $compact : + bool + = false ] + ) + : string + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $start + : int +
+

The position to start from in the token stack.

+
+ $end + : int +
+

The position to end at in the token stack (inclusive).

+
+ $origContent + : bool + = false
+

Whether the original content or the tab replaced +content should be used. +Defaults to false (= tabs replaced with spaces).

+
+ $stripComments + : bool + = false
+

Whether comments should be stripped from the contents. +Defaults to false.

+
+ $stripWhitespace + : bool + = false
+

Whether whitespace should be stripped from the contents. +Defaults to false.

+
+ $compact + : bool + = false
+

Whether all whitespace tokens should be replaced with a +single space. Defaults to false.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified start position does not exist.

+
+ +
Return values
+ string + —

The token contents.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Lists.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Lists.html new file mode 100644 index 00000000..25419933 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Lists.html @@ -0,0 +1,351 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Lists +

+ + +

Utility functions to retrieve information when working with lists.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + +
isShortList()Determine whether a `T_OPEN/CLOSE_SHORT_ARRAY` token is a short list() construct.bool
getOpenClose()Find the list opener & closer based on a T_LIST or T_OPEN_SHORT_ARRAY token.array|bool
getAssignments()Retrieves information on the assignments made in the specified (long/short) list.array
+ + + +
+

Methods

+ +
+

isShortList()

+ +

Determine whether a `T_OPEN/CLOSE_SHORT_ARRAY` token is a short list() construct.

+ + public + static isShortList( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + +

This method also accepts T_OPEN/CLOSE_SQUARE_BRACKET tokens to allow it to be +PHPCS cross-version compatible as the short array tokenizing has been plagued by +a number of bugs over time, which affects the short list determination.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the short array bracket token.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True if the token passed is the open/close bracket of a short list. +False if the token is a short array bracket or plain square bracket +or not one of the accepted tokens.

+ +
+ +
+

getOpenClose()

+ +

Find the list opener & closer based on a T_LIST or T_OPEN_SHORT_ARRAY token.

+ + public + static getOpenClose( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $isShortList : + bool|null + = null ] + ) + : array|bool + + +

This method also accepts T_OPEN_SQUARE_BRACKET tokens to allow it to be +PHPCS cross-version compatible as the short array tokenizing has been plagued by +a number of bugs over time, which affects the short list determination.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_LIST or T_OPEN_SHORT_ARRAY +token in the stack.

+
+ $isShortList + : bool|null + = null
+

Short-circuit the short list check for T_OPEN_SHORT_ARRAY +tokens if it isn't necessary. +Efficiency tweak for when this has already been established, +i.e. when encountering a nested list while walking the +tokens in a list. +Use with care.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ array|bool + —

Array with two keys opener, closer or false if +not a (short) list token or if the opener/closer +could not be determined.

+ +
+ +
+

getAssignments()

+ +

Retrieves information on the assignments made in the specified (long/short) list.

+ + public + static getAssignments( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

This method also accepts T_OPEN_SQUARE_BRACKET tokens to allow it to be +PHPCS cross-version compatible as the short array tokenizing has been plagued by +a number of bugs over time, which affects the short list determination.

+

The returned array will contain the following basic information for each assignment:

+

+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. +'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. +

+

Assignments with keys will have the following additional array indexes set: + +'key' => string, // The content of the key, cleaned of comments. +'key_token' => int, // The stack pointer to the start of the key. +'key_end_token' => int, // The stack pointer to the end of the key. +'double_arrow_token' => int, // The stack pointer to the double arrow. +

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the function token +to acquire the parameters for.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified $stackPtr is not of +type T_LIST, T_OPEN_SHORT_ARRAY or +T_OPEN_SQUARE_BRACKET.

+
+ +
Return values
+ array + —

An array with information on each assignment made, including skipped assignments (empty), +or an empty array if no assignments are made at all (fatal error in PHP 7+).

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html new file mode 100644 index 00000000..19b03558 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html @@ -0,0 +1,518 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Namespaces +

+ + +

Utility functions for use when examining T_NAMESPACE tokens and to determine the +namespace of arbitrary tokens.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
getType()Determine what a T_NAMESPACE token is used for.string
isDeclaration()Determine whether a T_NAMESPACE token is the keyword for a namespace declaration.bool
isOperator()Determine whether a T_NAMESPACE token is used as an operator.bool
getDeclaredName()Get the complete namespace name as declared.string|bool
findNamespacePtr()Determine the namespace an arbitrary token lives in.int|bool
determineNamespace()Determine the namespace name an arbitrary token lives in.string
+ + + +
+

Methods

+ +
+

getType()

+ +

Determine what a T_NAMESPACE token is used for.

+ + public + static getType( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : string + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_NAMESPACE token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is +not a T_NAMESPACE token.

+
+ +
Return values
+ string + —

Either 'declaration', 'operator'. +An empty string will be returned if it couldn't be +reliably determined what the T_NAMESPACE token is used for, +which will normally mean the code contains a parse/fatal error.

+ +
+ +
+

isDeclaration()

+ +

Determine whether a T_NAMESPACE token is the keyword for a namespace declaration.

+ + public + static isDeclaration( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of a T_NAMESPACE token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is +not a T_NAMESPACE token.

+
+ +
Return values
+ bool + —

True if the token passed is the keyword for a namespace declaration. +False if not.

+ +
+ +
+

isOperator()

+ +

Determine whether a T_NAMESPACE token is used as an operator.

+ + public + static isOperator( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of a T_NAMESPACE token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is +not a T_NAMESPACE token.

+
+ +
Return values
+ bool + —

True if the token passed is used as an operator. False if not.

+ +
+ +
+

getDeclaredName()

+ +

Get the complete namespace name as declared.

+ + public + static getDeclaredName( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $clean : + bool + = true ] + ) + : string|bool + + +

For hierarchical namespaces, the name will be composed of several tokens, +i.e. MyProject\Sub\Level which will be returned together as one string.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of a T_NAMESPACE token.

+
+ $clean + : bool + = true
+

Optional. Whether to get the name stripped +of potentially interlaced whitespace and/or +comments. Defaults to true.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ string|bool + —

The namespace name, or false if the specified position is not a +T_NAMESPACE token, the token points to a namespace operator +or when parse errors are encountered/during live coding. +Note: The name can be an empty string for a valid global +namespace declaration.

+ +
+ +
+

findNamespacePtr()

+ +

Determine the namespace an arbitrary token lives in.

+ + public + static findNamespacePtr( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : int|bool + + +

Note: when a namespace declaration token or a token which is part of the namespace +name is passed to this method, the result will be false as technically, they are not +within a namespace.

+

Note: this method has no opinion on whether the token passed is actually subject +to namespacing.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The token for which to determine +the namespace.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Token pointer to the applicable namespace keyword or +false if it couldn't be determined or no namespace applies.

+ +
+ +
+

determineNamespace()

+ +

Determine the namespace name an arbitrary token lives in.

+ + public + static determineNamespace( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : string + + +

Note: this method has no opinion on whether the token passed is actually subject +to namespacing.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The token for which to determine +the namespace.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ string + —

Namespace name or empty string if it couldn't be determined +or no namespace applies.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Numbers.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Numbers.html new file mode 100644 index 00000000..aea25849 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Numbers.html @@ -0,0 +1,802 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Numbers +

+ + +

Utility functions for working with integer/float tokens.

+

PHP 7.4 introduced numeric literal separators which break number tokenization in older PHP versions. +PHPCS backfills this since PHPCS 3.5.3/4.

+

However, if an external standard intends to support PHPCS < 3.5.4 and PHP < 7.4, working with +number tokens has suddenly become a challenge.

+

The functions in this class have been put in place to ease that pain and it is +strongly recommended to always use these functions when sniffing for and examining the +contents of T_LNUMBER or T_DNUMBER tokens.

+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
REGEX_DECIMAL_INTRegex to determine whether the contents of an arbitrary string represents a decimal integer.'`^(?:0|[1-9][0-9]*)$`D'
REGEX_OCTAL_INTRegex to determine whether the contents of an arbitrary string represents an octal integer.'`^0[0-7]+$`D'
REGEX_BINARY_INTRegex to determine whether the contents of an arbitrary string represents a binary integer.'`^0b[0-1]+$`iD'
REGEX_HEX_INTRegex to determine whether the contents of an arbitrary string represents a hexidecimal integer.'`^0x[0-9A-F]+$`iD'
REGEX_FLOATRegex to determine whether the contents of an arbitrary string represents a float.'` + ^(?: + (?: + (?: + (?P<LNUM>[0-9]+) + | + (?P<DNUM>([0-9]*\\.(?P>LNUM)|(?P>LNUM)\\.[0-9]*)) + ) + [e][+-]?(?P>LNUM) + ) + | + (?P>DNUM) + | + (?:0|[1-9][0-9]*) + )$ + `ixD'
REGEX_NUMLIT_STRINGRegex to determine is a T_STRING following a T_[DL]NUMBER is part of a numeric literal sequence.'`^((?<![\\.e])_[0-9][0-9e\\.]*)+$`iD'
REGEX_HEX_NUMLIT_STRINGRegex to determine is a T_STRING following a T_[DL]NUMBER is part of a hexidecimal numeric literal sequence.'`^((?<!\\.)_[0-9A-F]*)+$`iD'
UNSUPPORTED_PHPCS_VERSIONPHPCS versions in which the backfill for PHP 7.4 numeric literal separators is broken.'3.5.3'
$numericLiteralAcceptedTokensValid tokens which could be part of a numeric literal sequence in PHP < 7.4.array
getCompleteNumber()Helper function to deal with numeric literals, potentially with underscore separators.array
getDecimalValue()Get the decimal number value of a numeric string.string|bool
isDecimalInt()Verify whether the contents of an arbitrary string represents a decimal integer.bool
isHexidecimalInt()Verify whether the contents of an arbitrary string represents a hexidecimal integer.bool
isBinaryInt()Verify whether the contents of an arbitrary string represents a binary integer.bool
isOctalInt()Verify whether the contents of an arbitrary string represents an octal integer.bool
isFloat()Verify whether the contents of an arbitrary string represents a floating point number.bool
+ +
+

Constants

+ +
+

REGEX_DECIMAL_INT

+ +

Regex to determine whether the contents of an arbitrary string represents a decimal integer.

+ + + string + $REGEX_DECIMAL_INT + = '`^(?:0|[1-9][0-9]*)$`D' + +
+ +
+

REGEX_OCTAL_INT

+ +

Regex to determine whether the contents of an arbitrary string represents an octal integer.

+ + + string + $REGEX_OCTAL_INT + = '`^0[0-7]+$`D' + +
+ +
+

REGEX_BINARY_INT

+ +

Regex to determine whether the contents of an arbitrary string represents a binary integer.

+ + + string + $REGEX_BINARY_INT + = '`^0b[0-1]+$`iD' + +
+ +
+

REGEX_HEX_INT

+ +

Regex to determine whether the contents of an arbitrary string represents a hexidecimal integer.

+ + + string + $REGEX_HEX_INT + = '`^0x[0-9A-F]+$`iD' + +
+ +
+

REGEX_FLOAT

+ +

Regex to determine whether the contents of an arbitrary string represents a float.

+ + + string + $REGEX_FLOAT + = '` + ^(?: + (?: + (?: + (?P<LNUM>[0-9]+) + | + (?P<DNUM>([0-9]*\\.(?P>LNUM)|(?P>LNUM)\\.[0-9]*)) + ) + [e][+-]?(?P>LNUM) + ) + | + (?P>DNUM) + | + (?:0|[1-9][0-9]*) + )$ + `ixD' + +
+ +
+

REGEX_NUMLIT_STRING

+ +

Regex to determine is a T_STRING following a T_[DL]NUMBER is part of a numeric literal sequence.

+ + + string + $REGEX_NUMLIT_STRING + = '`^((?<![\\.e])_[0-9][0-9e\\.]*)+$`iD' + +
PHP cross-version compat for PHP 7.4 numeric literals with underscore separators.
+
+ +
+

REGEX_HEX_NUMLIT_STRING

+ +

Regex to determine is a T_STRING following a T_[DL]NUMBER is part of a hexidecimal numeric literal sequence.

+ + + string + $REGEX_HEX_NUMLIT_STRING + = '`^((?<!\\.)_[0-9A-F]*)+$`iD' + +
PHP cross-version compat for PHP 7.4 numeric literals with underscore separators.
+
+ +
+

UNSUPPORTED_PHPCS_VERSION

+ +

PHPCS versions in which the backfill for PHP 7.4 numeric literal separators is broken.

+ + + string + $UNSUPPORTED_PHPCS_VERSION + = '3.5.3' + +
+
+ +
+

Properties

+ +
+

$numericLiteralAcceptedTokens

+ +

Valid tokens which could be part of a numeric literal sequence in PHP < 7.4.

+ + private + static array + $numericLiteralAcceptedTokens + = [\T_LNUMBER => true, \T_DNUMBER => true, \T_STRING => true] +
+
+ +
+

Methods

+ +
+

getCompleteNumber()

+ +

Helper function to deal with numeric literals, potentially with underscore separators.

+ + public + static getCompleteNumber( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

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 +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 +PHP 7.4 numbers with underscore separators are tokenized incorrectly - with the +exception of PHPCS 3.5.3 as the buggyness of the original backfill implementation makes +it impossible to provide reliable results.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of a T_LNUMBER or T_DNUMBER token.

+
+ +
Tags
+
+
+ link +
+
+
+ link +
+
+
+ since +
+
+
+ throws +
+

If the specified token is not of type +T_LNUMBER or T_DNUMBER.

+
+ throws +
+

If this function is called in combination +with an unsupported PHPCS version.

+
+ +
Return values
+ array + —

An array with the following information about the number:

+
    +
  • 'orig_content' string The (potentially concatenated) original content of the tokens;
  • +
  • 'content' string The (potentially concatenated) content, underscore(s) removed;
  • +
  • 'code' int The token code of the number, either T_LNUMBER or T_DNUMBER.
  • +
  • 'type' string The token type, either 'T_LNUMBER' or 'T_DNUMBER'.
  • +
  • 'decimal' string The decimal value of the number;
  • +
  • 'last_token' int The stackPtr to the last token which was part of the number; +This will be the same as the original stackPtr if it is not +a PHP 7.4 number with underscores.
  • +
+ +
+ +
+

getDecimalValue()

+ +

Get the decimal number value of a numeric string.

+ + public + static getDecimalValue( + + $string : + string + + ) + : string|bool + + +

Takes PHP 7.4 numeric literal separators in numbers into account.

+ +
Parameters
+
+
+ $string + : string +
+

Arbitrary token content string.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ string|bool + —

Decimal number as a string or false if the passed parameter +was not a numeric string. +Note: floating point numbers with exponent will not be expanded, +but returned as-is.

+ +
+ +
+

isDecimalInt()

+ +

Verify whether the contents of an arbitrary string represents a decimal integer.

+ + public + static isDecimalInt( + + $string : + string + + ) + : bool + + +

Takes PHP 7.4 numeric literal separators in numbers into account.

+ +
Parameters
+
+
+ $string + : string +
+

Arbitrary string.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isHexidecimalInt()

+ +

Verify whether the contents of an arbitrary string represents a hexidecimal integer.

+ + public + static isHexidecimalInt( + + $string : + string + + ) + : bool + + +

Takes PHP 7.4 numeric literal separators in numbers into account.

+ +
Parameters
+
+
+ $string + : string +
+

Arbitrary string.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isBinaryInt()

+ +

Verify whether the contents of an arbitrary string represents a binary integer.

+ + public + static isBinaryInt( + + $string : + string + + ) + : bool + + +

Takes PHP 7.4 numeric literal separators in numbers into account.

+ +
Parameters
+
+
+ $string + : string +
+

Arbitrary string.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isOctalInt()

+ +

Verify whether the contents of an arbitrary string represents an octal integer.

+ + public + static isOctalInt( + + $string : + string + + ) + : bool + + +

Takes PHP 7.4 numeric literal separators in numbers into account.

+ +
Parameters
+
+
+ $string + : string +
+

Arbitrary string.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isFloat()

+ +

Verify whether the contents of an arbitrary string represents a floating point number.

+ + public + static isFloat( + + $string : + string + + ) + : bool + + +

Takes PHP 7.4 numeric literal separators in numbers into account.

+ +
Parameters
+
+
+ $string + : string +
+

Arbitrary string.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html b/docs/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html new file mode 100644 index 00000000..2848b26f --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html @@ -0,0 +1,609 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ ObjectDeclarations +

+ + +

Utility functions for use when examining object declaration statements.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
getName()Retrieves the declaration name for classes, interfaces, traits, and functions.string|null
getClassProperties()Retrieves the implementation properties of a class.array
findExtendedClassName()Retrieves the name of the class that the specified class extends.string|bool
findImplementedInterfaceNames()Retrieves the names of the interfaces that the specified class implements.array|bool
findExtendedInterfaceNames()Retrieves the names of the interfaces that the specified interface extends.array|bool
findNames()Retrieves the names of the extended classes or interfaces or the implemented +interfaces that the specific class/interface declaration extends/implements.array|bool
+ + + +
+

Methods

+ +
+

getName()

+ +

Retrieves the declaration name for classes, interfaces, traits, and functions.

+ + public + static getName( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : string|null + + +

Note: For ES6 classes in combination with PHPCS 2.x, passing a T_STRING token to +this method will be accepted for JS files. +Note: support for JS ES6 method syntax has not (yet) been back-filled for PHPCS < 3.0.0.

+

Main differences with the PHPCS version:

+
    +
  • Defensive coding against incorrect calls to this method.
  • +
  • Improved handling of invalid names, like names starting with a number. +This allows sniffs to report on invalid names instead of ignoring them.
  • +
  • Bug fix: improved handling of parse errors. +Using the original method, a parse error due to an invalid name could cause the method +to return the name of the next construct, a partial name and/or the name of a class +being extended/interface being implemented. +Using this version of the utility method, either the complete name (invalid or not) will +be returned or null in case of no name (parse error).
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the declaration token +which declared the class, interface, +trait, or function.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ throws +
+

If the specified token is not of type +T_FUNCTION, T_CLASS, T_TRAIT, or T_INTERFACE.

+
+ +
Return values
+ string|null + —

The name of the class, interface, trait, or function; +or NULL if the passed token doesn't exist, the function or +class is anonymous or in case of a parse error/live coding.

+ +
+ +
+

getClassProperties()

+ +

Retrieves the implementation properties of a class.

+ + public + static getClassProperties( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

The format of the return value is: + +array( +'is_abstract' => false, // true if the abstract keyword was found. +'is_final' => false, // true if the final keyword was found. +); +

+

Main differences with the PHPCS version:

+
    +
  • Bugs fixed: +
      +
    • Handling of PHPCS annotations.
    • +
    • Handling of unorthodox docblock placement.
    • +
    • A class cannot both be abstract as well as final, so this utility should not allow for that.
    • +
  • +
  • Defensive coding against incorrect calls to this method.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the T_CLASS +token to acquire the properties for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_CLASS token.

+
+ +
Return values
+ array + +
+ +
+

findExtendedClassName()

+ +

Retrieves the name of the class that the specified class extends.

+ + public + static findExtendedClassName( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : string|bool + + +

Works for classes, anonymous classes and interfaces, though it is strongly recommended +to use the \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.

+

Main differences with the PHPCS version:

+
    +
  • Bugs fixed: +
      +
    • Handling of PHPCS annotations.
    • +
    • Handling of comments.
    • +
  • +
  • Improved handling of parse errors.
  • +
  • The returned name will be clean of superfluous whitespace and/or comments.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The stack position of the class or interface.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of +the original.

+
+ see +
+

Similar method for extended interfaces.

+
+ since +
+
+
+ +
Return values
+ string|bool + —

The extended class name or FALSE on error or if there +is no extended class name.

+ +
+ +
+

findImplementedInterfaceNames()

+ +

Retrieves the names of the interfaces that the specified class implements.

+ + public + static findImplementedInterfaceNames( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array|bool + + +

Main differences with the PHPCS version:

+
    +
  • Bugs fixed: +
      +
    • Handling of PHPCS annotations.
    • +
    • Handling of comments.
    • +
  • +
  • Improved handling of parse errors.
  • +
  • The returned name(s) will be clean of superfluous whitespace and/or comments.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The stack position of the class.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of +the original.

+
+ since +
+
+
+ +
Return values
+ array|bool + —

Array with names of the implemented interfaces or FALSE on +error or if there are no implemented interface names.

+ +
+ +
+

findExtendedInterfaceNames()

+ +

Retrieves the names of the interfaces that the specified interface extends.

+ + public + static findExtendedInterfaceNames( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array|bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The stack position of the interface keyword.

+
+ +
Tags
+
+
+ see +
+

Similar method for extended classes.

+
+ since +
+
+
+ +
Return values
+ array|bool + —

Array with names of the extended interfaces or FALSE on +error or if there are no extended interface names.

+ +
+ +
+

findNames()

+ +

Retrieves the names of the extended classes or interfaces or the implemented +interfaces that the specific class/interface declaration extends/implements.

+ + private + static findNames( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $keyword : + int + + + , $allowedFor : + array + + ) + : array|bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The stack position of the +class/interface declaration keyword.

+
+ $keyword + : int +
+

The token constant for the keyword to examine. +Either T_EXTENDS or T_IMPLEMENTS.

+
+ $allowedFor + : array +
+

Array of OO types for which use of the keyword +is allowed.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ array|bool + —

Returns an array of names or false on error or when the object +being declared does not extend/implement another object.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Operators.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Operators.html new file mode 100644 index 00000000..1b8cf9ea --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Operators.html @@ -0,0 +1,332 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Operators +

+ + +

Utility functions for use when working with operators.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + +
$extraUnaryIndicatorsTokens which indicate that a plus/minus is unary when they preceed it.array
isReference()Determine if the passed token is a reference operator.bool
isUnaryPlusMinus()Determine whether a T_MINUS/T_PLUS token is a unary operator.bool
isShortTernary()Determine whether a ternary is a short ternary/elvis operator, i.e. without "middle".bool
+ + +
+

Properties

+ +
+

$extraUnaryIndicators

+ +

Tokens which indicate that a plus/minus is unary when they preceed it.

+ + private + static array + $extraUnaryIndicators + = [\T_STRING_CONCAT => true, \T_RETURN => true, \T_ECHO => true, \T_PRINT => true, \T_YIELD => true, \T_COMMA => true, \T_OPEN_PARENTHESIS => true, \T_OPEN_SQUARE_BRACKET => true, \T_OPEN_SHORT_ARRAY => true, \T_OPEN_CURLY_BRACKET => true, \T_COLON => true, \T_INLINE_THEN => true, \T_INLINE_ELSE => true, \T_CASE => true] +
+
+ +
+

Methods

+ +
+

isReference()

+ +

Determine if the passed token is a reference operator.

+ + public + static isReference( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + +

Main differences with the PHPCS version:

+
    +
  • Defensive coding against incorrect calls to this method.
  • +
  • Improved handling of select tokenizer errors involving short lists/short arrays.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_BITWISE_AND token.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ +
Return values
+ bool + —

TRUE if the specified token position represents a reference. +FALSE if the token represents a bitwise operator.

+ +
+ +
+

isUnaryPlusMinus()

+ +

Determine whether a T_MINUS/T_PLUS token is a unary operator.

+ + public + static isUnaryPlusMinus( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the plus/minus token.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True if the token passed is a unary operator. +False otherwise or if the token is not a T_PLUS/T_MINUS token.

+ +
+ +
+

isShortTernary()

+ +

Determine whether a ternary is a short ternary/elvis operator, i.e. without "middle".

+ + public + static isShortTernary( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the ternary then/else +operator in the stack.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True if short ternary, or false otherwise.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Orthography.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Orthography.html new file mode 100644 index 00000000..3a96d76a --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Orthography.html @@ -0,0 +1,320 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Orthography +

+ + +

Utility functions for checking the orthography of arbitrary text strings.

+
+

An orthography is a set of conventions for writing a language. It includes norms of spelling, +hyphenation, capitalization, word breaks, emphasis, and punctuation. +Source: https://en.wikipedia.org/wiki/Orthography

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + +
TERMINAL_POINTSCharacters which are considered terminal points for a sentence.'.?!'
isFirstCharCapitalized()Check if the first character of an arbitrary text string is a capital letter.bool
isFirstCharLowercase()Check if the first character of an arbitrary text string is a lowercase letter.bool
isLastCharPunctuation()Check if the last character of an arbitrary text string is a valid punctuation character.bool
+ +
+

Constants

+ +
+

TERMINAL_POINTS

+ +

Characters which are considered terminal points for a sentence.

+ + + string + $TERMINAL_POINTS + = '.?!' + +
+
+ + +
+

Methods

+ +
+

isFirstCharCapitalized()

+ +

Check if the first character of an arbitrary text string is a capital letter.

+ + public + static isFirstCharCapitalized( + + $string : + string + + ) + : bool + + +

Letter characters which do not have a concept of lower/uppercase will +be accepted as correctly capitalized.

+ +
Parameters
+
+
+ $string + : string +
+

The text string to examine. +This can be the contents of a text string token, +but also, for instance, a comment text. +Potential text delimiter quotes should be stripped +off a text string before passing it to this method.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True when the first character is a capital letter or a letter +which doesn't have a concept of capitalization. +False otherwise, including for non-letter characters.

+ +
+ +
+

isFirstCharLowercase()

+ +

Check if the first character of an arbitrary text string is a lowercase letter.

+ + public + static isFirstCharLowercase( + + $string : + string + + ) + : bool + + + +
Parameters
+
+
+ $string + : string +
+

The text string to examine. +This can be the contents of a text string token, +but also, for instance, a comment text. +Potential text delimiter quotes should be stripped +off a text string before passing it to this method.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True when the first character is a lowercase letter. +False otherwise, including for letters which don't have a concept of +capitalization and for non-letter characters.

+ +
+ +
+

isLastCharPunctuation()

+ +

Check if the last character of an arbitrary text string is a valid punctuation character.

+ + public + static isLastCharPunctuation( + + $string : + string + + + [, $allowedChars : + string + = self::TERMINAL_POINTS ] + ) + : bool + + + +
Parameters
+
+
+ $string + : string +
+

The text string to examine. +This can be the contents of a text string token, +but also, for instance, a comment text. +Potential text delimiter quotes should be stripped +off a text string before passing it to this method.

+
+ $allowedChars + : string + = self::TERMINAL_POINTS
+

Characters which are considered valid punctuation +to end the text string. +Defaults to '.?!', i.e. a full stop, question mark +or exclamation mark.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html new file mode 100644 index 00000000..a2b1903d --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html @@ -0,0 +1,1028 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Parentheses +

+ + +

Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped in +parentheses.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
getOwner()Get the pointer to the parentheses owner of an open/close parenthesis.int|bool
isOwnerIn()Check whether the parenthesis owner of an open/close parenthesis is within a limited +set of valid owners.bool
hasOwner()Check whether the passed token is nested within parentheses owned by one of the valid owners.bool
getFirstOpener()Retrieve the position of the opener to the first (outer) set of parentheses an arbitrary +token is wrapped in, where the parentheses owner is within the set of valid owners.int|bool
getFirstCloser()Retrieve the position of the closer to the first (outer) set of parentheses an arbitrary +token is wrapped in, where the parentheses owner is within the set of valid owners.int|bool
getFirstOwner()Retrieve the position of the parentheses owner to the first (outer) set of parentheses an +arbitrary token is wrapped in, where the parentheses owner is within the set of valid owners.int|bool
getLastOpener()Retrieve the position of the opener to the last (inner) set of parentheses an arbitrary +token is wrapped in, where the parentheses owner is within the set of valid owners.int|bool
getLastCloser()Retrieve the position of the closer to the last (inner) set of parentheses an arbitrary +token is wrapped in, where the parentheses owner is within the set of valid owners.int|bool
getLastOwner()Retrieve the position of the parentheses owner to the last (inner) set of parentheses an +arbitrary token is wrapped in where the parentheses owner is within the set of valid owners.int|bool
firstOwnerIn()Check whether the owner of a outermost wrapping set of parentheses of an arbitrary token +is within a limited set of acceptable token types.int|bool
lastOwnerIn()Check whether the owner of a innermost wrapping set of parentheses of an arbitrary token +is within a limited set of acceptable token types.int|bool
nestedParensWalker()Helper method. Retrieve the position of a parentheses opener for an arbitrary passed token.int|bool
+ + + +
+

Methods

+ +
+

getOwner()

+ +

Get the pointer to the parentheses owner of an open/close parenthesis.

+ + public + static getOwner( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : int|bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of T_OPEN/CLOSE_PARENTHESIS token.

+
+ +
Tags
+
+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ +
Return values
+ int|bool + —

Integer stack pointer to the parentheses owner or false if the +parenthesis does not have a (direct) owner or if the token passed +was not a parenthesis.

+ +
+ +
+

isOwnerIn()

+ +

Check whether the parenthesis owner of an open/close parenthesis is within a limited +set of valid owners.

+ + public + static isOwnerIn( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $validOwners : + int|string|array + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of T_OPEN/CLOSE_PARENTHESIS token.

+
+ $validOwners + : int|string|array +
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ since +
+

Added BC support for PHP 7.4 arrow functions.

+
+ +
Return values
+ bool + —

True if the owner is within the list of $validOwners, false if not and +if the parenthesis does not have a (direct) owner.

+ +
+ +
+

hasOwner()

+ +

Check whether the passed token is nested within parentheses owned by one of the valid owners.

+ + public + static hasOwner( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $validOwners : + int|string|array + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $validOwners + : int|string|array +
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

getFirstOpener()

+ +

Retrieve the position of the opener to the first (outer) set of parentheses an arbitrary +token is wrapped in, where the parentheses owner is within the set of valid owners.

+ + public + static getFirstOpener( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $validOwners : + int|string|array + = [] ] + ) + : int|bool + + +

If no $validOwners are specified, the opener to the first set of parentheses surrounding +the token will be returned.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $validOwners + : int|string|array + = []
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the parentheses opener or false if the token +does not have parentheses owned by any of the valid owners or if +the token is not nested in parentheses at all.

+ +
+ +
+

getFirstCloser()

+ +

Retrieve the position of the closer to the first (outer) set of parentheses an arbitrary +token is wrapped in, where the parentheses owner is within the set of valid owners.

+ + public + static getFirstCloser( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $validOwners : + int|string|array + = [] ] + ) + : int|bool + + +

If no $validOwners are specified, the closer to the first set of parentheses surrounding +the token will be returned.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $validOwners + : int|string|array + = []
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the parentheses closer or false if the token +does not have parentheses owned by any of the valid owners or if +the token is not nested in parentheses at all.

+ +
+ +
+

getFirstOwner()

+ +

Retrieve the position of the parentheses owner to the first (outer) set of parentheses an +arbitrary token is wrapped in, where the parentheses owner is within the set of valid owners.

+ + public + static getFirstOwner( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $validOwners : + int|string|array + = [] ] + ) + : int|bool + + +

If no $validOwners are specified, the owner to the first set of parentheses surrounding +the token will be returned or false if the first set of parentheses does not have an owner.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $validOwners + : int|string|array + = []
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the parentheses owner or false if the token +does not have parentheses owned by any of the valid owners or if +the token is not nested in parentheses at all.

+ +
+ +
+

getLastOpener()

+ +

Retrieve the position of the opener to the last (inner) set of parentheses an arbitrary +token is wrapped in, where the parentheses owner is within the set of valid owners.

+ + public + static getLastOpener( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $validOwners : + int|string|array + = [] ] + ) + : int|bool + + +

If no $validOwners are specified, the opener to the last set of parentheses surrounding +the token will be returned.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $validOwners + : int|string|array + = []
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the parentheses opener or false if the token +does not have parentheses owned by any of the valid owners or if +the token is not nested in parentheses at all.

+ +
+ +
+

getLastCloser()

+ +

Retrieve the position of the closer to the last (inner) set of parentheses an arbitrary +token is wrapped in, where the parentheses owner is within the set of valid owners.

+ + public + static getLastCloser( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $validOwners : + int|string|array + = [] ] + ) + : int|bool + + +

If no $validOwners are specified, the closer to the last set of parentheses surrounding +the token will be returned.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $validOwners + : int|string|array + = []
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the parentheses closer or false if the token +does not have parentheses owned by any of the valid owners or if +the token is not nested in parentheses at all.

+ +
+ +
+

getLastOwner()

+ +

Retrieve the position of the parentheses owner to the last (inner) set of parentheses an +arbitrary token is wrapped in where the parentheses owner is within the set of valid owners.

+ + public + static getLastOwner( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $validOwners : + int|string|array + = [] ] + ) + : int|bool + + +

If no $validOwners are specified, the owner to the last set of parentheses surrounding +the token will be returned or false if the last set of parentheses does not have an owner.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $validOwners + : int|string|array + = []
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the parentheses owner or false if the token +does not have parentheses owned by any of the valid owners or if +the token is not nested in parentheses at all.

+ +
+ +
+

firstOwnerIn()

+ +

Check whether the owner of a outermost wrapping set of parentheses of an arbitrary token +is within a limited set of acceptable token types.

+ + public + static firstOwnerIn( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $validOwners : + int|string|array + + ) + : int|bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position in the stack of the +token to verify.

+
+ $validOwners + : int|string|array +
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the valid parentheses owner or false if +the token was not wrapped in parentheses or if the outermost set +of parentheses in which the token is wrapped does not have an owner +within the set of owners considered valid.

+ +
+ +
+

lastOwnerIn()

+ +

Check whether the owner of a innermost wrapping set of parentheses of an arbitrary token +is within a limited set of acceptable token types.

+ + public + static lastOwnerIn( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $validOwners : + int|string|array + + ) + : int|bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position in the stack of the +token to verify.

+
+ $validOwners + : int|string|array +
+

Array of token constants for the owners +which should be considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the valid parentheses owner or false if +the token was not wrapped in parentheses or if the innermost set +of parentheses in which the token is wrapped does not have an owner +within the set of owners considered valid.

+ +
+ +
+

nestedParensWalker()

+ +

Helper method. Retrieve the position of a parentheses opener for an arbitrary passed token.

+ + private + static nestedParensWalker( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $validOwners : + int|string|array + = [] ] + + [, $reverse : + bool + = false ] + ) + : int|bool + + +

If no $validOwners are specified, the opener to the first set of parentheses surrounding +the token - or if $reverse=true, the last set of parentheses - will be returned.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the token we are checking.

+
+ $validOwners + : int|string|array + = []
+

Optional. Array of token constants for the owners +which should be considered valid.

+
+ $reverse + : bool + = false
+

Optional. Whether to search for the first/outermost +(false) or the last/innermost (true) set of +parentheses with the specified owner(s).

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the parentheses opener or false if the token +does not have parentheses owned by any of the valid owners or if +the token is not nested in parentheses at all.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html b/docs/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html new file mode 100644 index 00000000..8efeb59a --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html @@ -0,0 +1,467 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ PassedParameters +

+ + +

Utility functions to retrieve information about parameters passed to function calls, +array declarations, isset and unset constructs.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
$allowedConstructsThe token types these methods can handle.array
$callParsingStopPointsTokens which are considered stop point, either because they are the end +of the parameter (comma) or because we need to skip over them.array
hasParameters()Checks if any parameters have been passed.bool
getParameters()Get information on all parameters passed.array
getParameter()Get information on a specific parameter passed.array|bool
getParameterCount()Count the number of parameters which have been passed.int
+ + +
+

Properties

+ +
+

$allowedConstructs

+ +

The token types these methods can handle.

+ + private + static array + $allowedConstructs + = [ + \T_STRING => true, + \T_VARIABLE => true, + \T_SELF => true, + \T_STATIC => true, + \T_ARRAY => true, + \T_OPEN_SHORT_ARRAY => true, + \T_ISSET => true, + \T_UNSET => true, + // BC for various short array tokenizer issues. See the Arrays class for more details. + \T_OPEN_SQUARE_BRACKET => true, +] +
+ +
+

$callParsingStopPoints

+ +

Tokens which are considered stop point, either because they are the end +of the parameter (comma) or because we need to skip over them.

+ + private + static array + $callParsingStopPoints + = [\T_COMMA => \T_COMMA, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_OPEN_PARENTHESIS => \T_OPEN_PARENTHESIS, \T_DOC_COMMENT_OPEN_TAG => \T_DOC_COMMENT_OPEN_TAG] +
+
+ +
+

Methods

+ +
+

hasParameters()

+ +

Checks if any parameters have been passed.

+ + public + static hasParameters( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + +
    +
  • If passed a T_STRING or T_VARIABLE stack pointer, it will treat it as a function call. +If a T_STRING or T_VARIABLE which is not a function call is passed, the behaviour is +unreliable.
  • +
  • If passed a T_SELF or T_STATIC stack pointer, it will accept it as a +function call when used like new self().
  • +
  • If passed a T_ARRAY or T_OPEN_SHORT_ARRAY stack pointer, it will detect +whether the array has values or is empty.
  • +
  • If passed a T_ISSET or T_UNSET stack pointer, it will detect whether those +language constructs have "parameters".
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the T_STRING, T_VARIABLE, T_ARRAY, +T_OPEN_SHORT_ARRAY, T_ISSET, or T_UNSET token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the token passed is not one of the +accepted types or doesn't exist.

+
+ +
Return values
+ bool + +
+ +
+

getParameters()

+ +

Get information on all parameters passed.

+ + public + static getParameters( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

See \PHPCSUtils\Utils\PHPCSUtils\Utils\PassedParameters::hasParameters() for information on the supported +constructs.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the T_STRING, T_VARIABLE, T_ARRAY, +T_OPEN_SHORT_ARRAY, T_ISSET, or T_UNSET token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the token passed is not one of the +accepted types or doesn't exist.

+
+ +
Return values
+ array + —

Returns a multi-dimentional array with the "start" token pointer, "end" token +pointer, "raw" parameter value and "clean" (only code, no comments) parameter +value for all parameters. The array starts at index 1. +If no parameters are found, will return an empty array.

+ +
+ +
+

getParameter()

+ +

Get information on a specific parameter passed.

+ + public + static getParameter( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $paramOffset : + int + + ) + : array|bool + + +

See \PHPCSUtils\Utils\PHPCSUtils\Utils\PassedParameters::hasParameters() for information on the supported +constructs.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the T_STRING, T_VARIABLE, T_ARRAY, +T_OPEN_SHORT_ARRAY, T_ISSET or T_UNSET token.

+
+ $paramOffset + : int +
+

The 1-based index position of the parameter to retrieve.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the token passed is not one of the +accepted types or doesn't exist.

+
+ +
Return values
+ array|bool + —

Returns an array with the "start" token pointer, "end" token pointer, +"raw" parameter value and "clean" (only code, no comments) parameter +value for the parameter at the specified offset. +Or FALSE if the specified parameter is not found.

+ +
+ +
+

getParameterCount()

+ +

Count the number of parameters which have been passed.

+ + public + static getParameterCount( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : int + + +

See \PHPCSUtils\Utils\PHPCSUtils\Utils\PassedParameters::hasParameters() for information on the supported +constructs.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position of the T_STRING, T_VARIABLE, T_ARRAY, +T_OPEN_SHORT_ARRAY, T_ISSET or T_UNSET token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the token passed is not one of the +accepted types or doesn't exist.

+
+ +
Return values
+ int + +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Scopes.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Scopes.html new file mode 100644 index 00000000..96a444d5 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Scopes.html @@ -0,0 +1,360 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Scopes +

+ + +

Utility functions for use when examining token scopes.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + +
validDirectScope()Check whether the direct wrapping scope of a token is within a limited set of +acceptable tokens.int|bool
isOOConstant()Check whether a `T_CONST` token is a class/interface constant declaration.bool
isOOProperty()Check whether a `T_VARIABLE` token is a class/trait property declaration.bool
isOOMethod()Check whether a `T_FUNCTION` token is a class/interface/trait method declaration.bool
+ + + +
+

Methods

+ +
+

validDirectScope()

+ +

Check whether the direct wrapping scope of a token is within a limited set of +acceptable tokens.

+ + public + static validDirectScope( + + $phpcsFile : + File + + + , $stackPtr : + int + + + , $validScopes : + int|string|array + + ) + : int|bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position in the stack of the +token to verify.

+
+ $validScopes + : int|string|array +
+

Array of token constants representing +the scopes considered valid.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ int|bool + —

Integer stack pointer to the valid direct scope or false if +no valid direct scope was found.

+ +
+ +
+

isOOConstant()

+ +

Check whether a `T_CONST` token is a class/interface constant declaration.

+ + public + static isOOConstant( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position in the stack of the +T_CONST token to verify.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isOOProperty()

+ +

Check whether a `T_VARIABLE` token is a class/trait property declaration.

+ + public + static isOOProperty( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position in the stack of the +T_VARIABLE token to verify.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isOOMethod()

+ +

Check whether a `T_FUNCTION` token is a class/interface/trait method declaration.

+ + public + static isOOMethod( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position in the stack of the +T_FUNCTION token to verify.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html b/docs/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html new file mode 100644 index 00000000..1669a9af --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html @@ -0,0 +1,234 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ TextStrings +

+ + +

Utility functions for working with text string tokens.

+
+ +

Table of Contents

+ + + + + + + + + + + +
getCompleteTextString()Get the complete contents of a - potentially multi-line - text string.string
stripQuotes()Strip text delimiter quotes from an arbitrary string.string
+ + + +
+

Methods

+ +
+

getCompleteTextString()

+ +

Get the complete contents of a - potentially multi-line - text string.

+ + public + static getCompleteTextString( + + $phpcsFile : + File + + + , $stackPtr : + int + + + [, $stripQuotes : + bool + = true ] + ) + : string + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

Pointer to the first text string token +of a multi-line text string or to a +Nowdoc/Heredoc opener.

+
+ $stripQuotes + : bool + = true
+

Optional. Whether to strip text delimiter +quotes off the resulting text string. +Defaults to true.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is not a +valid text string token or if the +token is not the first text string token.

+
+ +
Return values
+ string + +
+ +
+

stripQuotes()

+ +

Strip text delimiter quotes from an arbitrary string.

+ + public + static stripQuotes( + + $string : + string + + ) + : string + + +

Intended for use with the "contents" of a T_CONSTANT_ENCAPSED_STRING / T_DOUBLE_QUOTED_STRING.

+

Prevents stripping mis-matched quotes. +Prevents stripping quotes from the textual content of the string.

+ +
Parameters
+
+
+ $string + : string +
+

The raw string.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ string + —

String without quotes around it.

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html b/docs/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html new file mode 100644 index 00000000..9fdace73 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html @@ -0,0 +1,449 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ UseStatements +

+ + +

Utility functions for examining use statements.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
getType()Determine what a T_USE token is used for.string
isClosureUse()Determine whether a T_USE token represents a closure use statement.bool
isImportUse()Determine whether a T_USE token represents a class/function/constant import use statement.bool
isTraitUse()Determine whether a T_USE token represents a trait use statement.bool
splitImportUseStatement()Split an import use statement into individual imports.array
+ + + +
+

Methods

+ +
+

getType()

+ +

Determine what a T_USE token is used for.

+ + public + static getType( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : string + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_USE token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_USE token.

+
+ +
Return values
+ string + —

Either 'closure', 'import' or 'trait'. +An empty string will be returned if the token is used in an +invalid context or if it couldn't be reliably determined +what the T_USE token is used for.

+ +
+ +
+

isClosureUse()

+ +

Determine whether a T_USE token represents a closure use statement.

+ + public + static isClosureUse( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_USE token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_USE token.

+
+ +
Return values
+ bool + —

True if the token passed is a closure use statement. +False if it's not.

+ +
+ +
+

isImportUse()

+ +

Determine whether a T_USE token represents a class/function/constant import use statement.

+ + public + static isImportUse( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_USE token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_USE token.

+
+ +
Return values
+ bool + —

True if the token passed is an import use statement. +False if it's not.

+ +
+ +
+

isTraitUse()

+ +

Determine whether a T_USE token represents a trait use statement.

+ + public + static isTraitUse( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position of the T_USE token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_USE token.

+
+ +
Return values
+ bool + —

True if the token passed is a trait use statement. +False if it's not.

+ +
+ +
+

splitImportUseStatement()

+ +

Split an import use statement into individual imports.

+ + public + static splitImportUseStatement( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

Handles single import, multi-import and group-import statements.

+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position in the stack of the T_USE token.

+
+ +
Tags
+
+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_USE token or not an import use statement.

+
+ +
Return values
+ array + —

A multi-level array containing information about the use statement. +The first level is 'name', 'function' and 'const'. These keys will always exist. +If any statements are found for any of these categories, the second level +will contain the alias/name as the key and the full original use name as the +value for each of the found imports or an empty array if no imports were found +in this use statement for this category.

+

For example, for this function group use statement: +use function Vendor\Package\{LevelA\Name as Alias, LevelB\Another_Name} +the return value would look like this: +[ 'name' => [], 'function' => [ 'Alias' => 'Vendor\Package\LevelA\Name', 'Another_Name' => 'Vendor\Package\LevelB\Another_Name', ], 'const' => [], ]

+ +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Variables.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Variables.html new file mode 100644 index 00000000..13aabdce --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Variables.html @@ -0,0 +1,431 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

+ Variables +

+ + +

Utility functions for use when examining variables.

+
+ +

Table of Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
$phpReservedVarsList of PHP Reserved variables.array
getMemberProperties()Retrieve the visibility and implementation properties of a class member var.array
isPHPReservedVarName()Verify if a given variable name is the name of a PHP reserved variable.bool
isSuperglobal()Verify if a given variable or array key token points to a PHP superglobal.bool
isSuperglobalName()Verify if a given variable name is the name of a PHP superglobal.bool
+ + +
+

Properties

+ +
+

$phpReservedVars

+ +

List of PHP Reserved variables.

+ + public + static array + $phpReservedVars + = [ + '_SERVER' => true, + '_GET' => true, + '_POST' => true, + '_REQUEST' => true, + '_SESSION' => true, + '_ENV' => true, + '_COOKIE' => true, + '_FILES' => true, + 'GLOBALS' => true, + 'http_response_header' => false, + 'argc' => false, + 'argv' => false, + // Deprecated. + 'php_errormsg' => false, + // Removed PHP 5.4.0. + 'HTTP_SERVER_VARS' => false, + 'HTTP_GET_VARS' => false, + 'HTTP_POST_VARS' => false, + 'HTTP_SESSION_VARS' => false, + 'HTTP_ENV_VARS' => false, + 'HTTP_COOKIE_VARS' => false, + 'HTTP_POST_FILES' => false, + // Removed PHP 5.6.0. + 'HTTP_RAW_POST_DATA' => false, +] +
The array keys are the variable names without the leading dollar sign, the values indicate +whether the variable is a superglobal or not. + +{@internal The variables names are set without the leading dollar sign to allow this array +to be used with array index keys as well. Think: `'_GET'` in `$GLOBALS['_GET']`.}
+
+
+ +
+

Methods

+ +
+

getMemberProperties()

+ +

Retrieve the visibility and implementation properties of a class member var.

+ + public + static getMemberProperties( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : array + + +

The format of the return value is:

+

+array( +'scope' => string, // Public, private, or protected. +'scope_specified' => boolean, // TRUE if the scope was explicitly specified. +'is_static' => boolean, // TRUE if the static keyword was found. +'type' => string, // The type of the var (empty if no type specified). +'type_token' => integer, // The stack pointer to the start of the type +// or FALSE if there is no type. +'type_end_token' => integer, // The stack pointer to the end of the type +// or FALSE if there is no type. +'nullable_type' => boolean, // TRUE if the type is nullable. +); +

+

Main differences with the PHPCS version:

+
    +
  • Removed the parse error warning for properties in interfaces. +This will now throw the same "$stackPtr is not a class member var" runtime exception as +other non-property variables passed to the method.
  • +
  • Defensive coding against incorrect calls to this method.
  • +
+ +
Parameters
+
+
+ $phpcsFile + : File +
+

The file being scanned.

+
+ $stackPtr + : int +
+

The position in the stack of the T_VARIABLE token to +acquire the properties for.

+
+ +
Tags
+
+
+ see +
+

Original source.

+
+ see +
+

Cross-version compatible version of the original.

+
+ since +
+
+
+ throws +
+

If the specified position is not a +T_VARIABLE token, or if the position is not +a class member variable.

+
+ +
Return values
+ array + +
+ +
+

isPHPReservedVarName()

+ +

Verify if a given variable name is the name of a PHP reserved variable.

+ + public + static isPHPReservedVarName( + + $name : + string + + ) + : bool + + + +
Parameters
+
+
+ $name + : string +
+

The full variable name with or without leading dollar sign. +This allows for passing an array key variable name, such as +'_GET' retrieved from $GLOBALS['_GET']. +Note: when passing an array key, string quotes are expected +to have been stripped already.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+ +
+

isSuperglobal()

+ +

Verify if a given variable or array key token points to a PHP superglobal.

+ + public + static isSuperglobal( + + $phpcsFile : + File + + + , $stackPtr : + int + + ) + : bool + + + +
Parameters
+
+
+ $phpcsFile + : File +
+

The file where this token was found.

+
+ $stackPtr + : int +
+

The position in the stack of a T_VARIABLE +token or of the T_CONSTANT_ENCAPSED_STRING +array key to a variable in $GLOBALS.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + —

True if this points to a superglobal. False when not; or when an unsupported +token has been passed; or when a T_CONSTANT_ENCAPSED_STRING is not an array +index key; or when it is, but not an index to the $GLOBALS variable.

+ +
+ +
+

isSuperglobalName()

+ +

Verify if a given variable name is the name of a PHP superglobal.

+ + public + static isSuperglobalName( + + $name : + string + + ) + : bool + + + +
Parameters
+
+
+ $name + : string +
+

The full variable name with or without leading dollar sign. +This allows for passing an array key variable name, such as +'_GET' retrieved from $GLOBALS['_GET']. +Note: when passing an array key, string quotes are expected +to have been stripped already.

+
+ +
Tags
+
+
+ since +
+
+
+ +
Return values
+ bool + +
+
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/css/normalize.css b/docs/phpdoc/css/normalize.css new file mode 100644 index 00000000..46f646a5 --- /dev/null +++ b/docs/phpdoc/css/normalize.css @@ -0,0 +1,427 @@ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/docs/phpdoc/css/template.css b/docs/phpdoc/css/template.css new file mode 100644 index 00000000..bf2b6b62 --- /dev/null +++ b/docs/phpdoc/css/template.css @@ -0,0 +1,915 @@ +:root { + /* Typography */ + --font-primary: 'Source Sans Pro', Helvetica, Arial, sans-serif; + --font-secondary: 'Source Sans Pro', Helvetica, Arial, sans-serif; + --line-height--primary: 1.6; + --letter-spacing--primary: .05rem; + --text-base-size: 1em; + --text-scale-ratio: 1.2; + + --text-xxs: calc(var(--text-base-size) / var(--text-scale-ratio) / var(--text-scale-ratio) / var(--text-scale-ratio)); + --text-xs: calc(var(--text-base-size) / var(--text-scale-ratio) / var(--text-scale-ratio)); + --text-sm: calc(var(--text-base-size) / var(--text-scale-ratio)); + --text-md: var(--text-base-size); + --text-lg: calc(var(--text-base-size) * var(--text-scale-ratio)); + --text-xl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + + /* Colors */ + --primary-color: hsl(96, 57%, 60%); + --primary-color-darken: hsl(96, 57%, 40%); + --primary-color-darker: hsl(96, 57%, 20%); + --primary-color-lighten: hsl(96, 57%, 80%); + --primary-color-lighter: hsl(96, 57%, 97%); + + --text-color: #4b3b40; + + --top-header-bg-color: var(--primary-color-lighter); /* #d1f5be; */ + --top-header-text-color: var(--text-color); + --header-bg-color: var(--primary-color); + --code-background-color: var(--primary-color-lighter); + --code-border-color: var(--primary-color-darken); + --button-border-color: var(--primary-color-darken); + --button-color: transparent; + --button-color-primary: var(--primary-color); + --button-text-color: #555; + --button-text-color-primary: white; + --popover-background-color: hsla(96, 57%, 95%, 0.9); + --link-color-primary: var(--primary-color-darken); + --link-hover-color-primary: var(--primary-color-darker); + --form-field-border-color: #D1D1D1; + --form-field-color: #fff; + --admonition-success-color: var(--primary-color); + --admonition-border-color: silver; + --table-separator-color: var(--primary-color-lighten); + --title-text-color: white; + --title-text-shadow-color: var(--primary-color-darker); + + /* Grid */ + --container-width: 960px; + --top-header-height: calc(var(--text-lg) + 2 * var(--spacing-sm)); + + /* Spacing */ + --spacing-base-size: 1rem; + --spacing-scale-ratio: 1.5; + + --spacing-xxxs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-xxs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-xs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-sm: calc(var(--spacing-base-size) / var(--spacing-scale-ratio)); + --spacing-md: var(--spacing-base-size); + --spacing-lg: calc(var(--spacing-base-size) * var(--spacing-scale-ratio)); + --spacing-xl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + --spacing-xxl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + --spacing-xxxl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + + --border-radius-base-size: 3px; +} + +/* Grid +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor-section { + box-sizing: border-box; + margin: 0 auto; + max-width: var(--container-width); + padding: 0 var(--spacing-lg); + position: relative; + width: 100%; +} + +.phpdocumentor-column, +.phpdocumentor-columns { + box-sizing: border-box; + float: left; + width: 100%; +} + +/* For devices larger than 400px */ +@media (min-width: 400px) { + .phpdocumentor-section { + padding: 0; + width: 85%; + } +} + +/* For devices larger than 550px */ +@media (min-width: 550px) { + .phpdocumentor-section { + width: 80%; + } + + .phpdocumentor-column, + .phpdocumentor-columns { + margin-left: 4%; + } + + .phpdocumentor-column:first-child, + .phpdocumentor-columns:first-child { + margin-left: 0; + } + + .one.phpdocumentor-column, + .one.phpdocumentor-columns { + width: 4.66666666667%; + } + + .two.phpdocumentor-columns { + width: 13.3333333333%; + } + + .three.phpdocumentor-columns { + width: 22%; + } + + .four.phpdocumentor-columns { + width: 30.6666666667%; + } + + .five.phpdocumentor-columns { + width: 39.3333333333%; + } + + .six.phpdocumentor-columns { + width: 48%; + } + + .seven.phpdocumentor-columns { + width: 56.6666666667%; + } + + .eight.phpdocumentor-columns { + width: 65.3333333333%; + } + + .nine.phpdocumentor-columns { + width: 74.0%; + } + + .ten.phpdocumentor-columns { + width: 82.6666666667%; + } + + .eleven.phpdocumentor-columns { + width: 91.3333333333%; + } + + .twelve.phpdocumentor-columns { + margin-left: 0; + width: 100%; + } + + .one-third.phpdocumentor-column { + width: 30.6666666667%; + } + + .two-thirds.phpdocumentor-column { + width: 65.3333333333%; + } + + .one-half.phpdocumentor-column { + width: 48%; + } + + /* Offsets */ + .offset-by-one.phpdocumentor-column, + .offset-by-one.phpdocumentor-columns { + margin-left: 8.66666666667%; + } + + .offset-by-two.phpdocumentor-column, + .offset-by-two.phpdocumentor-columns { + margin-left: 17.3333333333%; + } + + .offset-by-three.phpdocumentor-column, + .offset-by-three.phpdocumentor-columns { + margin-left: 26%; + } + + .offset-by-four.phpdocumentor-column, + .offset-by-four.phpdocumentor-columns { + margin-left: 34.6666666667%; + } + + .offset-by-five.phpdocumentor-column, + .offset-by-five.phpdocumentor-columns { + margin-left: 43.3333333333%; + } + + .offset-by-six.phpdocumentor-column, + .offset-by-six.phpdocumentor-columns { + margin-left: 52%; + } + + .offset-by-seven.phpdocumentor-column, + .offset-by-seven.phpdocumentor-columns { + margin-left: 60.6666666667%; + } + + .offset-by-eight.phpdocumentor-column, + .offset-by-eight.phpdocumentor-columns { + margin-left: 69.3333333333%; + } + + .offset-by-nine.phpdocumentor-column, + .offset-by-nine.phpdocumentor-columns { + margin-left: 78.0%; + } + + .offset-by-ten.phpdocumentor-column, + .offset-by-ten.phpdocumentor-columns { + margin-left: 86.6666666667%; + } + + .offset-by-eleven.phpdocumentor-column, + .offset-by-eleven.phpdocumentor-columns { + margin-left: 95.3333333333%; + } + + .offset-by-one-third.phpdocumentor-column, + .offset-by-one-third.phpdocumentor-columns { + margin-left: 34.6666666667%; + } + + .offset-by-two-thirds.phpdocumentor-column, + .offset-by-two-thirds.phpdocumentor-columns { + margin-left: 69.3333333333%; + } + + .offset-by-one-half.phpdocumentor-column, + .offset-by-one-half.phpdocumentor-columns { + margin-left: 52%; + } +} + +/* Base Styles +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +body { + color: var(--text-color); + font-family: var(--font-primary); + font-size: var(--text-md); + letter-spacing: var(--letter-spacing--primary); + line-height: var(--line-height--primary); +} + +/* Used for screen readers and such */ +.visually-hidden { + display: none; +} + +/* Typography +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor h1, +.phpdocumentor h2, +.phpdocumentor h3, +.phpdocumentor h4, +.phpdocumentor h5, +.phpdocumentor h6 { + margin-bottom: var(--spacing-lg); + margin-top: var(--spacing-lg); +} + +.phpdocumentor h1 { + font-size: var(--text-xxxxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.2; + margin-top: 0; +} + +.phpdocumentor h2 { + font-size: var(--text-xxxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.25; + margin-top: 0; +} + +.phpdocumentor h3 { + font-size: var(--text-xxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.3; +} + +.phpdocumentor h4 { + font-size: var(--text-xl); + letter-spacing: calc(var(--letter-spacing--primary) / 2); + line-height: 1.35; + margin-bottom: var(--spacing-md); +} + +.phpdocumentor h5 { + font-size: var(--text-lg); + letter-spacing: calc(var(--letter-spacing--primary) / 4); + line-height: 1.5; + margin-bottom: var(--spacing-md); + margin-top: var(--spacing-md); +} + +.phpdocumentor h6 { + font-size: var(--text-md); + letter-spacing: 0; + line-height: var(--line-height--primary); + margin-bottom: var(--spacing-md); + margin-top: var(--spacing-md); +} + +.phpdocumentor p { + margin-top: 0; +} + +/* Links +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor a { + color: var(--link-color-primary); +} + +.phpdocumentor a:hover { + color: var(--link-hover-color-primary); +} + +/* Buttons +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor-button { + background-color: var(--button-color); + border: 1px solid var(--button-border-color); + border-radius: var(--border-radius-base-size); + box-sizing: border-box; + color: var(--button-text-color); + cursor: pointer; + display: inline-block; + font-size: var(--text-sm); + font-weight: 600; + height: 38px; + letter-spacing: .1rem; + line-height: 38px; + padding: 0 var(--spacing-xxl); + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; +} + +.phpdocumentor-button--wide { + width: 100%; +} + +.phpdocumentor-button:hover, +.phpdocumentor-button:focus { + border-color: #888; + color: #333; + outline: 0; +} + +.phpdocumentor-button.button-primary { + background-color: var(--button-color-primary); + border-color: var(--button-color-primary); + color: var(--button-text-color-primary); +} + +.phpdocumentor-button.phpdocumentor-button--primary:hover, +.phpdocumentor-button.phpdocumentor-button--primary:focus { + background-color: var(--link-color-primary); + border-color: var(--link-color-primary); + color: var(--button-text-color-primary); +} + +/* Forms +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor-field { + background-color: var(--form-field-color); + border: 1px solid var(--form-field-border-color); + border-radius: var(--border-radius-base-size); + box-shadow: none; + box-sizing: border-box; + height: 38px; + padding: var(--spacing-xxxs) var(--spacing-xxs); /* The 6px vertically centers text on FF, ignored by Webkit */ +} + +/* Removes awkward default styles on some inputs for iOS */ +input[type="email"], +input[type="number"], +input[type="search"], +input[type="text"], +input[type="tel"], +input[type="url"], +input[type="password"], +textarea { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; +} + +.phpdocumentor-textarea { + min-height: 65px; + padding-bottom: var(--spacing-xxxs); + padding-top: var(--spacing-xxxs); +} + +.phpdocumentor-field:focus { + border: 1px solid var(--button-color-primary); + outline: 0; +} + +.phpdocumentor-label { + display: block; + margin-bottom: var(--spacing-xs); +} + +.phpdocumentor-fieldset { + border-width: 0; + padding: 0; +} + +input[type="checkbox"].phpdocumentor-field, +input[type="radio"].phpdocumentor-field { + display: inline; +} + +.phpdocumentor-label > .phpdocumentor-label--body { + display: inline-block; + font-weight: normal; + margin-left: var(--spacing-xs); +} + +/* Lists +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +div.phpdocumentor-list > ul, +ul.phpdocumentor-list { + list-style: circle inside; +} + +ol.phpdocumentor-list { + list-style: decimal inside; +} + +div.phpdocumentor-list > ul, +ol.phpdocumentor-list, +ul.phpdocumentor-list { + margin-top: 0; + padding-left: 0; +} + +div.phpdocumentor-list > ul ul, +ul.phpdocumentor-list ul.phpdocumentor-list, +ul.phpdocumentor-list ol.phpdocumentor-list, +ol.phpdocumentor-list ol.phpdocumentor-list, +ol.phpdocumentor-list ul.phpdocumentor-list { + font-size: var(--text-sm); + margin: var(--spacing-xs) 0 var(--spacing-xs) calc(var(--spacing-xs) * 2); +} + +li.phpdocumentor-list { + margin-bottom: var(--spacing-md); +} + +ul.phpdocumentor-breadcrumbs { + font-size: var(--text-sm); + list-style: none; + margin: 0; + padding: 0; +} + +ul.phpdocumentor-breadcrumbs > li { + display: inline-block; + margin: 0; +} + +ul.phpdocumentor-breadcrumbs > li + li:before { + color: #ccc; + content: "\\\A0"; + padding: 0 var(--spacing-xxs); +} + +/* Code +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor-code { + background: var(--code-background-color); + border: 1px solid var(--code-border-color); + border-radius: var(--border-radius-base-size); + font-size: var(--text-sm); + padding: var(--spacing-xs) var(--spacing-sm); +} + +pre > .phpdocumentor-code { + display: block; + white-space: pre; +} + +/* Tables +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +th.phpdocumentor-heading, +td.phpdocumentor-cell { + border-bottom: 1px solid var(--table-separator-color); + padding: var(--spacing-sm) var(--spacing-md); + text-align: left; +} + +th.phpdocumentor-heading:first-child, +td.phpdocumentor-cell:first-child { + padding-left: 0; +} + +th.phpdocumentor-heading:last-child, +td.phpdocumentor-cell:last-child { + padding-right: 0; +} + +/* Spacing +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor-button { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-field { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor pre, +.phpdocumentor blockquote, +.phpdocumentor dl, +.phpdocumentor figure, +.phpdocumentor table, +.phpdocumentor p, +.phpdocumentor ul, +.phpdocumentor ol, +.phpdocumentor form { + margin-bottom: var(--spacing-md); +} + +/* Utilities +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor-full-width { + box-sizing: border-box; + width: 100%; +} + +.phpdocumentor-max-full-width { + box-sizing: border-box; + max-width: 100%; +} + +.phpdocumentor-pull-right { + float: right; +} + +.phpdocumentor-pull-left { + float: left; +} + +/* Misc +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +.phpdocumentor-line { + border-top: 1px solid #E1E1E1; + border-width: 0; + margin-bottom: var(--spacing-xxl); + margin-top: var(--spacing-xxl); +} + +.phpdocumentor-admonition { + border: 1px solid var(--admonition-border-color); + border-radius: var(--border-radius-base-size); + padding: var(--spacing-sm) var(--spacing-md); +} + +.phpdocumentor-admonition--success { + border-color: var(--admonition-success-color); +} + +/* Clearing +–––––––––––––––––––––––––––––––––––––––––––––––––– */ + +/* Self Clearing Goodness */ +.phpdocumentor-section:after, +.phpdocumentor-row:after, +.phpdocumentor-cf { + clear: both; + content: ""; + display: table; +} + +/* Elements +–––––––––––––––––––––––––––––––––––––––––––––––––– */ + +.phpdocumentor-top-header { + align-items: center; + background: var(--top-header-bg-color); + color: var(--top-header-text-color); + display: flex; + flex-direction: row; + font-size: var(--text-md); + min-height: var(--top-header-height); + padding: 0 var(--spacing-sm); + text-align: right; +} + +.phpdocumentor-top-header a { + color: var(--primary-color-darker); + display: inline-block; + text-decoration: none; +} +.phpdocumentor-top-header a span { + border-bottom: 1px solid transparent; + transition: border-bottom-color .2s ease-in-out; +} +.phpdocumentor-top-header a:hover { + color: var(--text-color); +} +.phpdocumentor-top-header a:hover span { + border-bottom: 1px solid var(--text-color); +} +.phpdocumentor-top-header a:not(:first-of-type):before { + display: inline-block; + color: #ccc; + content: "/"; + padding: 0 var(--spacing-xxs); +} + +.phpdocumentor-header { + background: var(--header-bg-color); + display: flex; + margin-bottom: var(--spacing-xl); + position: relative; +} + +.phpdocumentor-header:after { + border-bottom: 3px solid var(--header-bg-color); + bottom: -8px; + content: ''; + left: 0; + position: absolute; + right: 0; +} + +.phpdocumentor-header p { + color: white; + font-size: var(--text-lg); +} + +.phpdocumentor-title { + color: var(--title-text-color); + font-size: var(--text-xxxxl); + letter-spacing: .05rem; + line-height: 1.2; + text-shadow: 0 0 2px var(--title-text-shadow-color); +} +.phpdocumentor-title small { + text-shadow: none; + font-size: var(--text-xxs); + display: block; + margin: var(--spacing-sm) 0; +} + +.phpdocumentor-summary, +.phpdocumentor-class__summary, +.phpdocumentor-trait__summary, +.phpdocumentor-interface__summary { + font-style: italic; +} + +.phpdocumentor-element__package, +.phpdocumentor-interface__extends, +.phpdocumentor-class__extends, +.phpdocumentor-class__implements { + display: block; + font-size: var(--text-xxs); + font-weight: normal; + opacity: .7; +} + +.phpdocumentor-element__package .phpdocumentor-breadcrumbs { + display: inline; +} + +.phpdocumentor-description { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-element, +.phpdocumentor-function, +.phpdocumentor-constant, +.phpdocumentor-property, +.phpdocumentor-method { + position: relative; +} + +.phpdocumentor-element--deprecated .phpdocumentor-function__name, +.phpdocumentor-element--deprecated .phpdocumentor-method__name, +.phpdocumentor-element--deprecated .phpdocumentor-constant__name, +.phpdocumentor-element--deprecated .phpdocumentor-property__name, +.phpdocumentor-signature--deprecated .phpdocumentor-signature__name { + text-decoration: line-through; +} + +.phpdocumentor-signature { + display: inline-block; + font-size: var(--text-sm); + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-table_of_contents { + font-size: var(--text-sm); +} + +.phpdocumentor .phpdocumentor-sidebar li { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.phpdocumentor .phpdocumentor-sidebar__category-header { + font-size: var(--text-lg); + margin-bottom: var(--spacing-sm); +} + +.phpdocumentor .phpdocumentor-sidebar__root-package, +.phpdocumentor .phpdocumentor-sidebar__root-namespace { + font-size: var(--text-md); + margin-bottom: var(--spacing-xxs); +} + +.phpdocumentor-constant:not(:last-child), +.phpdocumentor-function:not(:last-child), +.phpdocumentor-method:not(:last-child), +.phpdocumentor-property:not(:last-child) { + border-bottom: 1px solid var(--primary-color-lighten); + padding-bottom: var(--spacing-lg); +} + +.phpdocumentor-functions__header, +.phpdocumentor-constants__header, +.phpdocumentor-properties__header, +.phpdocumentor-methods__header { + border-bottom: 2px solid var(--primary-color-darken); + padding-bottom: var(--spacing-md); +} + +.phpdocumentor-content { + position: relative; +} + +.phpdocumentor-search-results { + backdrop-filter: blur(5px); + background: var(--popover-background-color); + min-height: 100%; + left: calc(var(--spacing-lg) * -1); + position: absolute; + right: calc(var(--spacing-lg) * -1); + top: 0; + padding: 0 var(--spacing-lg); + opacity: 1; + pointer-events: all; + + transition: opacity .3s, background .3s; +} + +.phpdocumentor-search-results--hidden { + background: transparent; + backdrop-filter: blur(0); + opacity: 0; + pointer-events: none; +} + +.phpdocumentor-search-results__entries { + list-style: none; + padding: 0; +} + +.phpdocumentor-search-results__entry { + border-bottom: 1px solid var(--table-separator-color); + padding: var(--spacing-sm) var(--spacing-md); + text-align: left; +} + +.phpdocumentor-search-results__entry a { + display: block; +} + +.phpdocumentor-search-results__entry small { + margin-top: var(--spacing-xs); + margin-bottom: var(--spacing-md); + color: var(--primary-color-darker); + display: block; +} +.phpdocumentor-search-results__entry h3 { + margin: 0; +} + +.phpdocumentor-search { + position: relative; + display: none; /** disable by default for non-js flow */ + opacity: .3; /** white-out default for loading indication */ + transition: opacity .3s, background .3s; +} +.phpdocumentor-search:before { + content: ''; + background: transparent; + left: calc(-1 * var(--spacing-md)); + height: 100%; + position: absolute; + right: -15px; + z-index: -1; + opacity: 0; + transition: opacity .3s, background .3s; +} + +.phpdocumentor-search--enabled { + display: block; +} + +.phpdocumentor-search--active { + opacity: 1; +} +.phpdocumentor-search--has-results:before { + background: var(--popover-background-color); + opacity: 1; +} + +.phpdocumentor-search input:disabled { + background-color: lightgray; +} + +.phpdocumentor-element-found-in { + position: absolute; + top: 0; + right: 0; + font-size: var(--text-sm); + color: gray; +} + +.phpdocumentor-class-graph { + width: 100%; height: 600px; border:1px solid black; overflow: hidden +} + +.phpdocumentor-class-graph__graph { + width: 100%; +} + +/* Other +–––––––––––––––––––––––––––––––––––––––––––––––––– */ + +.phpdocumentor-content h1 .headerlink, +.phpdocumentor-content h2 .headerlink, +.phpdocumentor-content h3 .headerlink, +.phpdocumentor-content h4 .headerlink, +.phpdocumentor-content h5 .headerlink, +.phpdocumentor-content h6 .headerlink +{ + display: none; + padding-left: 10px; + text-decoration: none; + color: silver; +} + +.phpdocumentor-content h1:hover .headerlink, +.phpdocumentor-content h2:hover .headerlink, +.phpdocumentor-content h3:hover .headerlink, +.phpdocumentor-content h4:hover .headerlink, +.phpdocumentor-content h5:hover .headerlink, +.phpdocumentor-content h6:hover .headerlink +{ + display: initial; +} + +/* Media Queries +–––––––––––––––––––––––––––––––––––––––––––––––––– */ +/* +Note: The best way to structure the use of media queries is to create the queries +near the relevant code. For example, if you wanted to change the styles for buttons +on small devices, paste the mobile query code up in the buttons section and style it +there. +*/ + +/* Larger than mobile */ +@media (min-width: 400px) { +} + +/* Larger than phablet (also point when grid becomes active) */ +@media (min-width: 550px) { +} + +/* Larger than tablet */ +@media (min-width: 750px) { +} + +/* Larger than desktop */ +@media (min-width: 1000px) { +} + +/* Larger than Desktop HD */ +@media (min-width: 1200px) { +} + +.phpdocumentor-logo__link { + text-decoration: none; +} + +.phpdocumentor-logo { + display: inline-block; + float: left; + width: 80px; + border: 5px solid white; + border-radius: 15px; + margin: 20px 20px 20px 0; +} diff --git a/docs/phpdoc/files/phpcsutils-abstractsniffs-abstractarraydeclarationsniff.html b/docs/phpdoc/files/phpcsutils-abstractsniffs-abstractarraydeclarationsniff.html new file mode 100644 index 00000000..d85de533 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-abstractsniffs-abstractarraydeclarationsniff.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

AbstractArrayDeclarationSniff.php

+ +

Interfaces, Classes and Traits

+
+ +
AbstractArrayDeclarationSniff
+
Abstract sniff to easily examine all parts of an array declaration.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-autoload.html b/docs/phpdoc/files/phpcsutils-autoload.html new file mode 100644 index 00000000..1a555a9f --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-autoload.html @@ -0,0 +1,78 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

phpcsutils-autoload.php

+ + + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-backcompat-bcfile.html b/docs/phpdoc/files/phpcsutils-backcompat-bcfile.html new file mode 100644 index 00000000..049c359d --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-backcompat-bcfile.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

BCFile.php

+ +

Interfaces, Classes and Traits

+
+ +
BCFile
+
PHPCS native utility functions.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-backcompat-bctokens.html b/docs/phpdoc/files/phpcsutils-backcompat-bctokens.html new file mode 100644 index 00000000..4d61d904 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-backcompat-bctokens.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

BCTokens.php

+ +

Interfaces, Classes and Traits

+
+ +
BCTokens
+
Token arrays related utility methods.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-backcompat-helper.html b/docs/phpdoc/files/phpcsutils-backcompat-helper.html new file mode 100644 index 00000000..611ef875 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-backcompat-helper.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Helper.php

+ +

Interfaces, Classes and Traits

+
+ +
Helper
+
Utility methods to retrieve (configuration) information from PHP_CodeSniffer.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-fixers-spacesfixer.html b/docs/phpdoc/files/phpcsutils-fixers-spacesfixer.html new file mode 100644 index 00000000..e23b7e4d --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-fixers-spacesfixer.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

SpacesFixer.php

+ +

Interfaces, Classes and Traits

+
+ +
SpacesFixer
+
Utility to check and, if necessary, fix the whitespace between two tokens.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-testutils-utilitymethodtestcase.html b/docs/phpdoc/files/phpcsutils-testutils-utilitymethodtestcase.html new file mode 100644 index 00000000..3dc189a0 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-testutils-utilitymethodtestcase.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

UtilityMethodTestCase.php

+ +

Interfaces, Classes and Traits

+
+ +
UtilityMethodTestCase
+
Base class for use when testing utility methods for PHP_CodeSniffer.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-tokens-collections.html b/docs/phpdoc/files/phpcsutils-tokens-collections.html new file mode 100644 index 00000000..ad299d98 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-tokens-collections.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Collections.php

+ +

Interfaces, Classes and Traits

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

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-arrays.html b/docs/phpdoc/files/phpcsutils-utils-arrays.html new file mode 100644 index 00000000..4de49bb9 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-arrays.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Arrays.php

+ +

Interfaces, Classes and Traits

+
+ +
Arrays
+
Utility functions for use when examining arrays.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-conditions.html b/docs/phpdoc/files/phpcsutils-utils-conditions.html new file mode 100644 index 00000000..460f5d4f --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-conditions.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Conditions.php

+ +

Interfaces, Classes and Traits

+
+ +
Conditions
+
Utility functions for use when examining token conditions.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-controlstructures.html b/docs/phpdoc/files/phpcsutils-utils-controlstructures.html new file mode 100644 index 00000000..532d056f --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-controlstructures.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

ControlStructures.php

+ +

Interfaces, Classes and Traits

+
+ +
ControlStructures
+
Utility functions for use when examining control structures.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-functiondeclarations.html b/docs/phpdoc/files/phpcsutils-utils-functiondeclarations.html new file mode 100644 index 00000000..fb27e9d7 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-functiondeclarations.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

FunctionDeclarations.php

+ +

Interfaces, Classes and Traits

+
+ +
FunctionDeclarations
+
Utility functions for use when examining function declaration statements.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-gettokensasstring.html b/docs/phpdoc/files/phpcsutils-utils-gettokensasstring.html new file mode 100644 index 00000000..ccb7c646 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-gettokensasstring.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

GetTokensAsString.php

+ +

Interfaces, Classes and Traits

+
+ +
GetTokensAsString
+
Utility functions to retrieve the content of a set of tokens as a string.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-lists.html b/docs/phpdoc/files/phpcsutils-utils-lists.html new file mode 100644 index 00000000..0f89ec78 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-lists.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Lists.php

+ +

Interfaces, Classes and Traits

+
+ +
Lists
+
Utility functions to retrieve information when working with lists.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-namespaces.html b/docs/phpdoc/files/phpcsutils-utils-namespaces.html new file mode 100644 index 00000000..5b93500a --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-namespaces.html @@ -0,0 +1,86 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Namespaces.php

+ +

Interfaces, Classes and Traits

+
+ +
Namespaces
+
Utility functions for use when examining T_NAMESPACE tokens and to determine the +namespace of arbitrary tokens.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-numbers.html b/docs/phpdoc/files/phpcsutils-utils-numbers.html new file mode 100644 index 00000000..ff2975e9 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-numbers.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Numbers.php

+ +

Interfaces, Classes and Traits

+
+ +
Numbers
+
Utility functions for working with integer/float tokens.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-objectdeclarations.html b/docs/phpdoc/files/phpcsutils-utils-objectdeclarations.html new file mode 100644 index 00000000..e06a1839 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-objectdeclarations.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

ObjectDeclarations.php

+ +

Interfaces, Classes and Traits

+
+ +
ObjectDeclarations
+
Utility functions for use when examining object declaration statements.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-operators.html b/docs/phpdoc/files/phpcsutils-utils-operators.html new file mode 100644 index 00000000..cf45c021 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-operators.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Operators.php

+ +

Interfaces, Classes and Traits

+
+ +
Operators
+
Utility functions for use when working with operators.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-orthography.html b/docs/phpdoc/files/phpcsutils-utils-orthography.html new file mode 100644 index 00000000..59c7af79 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-orthography.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Orthography.php

+ +

Interfaces, Classes and Traits

+
+ +
Orthography
+
Utility functions for checking the orthography of arbitrary text strings.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-parentheses.html b/docs/phpdoc/files/phpcsutils-utils-parentheses.html new file mode 100644 index 00000000..762eb400 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-parentheses.html @@ -0,0 +1,86 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Parentheses.php

+ +

Interfaces, Classes and Traits

+
+ +
Parentheses
+
Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped in +parentheses.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-passedparameters.html b/docs/phpdoc/files/phpcsutils-utils-passedparameters.html new file mode 100644 index 00000000..121248b9 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-passedparameters.html @@ -0,0 +1,86 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

PassedParameters.php

+ +

Interfaces, Classes and Traits

+
+ +
PassedParameters
+
Utility functions to retrieve information about parameters passed to function calls, +array declarations, isset and unset constructs.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-scopes.html b/docs/phpdoc/files/phpcsutils-utils-scopes.html new file mode 100644 index 00000000..6986e1bc --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-scopes.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Scopes.php

+ +

Interfaces, Classes and Traits

+
+ +
Scopes
+
Utility functions for use when examining token scopes.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-textstrings.html b/docs/phpdoc/files/phpcsutils-utils-textstrings.html new file mode 100644 index 00000000..cb7b61aa --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-textstrings.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

TextStrings.php

+ +

Interfaces, Classes and Traits

+
+ +
TextStrings
+
Utility functions for working with text string tokens.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-usestatements.html b/docs/phpdoc/files/phpcsutils-utils-usestatements.html new file mode 100644 index 00000000..3c2cffbf --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-usestatements.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

UseStatements.php

+ +

Interfaces, Classes and Traits

+
+ +
UseStatements
+
Utility functions for examining use statements.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/files/phpcsutils-utils-variables.html b/docs/phpdoc/files/phpcsutils-utils-variables.html new file mode 100644 index 00000000..49a474ce --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-variables.html @@ -0,0 +1,85 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Variables.php

+ +

Interfaces, Classes and Traits

+
+ +
Variables
+
Utility functions for use when examining variables.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/graphs/classes.html b/docs/phpdoc/graphs/classes.html new file mode 100644 index 00000000..0f6f6cb4 --- /dev/null +++ b/docs/phpdoc/graphs/classes.html @@ -0,0 +1,81 @@ + + + + + Documentation + + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+
+ +
+ +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/index.html b/docs/phpdoc/index.html new file mode 100644 index 00000000..c1d7febd --- /dev/null +++ b/docs/phpdoc/index.html @@ -0,0 +1,80 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+

Documentation

+ +

Namespaces

+
+
PHPCSUtils
+
+ + + + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/js/search.js b/docs/phpdoc/js/search.js new file mode 100644 index 00000000..20abbeb0 --- /dev/null +++ b/docs/phpdoc/js/search.js @@ -0,0 +1,150 @@ +// Search module for phpDocumentor +// +// This module is a wrapper around fuse.js that will use a given index and attach itself to a +// search form and to a search results pane identified by the following data attributes: +// +// 1. data-search-form +// 2. data-search-results +// +// The data-search-form is expected to have a single input element of type 'search' that will trigger searching for +// a series of results, were the data-search-results pane is expected to have a direct UL child that will be populated +// with rendered results. +// +// The search has various stages, upon loading this stage the data-search-form receives the CSS class +// 'phpdocumentor-search--enabled'; this indicates that JS is allowed and indices are being loaded. It is recommended +// to hide the form by default and show it when it receives this class to achieve progressive enhancement for this +// feature. +// +// After loading this module, it is expected to load a search index asynchronously, for example: +// +// +// +// In this script the generated index should attach itself to the search module using the `appendIndex` function. By +// doing it like this the page will continue loading, unhindered by the loading of the search. +// +// After the page has fully loaded, and all these deferred indexes loaded, the initialization of the search module will +// be called and the form will receive the class 'phpdocumentor-search--active', indicating search is ready. At this +// point, the input field will also have it's 'disabled' attribute removed. +var Search = (function () { + var fuse; + var index = []; + var options = { + shouldSort: true, + threshold: 0.6, + location: 0, + distance: 100, + maxPatternLength: 32, + minMatchCharLength: 1, + keys: [ + "fqsen", + "name", + "summary", + "url" + ] + }; + + // Credit David Walsh (https://davidwalsh.name/javascript-debounce-function) + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + function debounce(func, wait, immediate) { + var timeout; + + return function executedFunction() { + var context = this; + var args = arguments; + + var later = function () { + timeout = null; + if (!immediate) func.apply(context, args); + }; + + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + } + + function close() { + var form = document.querySelector('[data-search-form]'); + var searchResults = document.querySelector('[data-search-results]'); + + form.classList.toggle('phpdocumentor-search--has-results', false); + searchResults.classList.add('phpdocumentor-search-results--hidden'); + } + + function search(event) { + // prevent enter's from autosubmitting + event.stopPropagation(); + + var form = document.querySelector('[data-search-form]'); + var searchResults = document.querySelector('[data-search-results]'); + var searchResultEntries = document.querySelector('[data-search-results] > ul'); + + searchResultEntries.innerHTML = ''; + + if (!event.target.value) { + close(); + return; + } + + form.classList.toggle('phpdocumentor-search--has-results', true); + searchResults.classList.remove('phpdocumentor-search-results--hidden'); + var results = fuse.search(event.target.value); + + results.forEach(function (result) { + var entry = document.createElement("li"); + entry.classList.add("phpdocumentor-search-results__entry"); + entry.innerHTML += '

' + result.name + "

\n"; + entry.innerHTML += '' + result.fqsen + "\n"; + entry.innerHTML += '
' + result.summary + '
'; + searchResultEntries.appendChild(entry) + }); + } + + function appendIndex(added) { + index = index.concat(added); + + // re-initialize search engine when appending an index after initialisation + if (typeof fuse !== 'undefined') { + fuse = new Fuse(index, options); + } + } + + function init() { + fuse = new Fuse(index, options); + + var form = document.querySelector('[data-search-form]'); + var searchField = document.querySelector('[data-search-form] input[type="search"'); + + form.classList.add('phpdocumentor-search--active'); + + searchField.setAttribute('placeholder', 'Search for ..'); + searchField.removeAttribute('disabled'); + searchField.addEventListener('keyup', debounce(search, 300)); + + window.addEventListener('keyup', function (event) { + if (event.code === 'Escape') { + close(); + } + }); + } + + return { + appendIndex, + init + } +})(); + +window.addEventListener('DOMContentLoaded', function () { + var form = document.querySelector('[data-search-form]'); + + // When JS is supported; show search box. Must be before including the search for it to take effect immediately + form.classList.add('phpdocumentor-search--enabled'); +}); + +window.addEventListener('load', function () { + Search.init(); +}); diff --git a/docs/phpdoc/js/searchIndex.js b/docs/phpdoc/js/searchIndex.js new file mode 100644 index 00000000..7e737d9a --- /dev/null +++ b/docs/phpdoc/js/searchIndex.js @@ -0,0 +1,1124 @@ +Search.appendIndex( + [ + { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff", + "name": "AbstractArrayDeclarationSniff", + "summary": "Abstract\u0020sniff\u0020to\u0020easily\u0020examine\u0020all\u0020parts\u0020of\u0020an\u0020array\u0020declaration.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Set\u0020up\u0020this\u0020class.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method___construct" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003Aregister\u0028\u0029", + "name": "register", + "summary": "Returns\u0020an\u0020array\u0020of\u0020tokens\u0020this\u0020test\u0020wants\u0020to\u0020listen\u0020for.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_register" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003Aprocess\u0028\u0029", + "name": "process", + "summary": "Processes\u0020this\u0020test\u0020when\u0020one\u0020of\u0020its\u0020tokens\u0020is\u0020encountered.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_process" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003AprocessArray\u0028\u0029", + "name": "processArray", + "summary": "Process\u0020every\u0020part\u0020of\u0020the\u0020array\u0020declaration.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_processArray" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003AprocessOpenClose\u0028\u0029", + "name": "processOpenClose", + "summary": "Process\u0020the\u0020array\u0020opener\u0020and\u0020closer.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_processOpenClose" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003AprocessKey\u0028\u0029", + "name": "processKey", + "summary": "Process\u0020the\u0020tokens\u0020in\u0020an\u0020array\u0020key.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_processKey" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003AprocessNoKey\u0028\u0029", + "name": "processNoKey", + "summary": "Process\u0020an\u0020array\u0020item\u0020without\u0020an\u0020array\u0020key.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_processNoKey" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003AprocessArrow\u0028\u0029", + "name": "processArrow", + "summary": "Process\u0020the\u0020double\u0020arrow.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_processArrow" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003AprocessValue\u0028\u0029", + "name": "processValue", + "summary": "Process\u0020the\u0020tokens\u0020in\u0020an\u0020array\u0020value.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_processValue" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003AprocessComma\u0028\u0029", + "name": "processComma", + "summary": "Process\u0020the\u0020comma\u0020after\u0020an\u0020array\u0020item.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_processComma" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003AgetActualArrayKey\u0028\u0029", + "name": "getActualArrayKey", + "summary": "Determine\u0020what\u0020the\u0020actual\u0020array\u0020key\u0020would\u0020be.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#method_getActualArrayKey" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A\u0024stackPtr", + "name": "stackPtr", + "summary": "The\u0020stack\u0020pointer\u0020to\u0020the\u0020array\u0020keyword\u0020or\u0020the\u0020short\u0020array\u0020open\u0020token.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#property_stackPtr" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A\u0024tokens", + "name": "tokens", + "summary": "The\u0020token\u0020stack\u0020for\u0020the\u0020current\u0020file\u0020being\u0020examined.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#property_tokens" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A\u0024arrayOpener", + "name": "arrayOpener", + "summary": "The\u0020stack\u0020pointer\u0020to\u0020the\u0020array\u0020opener.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#property_arrayOpener" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A\u0024arrayCloser", + "name": "arrayCloser", + "summary": "The\u0020stack\u0020pointer\u0020to\u0020the\u0020array\u0020closer.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#property_arrayCloser" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A\u0024arrayItems", + "name": "arrayItems", + "summary": "A\u0020multi\u002Ddimentional\u0020array\u0020with\u0020information\u0020on\u0020each\u0020array\u0020item.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#property_arrayItems" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A\u0024itemCount", + "name": "itemCount", + "summary": "How\u0020many\u0020items\u0020are\u0020in\u0020the\u0020array.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#property_itemCount" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A\u0024singleLine", + "name": "singleLine", + "summary": "Whether\u0020or\u0020not\u0020the\u0020array\u0020is\u0020single\u0020line.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#property_singleLine" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs\\AbstractArrayDeclarationSniff\u003A\u003A\u0024acceptedTokens", + "name": "acceptedTokens", + "summary": "List\u0020of\u0020tokens\u0020which\u0020can\u0020safely\u0020be\u0020used\u0020with\u0020an\u0020eval\u0028\u0029\u0020expression.", + "url": "../classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html#property_acceptedTokens" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile", + "name": "BCFile", + "summary": "PHPCS\u0020native\u0020utility\u0020functions.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AgetDeclarationName\u0028\u0029", + "name": "getDeclarationName", + "summary": "Returns\u0020the\u0020declaration\u0020names\u0020for\u0020classes,\u0020interfaces,\u0020traits,\u0020and\u0020functions.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_getDeclarationName" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AgetMethodParameters\u0028\u0029", + "name": "getMethodParameters", + "summary": "Returns\u0020the\u0020method\u0020parameters\u0020for\u0020the\u0020specified\u0020function\u0020token.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_getMethodParameters" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AgetMethodProperties\u0028\u0029", + "name": "getMethodProperties", + "summary": "Returns\u0020the\u0020visibility\u0020and\u0020implementation\u0020properties\u0020of\u0020a\u0020method.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_getMethodProperties" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AgetMemberProperties\u0028\u0029", + "name": "getMemberProperties", + "summary": "Returns\u0020the\u0020visibility\u0020and\u0020implementation\u0020properties\u0020of\u0020a\u0020class\u0020member\u0020var.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_getMemberProperties" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AgetClassProperties\u0028\u0029", + "name": "getClassProperties", + "summary": "Returns\u0020the\u0020implementation\u0020properties\u0020of\u0020a\u0020class.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_getClassProperties" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AisReference\u0028\u0029", + "name": "isReference", + "summary": "Determine\u0020if\u0020the\u0020passed\u0020token\u0020is\u0020a\u0020reference\u0020operator.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_isReference" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AgetTokensAsString\u0028\u0029", + "name": "getTokensAsString", + "summary": "Returns\u0020the\u0020content\u0020of\u0020the\u0020tokens\u0020from\u0020the\u0020specified\u0020start\u0020position\u0020in\nthe\u0020token\u0020stack\u0020for\u0020the\u0020specified\u0020length.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_getTokensAsString" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AfindStartOfStatement\u0028\u0029", + "name": "findStartOfStatement", + "summary": "Returns\u0020the\u0020position\u0020of\u0020the\u0020first\u0020non\u002Dwhitespace\u0020token\u0020in\u0020a\u0020statement.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_findStartOfStatement" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AfindEndOfStatement\u0028\u0029", + "name": "findEndOfStatement", + "summary": "Returns\u0020the\u0020position\u0020of\u0020the\u0020last\u0020non\u002Dwhitespace\u0020token\u0020in\u0020a\u0020statement.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_findEndOfStatement" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AhasCondition\u0028\u0029", + "name": "hasCondition", + "summary": "Determine\u0020if\u0020the\u0020passed\u0020token\u0020has\u0020a\u0020condition\u0020of\u0020one\u0020of\u0020the\u0020passed\u0020types.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_hasCondition" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AgetCondition\u0028\u0029", + "name": "getCondition", + "summary": "Return\u0020the\u0020position\u0020of\u0020the\u0020condition\u0020for\u0020the\u0020passed\u0020token.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_getCondition" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AfindExtendedClassName\u0028\u0029", + "name": "findExtendedClassName", + "summary": "Returns\u0020the\u0020name\u0020of\u0020the\u0020class\u0020that\u0020the\u0020specified\u0020class\u0020extends.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_findExtendedClassName" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCFile\u003A\u003AfindImplementedInterfaceNames\u0028\u0029", + "name": "findImplementedInterfaceNames", + "summary": "Returns\u0020the\u0020names\u0020of\u0020the\u0020interfaces\u0020that\u0020the\u0020specified\u0020class\u0020implements.", + "url": "../classes/PHPCSUtils-BackCompat-BCFile.html#method_findImplementedInterfaceNames" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens", + "name": "BCTokens", + "summary": "Token\u0020arrays\u0020related\u0020utility\u0020methods.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003A__callStatic\u0028\u0029", + "name": "__callStatic", + "summary": "Handle\u0020calls\u0020to\u0020\u0028undeclared\u0029\u0020methods\u0020for\u0020token\u0020arrays\u0020which\u0020haven\u0027t\u0020received\u0020any\nchanges\u0020since\u0020PHPCS\u00202.6.0.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#method___callStatic" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003AassignmentTokens\u0028\u0029", + "name": "assignmentTokens", + "summary": "Retrieve\u0020the\u0020PHPCS\u0020assignment\u0020tokens\u0020array\u0020in\u0020a\u0020cross\u002Dversion\u0020compatible\u0020manner.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#method_assignmentTokens" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003AcomparisonTokens\u0028\u0029", + "name": "comparisonTokens", + "summary": "Retrieve\u0020the\u0020PHPCS\u0020comparison\u0020tokens\u0020array\u0020in\u0020a\u0020cross\u002Dversion\u0020compatible\u0020manner.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#method_comparisonTokens" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003AarithmeticTokens\u0028\u0029", + "name": "arithmeticTokens", + "summary": "Retrieve\u0020the\u0020PHPCS\u0020arithmetic\u0020tokens\u0020array\u0020in\u0020a\u0020cross\u002Dversion\u0020compatible\u0020manner.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#method_arithmeticTokens" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003Aoperators\u0028\u0029", + "name": "operators", + "summary": "Retrieve\u0020the\u0020PHPCS\u0020operator\u0020tokens\u0020array\u0020in\u0020a\u0020cross\u002Dversion\u0020compatible\u0020manner.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#method_operators" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003AparenthesisOpeners\u0028\u0029", + "name": "parenthesisOpeners", + "summary": "Retrieve\u0020the\u0020PHPCS\u0020parenthesis\u0020openers\u0020tokens\u0020array\u0020in\u0020a\u0020cross\u002Dversion\u0020compatible\u0020manner.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#method_parenthesisOpeners" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003AphpcsCommentTokens\u0028\u0029", + "name": "phpcsCommentTokens", + "summary": "Retrieve\u0020the\u0020PHPCS\u0020comment\u0020tokens\u0020array\u0020in\u0020a\u0020cross\u002Dversion\u0020compatible\u0020manner.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#method_phpcsCommentTokens" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003A\u0024textStringTokens", + "name": "textStringTokens", + "summary": "Tokens\u0020that\u0020represent\u0020text\u0020strings.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#property_textStringTokens" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003AfunctionNameTokens\u0028\u0029", + "name": "functionNameTokens", + "summary": "Retrieve\u0020the\u0020PHPCS\u0020function\u0020name\u0020tokens\u0020array\u0020in\u0020a\u0020cross\u002Dversion\u0020compatible\u0020manner.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#method_functionNameTokens" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003A\u0024ooScopeTokens", + "name": "ooScopeTokens", + "summary": "Tokens\u0020that\u0020open\u0020class\u0020and\u0020object\u0020scopes.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#property_ooScopeTokens" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\BCTokens\u003A\u003A\u0024phpcsCommentTokensTypes", + "name": "phpcsCommentTokensTypes", + "summary": "Token\u0020types\u0020that\u0020are\u0020comments\u0020containing\u0020PHPCS\u0020instructions.", + "url": "../classes/PHPCSUtils-BackCompat-BCTokens.html#property_phpcsCommentTokensTypes" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\Helper", + "name": "Helper", + "summary": "Utility\u0020methods\u0020to\u0020retrieve\u0020\u0028configuration\u0029\u0020information\u0020from\u0020PHP_CodeSniffer.", + "url": "../classes/PHPCSUtils-BackCompat-Helper.html" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\Helper\u003A\u003AgetVersion\u0028\u0029", + "name": "getVersion", + "summary": "Get\u0020the\u0020PHP_CodeSniffer\u0020version\u0020number.", + "url": "../classes/PHPCSUtils-BackCompat-Helper.html#method_getVersion" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\Helper\u003A\u003AsetConfigData\u0028\u0029", + "name": "setConfigData", + "summary": "Pass\u0020config\u0020data\u0020to\u0020PHP_CodeSniffer.", + "url": "../classes/PHPCSUtils-BackCompat-Helper.html#method_setConfigData" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\Helper\u003A\u003AgetConfigData\u0028\u0029", + "name": "getConfigData", + "summary": "Get\u0020the\u0020value\u0020of\u0020a\u0020single\u0020PHP_CodeSniffer\u0020config\u0020key.", + "url": "../classes/PHPCSUtils-BackCompat-Helper.html#method_getConfigData" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\Helper\u003A\u003AgetCommandLineData\u0028\u0029", + "name": "getCommandLineData", + "summary": "Get\u0020the\u0020value\u0020of\u0020a\u0020CLI\u0020overrulable\u0020single\u0020PHP_CodeSniffer\u0020config\u0020key.", + "url": "../classes/PHPCSUtils-BackCompat-Helper.html#method_getCommandLineData" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\Helper\u003A\u003AgetTabWidth\u0028\u0029", + "name": "getTabWidth", + "summary": "Get\u0020the\u0020applicable\u0020tab\u0020width\u0020as\u0020passed\u0020to\u0020PHP_CodeSniffer\u0020from\u0020the\ncommand\u002Dline\u0020or\u0020the\u0020ruleset.", + "url": "../classes/PHPCSUtils-BackCompat-Helper.html#method_getTabWidth" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\Helper\u003A\u003AignoreAnnotations\u0028\u0029", + "name": "ignoreAnnotations", + "summary": "Check\u0020whether\u0020the\u0020\u0060\u002D\u002Dignore\u002Dannotations\u0060\u0020option\u0020has\u0020been\u0020used.", + "url": "../classes/PHPCSUtils-BackCompat-Helper.html#method_ignoreAnnotations" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat\\Helper\u003A\u003ADEFAULT_TABWIDTH", + "name": "DEFAULT_TABWIDTH", + "summary": "The\u0020default\u0020tab\u0020width\u0020used\u0020by\u0020PHP_CodeSniffer.", + "url": "../classes/PHPCSUtils-BackCompat-Helper.html#constant_DEFAULT_TABWIDTH" + }, { + "fqsen": "\\PHPCSUtils\\Fixers\\SpacesFixer", + "name": "SpacesFixer", + "summary": "Utility\u0020to\u0020check\u0020and,\u0020if\u0020necessary,\u0020fix\u0020the\u0020whitespace\u0020between\u0020two\u0020tokens.", + "url": "../classes/PHPCSUtils-Fixers-SpacesFixer.html" + }, { + "fqsen": "\\PHPCSUtils\\Fixers\\SpacesFixer\u003A\u003AcheckAndFix\u0028\u0029", + "name": "checkAndFix", + "summary": "Check\u0020the\u0020whitespace\u0020between\u0020two\u0020tokens,\u0020throw\u0020an\u0020error\u0020if\u0020it\u0020doesn\u0027t\u0020match\u0020the\nexpected\u0020whitespace\u0020and\u0020if\u0020relevant,\u0020fix\u0020it.", + "url": "../classes/PHPCSUtils-Fixers-SpacesFixer.html#method_checkAndFix" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase", + "name": "UtilityMethodTestCase", + "summary": "Base\u0020class\u0020for\u0020use\u0020when\u0020testing\u0020utility\u0020methods\u0020for\u0020PHP_CodeSniffer.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003AsetUpTestFile\u0028\u0029", + "name": "setUpTestFile", + "summary": "Initialize\u0020PHPCS\u0020\u0026\u0020tokenize\u0020the\u0020test\u0020case\u0020file.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#method_setUpTestFile" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003AresetTestFile\u0028\u0029", + "name": "resetTestFile", + "summary": "Clean\u0020up\u0020after\u0020finished\u0020test.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#method_resetTestFile" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003AgetTargetToken\u0028\u0029", + "name": "getTargetToken", + "summary": "Get\u0020the\u0020token\u0020pointer\u0020for\u0020a\u0020target\u0020token\u0020based\u0020on\u0020a\u0020specific\u0020comment\u0020found\u0020on\u0020the\u0020line\u0020before.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#method_getTargetToken" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003AexpectPhpcsException\u0028\u0029", + "name": "expectPhpcsException", + "summary": "Helper\u0020method\u0020to\u0020tell\u0020PHPUnit\u0020to\u0020expect\u0020a\u0020PHPCS\u0020Exception\u0020in\u0020a\u0020PHPUnit\u0020cross\u002Dversion\ncompatible\u0020manner.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#method_expectPhpcsException" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003A\u0024fileExtension", + "name": "fileExtension", + "summary": "The\u0020file\u0020extension\u0020of\u0020the\u0020test\u0020case\u0020file\u0020\u0028without\u0020leading\u0020dot\u0029.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#property_fileExtension" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003A\u0024caseFile", + "name": "caseFile", + "summary": "Full\u0020path\u0020to\u0020the\u0020test\u0020case\u0020file\u0020associated\u0020with\u0020the\u0020concrete\u0020test\u0020class.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#property_caseFile" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003A\u0024tabWidth", + "name": "tabWidth", + "summary": "The\u0020tab\u0020width\u0020setting\u0020to\u0020use\u0020when\u0020tokenizing\u0020the\u0020file.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#property_tabWidth" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003A\u0024phpcsFile", + "name": "phpcsFile", + "summary": "The\u0020\u007B\u0040see\u0020\\PHP_CodeSniffer\\Files\\File\u007D\u0020object\u0020containing\u0020the\u0020parsed\u0020contents\u0020of\u0020the\u0020test\u0020case\u0020file.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#property_phpcsFile" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils\\UtilityMethodTestCase\u003A\u003A\u0024selectedSniff", + "name": "selectedSniff", + "summary": "Set\u0020the\u0020name\u0020of\u0020a\u0020sniff\u0020to\u0020pass\u0020to\u0020PHPCS\u0020to\u0020limit\u0020the\u0020run\u0020\u0028and\u0020force\u0020it\u0020to\u0020record\u0020errors\u0029.", + "url": "../classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#property_selectedSniff" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections", + "name": "Collections", + "summary": "Collections\u0020of\u0020related\u0020tokens\u0020as\u0020often\u0020used\u0020and\u0020needed\u0020for\u0020sniffs.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003AarrowFunctionTokensBC\u0028\u0029", + "name": "arrowFunctionTokensBC", + "summary": "Tokens\u0020which\u0020can\u0020represent\u0020the\u0020arrow\u0020function\u0020keyword.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#method_arrowFunctionTokensBC" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024alternativeControlStructureSyntaxTokens", + "name": "alternativeControlStructureSyntaxTokens", + "summary": "Control\u0020structures\u0020which\u0020can\u0020use\u0020the\u0020alternative\u0020control\u0020structure\u0020syntax.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_alternativeControlStructureSyntaxTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024alternativeControlStructureSyntaxCloserTokens", + "name": "alternativeControlStructureSyntaxCloserTokens", + "summary": "Alternative\u0020control\u0020structure\u0020syntax\u0020closer\u0020keyword\u0020tokens.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_alternativeControlStructureSyntaxCloserTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024arrayTokens", + "name": "arrayTokens", + "summary": "Tokens\u0020which\u0020are\u0020used\u0020to\u0020create\u0020arrays.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_arrayTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024arrayTokensBC", + "name": "arrayTokensBC", + "summary": "Tokens\u0020which\u0020are\u0020used\u0020to\u0020create\u0020arrays.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_arrayTokensBC" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024classModifierKeywords", + "name": "classModifierKeywords", + "summary": "Modifier\u0020keywords\u0020which\u0020can\u0020be\u0020used\u0020for\u0020a\u0020class\u0020declaration.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_classModifierKeywords" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024closedScopes", + "name": "closedScopes", + "summary": "List\u0020of\u0020tokens\u0020which\u0020represent\u0020\u0022closed\u0022\u0020scopes.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_closedScopes" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024controlStructureTokens", + "name": "controlStructureTokens", + "summary": "Control\u0020structure\u0020tokens.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_controlStructureTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024listTokens", + "name": "listTokens", + "summary": "Tokens\u0020which\u0020are\u0020used\u0020to\u0020create\u0020lists.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_listTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024listTokensBC", + "name": "listTokensBC", + "summary": "Tokens\u0020which\u0020are\u0020used\u0020to\u0020create\u0020lists.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_listTokensBC" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024namespaceDeclarationClosers", + "name": "namespaceDeclarationClosers", + "summary": "List\u0020of\u0020tokens\u0020which\u0020can\u0020end\u0020a\u0020namespace\u0020declaration\u0020statement.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_namespaceDeclarationClosers" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024OOCanExtend", + "name": "OOCanExtend", + "summary": "OO\u0020structures\u0020which\u0020can\u0020use\u0020the\u0020\u0060extends\u0060\u0020keyword.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_OOCanExtend" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024OOCanImplement", + "name": "OOCanImplement", + "summary": "OO\u0020structures\u0020which\u0020can\u0020use\u0020the\u0020\u0060implements\u0060\u0020keyword.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_OOCanImplement" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024OOConstantScopes", + "name": "OOConstantScopes", + "summary": "OO\u0020scopes\u0020in\u0020which\u0020constants\u0020can\u0020be\u0020declared.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_OOConstantScopes" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024OOPropertyScopes", + "name": "OOPropertyScopes", + "summary": "OO\u0020scopes\u0020in\u0020which\u0020properties\u0020can\u0020be\u0020declared.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_OOPropertyScopes" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024parameterTypeTokens", + "name": "parameterTypeTokens", + "summary": "Token\u0020types\u0020which\u0020can\u0020be\u0020encountered\u0020in\u0020a\u0020parameter\u0020type\u0020declaration.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_parameterTypeTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024propertyModifierKeywords", + "name": "propertyModifierKeywords", + "summary": "Modifier\u0020keywords\u0020which\u0020can\u0020be\u0020used\u0020for\u0020a\u0020property\u0020declaration.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_propertyModifierKeywords" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024propertyTypeTokens", + "name": "propertyTypeTokens", + "summary": "Token\u0020types\u0020which\u0020can\u0020be\u0020encountered\u0020in\u0020a\u0020property\u0020type\u0020declaration.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_propertyTypeTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024returnTypeTokens", + "name": "returnTypeTokens", + "summary": "Token\u0020types\u0020which\u0020can\u0020be\u0020encountered\u0020in\u0020a\u0020return\u0020type\u0020declaration.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_returnTypeTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024shortArrayTokens", + "name": "shortArrayTokens", + "summary": "Tokens\u0020which\u0020are\u0020used\u0020for\u0020short\u0020arrays.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_shortArrayTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024shortArrayTokensBC", + "name": "shortArrayTokensBC", + "summary": "Tokens\u0020which\u0020are\u0020used\u0020for\u0020short\u0020arrays.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_shortArrayTokensBC" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024shortListTokens", + "name": "shortListTokens", + "summary": "Tokens\u0020which\u0020are\u0020used\u0020for\u0020short\u0020lists.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_shortListTokens" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024shortListTokensBC", + "name": "shortListTokensBC", + "summary": "Tokens\u0020which\u0020are\u0020used\u0020for\u0020short\u0020lists.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_shortListTokensBC" + }, { + "fqsen": "\\PHPCSUtils\\Tokens\\Collections\u003A\u003A\u0024textStingStartTokens", + "name": "textStingStartTokens", + "summary": "Tokens\u0020which\u0020can\u0020start\u0020a\u0020\u002D\u0020potentially\u0020multi\u002Dline\u0020\u002D\u0020text\u0020string.", + "url": "../classes/PHPCSUtils-Tokens-Collections.html#property_textStingStartTokens" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Arrays", + "name": "Arrays", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020arrays.", + "url": "../classes/PHPCSUtils-Utils-Arrays.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Arrays\u003A\u003AisShortArray\u0028\u0029", + "name": "isShortArray", + "summary": "Determine\u0020whether\u0020a\u0020\u0060T_OPEN\/CLOSE_SHORT_ARRAY\u0060\u0020token\u0020is\u0020a\u0020short\u0020array\u0028\u0029\u0020construct\nand\u0020not\u0020a\u0020short\u0020list.", + "url": "../classes/PHPCSUtils-Utils-Arrays.html#method_isShortArray" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Arrays\u003A\u003AgetOpenClose\u0028\u0029", + "name": "getOpenClose", + "summary": "Find\u0020the\u0020array\u0020opener\u0020\u0026\u0020closer\u0020based\u0020on\u0020a\u0020T_ARRAY\u0020or\u0020T_OPEN_SHORT_ARRAY\u0020token.", + "url": "../classes/PHPCSUtils-Utils-Arrays.html#method_getOpenClose" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Arrays\u003A\u003AgetDoubleArrowPtr\u0028\u0029", + "name": "getDoubleArrowPtr", + "summary": "Get\u0020the\u0020stack\u0020pointer\u0020position\u0020of\u0020the\u0020double\u0020arrow\u0020within\u0020an\u0020array\u0020item.", + "url": "../classes/PHPCSUtils-Utils-Arrays.html#method_getDoubleArrowPtr" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Arrays\u003A\u003A\u0024doubleArrowTargets", + "name": "doubleArrowTargets", + "summary": "The\u0020tokens\u0020to\u0020target\u0020to\u0020find\u0020the\u0020double\u0020arrow\u0020in\u0020an\u0020array\u0020item.", + "url": "../classes/PHPCSUtils-Utils-Arrays.html#property_doubleArrowTargets" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Conditions", + "name": "Conditions", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020token\u0020conditions.", + "url": "../classes/PHPCSUtils-Utils-Conditions.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Conditions\u003A\u003AgetCondition\u0028\u0029", + "name": "getCondition", + "summary": "Retrieve\u0020the\u0020position\u0020of\u0020a\u0020condition\u0020for\u0020the\u0020passed\u0020token.", + "url": "../classes/PHPCSUtils-Utils-Conditions.html#method_getCondition" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Conditions\u003A\u003AhasCondition\u0028\u0029", + "name": "hasCondition", + "summary": "Determine\u0020if\u0020the\u0020passed\u0020token\u0020has\u0020a\u0020condition\u0020of\u0020one\u0020of\u0020the\u0020passed\u0020types.", + "url": "../classes/PHPCSUtils-Utils-Conditions.html#method_hasCondition" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Conditions\u003A\u003AgetFirstCondition\u0028\u0029", + "name": "getFirstCondition", + "summary": "Return\u0020the\u0020position\u0020of\u0020the\u0020first\u0020\u0028outermost\u0029\u0020condition\u0020of\u0020a\u0020certain\u0020type\u0020for\u0020the\u0020passed\u0020token.", + "url": "../classes/PHPCSUtils-Utils-Conditions.html#method_getFirstCondition" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Conditions\u003A\u003AgetLastCondition\u0028\u0029", + "name": "getLastCondition", + "summary": "Return\u0020the\u0020position\u0020of\u0020the\u0020last\u0020\u0028innermost\u0029\u0020condition\u0020of\u0020a\u0020certain\u0020type\u0020for\u0020the\u0020passed\u0020token.", + "url": "../classes/PHPCSUtils-Utils-Conditions.html#method_getLastCondition" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ControlStructures", + "name": "ControlStructures", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020control\u0020structures.", + "url": "../classes/PHPCSUtils-Utils-ControlStructures.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ControlStructures\u003A\u003AhasBody\u0028\u0029", + "name": "hasBody", + "summary": "Check\u0020whether\u0020a\u0020control\u0020structure\u0020has\u0020a\u0020body.", + "url": "../classes/PHPCSUtils-Utils-ControlStructures.html#method_hasBody" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ControlStructures\u003A\u003AisElseIf\u0028\u0029", + "name": "isElseIf", + "summary": "Check\u0020whether\u0020an\u0020IF\u0020or\u0020ELSE\u0020token\u0020is\u0020part\u0020of\u0020an\u0020\u0060else\u0020if\u0060.", + "url": "../classes/PHPCSUtils-Utils-ControlStructures.html#method_isElseIf" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ControlStructures\u003A\u003AgetDeclareScopeOpenClose\u0028\u0029", + "name": "getDeclareScopeOpenClose", + "summary": "Get\u0020the\u0020scope\u0020opener\u0020and\u0020closer\u0020for\u0020a\u0020\u0060declare\u0060\u0020statement.", + "url": "../classes/PHPCSUtils-Utils-ControlStructures.html#method_getDeclareScopeOpenClose" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations", + "name": "FunctionDeclarations", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020function\u0020declaration\u0020statements.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AgetName\u0028\u0029", + "name": "getName", + "summary": "Returns\u0020the\u0020declaration\u0020name\u0020for\u0020a\u0020function.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_getName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AgetProperties\u0028\u0029", + "name": "getProperties", + "summary": "Retrieves\u0020the\u0020visibility\u0020and\u0020implementation\u0020properties\u0020of\u0020a\u0020method.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_getProperties" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AgetParameters\u0028\u0029", + "name": "getParameters", + "summary": "Retrieves\u0020the\u0020method\u0020parameters\u0020for\u0020the\u0020specified\u0020function\u0020token.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_getParameters" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisArrowFunction\u0028\u0029", + "name": "isArrowFunction", + "summary": "Check\u0020if\u0020an\u0020arbitrary\u0020token\u0020is\u0020the\u0020\u0022fn\u0022\u0020keyword\u0020for\u0020a\u0020PHP\u00207.4\u0020arrow\u0020function.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isArrowFunction" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AgetArrowFunctionOpenClose\u0028\u0029", + "name": "getArrowFunctionOpenClose", + "summary": "Retrieve\u0020the\u0020parenthesis\u0020opener,\u0020parenthesis\u0020closer,\u0020the\u0020scope\u0020opener\u0020and\u0020the\u0020scope\u0020closer\nfor\u0020an\u0020arrow\u0020function.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_getArrowFunctionOpenClose" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisMagicFunction\u0028\u0029", + "name": "isMagicFunction", + "summary": "Checks\u0020if\u0020a\u0020given\u0020function\u0020is\u0020a\u0020PHP\u0020magic\u0020function.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isMagicFunction" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisMagicFunctionName\u0028\u0029", + "name": "isMagicFunctionName", + "summary": "Verify\u0020if\u0020a\u0020given\u0020function\u0020name\u0020is\u0020the\u0020name\u0020of\u0020a\u0020PHP\u0020magic\u0020function.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isMagicFunctionName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisMagicMethod\u0028\u0029", + "name": "isMagicMethod", + "summary": "Checks\u0020if\u0020a\u0020given\u0020function\u0020is\u0020a\u0020PHP\u0020magic\u0020method.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isMagicMethod" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisMagicMethodName\u0028\u0029", + "name": "isMagicMethodName", + "summary": "Verify\u0020if\u0020a\u0020given\u0020function\u0020name\u0020is\u0020the\u0020name\u0020of\u0020a\u0020PHP\u0020magic\u0020method.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isMagicMethodName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisPHPDoubleUnderscoreMethod\u0028\u0029", + "name": "isPHPDoubleUnderscoreMethod", + "summary": "Checks\u0020if\u0020a\u0020given\u0020function\u0020is\u0020a\u0020PHP\u0020native\u0020double\u0020underscore\u0020method.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isPHPDoubleUnderscoreMethod" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisPHPDoubleUnderscoreMethodName\u0028\u0029", + "name": "isPHPDoubleUnderscoreMethodName", + "summary": "Verify\u0020if\u0020a\u0020given\u0020function\u0020name\u0020is\u0020the\u0020name\u0020of\u0020a\u0020PHP\u0020native\u0020double\u0020underscore\u0020method.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isPHPDoubleUnderscoreMethodName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisSpecialMethod\u0028\u0029", + "name": "isSpecialMethod", + "summary": "Checks\u0020if\u0020a\u0020given\u0020function\u0020is\u0020a\u0020magic\u0020method\u0020or\u0020a\u0020PHP\u0020native\u0020double\u0020underscore\u0020method.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isSpecialMethod" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003AisSpecialMethodName\u0028\u0029", + "name": "isSpecialMethodName", + "summary": "Verify\u0020if\u0020a\u0020given\u0020function\u0020name\u0020is\u0020the\u0020name\u0020of\u0020a\u0020magic\u0020method\u0020or\u0020a\u0020PHP\u0020native\u0020double\u0020underscore\u0020method.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isSpecialMethodName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003A\u0024magicFunctions", + "name": "magicFunctions", + "summary": "A\u0020list\u0020of\u0020all\u0020PHP\u0020magic\u0020functions.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#property_magicFunctions" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003A\u0024magicMethods", + "name": "magicMethods", + "summary": "A\u0020list\u0020of\u0020all\u0020PHP\u0020magic\u0020methods.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#property_magicMethods" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003A\u0024methodsDoubleUnderscore", + "name": "methodsDoubleUnderscore", + "summary": "A\u0020list\u0020of\u0020all\u0020PHP\u0020native\u0020non\u002Dmagic\u0020methods\u0020starting\u0020with\u0020a\u0020double\u0020underscore.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#property_methodsDoubleUnderscore" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\FunctionDeclarations\u003A\u003A\u0024arrowFunctionEndTokens", + "name": "arrowFunctionEndTokens", + "summary": "Tokens\u0020which\u0020can\u0020be\u0020the\u0020end\u0020token\u0020of\u0020an\u0020arrow\u0020function.", + "url": "../classes/PHPCSUtils-Utils-FunctionDeclarations.html#property_arrowFunctionEndTokens" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\GetTokensAsString", + "name": "GetTokensAsString", + "summary": "Utility\u0020functions\u0020to\u0020retrieve\u0020the\u0020content\u0020of\u0020a\u0020set\u0020of\u0020tokens\u0020as\u0020a\u0020string.", + "url": "../classes/PHPCSUtils-Utils-GetTokensAsString.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\GetTokensAsString\u003A\u003Anormal\u0028\u0029", + "name": "normal", + "summary": "Retrieve\u0020the\u0020tab\u002Dreplaced\u0020content\u0020of\u0020the\u0020tokens\u0020from\u0020the\u0020specified\u0020start\u0020position\u0020in\nthe\u0020token\u0020stack\u0020to\u0020the\u0020specified\u0020end\u0020position\u0020\u0028inclusive\u0029.", + "url": "../classes/PHPCSUtils-Utils-GetTokensAsString.html#method_normal" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\GetTokensAsString\u003A\u003AtabReplaced\u0028\u0029", + "name": "tabReplaced", + "summary": "Retrieve\u0020the\u0020tab\u002Dreplaced\u0020content\u0020of\u0020the\u0020tokens\u0020from\u0020the\u0020specified\u0020start\u0020position\u0020in\nthe\u0020token\u0020stack\u0020to\u0020the\u0020specified\u0020end\u0020position\u0020\u0028inclusive\u0029.", + "url": "../classes/PHPCSUtils-Utils-GetTokensAsString.html#method_tabReplaced" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\GetTokensAsString\u003A\u003AorigContent\u0028\u0029", + "name": "origContent", + "summary": "Retrieve\u0020the\u0020original\u0020content\u0020of\u0020the\u0020tokens\u0020from\u0020the\u0020specified\u0020start\u0020position\u0020in\nthe\u0020token\u0020stack\u0020to\u0020the\u0020specified\u0020end\u0020position\u0020\u0028inclusive\u0029.", + "url": "../classes/PHPCSUtils-Utils-GetTokensAsString.html#method_origContent" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\GetTokensAsString\u003A\u003AnoComments\u0028\u0029", + "name": "noComments", + "summary": "Retrieve\u0020the\u0020content\u0020of\u0020the\u0020tokens\u0020from\u0020the\u0020specified\u0020start\u0020position\u0020in\u0020the\u0020token\nstack\u0020to\u0020the\u0020specified\u0020end\u0020position\u0020\u0028inclusive\u0029\u0020without\u0020comments.", + "url": "../classes/PHPCSUtils-Utils-GetTokensAsString.html#method_noComments" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\GetTokensAsString\u003A\u003AnoEmpties\u0028\u0029", + "name": "noEmpties", + "summary": "Retrieve\u0020the\u0020code\u002Dtokens\u0020only\u0020content\u0020of\u0020the\u0020tokens\u0020from\u0020the\u0020specified\u0020start\u0020position\nin\u0020the\u0020token\u0020stack\u0020to\u0020the\u0020specified\u0020end\u0020position\u0020\u0028inclusive\u0029\u0020without\u0020whitespace\u0020or\u0020comments.", + "url": "../classes/PHPCSUtils-Utils-GetTokensAsString.html#method_noEmpties" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\GetTokensAsString\u003A\u003Acompact\u0028\u0029", + "name": "compact", + "summary": "Retrieve\u0020the\u0020content\u0020of\u0020the\u0020tokens\u0020from\u0020the\u0020specified\u0020start\u0020position\u0020in\u0020the\u0020token\nstack\u0020to\u0020the\u0020specified\u0020end\u0020position\u0020\u0028inclusive\u0029\u0020with\u0020all\u0020whitespace\u0020tokens\u0020\u002D\u0020tabs,\nnew\u0020lines,\u0020multiple\u0020spaces\u0020\u002D\u0020replaced\u0020by\u0020a\u0020single\u0020space\u0020and\u0020optionally\u0020without\u0020comments.", + "url": "../classes/PHPCSUtils-Utils-GetTokensAsString.html#method_compact" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\GetTokensAsString\u003A\u003AgetString\u0028\u0029", + "name": "getString", + "summary": "Retrieve\u0020the\u0020content\u0020of\u0020the\u0020tokens\u0020from\u0020the\u0020specified\u0020start\u0020position\u0020in\u0020the\u0020token\u0020stack\nto\u0020the\u0020specified\u0020end\u0020position\u0020\u0028inclusive\u0029.", + "url": "../classes/PHPCSUtils-Utils-GetTokensAsString.html#method_getString" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Lists", + "name": "Lists", + "summary": "Utility\u0020functions\u0020to\u0020retrieve\u0020information\u0020when\u0020working\u0020with\u0020lists.", + "url": "../classes/PHPCSUtils-Utils-Lists.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Lists\u003A\u003AisShortList\u0028\u0029", + "name": "isShortList", + "summary": "Determine\u0020whether\u0020a\u0020\u0060T_OPEN\/CLOSE_SHORT_ARRAY\u0060\u0020token\u0020is\u0020a\u0020short\u0020list\u0028\u0029\u0020construct.", + "url": "../classes/PHPCSUtils-Utils-Lists.html#method_isShortList" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Lists\u003A\u003AgetOpenClose\u0028\u0029", + "name": "getOpenClose", + "summary": "Find\u0020the\u0020list\u0020opener\u0020\u0026\u0020closer\u0020based\u0020on\u0020a\u0020T_LIST\u0020or\u0020T_OPEN_SHORT_ARRAY\u0020token.", + "url": "../classes/PHPCSUtils-Utils-Lists.html#method_getOpenClose" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Lists\u003A\u003AgetAssignments\u0028\u0029", + "name": "getAssignments", + "summary": "Retrieves\u0020information\u0020on\u0020the\u0020assignments\u0020made\u0020in\u0020the\u0020specified\u0020\u0028long\/short\u0029\u0020list.", + "url": "../classes/PHPCSUtils-Utils-Lists.html#method_getAssignments" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Namespaces", + "name": "Namespaces", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020T_NAMESPACE\u0020tokens\u0020and\u0020to\u0020determine\u0020the\nnamespace\u0020of\u0020arbitrary\u0020tokens.", + "url": "../classes/PHPCSUtils-Utils-Namespaces.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Namespaces\u003A\u003AgetType\u0028\u0029", + "name": "getType", + "summary": "Determine\u0020what\u0020a\u0020T_NAMESPACE\u0020token\u0020is\u0020used\u0020for.", + "url": "../classes/PHPCSUtils-Utils-Namespaces.html#method_getType" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Namespaces\u003A\u003AisDeclaration\u0028\u0029", + "name": "isDeclaration", + "summary": "Determine\u0020whether\u0020a\u0020T_NAMESPACE\u0020token\u0020is\u0020the\u0020keyword\u0020for\u0020a\u0020namespace\u0020declaration.", + "url": "../classes/PHPCSUtils-Utils-Namespaces.html#method_isDeclaration" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Namespaces\u003A\u003AisOperator\u0028\u0029", + "name": "isOperator", + "summary": "Determine\u0020whether\u0020a\u0020T_NAMESPACE\u0020token\u0020is\u0020used\u0020as\u0020an\u0020operator.", + "url": "../classes/PHPCSUtils-Utils-Namespaces.html#method_isOperator" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Namespaces\u003A\u003AgetDeclaredName\u0028\u0029", + "name": "getDeclaredName", + "summary": "Get\u0020the\u0020complete\u0020namespace\u0020name\u0020as\u0020declared.", + "url": "../classes/PHPCSUtils-Utils-Namespaces.html#method_getDeclaredName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Namespaces\u003A\u003AfindNamespacePtr\u0028\u0029", + "name": "findNamespacePtr", + "summary": "Determine\u0020the\u0020namespace\u0020an\u0020arbitrary\u0020token\u0020lives\u0020in.", + "url": "../classes/PHPCSUtils-Utils-Namespaces.html#method_findNamespacePtr" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Namespaces\u003A\u003AdetermineNamespace\u0028\u0029", + "name": "determineNamespace", + "summary": "Determine\u0020the\u0020namespace\u0020name\u0020an\u0020arbitrary\u0020token\u0020lives\u0020in.", + "url": "../classes/PHPCSUtils-Utils-Namespaces.html#method_determineNamespace" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers", + "name": "Numbers", + "summary": "Utility\u0020functions\u0020for\u0020working\u0020with\u0020integer\/float\u0020tokens.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AgetCompleteNumber\u0028\u0029", + "name": "getCompleteNumber", + "summary": "Helper\u0020function\u0020to\u0020deal\u0020with\u0020numeric\u0020literals,\u0020potentially\u0020with\u0020underscore\u0020separators.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#method_getCompleteNumber" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AgetDecimalValue\u0028\u0029", + "name": "getDecimalValue", + "summary": "Get\u0020the\u0020decimal\u0020number\u0020value\u0020of\u0020a\u0020numeric\u0020string.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#method_getDecimalValue" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AisDecimalInt\u0028\u0029", + "name": "isDecimalInt", + "summary": "Verify\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020a\u0020decimal\u0020integer.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#method_isDecimalInt" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AisHexidecimalInt\u0028\u0029", + "name": "isHexidecimalInt", + "summary": "Verify\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020a\u0020hexidecimal\u0020integer.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#method_isHexidecimalInt" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AisBinaryInt\u0028\u0029", + "name": "isBinaryInt", + "summary": "Verify\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020a\u0020binary\u0020integer.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#method_isBinaryInt" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AisOctalInt\u0028\u0029", + "name": "isOctalInt", + "summary": "Verify\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020an\u0020octal\u0020integer.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#method_isOctalInt" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AisFloat\u0028\u0029", + "name": "isFloat", + "summary": "Verify\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020a\u0020floating\u0020point\u0020number.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#method_isFloat" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AREGEX_DECIMAL_INT", + "name": "REGEX_DECIMAL_INT", + "summary": "Regex\u0020to\u0020determine\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020a\u0020decimal\u0020integer.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#constant_REGEX_DECIMAL_INT" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AREGEX_OCTAL_INT", + "name": "REGEX_OCTAL_INT", + "summary": "Regex\u0020to\u0020determine\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020an\u0020octal\u0020integer.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#constant_REGEX_OCTAL_INT" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AREGEX_BINARY_INT", + "name": "REGEX_BINARY_INT", + "summary": "Regex\u0020to\u0020determine\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020a\u0020binary\u0020integer.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#constant_REGEX_BINARY_INT" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AREGEX_HEX_INT", + "name": "REGEX_HEX_INT", + "summary": "Regex\u0020to\u0020determine\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020a\u0020hexidecimal\u0020integer.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#constant_REGEX_HEX_INT" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AREGEX_FLOAT", + "name": "REGEX_FLOAT", + "summary": "Regex\u0020to\u0020determine\u0020whether\u0020the\u0020contents\u0020of\u0020an\u0020arbitrary\u0020string\u0020represents\u0020a\u0020float.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#constant_REGEX_FLOAT" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AREGEX_NUMLIT_STRING", + "name": "REGEX_NUMLIT_STRING", + "summary": "Regex\u0020to\u0020determine\u0020is\u0020a\u0020T_STRING\u0020following\u0020a\u0020T_\u005BDL\u005DNUMBER\u0020is\u0020part\u0020of\u0020a\u0020numeric\u0020literal\u0020sequence.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#constant_REGEX_NUMLIT_STRING" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AREGEX_HEX_NUMLIT_STRING", + "name": "REGEX_HEX_NUMLIT_STRING", + "summary": "Regex\u0020to\u0020determine\u0020is\u0020a\u0020T_STRING\u0020following\u0020a\u0020T_\u005BDL\u005DNUMBER\u0020is\u0020part\u0020of\u0020a\u0020hexidecimal\u0020numeric\u0020literal\u0020sequence.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#constant_REGEX_HEX_NUMLIT_STRING" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003AUNSUPPORTED_PHPCS_VERSION", + "name": "UNSUPPORTED_PHPCS_VERSION", + "summary": "PHPCS\u0020versions\u0020in\u0020which\u0020the\u0020backfill\u0020for\u0020PHP\u00207.4\u0020numeric\u0020literal\u0020separators\u0020is\u0020broken.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#constant_UNSUPPORTED_PHPCS_VERSION" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Numbers\u003A\u003A\u0024numericLiteralAcceptedTokens", + "name": "numericLiteralAcceptedTokens", + "summary": "Valid\u0020tokens\u0020which\u0020could\u0020be\u0020part\u0020of\u0020a\u0020numeric\u0020literal\u0020sequence\u0020in\u0020PHP\u0020\u003C\u00207.4.", + "url": "../classes/PHPCSUtils-Utils-Numbers.html#property_numericLiteralAcceptedTokens" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ObjectDeclarations", + "name": "ObjectDeclarations", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020object\u0020declaration\u0020statements.", + "url": "../classes/PHPCSUtils-Utils-ObjectDeclarations.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ObjectDeclarations\u003A\u003AgetName\u0028\u0029", + "name": "getName", + "summary": "Retrieves\u0020the\u0020declaration\u0020name\u0020for\u0020classes,\u0020interfaces,\u0020traits,\u0020and\u0020functions.", + "url": "../classes/PHPCSUtils-Utils-ObjectDeclarations.html#method_getName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ObjectDeclarations\u003A\u003AgetClassProperties\u0028\u0029", + "name": "getClassProperties", + "summary": "Retrieves\u0020the\u0020implementation\u0020properties\u0020of\u0020a\u0020class.", + "url": "../classes/PHPCSUtils-Utils-ObjectDeclarations.html#method_getClassProperties" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ObjectDeclarations\u003A\u003AfindExtendedClassName\u0028\u0029", + "name": "findExtendedClassName", + "summary": "Retrieves\u0020the\u0020name\u0020of\u0020the\u0020class\u0020that\u0020the\u0020specified\u0020class\u0020extends.", + "url": "../classes/PHPCSUtils-Utils-ObjectDeclarations.html#method_findExtendedClassName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ObjectDeclarations\u003A\u003AfindImplementedInterfaceNames\u0028\u0029", + "name": "findImplementedInterfaceNames", + "summary": "Retrieves\u0020the\u0020names\u0020of\u0020the\u0020interfaces\u0020that\u0020the\u0020specified\u0020class\u0020implements.", + "url": "../classes/PHPCSUtils-Utils-ObjectDeclarations.html#method_findImplementedInterfaceNames" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ObjectDeclarations\u003A\u003AfindExtendedInterfaceNames\u0028\u0029", + "name": "findExtendedInterfaceNames", + "summary": "Retrieves\u0020the\u0020names\u0020of\u0020the\u0020interfaces\u0020that\u0020the\u0020specified\u0020interface\u0020extends.", + "url": "../classes/PHPCSUtils-Utils-ObjectDeclarations.html#method_findExtendedInterfaceNames" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\ObjectDeclarations\u003A\u003AfindNames\u0028\u0029", + "name": "findNames", + "summary": "Retrieves\u0020the\u0020names\u0020of\u0020the\u0020extended\u0020classes\u0020or\u0020interfaces\u0020or\u0020the\u0020implemented\ninterfaces\u0020that\u0020the\u0020specific\u0020class\/interface\u0020declaration\u0020extends\/implements.", + "url": "../classes/PHPCSUtils-Utils-ObjectDeclarations.html#method_findNames" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Operators", + "name": "Operators", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020working\u0020with\u0020operators.", + "url": "../classes/PHPCSUtils-Utils-Operators.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Operators\u003A\u003AisReference\u0028\u0029", + "name": "isReference", + "summary": "Determine\u0020if\u0020the\u0020passed\u0020token\u0020is\u0020a\u0020reference\u0020operator.", + "url": "../classes/PHPCSUtils-Utils-Operators.html#method_isReference" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Operators\u003A\u003AisUnaryPlusMinus\u0028\u0029", + "name": "isUnaryPlusMinus", + "summary": "Determine\u0020whether\u0020a\u0020T_MINUS\/T_PLUS\u0020token\u0020is\u0020a\u0020unary\u0020operator.", + "url": "../classes/PHPCSUtils-Utils-Operators.html#method_isUnaryPlusMinus" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Operators\u003A\u003AisShortTernary\u0028\u0029", + "name": "isShortTernary", + "summary": "Determine\u0020whether\u0020a\u0020ternary\u0020is\u0020a\u0020short\u0020ternary\/elvis\u0020operator,\u0020i.e.\u0020without\u0020\u0022middle\u0022.", + "url": "../classes/PHPCSUtils-Utils-Operators.html#method_isShortTernary" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Operators\u003A\u003A\u0024extraUnaryIndicators", + "name": "extraUnaryIndicators", + "summary": "Tokens\u0020which\u0020indicate\u0020that\u0020a\u0020plus\/minus\u0020is\u0020unary\u0020when\u0020they\u0020preceed\u0020it.", + "url": "../classes/PHPCSUtils-Utils-Operators.html#property_extraUnaryIndicators" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Orthography", + "name": "Orthography", + "summary": "Utility\u0020functions\u0020for\u0020checking\u0020the\u0020orthography\u0020of\u0020arbitrary\u0020text\u0020strings.", + "url": "../classes/PHPCSUtils-Utils-Orthography.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Orthography\u003A\u003AisFirstCharCapitalized\u0028\u0029", + "name": "isFirstCharCapitalized", + "summary": "Check\u0020if\u0020the\u0020first\u0020character\u0020of\u0020an\u0020arbitrary\u0020text\u0020string\u0020is\u0020a\u0020capital\u0020letter.", + "url": "../classes/PHPCSUtils-Utils-Orthography.html#method_isFirstCharCapitalized" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Orthography\u003A\u003AisFirstCharLowercase\u0028\u0029", + "name": "isFirstCharLowercase", + "summary": "Check\u0020if\u0020the\u0020first\u0020character\u0020of\u0020an\u0020arbitrary\u0020text\u0020string\u0020is\u0020a\u0020lowercase\u0020letter.", + "url": "../classes/PHPCSUtils-Utils-Orthography.html#method_isFirstCharLowercase" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Orthography\u003A\u003AisLastCharPunctuation\u0028\u0029", + "name": "isLastCharPunctuation", + "summary": "Check\u0020if\u0020the\u0020last\u0020character\u0020of\u0020an\u0020arbitrary\u0020text\u0020string\u0020is\u0020a\u0020valid\u0020punctuation\u0020character.", + "url": "../classes/PHPCSUtils-Utils-Orthography.html#method_isLastCharPunctuation" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Orthography\u003A\u003ATERMINAL_POINTS", + "name": "TERMINAL_POINTS", + "summary": "Characters\u0020which\u0020are\u0020considered\u0020terminal\u0020points\u0020for\u0020a\u0020sentence.", + "url": "../classes/PHPCSUtils-Utils-Orthography.html#constant_TERMINAL_POINTS" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses", + "name": "Parentheses", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020parenthesis\u0020tokens\u0020and\u0020arbitrary\u0020tokens\u0020wrapped\u0020in\nparentheses.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AgetOwner\u0028\u0029", + "name": "getOwner", + "summary": "Get\u0020the\u0020pointer\u0020to\u0020the\u0020parentheses\u0020owner\u0020of\u0020an\u0020open\/close\u0020parenthesis.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_getOwner" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AisOwnerIn\u0028\u0029", + "name": "isOwnerIn", + "summary": "Check\u0020whether\u0020the\u0020parenthesis\u0020owner\u0020of\u0020an\u0020open\/close\u0020parenthesis\u0020is\u0020within\u0020a\u0020limited\nset\u0020of\u0020valid\u0020owners.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_isOwnerIn" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AhasOwner\u0028\u0029", + "name": "hasOwner", + "summary": "Check\u0020whether\u0020the\u0020passed\u0020token\u0020is\u0020nested\u0020within\u0020parentheses\u0020owned\u0020by\u0020one\u0020of\u0020the\u0020valid\u0020owners.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_hasOwner" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AgetFirstOpener\u0028\u0029", + "name": "getFirstOpener", + "summary": "Retrieve\u0020the\u0020position\u0020of\u0020the\u0020opener\u0020to\u0020the\u0020first\u0020\u0028outer\u0029\u0020set\u0020of\u0020parentheses\u0020an\u0020arbitrary\ntoken\u0020is\u0020wrapped\u0020in,\u0020where\u0020the\u0020parentheses\u0020owner\u0020is\u0020within\u0020the\u0020set\u0020of\u0020valid\u0020owners.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_getFirstOpener" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AgetFirstCloser\u0028\u0029", + "name": "getFirstCloser", + "summary": "Retrieve\u0020the\u0020position\u0020of\u0020the\u0020closer\u0020to\u0020the\u0020first\u0020\u0028outer\u0029\u0020set\u0020of\u0020parentheses\u0020an\u0020arbitrary\ntoken\u0020is\u0020wrapped\u0020in,\u0020where\u0020the\u0020parentheses\u0020owner\u0020is\u0020within\u0020the\u0020set\u0020of\u0020valid\u0020owners.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_getFirstCloser" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AgetFirstOwner\u0028\u0029", + "name": "getFirstOwner", + "summary": "Retrieve\u0020the\u0020position\u0020of\u0020the\u0020parentheses\u0020owner\u0020to\u0020the\u0020first\u0020\u0028outer\u0029\u0020set\u0020of\u0020parentheses\u0020an\narbitrary\u0020token\u0020is\u0020wrapped\u0020in,\u0020where\u0020the\u0020parentheses\u0020owner\u0020is\u0020within\u0020the\u0020set\u0020of\u0020valid\u0020owners.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_getFirstOwner" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AgetLastOpener\u0028\u0029", + "name": "getLastOpener", + "summary": "Retrieve\u0020the\u0020position\u0020of\u0020the\u0020opener\u0020to\u0020the\u0020last\u0020\u0028inner\u0029\u0020set\u0020of\u0020parentheses\u0020an\u0020arbitrary\ntoken\u0020is\u0020wrapped\u0020in,\u0020where\u0020the\u0020parentheses\u0020owner\u0020is\u0020within\u0020the\u0020set\u0020of\u0020valid\u0020owners.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_getLastOpener" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AgetLastCloser\u0028\u0029", + "name": "getLastCloser", + "summary": "Retrieve\u0020the\u0020position\u0020of\u0020the\u0020closer\u0020to\u0020the\u0020last\u0020\u0028inner\u0029\u0020set\u0020of\u0020parentheses\u0020an\u0020arbitrary\ntoken\u0020is\u0020wrapped\u0020in,\u0020where\u0020the\u0020parentheses\u0020owner\u0020is\u0020within\u0020the\u0020set\u0020of\u0020valid\u0020owners.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_getLastCloser" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AgetLastOwner\u0028\u0029", + "name": "getLastOwner", + "summary": "Retrieve\u0020the\u0020position\u0020of\u0020the\u0020parentheses\u0020owner\u0020to\u0020the\u0020last\u0020\u0028inner\u0029\u0020set\u0020of\u0020parentheses\u0020an\narbitrary\u0020token\u0020is\u0020wrapped\u0020in\u0020where\u0020the\u0020parentheses\u0020owner\u0020is\u0020within\u0020the\u0020set\u0020of\u0020valid\u0020owners.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_getLastOwner" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AfirstOwnerIn\u0028\u0029", + "name": "firstOwnerIn", + "summary": "Check\u0020whether\u0020the\u0020owner\u0020of\u0020a\u0020outermost\u0020wrapping\u0020set\u0020of\u0020parentheses\u0020of\u0020an\u0020arbitrary\u0020token\nis\u0020within\u0020a\u0020limited\u0020set\u0020of\u0020acceptable\u0020token\u0020types.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_firstOwnerIn" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AlastOwnerIn\u0028\u0029", + "name": "lastOwnerIn", + "summary": "Check\u0020whether\u0020the\u0020owner\u0020of\u0020a\u0020innermost\u0020wrapping\u0020set\u0020of\u0020parentheses\u0020of\u0020an\u0020arbitrary\u0020token\nis\u0020within\u0020a\u0020limited\u0020set\u0020of\u0020acceptable\u0020token\u0020types.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_lastOwnerIn" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Parentheses\u003A\u003AnestedParensWalker\u0028\u0029", + "name": "nestedParensWalker", + "summary": "Helper\u0020method.\u0020Retrieve\u0020the\u0020position\u0020of\u0020a\u0020parentheses\u0020opener\u0020for\u0020an\u0020arbitrary\u0020passed\u0020token.", + "url": "../classes/PHPCSUtils-Utils-Parentheses.html#method_nestedParensWalker" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\PassedParameters", + "name": "PassedParameters", + "summary": "Utility\u0020functions\u0020to\u0020retrieve\u0020information\u0020about\u0020parameters\u0020passed\u0020to\u0020function\u0020calls,\narray\u0020declarations,\u0020isset\u0020and\u0020unset\u0020constructs.", + "url": "../classes/PHPCSUtils-Utils-PassedParameters.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\PassedParameters\u003A\u003AhasParameters\u0028\u0029", + "name": "hasParameters", + "summary": "Checks\u0020if\u0020any\u0020parameters\u0020have\u0020been\u0020passed.", + "url": "../classes/PHPCSUtils-Utils-PassedParameters.html#method_hasParameters" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\PassedParameters\u003A\u003AgetParameters\u0028\u0029", + "name": "getParameters", + "summary": "Get\u0020information\u0020on\u0020all\u0020parameters\u0020passed.", + "url": "../classes/PHPCSUtils-Utils-PassedParameters.html#method_getParameters" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\PassedParameters\u003A\u003AgetParameter\u0028\u0029", + "name": "getParameter", + "summary": "Get\u0020information\u0020on\u0020a\u0020specific\u0020parameter\u0020passed.", + "url": "../classes/PHPCSUtils-Utils-PassedParameters.html#method_getParameter" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\PassedParameters\u003A\u003AgetParameterCount\u0028\u0029", + "name": "getParameterCount", + "summary": "Count\u0020the\u0020number\u0020of\u0020parameters\u0020which\u0020have\u0020been\u0020passed.", + "url": "../classes/PHPCSUtils-Utils-PassedParameters.html#method_getParameterCount" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\PassedParameters\u003A\u003A\u0024allowedConstructs", + "name": "allowedConstructs", + "summary": "The\u0020token\u0020types\u0020these\u0020methods\u0020can\u0020handle.", + "url": "../classes/PHPCSUtils-Utils-PassedParameters.html#property_allowedConstructs" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\PassedParameters\u003A\u003A\u0024callParsingStopPoints", + "name": "callParsingStopPoints", + "summary": "Tokens\u0020which\u0020are\u0020considered\u0020stop\u0020point,\u0020either\u0020because\u0020they\u0020are\u0020the\u0020end\nof\u0020the\u0020parameter\u0020\u0028comma\u0029\u0020or\u0020because\u0020we\u0020need\u0020to\u0020skip\u0020over\u0020them.", + "url": "../classes/PHPCSUtils-Utils-PassedParameters.html#property_callParsingStopPoints" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Scopes", + "name": "Scopes", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020token\u0020scopes.", + "url": "../classes/PHPCSUtils-Utils-Scopes.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Scopes\u003A\u003AvalidDirectScope\u0028\u0029", + "name": "validDirectScope", + "summary": "Check\u0020whether\u0020the\u0020direct\u0020wrapping\u0020scope\u0020of\u0020a\u0020token\u0020is\u0020within\u0020a\u0020limited\u0020set\u0020of\nacceptable\u0020tokens.", + "url": "../classes/PHPCSUtils-Utils-Scopes.html#method_validDirectScope" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Scopes\u003A\u003AisOOConstant\u0028\u0029", + "name": "isOOConstant", + "summary": "Check\u0020whether\u0020a\u0020\u0060T_CONST\u0060\u0020token\u0020is\u0020a\u0020class\/interface\u0020constant\u0020declaration.", + "url": "../classes/PHPCSUtils-Utils-Scopes.html#method_isOOConstant" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Scopes\u003A\u003AisOOProperty\u0028\u0029", + "name": "isOOProperty", + "summary": "Check\u0020whether\u0020a\u0020\u0060T_VARIABLE\u0060\u0020token\u0020is\u0020a\u0020class\/trait\u0020property\u0020declaration.", + "url": "../classes/PHPCSUtils-Utils-Scopes.html#method_isOOProperty" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Scopes\u003A\u003AisOOMethod\u0028\u0029", + "name": "isOOMethod", + "summary": "Check\u0020whether\u0020a\u0020\u0060T_FUNCTION\u0060\u0020token\u0020is\u0020a\u0020class\/interface\/trait\u0020method\u0020declaration.", + "url": "../classes/PHPCSUtils-Utils-Scopes.html#method_isOOMethod" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\TextStrings", + "name": "TextStrings", + "summary": "Utility\u0020functions\u0020for\u0020working\u0020with\u0020text\u0020string\u0020tokens.", + "url": "../classes/PHPCSUtils-Utils-TextStrings.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\TextStrings\u003A\u003AgetCompleteTextString\u0028\u0029", + "name": "getCompleteTextString", + "summary": "Get\u0020the\u0020complete\u0020contents\u0020of\u0020a\u0020\u002D\u0020potentially\u0020multi\u002Dline\u0020\u002D\u0020text\u0020string.", + "url": "../classes/PHPCSUtils-Utils-TextStrings.html#method_getCompleteTextString" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\TextStrings\u003A\u003AstripQuotes\u0028\u0029", + "name": "stripQuotes", + "summary": "Strip\u0020text\u0020delimiter\u0020quotes\u0020from\u0020an\u0020arbitrary\u0020string.", + "url": "../classes/PHPCSUtils-Utils-TextStrings.html#method_stripQuotes" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\UseStatements", + "name": "UseStatements", + "summary": "Utility\u0020functions\u0020for\u0020examining\u0020use\u0020statements.", + "url": "../classes/PHPCSUtils-Utils-UseStatements.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\UseStatements\u003A\u003AgetType\u0028\u0029", + "name": "getType", + "summary": "Determine\u0020what\u0020a\u0020T_USE\u0020token\u0020is\u0020used\u0020for.", + "url": "../classes/PHPCSUtils-Utils-UseStatements.html#method_getType" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\UseStatements\u003A\u003AisClosureUse\u0028\u0029", + "name": "isClosureUse", + "summary": "Determine\u0020whether\u0020a\u0020T_USE\u0020token\u0020represents\u0020a\u0020closure\u0020use\u0020statement.", + "url": "../classes/PHPCSUtils-Utils-UseStatements.html#method_isClosureUse" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\UseStatements\u003A\u003AisImportUse\u0028\u0029", + "name": "isImportUse", + "summary": "Determine\u0020whether\u0020a\u0020T_USE\u0020token\u0020represents\u0020a\u0020class\/function\/constant\u0020import\u0020use\u0020statement.", + "url": "../classes/PHPCSUtils-Utils-UseStatements.html#method_isImportUse" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\UseStatements\u003A\u003AisTraitUse\u0028\u0029", + "name": "isTraitUse", + "summary": "Determine\u0020whether\u0020a\u0020T_USE\u0020token\u0020represents\u0020a\u0020trait\u0020use\u0020statement.", + "url": "../classes/PHPCSUtils-Utils-UseStatements.html#method_isTraitUse" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\UseStatements\u003A\u003AsplitImportUseStatement\u0028\u0029", + "name": "splitImportUseStatement", + "summary": "Split\u0020an\u0020import\u0020use\u0020statement\u0020into\u0020individual\u0020imports.", + "url": "../classes/PHPCSUtils-Utils-UseStatements.html#method_splitImportUseStatement" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Variables", + "name": "Variables", + "summary": "Utility\u0020functions\u0020for\u0020use\u0020when\u0020examining\u0020variables.", + "url": "../classes/PHPCSUtils-Utils-Variables.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Variables\u003A\u003AgetMemberProperties\u0028\u0029", + "name": "getMemberProperties", + "summary": "Retrieve\u0020the\u0020visibility\u0020and\u0020implementation\u0020properties\u0020of\u0020a\u0020class\u0020member\u0020var.", + "url": "../classes/PHPCSUtils-Utils-Variables.html#method_getMemberProperties" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Variables\u003A\u003AisPHPReservedVarName\u0028\u0029", + "name": "isPHPReservedVarName", + "summary": "Verify\u0020if\u0020a\u0020given\u0020variable\u0020name\u0020is\u0020the\u0020name\u0020of\u0020a\u0020PHP\u0020reserved\u0020variable.", + "url": "../classes/PHPCSUtils-Utils-Variables.html#method_isPHPReservedVarName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Variables\u003A\u003AisSuperglobal\u0028\u0029", + "name": "isSuperglobal", + "summary": "Verify\u0020if\u0020a\u0020given\u0020variable\u0020or\u0020array\u0020key\u0020token\u0020points\u0020to\u0020a\u0020PHP\u0020superglobal.", + "url": "../classes/PHPCSUtils-Utils-Variables.html#method_isSuperglobal" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Variables\u003A\u003AisSuperglobalName\u0028\u0029", + "name": "isSuperglobalName", + "summary": "Verify\u0020if\u0020a\u0020given\u0020variable\u0020name\u0020is\u0020the\u0020name\u0020of\u0020a\u0020PHP\u0020superglobal.", + "url": "../classes/PHPCSUtils-Utils-Variables.html#method_isSuperglobalName" + }, { + "fqsen": "\\PHPCSUtils\\Utils\\Variables\u003A\u003A\u0024phpReservedVars", + "name": "phpReservedVars", + "summary": "List\u0020of\u0020PHP\u0020Reserved\u0020variables.", + "url": "../classes/PHPCSUtils-Utils-Variables.html#property_phpReservedVars" + }, { + "fqsen": "\\", + "name": "\\", + "summary": "", + "url": "../namespaces/default.html" + }, { + "fqsen": "\\PHPCSUtils\\AbstractSniffs", + "name": "AbstractSniffs", + "summary": "", + "url": "../namespaces/phpcsutils-abstractsniffs.html" + }, { + "fqsen": "\\PHPCSUtils", + "name": "PHPCSUtils", + "summary": "", + "url": "../namespaces/phpcsutils.html" + }, { + "fqsen": "\\PHPCSUtils\\BackCompat", + "name": "BackCompat", + "summary": "", + "url": "../namespaces/phpcsutils-backcompat.html" + }, { + "fqsen": "\\PHPCSUtils\\Fixers", + "name": "Fixers", + "summary": "", + "url": "../namespaces/phpcsutils-fixers.html" + }, { + "fqsen": "\\PHPCSUtils\\TestUtils", + "name": "TestUtils", + "summary": "", + "url": "../namespaces/phpcsutils-testutils.html" + }, { + "fqsen": "\\PHPCSUtils\\Tokens", + "name": "Tokens", + "summary": "", + "url": "../namespaces/phpcsutils-tokens.html" + }, { + "fqsen": "\\PHPCSUtils\\Utils", + "name": "Utils", + "summary": "", + "url": "../namespaces/phpcsutils-utils.html" + } ] +); diff --git a/docs/phpdoc/namespaces/default.html b/docs/phpdoc/namespaces/default.html new file mode 100644 index 00000000..33cf6181 --- /dev/null +++ b/docs/phpdoc/namespaces/default.html @@ -0,0 +1,83 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

API Documentation

+ +

Namespaces

+
+
PHPCSUtils
+
+ + + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/namespaces/phpcsutils-abstractsniffs.html b/docs/phpdoc/namespaces/phpcsutils-abstractsniffs.html new file mode 100644 index 00000000..0898b34c --- /dev/null +++ b/docs/phpdoc/namespaces/phpcsutils-abstractsniffs.html @@ -0,0 +1,87 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

AbstractSniffs

+ + +

Interfaces, Classes and Traits

+
+ +
AbstractArrayDeclarationSniff
+
Abstract sniff to easily examine all parts of an array declaration.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/namespaces/phpcsutils-backcompat.html b/docs/phpdoc/namespaces/phpcsutils-backcompat.html new file mode 100644 index 00000000..d9287d21 --- /dev/null +++ b/docs/phpdoc/namespaces/phpcsutils-backcompat.html @@ -0,0 +1,91 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

BackCompat

+ + +

Interfaces, Classes and Traits

+
+ +
BCFile
+
PHPCS native utility functions.
+
BCTokens
+
Token arrays related utility methods.
+
Helper
+
Utility methods to retrieve (configuration) information from PHP_CodeSniffer.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/namespaces/phpcsutils-fixers.html b/docs/phpdoc/namespaces/phpcsutils-fixers.html new file mode 100644 index 00000000..a94d76b6 --- /dev/null +++ b/docs/phpdoc/namespaces/phpcsutils-fixers.html @@ -0,0 +1,87 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Fixers

+ + +

Interfaces, Classes and Traits

+
+ +
SpacesFixer
+
Utility to check and, if necessary, fix the whitespace between two tokens.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/namespaces/phpcsutils-testutils.html b/docs/phpdoc/namespaces/phpcsutils-testutils.html new file mode 100644 index 00000000..079bcfd0 --- /dev/null +++ b/docs/phpdoc/namespaces/phpcsutils-testutils.html @@ -0,0 +1,87 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

TestUtils

+ + +

Interfaces, Classes and Traits

+
+ +
UtilityMethodTestCase
+
Base class for use when testing utility methods for PHP_CodeSniffer.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/namespaces/phpcsutils-tokens.html b/docs/phpdoc/namespaces/phpcsutils-tokens.html new file mode 100644 index 00000000..0928eadd --- /dev/null +++ b/docs/phpdoc/namespaces/phpcsutils-tokens.html @@ -0,0 +1,87 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Tokens

+ + +

Interfaces, Classes and Traits

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

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/namespaces/phpcsutils-utils.html b/docs/phpdoc/namespaces/phpcsutils-utils.html new file mode 100644 index 00000000..20bc0dc3 --- /dev/null +++ b/docs/phpdoc/namespaces/phpcsutils-utils.html @@ -0,0 +1,122 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

Utils

+ + +

Interfaces, Classes and Traits

+
+ +
Arrays
+
Utility functions for use when examining arrays.
+
Conditions
+
Utility functions for use when examining token conditions.
+
ControlStructures
+
Utility functions for use when examining control structures.
+
FunctionDeclarations
+
Utility functions for use when examining function declaration statements.
+
GetTokensAsString
+
Utility functions to retrieve the content of a set of tokens as a string.
+
Lists
+
Utility functions to retrieve information when working with lists.
+
Namespaces
+
Utility functions for use when examining T_NAMESPACE tokens and to determine the +namespace of arbitrary tokens.
+
Numbers
+
Utility functions for working with integer/float tokens.
+
ObjectDeclarations
+
Utility functions for use when examining object declaration statements.
+
Operators
+
Utility functions for use when working with operators.
+
Orthography
+
Utility functions for checking the orthography of arbitrary text strings.
+
Parentheses
+
Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped in +parentheses.
+
PassedParameters
+
Utility functions to retrieve information about parameters passed to function calls, +array declarations, isset and unset constructs.
+
Scopes
+
Utility functions for use when examining token scopes.
+
TextStrings
+
Utility functions for working with text string tokens.
+
UseStatements
+
Utility functions for examining use statements.
+
Variables
+
Utility functions for use when examining variables.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/namespaces/phpcsutils.html b/docs/phpdoc/namespaces/phpcsutils.html new file mode 100644 index 00000000..79353af3 --- /dev/null +++ b/docs/phpdoc/namespaces/phpcsutils.html @@ -0,0 +1,88 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

PHPCSUtils

+ +

Namespaces

+
+
AbstractSniffs
+
BackCompat
+
Fixers
+
TestUtils
+
Tokens
+
Utils
+
+ + + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/packages/PHPCSUtils.html b/docs/phpdoc/packages/PHPCSUtils.html new file mode 100644 index 00000000..a30325f5 --- /dev/null +++ b/docs/phpdoc/packages/PHPCSUtils.html @@ -0,0 +1,135 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

PHPCSUtils

+ + +

Interfaces, Classes and Traits

+
+ +
AbstractArrayDeclarationSniff
+
Abstract sniff to easily examine all parts of an array declaration.
+
BCFile
+
PHPCS native utility functions.
+
BCTokens
+
Token arrays related utility methods.
+
Helper
+
Utility methods to retrieve (configuration) information from PHP_CodeSniffer.
+
SpacesFixer
+
Utility to check and, if necessary, fix the whitespace between two tokens.
+
UtilityMethodTestCase
+
Base class for use when testing utility methods for PHP_CodeSniffer.
+
Collections
+
Collections of related tokens as often used and needed for sniffs.
+
Arrays
+
Utility functions for use when examining arrays.
+
Conditions
+
Utility functions for use when examining token conditions.
+
ControlStructures
+
Utility functions for use when examining control structures.
+
FunctionDeclarations
+
Utility functions for use when examining function declaration statements.
+
GetTokensAsString
+
Utility functions to retrieve the content of a set of tokens as a string.
+
Lists
+
Utility functions to retrieve information when working with lists.
+
Namespaces
+
Utility functions for use when examining T_NAMESPACE tokens and to determine the +namespace of arbitrary tokens.
+
Numbers
+
Utility functions for working with integer/float tokens.
+
ObjectDeclarations
+
Utility functions for use when examining object declaration statements.
+
Operators
+
Utility functions for use when working with operators.
+
Orthography
+
Utility functions for checking the orthography of arbitrary text strings.
+
Parentheses
+
Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped in +parentheses.
+
PassedParameters
+
Utility functions to retrieve information about parameters passed to function calls, +array declarations, isset and unset constructs.
+
Scopes
+
Utility functions for use when examining token scopes.
+
TextStrings
+
Utility functions for working with text string tokens.
+
UseStatements
+
Utility functions for examining use statements.
+
Variables
+
Utility functions for use when examining variables.
+ +
+ + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/packages/default.html b/docs/phpdoc/packages/default.html new file mode 100644 index 00000000..47536360 --- /dev/null +++ b/docs/phpdoc/packages/default.html @@ -0,0 +1,83 @@ + + + + + Documentation + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +

API Documentation

+ +

Packages

+
+
PHPCSUtils
+
+ + + + +
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/reports/deprecated.html b/docs/phpdoc/reports/deprecated.html new file mode 100644 index 00000000..dafe808d --- /dev/null +++ b/docs/phpdoc/reports/deprecated.html @@ -0,0 +1,82 @@ + + + + + Documentation » Deprecated elements + + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

Deprecated

+ + +
+ No deprecated elements have been found in this project. +
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/reports/errors.html b/docs/phpdoc/reports/errors.html new file mode 100644 index 00000000..2d1c6b61 --- /dev/null +++ b/docs/phpdoc/reports/errors.html @@ -0,0 +1,107 @@ + + + + + Documentation » Compilation errors + + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

Errors

+ +

Table of Contents

+ + + + + +
PHPCSUtils/BackCompat/BCFile.php1
+ + + +

BCFile.php

+ + + + + + + + + + + + + + + +
TypeLineDescription
ERROR0Tag "author" with body "@author Chris Wilkinson <c.wilkinson@elifesciences.org> + +With documentation contributions from:" has error
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + diff --git a/docs/phpdoc/reports/markers.html b/docs/phpdoc/reports/markers.html new file mode 100644 index 00000000..1fc9d0d0 --- /dev/null +++ b/docs/phpdoc/reports/markers.html @@ -0,0 +1,104 @@ + + + + + Documentation » Markers + + + + + + + + + + + + + + +
+
+
+

Documentation

+
+
+
+
+ + +
+ + +
+

Markers

+ +

Table of Contents

+ + + + + +
PHPCSUtils/Utils/FunctionDeclarations.php1
+ + +

FunctionDeclarations.php

+ + + + + + + + + + + + + + + +
TypeLineDescription
TODO814Add check for the function declaration being namespaced!
+
+
+ +

Search results

+
    + +
+
+
+
+
+ + + From afa25b02725153da12bdf845ca14ebe931c2d200 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 16 Feb 2020 06:05:12 +0100 Subject: [PATCH 45/48] Add homepage to the documentation --- docs/assets/css/style.css | 322 +++++++++++++++++ docs/assets/css/syntax.css | 76 ++++ .../fonts/Noto-Sans-700/Noto-Sans-700.eot | Bin 0 -> 16716 bytes .../fonts/Noto-Sans-700/Noto-Sans-700.svg | 336 +++++++++++++++++ .../fonts/Noto-Sans-700/Noto-Sans-700.ttf | Bin 0 -> 29704 bytes .../fonts/Noto-Sans-700/Noto-Sans-700.woff | Bin 0 -> 12632 bytes .../fonts/Noto-Sans-700/Noto-Sans-700.woff2 | Bin 0 -> 9724 bytes .../Noto-Sans-700italic.eot | Bin 0 -> 16849 bytes .../Noto-Sans-700italic.svg | 334 +++++++++++++++++ .../Noto-Sans-700italic.ttf | Bin 0 -> 28932 bytes .../Noto-Sans-700italic.woff | Bin 0 -> 12612 bytes .../Noto-Sans-700italic.woff2 | Bin 0 -> 9612 bytes .../Noto-Sans-italic/Noto-Sans-italic.eot | Bin 0 -> 15864 bytes .../Noto-Sans-italic/Noto-Sans-italic.svg | 337 ++++++++++++++++++ .../Noto-Sans-italic/Noto-Sans-italic.ttf | Bin 0 -> 26644 bytes .../Noto-Sans-italic/Noto-Sans-italic.woff | Bin 0 -> 12536 bytes .../Noto-Sans-italic/Noto-Sans-italic.woff2 | Bin 0 -> 9572 bytes .../Noto-Sans-regular/Noto-Sans-regular.eot | Bin 0 -> 16639 bytes .../Noto-Sans-regular/Noto-Sans-regular.svg | 335 +++++++++++++++++ .../Noto-Sans-regular/Noto-Sans-regular.ttf | Bin 0 -> 29288 bytes .../Noto-Sans-regular/Noto-Sans-regular.woff | Bin 0 -> 12840 bytes .../Noto-Sans-regular/Noto-Sans-regular.woff2 | Bin 0 -> 9932 bytes docs/assets/js/scale.fix.js | 27 ++ docs/index.html | 204 +++++++++++ 24 files changed, 1971 insertions(+) create mode 100644 docs/assets/css/style.css create mode 100644 docs/assets/css/syntax.css create mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.eot create mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.svg create mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.ttf create mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.woff create mode 100644 docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.woff2 create mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.eot create mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.svg create mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.ttf create mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff create mode 100644 docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff2 create mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.eot create mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.svg create mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.ttf create mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff create mode 100644 docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff2 create mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.eot create mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.svg create mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.ttf create mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff create mode 100644 docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff2 create mode 100644 docs/assets/js/scale.fix.js create mode 100644 docs/index.html diff --git a/docs/assets/css/style.css b/docs/assets/css/style.css new file mode 100644 index 00000000..bbda1925 --- /dev/null +++ b/docs/assets/css/style.css @@ -0,0 +1,322 @@ +@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/syntax.css b/docs/assets/css/syntax.css new file mode 100644 index 00000000..ffc36bdd --- /dev/null +++ b/docs/assets/css/syntax.css @@ -0,0 +1,76 @@ +/** + * Syntax highlighting as used on GitHub. + * Sources: + * https://github.com/mojombo/tpw/blob/master/css/syntax.css + * combined with: + * https://github.com/richleland/pygments-css/blob/master/github.css + */ +/*.highlight { background: #ffffff; }*/ +.highlight{background-color:#f8f8f8} +.highlight .hll { background-color: #ffffcc } +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .cd { color: #999988; font-style: italic } +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { color: #000000; font-weight: bold } /* Keyword */ +.highlight .kv { color: #000000; font-weight: bold } +.highlight .o { color: #000000; font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #aaaaaa } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { color: #000000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #000000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d01040 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nl { color: #990000; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #009999 } /* Literal.Number.Binary */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .mx { color: #009999 } +.highlight .sb { color: #d01040 } /* Literal.String.Backtick */ +.highlight .sc { color: #d01040 } /* Literal.String.Char */ +.highlight .sd { color: #d01040 } /* Literal.String.Doc */ +.highlight .s2 { color: #d01040 } /* Literal.String.Double */ +.highlight .se { color: #d01040 } /* Literal.String.Escape */ +.highlight .sh { color: #d01040 } /* Literal.String.Heredoc */ +.highlight .si { color: #d01040 } /* Literal.String.Interpol */ +.highlight .sx { color: #d01040 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d01040 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ diff --git a/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.eot b/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.eot new file mode 100644 index 0000000000000000000000000000000000000000..03bf93fec2a7341b1a6192ff0d596b05c1765c93 GIT binary patch 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 new file mode 100644 index 0000000000000000000000000000000000000000..4599e3ca9af9bf758f3b5d0b79314701f853c371 GIT binary patch literal 29704 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 literal 0 HcmV?d00001 diff --git a/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.woff2 b/docs/assets/fonts/Noto-Sans-700/Noto-Sans-700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..55fc44bcd1257bb772fb9c041cea4ad61381224f GIT binary patch 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 new file mode 100644 index 0000000000000000000000000000000000000000..6640dbeb333be6474e52c20ced829b8c071634cd GIT binary patch literal 28932 zcmbS!3tUvy7WdxgoOv(|%rG;|@MeZ#Ktx0w9^wN=1mxiZ5r{!S@QDvZ0yQ%eH8U|& z)6C4uYh`9;qnW9hS!!m!^7b&Vx6;a?b5 zz1IHkBcX(lAbbf#KR7opU-(ktA!Jeru9gli89wr^XUPeiPb0*yZSctQ91=`4gv_{( z``Y0nlY3w9*f5lk${skc9oJAdWBbV+_u~9vobMkutHo;hcdspkjPFkf4VyS)QbTi+ zFoO_x0U@djlj@phkRW15`D*0XPntGoVu>ev4e~}1GNQG9Lf!aZKbqQ&kTN_&((7?S z-|8QT@>%}a`i7Q!p82}xO5EQ<2wyv`aa`SOzj3di>HAT}&W5^sX7Gm;(Kz3L{MPAp z4HKfi?-NSMgi73hWJY6ii?^CgBxK@u?EZ|qC(Ky3YD*I#b*Pg!5sthK!e|t`2~Sic zV3)wFaFpFU*_qPIXbZAsAid2Ow!dD_&FNU8*nOj@Uib!2g?cY>I7MC^>FtWvQ!C|a z=|<|IypBdw&X1=wfD2H~a|akX6qubDWFVO#$zy7&tD91KQM=JbQ`4Qj&A}$6JtmGW z`PWmltmDzCb-AU}-G!y}5`X5#n^n_>(T-w&kBQ-)TPEbj3h}^V<#7Hv8Pnqb+A!el~O{kK`TZhkbWStf%W(I`!Qd`nWim zr8D1wNdj?tmkPB?6Nw@Yl1O@xr(6TH4nsdjv4cx;P@N;%!5IZdNPxb;!H2~e;+ox- z;9#RmZz?bvT;Yj)YGQ687n4XyqCOEh6Zd$(bD5Ak(Gcy=`!~DQN~MCIVW9jT??IPF z8&qK64SZ4$CCQdLomj0ui5|0#8!{6a!>WS}nPDONlZpR%85A)oRVsT%Tzrt(VvLJR zOHI$naH`A}Ra`tD#nJTiv{W1^mBA(pFKBN568~_IGmpM|YVflg#4qg2Y?~KMd0=|> zqShR-AbVJf-H?@6@*Tap=WNi?W7;CBnW~{V19si_^2fTzA2;WIH_%V~*jcwg?C>kd z>e(-l8=%VVKita269sAZUQw=494CIn0zSu+G?L_sh;TVuog2ZNm>$M(KFpvP9=Ia# zl|Vj_1PfsEiR#|j+0qaC5yJ(WoV^WcsTLE*WHK$)zy#Dm?bH~<+VAYmI&}rlwEc5duA1`Zyrqu`H$?AawN$yX zwqdh);n5eKc#%e~+_>xpWVOA0#(ULu(~s8Gj(SE_?BkPVqBy==C4nNaB&jPGnT>lMcI^b8xPqKsl@XYUMNk^p-QJ5?l!n+jg} z`pg$k9UAiE(HGwlS0Cz8*q!!RyrbjI%KTA-o2S$_mG|$KQy4OK)}hx|ovvHhdg$Ww zkBHwrD*lnVpg}ykhn6^}4jWj}k8A2z-#^n?UD$Ipp-ek)4oN#`U*$Qb7*5h;Su02y zK~@G(h@?o|&le!4KheC(^O{(68H!Gi5z28vdZV2y`knGr>HU4?50BAMI+Dw#{^AcE zJH$7|6XKT?hJkt;#Qoe9l%YWxYF?1bpn8tCksv+qG;mX{d&L{{*Ou=ei0Z)8ZYD426-O*+dr^#O)ieRUJ7^ zjpDuvT541LB0du-CW@XyIzs&6x$C2U+D@BLUIV!&5GI0l7kyB-o`Tf?nVRrOQuSpd`tOr>awWIV?(*J>5v>sAsLbSai=7i}%6{bU34R z0^I^R-2^F)a2Y9SbT`sxC^wwGLQm5#s6f%4rbJLb!=_3|va z9r$ax)2^G(Z z7Y@98@_A~1ldcdeN|x1T+><) z^2}Rh#lr`cAD=Pi@ZYBH-~agMY&4KS(6R(=h$mxQ{rM0}h-IdGMF@=!p&_YJh2P;P z)?7F&q$Y&ZhEN?JVhbn?F=`7#Li}SKj_78$L**aT><;h;<(;zjVRk1ZIZ-k_iPecs zO;Xdr5m=gFGn+AhF)%lb9cigHdxrEIXOHpqMkv|8Wzmu~;^jAgUQ>3s`suBr*w(Y~ zg@YBt9(-c{edpQ^d@9Ua|My6B*x%+X{`<_~)W5fLe$%$k?wdZSX#9y017E{@!}~2L zTO#qwNc!$2N|;b96M7?67!}QKzv0GLjBgovqmkEz_yrW`R7#%l&zZ7#WOVd2mYz{$=CaS zWG@{jJ`4(ngTnP_O9XMc!otnOY$V2JH>Q^sOV}(oh9AUNqq-P3pbYZw9|lb zkIb#9u?^!s6K{y;b!!}6|r{0(xFyV8`vL{(v1>+^V%Irkty&uyar{|4zmQ8*4*DQ7O;iq1DXy65msd9wMhvN% zyLY(aWZAm04<1cje&OD?r@Xh7c5i*)h1qY^x9?86Z`6n}Q_Blya?ey3K9E=NSne?J zs{;MWMSnuTuT)p04*b%Zb-HLBX6ibfU^a&~yUi-WuZs%2HDSjruu~n%A_OtMJwJkK z^tGQgTgZJ^+QNk!uey$rZDMZ-bISg3=3dk`dJq|&#lwnG6k}J?rIK<|IIY) zZmh{2(NI+|veQQJ_l=%9G_PV>A;veXnpA_57)YecpwZ8BYxIQIWA>n6)=eQRx*0rfzApbe+}fg;7}0AUr(2vD69(3rI?{uso1DEsQ5r} zRiSFdiAQk(hl*qcRgh3-p6^D5G>ryRDmdB;_&pu-xJAe5?iKXvRq>GcEojp~H^JJ& zlt9?rt{h4hy7iP2%3LrPEs=aM6+7jE;DagD3Spt!rKm;StqOs)qnCo6Zd52QDCi(o zu~e@ltdf7$bT=EQX|`aB)WGjy&7hmkpQnq@o%@e|p;FF8XV8_X_aOa%UZtv5oOtL3 z94eA2TGrVwBb7SVz%A;S$4aI9Fu@vdRn)H#i_ovl-b?%y*pU#-bcec9OzJ$LTzFo1 zO%Q~@8KjkPwPYjl5MBo#4nj*vOkhmJJa>#SP+jfT2D0gV=j651&%~rv(tuFBY!WKl zJK5({s$lW%@IZy|mYMerTHL#7)#z`|?l_e>?V*~2U~%L0F}WkAR~Eq|eRS{evWm3X z*4)qLz4Fw^#Z9BK>ng-YMonct>JTQiqrLgcBhWZ~NG?fsS;91Gs&=^q|3R4se|&n{ z()n&Z9cbrm?-GtBX4f#vRQ5UI?Xqf+Tn~%nH9=*|no+)##4$}{Zp}9&%PCJe1e=W-CF^Oo^PRt@OFwLW zV*G6Jl=w@>HJbMNV{_(gUHAU3nTub4Ua|YxO>5t_s>7B~zjPh$$D4JdmbMqPOxlDI zG#5TyhGaXfF1^`kB$M4nL8H~GCcCw4ste1_oG`+~qI2Gv5d@~gyU>Hv<_uY8;!$A)lkosaW}j5 z+AN;jvF&dmG||^f#d8vsoi3Z2pX^rq1r@3j0t(fjuiBs~RQvfAs?`dOlBbNtlIFq8 zn*B*WhBOq}6jf*xPdz9mJjiH3d(WX~=g<^xcE?hP?jddf>hd0e$yp%P1*!EDlme3- zUUQ3OU8L4#%g8Xs!>v>C7H&w#oY*&xt#fco90!hV@Rag9OFf>__F<)jiU-6}ZYRnN zAVIG~r9%ctj7-LqUVKb^8k?_T@{Cx*lA7wuA>-yoPzOyB&!qlaEDi54%~_-vf1~O5 z3$naPl+eOU_2d53V<}VtEd=@DS#iQlar=k!8sxsN-$0+DlRLI^CHWoj9y_wm(0_I0 z`l!n@8CIZmlqVoBCJPdiQ+i?Uh{DnsvAh^q>5APqi@e15l*)vsj3nHpRcnni&TGewa~Cz{8vXMYJJ03r;^pFXTA65)jEV<)t&s7dQa^ts9MxQo#~J~;R|uA zxIv>1k6tAeKY^C1?Y7m_Ae8p|WK{<|pPR?O*u?EZ*O<0i2k8$$42t>6fs@_-f)LCi zMlvy&m@{8lmU3rr;^-7{$yrvcdsp0Y!Ar!8@6ypc(HRT*t>Ptd z;MX)BTFQ^Uc}2Vs^}2ZQjn!+n)2w$Nc~aI`!e#VK19~R9LIr;?K`0Sw1wN1$1VkR8 zybujWUww`)i!iemnTQR(7q#^^Q%PON+3mt*@n!Lo4Km-?{c^n{YThHy*43>PwEq%+ z>VTI1M2u@|slJQZ^0}}+tk-%(VIl9lDljkzV_i_eb|_Tn`MbAtl+=9{3qSuQ1%CfX z6rb1`_LoFBEZWA3vuVL!62eD`ZJ>mjm`U2}M(A*;RkFwXv&$G*NX-6)g!pTVwC1rPd2lQCHt zX8QaelkB$3t%!@4V#V+PWoHmBki~4~cZ#2Oe75B6=V#m>-g{izjQcJ{B%Eof!*`H;wzgsH$kdsN#~h(XuVDI%hy56*0Rs)S%)8 z3|axRtly`#OoV(Kc4kEh4#B1U&U%gY1!#~+RxyZTm ziFN#Atd2b}98IVrkOaOasQEyZJWf%1hNSDzI-@1ngb+@+GYS*w{v9T9=X@IPx)C~S|>Hu-SxIKwRE7eN1ZG=Ba-!Wh^BSS5jUGTC4b}DhdNTww=YwF zNvr<5g?F|;{^x;bJ!2DT z7M}+3*n-_QwK|(wz%a6pm3@U}7fEiQp zoSISyt~B+K++JCkFnM95LXg15uWL_?|P)t}5lxJ%^$)FlMJhaNrQ#&_h4K;nSU2Npk{OYR@%UqU_@A2UGV$3tIXp=TsMrxwC!4LSoAb+A#g;l#%dSa}06SL30 zFpgw~uwbs@)~bxfnc?K^2t>qpx<^tJg05Zt;>sT$u3H|j&iwAm#X$9ggYsI34b9G- zTR6z{@xgcLq$6b|D{gLD_5807URpJ{dgbMoN-UIe#DUh-W6cd_gT%Qo^f5extKETm zB~b*Eh}*64*%=T}5fg6*Z=ng;kdoX=43VzU5N_-{rRu)lVgw~+B_yhcEg16Xiw|AN zD!OM_(ZE6X7Mq@3p)`pXcF!DJ@acgA;!_{+s~7$;v!u4|Uo$;yWP?KdFQ8B;A{07R zK(*UXr4J#*Ge6~ONWjcF=S!h zI@8(1AJI{77F@E#w0_ZATbFFVHr&UN8=!$1njIW51nY>2aU@FOh~+j7Bzy8-IKpNY zkVp8i8C|);n6l!B<)yRJ)SS{dgeHl*FB#N>pS0!A8eTjQtTBD^_F+2VXi-(f^m01! zkISp>8ush_c2ENB0VQNv$pIzQ;Lc>1E5I0OAjM>^zrLpFbddz-Z%%XQN&>BpmWAsxQfN zW#((O=TrW9cBp6y{Ux}hia)Zdtn9!mDHozk24-Dq4-}U(3Wtj(X*5P*y*b$xs*f^; zg~e67!}P}JYPZp>@UM2O72$BaS&W+n;8>CdCg|kkSw!9!UuHpW_^O@DrxqvNNI8HZ z2`0b$yWdj9n?KaQIBMhm`bB-B)CG@>T()WX4@;{SxYXi?+?HWQ*@Nc|9wOA-Tyo{B z=me^)81sHz&5%#tI!wo&$Q#q4Z~b*%N$sj{=CF}Vi31wF0a6=EB3yxbf0IdB?KbJP zaM6O9627g;jlK{Nn-wDX(>Z2U{2B4XrTS^3*Cvh?KV)MyzWYFR*1GX+k6XCqxz4#? zpAb`&rq|y2XlV5dPZmyGEfqifi6(W7 zxvOwU<><$S8mhd@oz=Hw9EuUIizW_w0QS<1s7atMc%oZJ)Vi(`z>4&7o{ccBOSrQN zEKge++d+GZ{~lWDt3cxPR$=SS1aY~l#8;I}sjH|7!`kKNM-+jAI#}jtW+q!Hv%!e^ zyd+Glo%}jlDF)I=(ewH}MKWd9_&WmBLXD{ISWllT5T8?;I*Kx9^^m#1ZICFUd6gp) zAs87@Ci>2ZihEKElpkXp$3edsV{}|>EU^UGf(;Q&!zwY^&h9PG)SQxGXN~G@xy>jz zOmY+tvxnP9POy?6az0U=zq|gS6_&-~hi&??HIH|zWo#WQv-PKMg8d#9n!ldWvUS~% z`i?~sW50P%Ouofoq2~10ozjFBnwc~O2Kfg;nu7FN-T#m#BWr-98}1Y(sm@bfrHIub ziIA+(%21C#ft#!Qz~J~R}QfQrR^F$sX5`(biwUuc;D`7?(~=BCgz zW_K%_3KY9n{IUBVKkuy>@@wlKXqj&|Ajv7e74*_!#;Nt!1rSXzQB1f+C4)3vdRusA zZQ)f*62KSrbL1ptw7lY&g3u>UHd*k?=4_cW zF}`0CaA}m(ppA`+A#A0{Wz?F2Oyk@-S74BiS13reTfxLro_U0wlw*{R-cm$ba*JS< zoDxC`V#{#@>l&Y2yIkA6F7ogL@1)T1-r_gS$}j8})9!zucNQ1Ey6p0mOC6V@EJaL@ zH)001Q>c+go-T+;BhMTVtYIn&Fr7{(_O|B*kGpdvDgyz8B%czeNfPx>wmljm)O0jU z8l0ZKx#{#*&u^%{2Q>i=C#*nC{zSjqU&*U-Mx4$Yx6uT@9aiN&|j_q19Ykos52{cp@L+3oD5IpbH1?HD!W{4 zjua&MUeM%NRm$K?tHQq*_d6+q8-Ci{uy1LBMl&MrJau+l5qB#!{AjPM<0~lLpfd}4 z92~%fbbR-A{f$cc^UY11`pLbRNdWmLJSX)B(H|E1@edX#h$csyATOvIl`*%%M(19n z1Dk)NW5uN3#C`K%eKv6eIGebW4(mAGfgvnzMTyNAo2w*VK>h`DaDbuO9T4s(bAss! zOht?~qd8diB`Ig?4Ax~#r15>UYE!QS06YeFRPGQ@Rb}S(Dx04k2D06lyx+OBoC~|j ziMxzf18OIvfQsHTh%6pOZMS_g$eE6#SU#zCGgBh5-Z$Uy`D6$#0i zmBfzs>Fc|=x4(a{V9 zVM*`y<@`CBxqI?J1$q?5Xp=G!bBcgnJP*VuWKse#If2eOdj7mJ@VbprYXdy9i|AP# zW()orzpyZaBaSy3WRH-wp0%A?5kX+>bgGz!!i3D823?81WTdfyngR74XV0L7mZ6EP z1HoC2H+CddSL$*?A8y>Db0`Z7ftR`7CwFgN(6UQqb>i1sAO4abSV$8Zrw95uHz(%3 z8Wo)0?IK1&0~aqi_<6)a8eE|PLZpx+@CXrV4cdinzSTg9f%@@=J>G+_hJ+WeUzfvQ zS71=OIK4q1qeosneAI<*-AbiL`GN9+Qb<;2D>(p+s%0nzX5$k4kRd{vq#44k`FR?% zya*hzPz+laW7?2bq|ZyA@T6->g{!8Q^WFiIp6EBe&OLMrpl~50K!jI-Vr^BvL}NGB_*X zpEg-5%P_dzzdS8&;~LrO@U*JJkz7rCvLbi%)FJuh4U(>V4!W)%B52WMu*(z~9gW3z zt)bZ+$VK~UHI30!%ZL?eEnvScEr6ZT+Gs7+s3<@lK9FW2^IC#3dn35V90LUqn38Gi z1Ya`KB+02n7!{YjKjp!;dEc(H?YGaGIy$XBXXN6MRi(uX^B#KE^!M2Jo_?F=98LI9c&s?(phM|13LHEVf_k^=bV-|9#{%{FP=R3U*;De581yeKj~*d>YvewhIA;Fp`DqyoRxEH&pE`Qps(DW5+*R|c>xVW@A67Db z2D1QgK@=K{Ml&gPB`FO?LyKDzs0(aytG>|vtn=ysuHd!2f&`<@RA-Dfaz>+;1}n7^ zT1bX_RWqQD4>crnlR{C$qhns3ieZcaEJnD)#?{hhnjtEW$G1ncJKB@Q&yw*I*&cuR zAWh)wxnUi_JKJ`C_8GpoAK_bc(J3kt;?nRc0nsCstXmkqnM!dTC>R9MBqhVtO#2ye ze)}1;*90jQ;Gy;)8DzZ6#V7d{Cb^R)C-L2r`X+IqNmQLglLAAX(fQ5_=R_y(aHcsq zvlB}tPU^38`o%`aPIKF$jeddC+<+x^oz8TkOVM!&S;~Z&@eV*zNHOD{iZMx^%z%j! z>I+)w0bj!SJnf8v2{FOM6QQ!}%b zj(292PfSVUek)&{7c(Jq^-Gm+m-X(`Jtr>x(Q$j4?GyU`ZEx{~$@!V_gL-B@N_&R5 zQ=R2W(W8?Y8ij5Yt_x130Q+QwuO8NmxIi3D0FPB|b%}b0x>YTFpuVc+)GYAD7W8TI z2^KzJ{Q%a-9^<%mL^lpEm{%}#KAkWBDkcsqnO1lg#0lRF)3MZhSy>Ow5DdRI4ceiX zTH$XbK|23v|3?4${ww@{_V@a$u$~xH8#E)RHRwXn)gS=q{DZ=}#~6F}3Ihxx>{#|O zOgxgIJ@v<&_=l!|lzL!sgJB4mXD$<%O3s8}z*G(Hdn}h>G6>Gzu|PO-vGy2&<2T;> zfLMLcz_EP~eDcqC?!P~4TKi+~(VF*<(5erPi7%WyEp9s0u#F~edzmJ@@``x&?L#uYa7mo;44#LiWr%;-(Kyh%dZ%FRW}FbeT%Z3W!dtTQn-P7f}J$I83FDBH16o9vp+V(SMW}#=6Qn z$a;ltng0|Rl!S;jO}cyZ`tbwHBGvKhpI+nVSCW!6EUmI|0(bf0)|sE*lh(VcBWHB| z<0Cc}O+7ff5j-aaq)M1Cs9~3|?&Z>}^|Tk|s8*+l23QB<8N>BtHB&bLLIAewkbes3 zs<*`Nmt1?FeoG%cAb$VQwc}hSJ^du2LYpShlZM-eOm|4QT|OJ@i@jVCI!gV4*TK3f zztFuxptS2z@9>X<-={A$t(OyMp6q_ND(V>>P@4n|2BH`#+vGl)dxlm%&8hRaNsDR3D;^i zj;`J~s%m3R_NdWW*)?NOM+3<35U#+(&>>z~pbc2)*6#JEQ~ashpLX}h9vO^hEC2oVi0u2 zb2I!_7fiSKD8Gl>_2l6UP@lH+}Bv9<|FC&{15`=JTVn`b2c^R{C^i|NHCmr%aeQhP7}s zm&qq7jzJqPa+O;xQTb6cHHyYWQN^+-sw{}AjN+o~yt&>?&DSl|;;Yvqu-|Xg?iI(ow|&I;tG3qdKjh4c&0E*l$x)6Px`f0|NvI5I{gc z%Cpra-#y7d$p~agr(hpFM=4vd?a{#m1FcRg`X#-UjojE*^ z$1;W)0Svg%n4tOmTxll6mN9)UGy|Toz$n(Pwq*CJT9q^wZuCWiX69qgp(ag0V4?T{ zt)NLu^mKIpfggWNKfbxib2vU?as`5bMICeV8Lw80?E*$2WIo2F2h@-%YOxvw_z53K zp)s9o-3e2UYV5i}N0_RxGgK3U*gI{)&P|*DmR0uYiL;lv(PF!@$DEqkZi&ro z#=$loY zH1t~yeLzEJVKD9SUUx;q_t7j>(n@8$@*X9xe8%q;KhDo(jwpcdZY3~p*_p|S)!1+2 zOq2!{+b)N-F18;)rHbeDr}tee3yIdd7EQ!T>>9efVXQ7`#PiVin_xu~U`4fAu4tFe_?=6%{aXUo;AVEWL&srU`+sd$^{W&Diya6B##rkYqM9FauI3t!<~J0^Xib zw`InI4}I|Rf~Dd`*IgyqW%)CO&8=r9uYKsqZ>xh|o!?+LRI7wKCew6()9&H?hI2K0?3!(2|2T1XCQ44EIY zBIK12#TXpE67p7v0K$gAYYYhqjFC{PItiuvO5j_8Tp%OFEni78=+#Y_27?P2*uH>o zhQ&8iW6;%%uD&I=Ic(bf_vT4J)z2;fs5<>Y099$N1Vwf;XLHr7lrGQ ze>=(POhUrkg0)uF2#M3dQy8;L6ENA0A^(Z1H*k*_{lGnHfXmY`+@l7#M-3E&5damV zkt!7iKZ6X%qySjm#y~PCD4T=HAutKt1e|JD^j;?-k^)Pn%xphhBvzak_weh5l1^-7 z%y5o$gv~Dz*GN6^p(L?2tg>SZlm5A)iQ!Sfhd7KV6}gu~XK-D@a7sMxCd-NUYl(w2 zz{kP=$T5q|lXIBFW%D6Jvhs@>5L~i_T zaIUys6u0?!t29ZYlNl}*IZCd})ClY3i-h}==+#@MximVVB_jVS$1FgDB|Q@RS2>Q5 z{c;X@fHT=+=t8L-axF*6NjZn(&N7&M$T_A+WiTz#Q_7OY>@L+}W8!+ux6@r_P--RF zNDh(@$W@|fB`evk0p?D!h#LFdZ3!z###3x(0;Bic&=oX;!iA$MW}D!XuA@mb7 zk{$z4?8CL(hcs!u_%Tgfi_i!3N~ymzZ&Cn5vEFxzniIKc?3-K+zLv8UF48#;Dt zpk&m7fp>i$!AtGTkg z?TU_9`_@j>4Zc0}^NZsXEC$Osx5;283Ds^0jWmgtaE%rTdM1HL&SIx{B zI=sC0o=`FIgO{s->{#p&lWCwbde_>!HxzYGi?F06j$ATw>w5#P4$DdFmY-G7l3R9f zj$>G6R^g<3ZVq_&HQ+sV3a?){0h&u_E2Ry5VbEqJ8T1xm7C$CPw)p>Xe^#?}KjE+L zLnE{2R4s@qz_DX90t)b?k4HI@6tVd+r06Ay%l58Z?s|V#(tk?9&@Rs(`ANFp?at?!l*r{z zxgg6x>MbdO{pAKpCA=f)jzQv6k|a_^XBo)BmvqT7%j=SJXghOY*2~MSkjpqCq8Uuj zX*zSTGGdji9deE-;=hoCX)&|h66mM`M8_9HYeeE59f>Zp*)h%?q6=5>W;25RQCKuL z1NaKRvQsvou;h)Da3#&s;smrrC#VB%m&FM=i8tOM0Nj+gidk(nKMgrJ!nI8N?afcW zT=3mv+p09Cx^F9|=QIr*nqPQ#_ArGhuKOF=LmyZ-b;=)W{}5Ll{pYFYseawO(>06M zv?ny~8$Wc^lwDItjA9%_&xGwtHcm%K96Ty)&h$i?M7>g(!!Jl23h#QqzRUet zSOEF69x3l~{|H7g?%z>>5ghDzbbV~0K4D7k`Cgd~7bO{R?q z=gRRkHmc?QI*CC}gjo>OMes}^xx#X&C#cIYHbizjUX+tlSTt~8aZ%2o0``kHCY=9y zNb#`3{L*2(P&{b+LPH+UxW}%EBe&$YWSU$Uep?((C=C3Nt5pzoC7SIO!w!+y% zd2zje3b%(rfYO#sTQl`B1_SC-Ieqff^t-=(fF23yD4Bj?v6u^x86-l&T}T`QE7_Qq zI8H-4IsWJSv*t67(dfUrf5al)kG%6f8%uKeQ}A*lHj-r1!n{ohZ6LK^wA6xG$Z@NN zPV^GuO2INNRYwBDHAbM9KtZ6FK+XS!Uh;vL5ZL-Nd?}7kTKjz4mrHk6``}Bj(xjY7 zr+QKF;8}%(3I@;3FBY0VK6F%Ev;SF!U{VwDzQ3=s@>bhf@8q^m zdGU_kVZy*PR<^Xl3}l=P5tIRfK2#uXL7QM6teT5e)?gsCs(0zJs|8Uk*>gk?3yy>y zj)b0hj`Chcs@3Y)Ru2sv35~#G%E=ojrbxFuN46H*xgP72?oPk4b3+<*j^$+PJX`{I_Q}e$|}s?jJRl2E1Q8A@ZqN zKnWxEn}OJGEn>fcB-9naYg(yGxl+kp#g0i9{dI<&U?Czq+OLwp95%DrBGkT{J#O;+ zbJ@F6X{ousw{R}4xw0fQb5~CK4wz7mGYMw}jdCYEBMZTf2c==QANA{{bKL`!bg$FF zG#EvP9jgxe9AENkummoXVGOFSffCKbcTaCy+BkjXQyJa6r}ygBJwtJH>f-s04Xq2O zN+A$%kJ5gqZvjv&!Q?JizukKJf}Wn$(+d4W{VYA7p&yLsEZM7|TNLzD1$8SXW2*?? zM^T{Q6#i(Vzp-_tAH9kuvL2(u(mS|VWVQ)`c=iJd#PsAKs4Ba`**l73xDO}Ck4-6d z^|M8%1n%hfdCJh7zR@wg%-eE=bGCR}A1C&)$6K8l;&F_|1iFjg&aG$G<8=yb_$%^$ z1^5xh47`RWg)d8?yT18G&Z%1bKXR%PJ99SkZ*x`fR+M<350PFzgwo>CE+s!#J?WW? zqbBiho4;!RSiAuBMy4QlsV}#nL?HHE^a(HVu%{cjB4q#4jdu$n`zacaDEIBR@919_ zT5sWE!cKL4@eb;!oN~qT6}H62LzkdELa0TlEsmb> zInsNC7-rfJh283n1l;hwM+hbIcDxh=?-P=`#eL>C{@IHmz32G)XZcJNGw0GAP;wdF z&K(mHAUEnA*gYz}vaXAzUbbf0(zTC2)b<#6dHu7`J+W@{W;}y+U2dHeqqYDoE-mVI zS<^j?yaTVt_!$~e~5B(CAUhz+Y~s34sX0mrkL#|SF;j)@olc;zlF02?YNBD zr3F;IbJq`E8N^#|9{yRtRwwB-MW~DIwEGNJA&xY;2K$>W<`%ayJR-cs&FdnfBa$O{ zzXj z%oaEFH3#&6jl1~xEzL1~5-^;(oe=b;sW!U`~u9&7+rubD^ zq@1hVruS(z)ykxfsujz0~ZCJ)G2hOy8WP0t$w}!p#FEP-=zmF z33?;w7ejwTn_;(6ZOk>!F+Od)XwsMlnx>i#n?4P;1<%K4pIL7nWq!td#S&myWjPv> z6S6Gi&5%nWKZTADy(e^Qs2Dap>}c3G;g0Z;;iJPhhhK_tMBEk85V0^~UBn-en#l0T z9+3kghevLXqEP`+QBlcJuBg(eaZxQ%i=!Tox(R$-WOUEy?C6r{vC&UQ|7KNK&DMBp zrnShr!1^oZH%6P?=CtM7%40M!=9svc^qBmZyJG5N=EStcY>4?ccxkc6!%H7*ue5KE zC9(QgYizIBfw3cEpNaLv9&#i(jyQe>xNvsd!*PF$+Y@&>?)&(__|*97_}TI6;`hd% z>Xz57uG^k&2f;DMHL4kKeqG*^V|4w0Cw^*NAmr`!slTw_6aT#M?#)XbTQrsG<>0X& zBv|?rPO^7#!au{7LXM>(63TBR#}tVqL8vEAm3g>=~5n;Exdt*7Is` zuMzKeo2VQ{<_X!}4MM!PnSaiEhCA!MF4WVb_}##0Ak*Fp+L7l#x8LyFj0C#Tqx@II zgtl!|ZXru~fvgkelLF}((4Jir2-(Ruu;)kvRy_M5jYj^jgp1z&iUDLb=)H(O=S{)& z1>7%W6P_n3EvfUR#r!tp1Ks~yQYC;N;Dy8o#tUC!eCV3MD@P|E7%#dev}*y*$1`4Z zO%gB8foJ(x!)LVqFG+a=^klpMAG#))4-yYz*|G36Xwu0C#*40r$=P<2DDi^vqcedQ z63_6<%21_|xvD@s+lX25)0o9J(ti9|lAzj-8QdPMHSPflAk({^pN-khY|K+`;Fu%J zxOJoe2}7_0`#Gg?!}yTQ&e^zBFUOJ>(QLSR>5pG9{s?_l9(%s;PYEx)%k76IR%0JH zR>5er{L7yq6FH*hIDa*VJ;Q#SZ~;>q7r6)F3wUh!8#;X0aCYSFkn2z{=PIp)KJ&#{ zjOZFzdqS*Oqi0Q%^*Y|Ah=mD)RWEj(sfYk_Kk?EOymazi?jPJgttM-jHOd-e?Q6}o zwph2t7-E9qud}}ZJhKrwOMN+w)(~q1a%SFue>8YtR7mM=iwdJp!_;} zp1rOhsfRT$q&_#PN1i>u)?=-+dhjE}*$Z$7m+W;OYpvB2ho8DGmuo#PsC&xxArIfSrvAx=VY$kx`$ScsKoK|T)W%q`AIq+Djf@P(n$bLY&JY0wTiXYn&-)% zRo|9Zi#F07{+dDdK@&7dJ;)A?KMwtI*_1&bKe}A0^IcIo^uH5!)58t&(9%j9`wPzpSK8Y0?biIZ+P1nq-qx{ptKQzWL#u6@ zkq2^u+80fgx}INJ>@kiQRq5dz`PTY65Ci|R?Y2JQwxC;i zP{4n`O+Xe92Nbq4GL}@fS@YVK<=Vn+dAWGn=4l;K$;h*8kCluK-$`7_iEa;9%kCWP zyc1l`?zDE^k+Zu%SUY%JJhHOQBRC4j+w(yAWp$p`v5>MUj6rt2C-7Rh&E94RvSucu zHsockC>%f8>QTgblT1Eb$&9}vDm}^e86J~8N0ugBkccyRWTo_o zd^OKw8sxzn%Y9FIlJoE^hCp5$leqs^mbQYW3m$gY_eH(-5tV!Ka_S2^Qmx^yI!P*V z=b|K!c@QKsF0ZX}{6tT5ZTNVM)rr>1aGS^FhE%xil@r`dR6)&z3uqetKmy2DS!MA^ zd+~^>N=SmuE!|-^SaE_Q?@z_pE5qetAhaILX04T6IPXSAJuX=DabVBsk8h94p+?e! zInq@o>^c3dl{B1m=0-C-3D&#`xxRet{Ek9#!aD{Pbe5)MrzmGoLAVWSLHbMT!Qr;m zS1}$}GwCc~_t-6{Hr!T2rU$WWGTlSiK(SWZC)nNgdaK7(Qprff$RlyYM+}KSG6##x zD!ZO_Ar{C)Y`85^&PPm7e&Q_}GU9p$OXnb|)x(w9J){g{uoZMK@lZznQPSWJhupct z@4Svna!LRD*>F$ce?D3$SIVAjQ`?J2wlN0VeeEP5NDxxt6p&&hU=k> zZT7=ci0{?7% zsH}1)FtdYdbKE;(aldk}l@OP7m19@gMV7_NPFQKBI8jUa!}q!fX_f8@(go>!+#X7# zYjP%BLjY+HCtuS``F6xf6}d2_AGb%4@3=Zk5O7T`Uu%`Fx!Ks}BlKk@8 z{2BS&)qL77pXTGz@RDKWy@mk_SX@4&q_{k~nCgnNi(e_`N0yY9XP44aT2eluq@*0M z4%aq^R-bQkTFbw%Qv6p3Rt_&2U1_Crt<*~S@@OYt9>sg3ug{~inqAQ|n|ntmw*1(_ zwY1Q~Ews5hIXcuCQjTr!gZ^r(@?HJwE_x^#+%mpZ2lFVSC%aq zzl5u=PLE~{4w%$0D?fJ9nn}-1+BHdnYWhuzj?dRmvQFaIBK5XOA>sMLB-5mpNqpu+ z>Yg}xBBz>2`%R!fPN2dB(}b1@y#M&>jOcOI-J^@gQvb0}j(uq?ANWxn4X>mAwc)ji zwa07E*Zx?m)LCoe67v1WoFBs(T{S&Z^IbJju*WqNfan!Z&1M)mP( zzW6~J;S4V~JA=!EsIFY^)Rn)YJFVk-=_uxJ<#aqLZzS`vKkjFOy?eCPOcitwUAd!d zWMX3R9+ej+->+nphd$(SjAY-g5mg@LLmpCIHL7w4rH{B5FJDe_B8xq}p#^Fq-Nl~q zOdYU;RvhRfcbG|zySX_rk)_1Mmgbh3HS7pqHOlSzJ3wX}vJ>_=F3Gp>BrB|i6)2S|=V94GuH3GI z8xxs}IX@zLUB5+>_Zo0wcn4hj8t+eHg=iA@d)Z3*|L30^KcG&;w+OjLSVUGYZfh64 zSG~2~tMGgD?fbmHhR`2u&k{L!*oC+AV(Ny)3ZNO?vPaV6ro>`z6im^UL}pCI<`5Z^IJ z%s7*;^P~hGj(jYT?&Kcdu>yEb_GWnYtP=6feZJ#BM8YoM-OY`p1<6WAk~%USyZv%- zHjRwOl|tO9!|`M?jts@s=~CV~WCoca-EF|#Nw_;5-&X8`go$XG#Ra4h?*P{V&(e6I0i3U%4zF zd@3Xji9s36gJv}vkPs_JiotlKXbZbOMs-z#8Fmq*B!k;VRB>jXFD8wNY=!pirq2N~#=p2iF z;*HXf0xkHSinYQFl7&0DKy3;%n;aJ;*24=Kf1-G@@& zLbS3BdgKsFeUF^P>i%hb*jp8J-oqpaDHeKhA<`nG2apycJ&3df=>+bdMhYVeuZL)m z;&8P)Qg5VGB)oy0^no7B#BX1u{@yRyjyAFe=`p0WNRK0}Lt2mYB=T-RdJ5@jq-T)- z5Uw9b*{6{5q;~1OpGs|Gk`n9P_n)=mdM_d73?b(m?Cei_^+A15AJkXsEA^H7N_nL`Gp@+EqHb;~oVKf+?W;_!jwB#?5l)FFou7cc4+nd`)+D6*C-___`efPh(mhZUZEP3nfzAH~= zFsaCg`ov{b_Elt~A{!Msn3~T$_eT}jSAqSZ^Ve&9S~cX%`?53ZwHfx3ITbxG9t(Kv zZpZZrZtF2U_kNoD3)z*zN@1m(QRQcqpH+TV`B~*>J{_J89dOdaMtx#%;l;#P#_o(jjsLP`=ba>=$vEyRL#g2;|7dy^bU0!uF zBRMyNa}?xA7|GrnM#3kK$urmcWF7XV$vjVut7;PUbU!mcqnO#Bk<2XZ_&w+EN5dXI z=c#!tAnSC|oh6WHKkDLAvj6IN9MZYa7tmwCeuD)|GWcom+55`qi^v$Ag7Jakmn?>I&`et$N Zg>x^Qd*R#*=U!G_8GbU#&kp(1`UCwMR@49h literal 0 HcmV?d00001 diff --git a/docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff b/docs/assets/fonts/Noto-Sans-700italic/Noto-Sans-700italic.woff new file mode 100644 index 0000000000000000000000000000000000000000..209739eeb0921ce1475ed1f357911ef9faaf0f3b GIT binary patch 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 new file mode 100644 index 0000000000000000000000000000000000000000..7f75a2d90964f801e9b9f916fc77d0fb46071a09 GIT binary patch literal 26644 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 Tox|}wpnWXuG8F&21R?()4C4-I literal 0 HcmV?d00001 diff --git a/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff b/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff new file mode 100644 index 0000000000000000000000000000000000000000..6dce67cede1847a0bb49092dbd2203b1bfac8b91 GIT binary patch literal 12536 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 Di>nx! literal 0 HcmV?d00001 diff --git a/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff2 b/docs/assets/fonts/Noto-Sans-italic/Noto-Sans-italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..a9c14c4920648bc420b1d68cf13d6672af6ded3c GIT binary patch literal 9572 zcmV-qC7arJPew8T0RR9103~Dq4gdfE07Z}h03{6o0SY|;00000000000000000000 z0000QQX7gw91I3v0D(La5DM))*BJpe0we>5U<-pX00bZff@lXI8^$-YqNMQ}5Jj+Y zBH%GkiK1!}%>K&+&cXE1mK8iKE{dYz)rLS*T!dbv-RuwgD~DlKGIEEZ4f)r6X6u$5yq;dWK@4fr?LRza-k6k4pUe&qm6h&DS z%JuX$Jk0B#Jch&JTsYBFm6Nm0Y<5^MF^rk9iP|_3acVj*oO7=7|GsPYe;?_zR(Cuj zSWXrJv&N+WR0y)#jPA6T8>VZ3~0eGc#q9cAIZ;5BHAfWCtop*UOio(HY zJboGMwejr`J5dz%X^Lo@0=X|->muW1Ud})1 zdCgCOMhfVyYGVf&Sv@^tCf}LbsTvR%Ge0>Y)&5?mt}4RRnP8$}NxDw{?|;bxlVm%s z97cs&#RbVOxd(nd4$viY{G>NZ!Q=Zv%kh&2| zZpJK&MJPgS_ixo>Y}FQ5wOLq;=nT?=Ui_b}0SmdZ-~l`1A)0DFBZ+umHJ=SK9#qX| zCkv0`gYY@o#DneN^LC2Id%Qh_g?ngC9^OxNMlK+)bsO zbj+Ejl5W=l@$QXIWmCDDc=(zFO{zaJz@zCf9=Fhmz2kj$R%tit{C(pjG_xKuR1)sf z;(JIti}(F&UJ5xL(d%EM%1yJY6DC1Tty+yLJMumWoxg@mc?D$1VuH%UsjoyX$UCvScN1PT%?RJaI{qC|_u#8RSEnQ}Ea zYSp=+UZW<>TC{4{sY|yWz4{CqGHk?zDbu)S&0Dc*&4xpF@;O+IBq`OB0_YUNporp= zht=GPF9=<+b5&nh6xdR^OTFe*w*}NgflM%=MOgg?Mnyq2bWjL`B8pX0K{GA1s;-*4 z>7kcC`qe_wB1~YgD2HKkbJM@<&1h69(jL4DmB0s`go6G{N4Y1z<`yYS@ z)c z8_(DCxCyjdqp`U{R+XH>TdPlYC%$LV9jvhTL5~Bp@BZH+c-I`z89To!Qq?++n$#~` zlWLNyD!uSJtxt4Cx~pif^D08*D|C5ayQ(UX29`i5DwJb99wN@y_JIBhbh_~Tlo{jKwk~6`eF1gN;bo3!z4Q8Z9z_Qkl0+W45yV~C>w=L;>G)zxW{7|* z?UZF0SCuog%t&QOm5$1?YppY^bjKK#g?-7rF&4IVhG8}~2J$y6YKuj=ee1~fYspOd zg`mfhg51L1Z*O3i*n&Sf9Y9soad&okr~} z`XHA7Cel3&Cb-9bG-)maUFGBCRpqV(IanwqB=G~U7-~@f>9`FROwo;P3?G===A{VX zXeuqOI`OFy*?3sFZjP9m?Y z-A62jYxNs7L1GM%=LB(a5&UOc|E05f8-WfLuwH30;Odxn46~QD&zc)*=W8rMgN! zF&jmg5!U?fE7b~}u~0bybml=e<76NA?C)c$?fioA5d}X^f6f(;AVnF#0-*qVshc$R z(dKtfa3D}s4>(wc(=Mio5E)ZoFuH;csP6l1%_|KAf{`&7=~je*L2_UWkU5$8v@!*k zg=je@AxNI&hR|}ST!8xdfZ&joF^%taeu2gV>#fFux71(I-f{d1VNkuV(i}UQaDvC$xN2c@d&Rj83 zSePXJwQROv^68K$}SdG80-`dcSzmzFzLdU23;pm`x`vV0rjsv@F*wpBzw@r4%#<*@)7^DjOuGc z(351Z219A2Z3ZAPfb~CvL@i2wv#`J;&imz*{?y9ANs4tPOr#}?58CUdoZ*agb+5(E znZ;`RjiKLzH)lBJ`Q}=ct1g*&VgN0FO$UFzbj4>wJ&*La%KpLPKWW5n7bNhydAkyr z_snY~z?gVv9Mfj^H}RZs%I0WOS4VbO4IPeGufZXGQ|^-OnxRz9p-ycK_LRhO=w1oT z;xmTQ{xpLxykG{~|6&@QNpHVcJIE_d;HVcu)(=E3v`QMkp_YF&m*H$kjGZH|O6(wi zDf8u~^guRimWdOn9m7zH`g@*g?S_u3FbISTG=u;Tk=(ocf2Q}D*UbN6i@AzW#ItV< z{f^s(=^F8lJB)}5(&A~ULgwIruJuBf!Wt8f*M>#CdRT3LiVlBjL*Q7(G7Mc5tr$GX zL^~trRW-`~`#z}8isc`NRUgE0%mHzHA-TfFI3~H=7=oIEe}BzqX3)6M+E2IjgA@*b z;YvCqh%s&Qj-F)WE`yXCCx&PCz)`v40Hfuhw>}dDN}pDZk*ELxyWGb%y7hyf5V=kj z8LlS~;7f?XWc`o@R7|;&{8zFdZ?9bV7VjM#>84k2<`w{VG0g(2L$x+*Q46^a_F zGtVzCi^Pa#rbn3B2l&VfdtMhyB196H#%pMxbmHcSrr3QWcVq0(c}~2Tb~Zc74xmTN zLr%{id5?9S4<Vdoa!W-f6zB8P!UAR z)3ZH@))~H$nog+%rzeEAOvIDGf|32zA@=yAd+7MK>YfJ&leJ^5MZrGwa>96oSY|rL zdwDAU)6DpvL#ftyxFyjGOQT@II-Jl!&*2Owl#flMg+~C)KOu#jn2Fy51_H&yzdG|m zdOxY;2a@>9YIuRdo4ClY_PoN~AJlWh2>+K=L4YaakIbA7sdIgW`s0)#)0E1;19Nf= zWeG_ZZ3M1nDfqvLUPoutG3LKLv^rq+dphFYkO(X4PKp{ZxvSdqMx_U6`uc>#cGJRc-G--`ZulSpYuS$IwEyxSW$o|H26 zm^k#_5`=I?RaiPFnyjnw116FxML_~z2()^ z;Zy_8YkFkwWFcHjs2Mn$6gTZWnotnVlP&3|Fmm@l5qs_r`;CU^-7$;pm}n}_yHQX{ zm*+5g9}JYhk`qy}%?>`M!PNE2pT~EGfD_T@jl1{gp&2TX?=og@-w~bMe_i7lBgY8U z6$*}_X8#)m)aZG$_m9TgYtHyHCwCcsqh091h2y#YoT>_%UWiD-C2yI^9F1$bxjEcXB=)wnW^U)Fn!u=vME`}9 z52p?pW-)QPgqWiAI?$`XCA*{8O21O^@*h$I=$YQSxj9ltYgwJ~$?{CPnMTQ2eu=JM zeX=oFGxu=UC&E6sHlBnZ+l~cYvZH1YGdOo_$Z6(Su7%8tKzi9r=K$Aw0bRUn{eZ7YrZBM&AD$5r2-A(Ti$Ee{ z{W!+X3J%N&{cW?T!P&k>3U$ASk{9ETyNLSk>k|~?rJF8;e@KbOL6dl;-LC8nsc9kX zG&i;IMsXA4zmGK)&Q#fO6?n2D(T<4p%+B)vh4K6Ue}8;|yt|e0_Pm0!0Q|KsN`vt* z;_Ypd-Y$!KkpGq^K10@IYHMWX5Ya8k5i6u&+El2S^S?#F=+n;czi;muPIFg9Lb=l( ziHe3-UXvAkyc-{P00UR<>EnUk^1;=XYY?JBW@E~+_7{O;sZg#_^2hqgvTQ^)rs9sc zOD^x|Vq+DtB7^x3SoJ{1M7HWvP8OCP^jA$_m zloe=kk@7h-{wihKJtKvl4J-iCyK|==%DU=NeQ@aCyrA{mJ)>MpvpDzict$A8jl> z=;r*s#>6~c8vKiZFlyLY32rD6Y(>@VQ3 z*kP(SbgX%F6mO$P=&+zsJ(+-ZT0mJ6e)=Yaj&18uh+xi3F2^1b6u@f>IKgkpu81X04K zDVL?9=Xu#M;Wics7L4LkkCy$Cwhkq87kH0H&lT5#gSESvk281Gj0O3|=C<@E^ma98 zfa1gFPw!|L-@wbyrK_HQQ#}K+%CA;f^3#iyyAW5ZEWXl4L8f!5?Dk(}iZ!pKwvJze zOEO%sT5k8$1f-3(Yiiyrx^KlmnZcJe04EJ zt`dt&OF;H@A(T6wgFmI#Pfj)tYW(?@`q()pMzthkY|2zU>Rekcl}Yl<)A+SM&w(Fn zC9P{yN2RE<&HClg1reFSi%2i@B%2nQb8%k?o<4$6(yuMfy`saFmb4yVc*ZZlU-~ndhbTR?d4JIA28Q?)7%IBVyI{n4VYdVd1DtX|kAKFEf8TAL693 z*gFDt^COq0Ns86a_s|3VaZ0Vv5J_8wuD$Q(^t~A^`3g*m7e`np#k-98p($syk<$IP{IKMOPfkW z7gkoVEM)ND{q*^6uc<;AOD9jW*k~J9FMVwUDEQSgq`uBJS8G=y{&Yg3`zO`0&KBwK zJ``=Dt!M=T)3;tH4<4wJc7EVtrv;SF5p#ijt5!66Vf38r^D=JYGw#+`n zIRY7&W>lFEl}2jWyL$PAb&_*0e;u4caiKXzZnT;*nx70Bm=$cLW|UxX1MDdNrhE#E z6yI49DKJ~RT@1ChnA?&$b&?n$n2wG*B#~ZZ?6uCyQ04G|N>| z*^-uabU7#STlrsR4|q%!8u9?@P&z^)+|#BRS-|<0@jy4h9DXJG?C`Jm^{xFl>;sxrfhnYl2fqkPaNw zQtg7Slq_LoH1Zi484i+xIl+VC0kgi;H#oCDrLQujs9}-;Py<5;AerXHWsgfn7?f9r zcarm7qR35XB$9n2NCbHri^{LApgE|--xGmJ_}c>O6t$+N>h;^XuU^wONTDdv#~Q$p z-E2hhpO;6U@ZR^jDLLjU%oQ5(TX*K1Gu=@3=KF3fCuH1&{rcg`io&MXBl$p{iUm+% z@|!ewpw_YW?vC8wIx}+vfdfZCP}OVNO&;PU{ytXlvLoizL%WDI?ONW5fdv-b|84av z*C29&DZ-5kW=}6sw7NV_uNF1RRYQ*rA>fCU%DYOO^olSUjI)DcYcG9NO`ekw?IsoG zW_KkskAjupuh$r{lyuj*d*0!iiMxJK-BsvoBWaky12He4?gy ziicdPJW{O9C=ZpvI5{e}_tIv>>xgLg3!%9UpPrkElN79j4xCrLdq1k11RBI$Jo%ob7>_c65FML zV%y0FOt$uBnnPX7D}4)aIjNUO&bG;NMaeq1rO^@e0O%d%t|hq}hq@*obnfn6E!uMr zRULjf176-EI-~OQ;RtGef-`{-?>u-Aa30tB`t>wtB$Wz>4MmRRG^8^;F>vh78O}^Y zm6V||6(uII%Cdy`(n{d|@a5AjiT~fqG1U}X)Y`o$TMG1=3nJ2Ji0A*ffuV{G;~qIhLzgew{5DLH2Vt^mffKVOkSdQE}-#$z}vka{Z6P zx2DN>tqh?~`qN64PtoRiu^!_H-|6($9Xbx8qGFHncA0Hn*`MyrgwYAN; zZfZ8}vbz%#v$ww$v34is?%^&Bws-60SJm6=5lLIaLr|^Z;StTjQO&WjQ4P(Zkzwf2 zuojTnkO)9!Ip)s5z%GMabiS4BbRtfsU#b8w8LnSjhTz3bzHPXM?^6Q zb!Ae+!`0pU@^ehyF4TyS8sR>dag8zACZ{#Pv09Kr6RK+l%*W-p0oM5t-xzAB@=I#_ zPE>MqG2z#q*1Wz;ur;|M}?OpA5kRNmP3})7%U9U8_G??Y56Fa*||~ zR-guyYPoqLlS$Rrc`ToYd*fUz;6R^$Ehk{BE+rw2QJ$9(ywQ*npFw5)DThcME(`Gp zbc(@Gv)Y}afcf~(%q+nj+@-G|$Mo$oTbRg+^S**^LQE_@s0B40(zJwrQiNcHyR)BW zlohP!bCYbD>Tn&$l6CZa|6ET?HvLvRIXf~CcMw7t% z5+GZ+X|wIl$%*MRvcgTNh@8~8cnVRpTix(bm|@;Uxe)SF8>W978~kl*+GJ+@H;8fo zKf<@Ua@$8%4DPH#haqxDtncuiDZ={9ovMM5p@ELa4ipyFDz(&=)$~48xNlC%El%hk zoWb5~>@Zkcdk6c31jl1f`*`#UwzlYmxV*`Yq8MsRYD`fdw)9;%eXEw4xcrXvn3~D| z4Ck+y)PLJ9MnB3^57#wjMFrn$N|q1SmCB29Ew2BtQ-}txDC<8w1ng+eHvNf~$>d+o zqvy*%DbVgcni$At;YwS9L6JiDLM6>VxQrO~?7F{`d6YwfM`Cl-*wgKWu~@g><6n z)B-}Rt$DbwZJ3jLimjPin7w1ty7!Ozmoq9P(QsBJCQuip!J*3gh+94$R z;&n;%6|McZo4`{-I;q_U>MK{2DZ4L($?cAd%`V#hzvQpYQ{~Fdy!%73 zl-lCV8Q%j#XzcbcN~xq-(^RhOw|041O4LSAkCW8c=m@e8vUf1!Gl0G`{VBjSj*=bZ?7~y&nDlEwD8cuS3Q$8ASRS7_I$Z8#NWE{W#ngtY z_y$VQTy{Jog=?&n`3j9Otx2e-BtlLx9@j()KFpyIazRc}U2~niWH!^=D@- zNo8UiF7dq;G5@!EY<^Dh0*0#5H8aIGkaAXYLU;IXDMbZIAK$~ReK zLYXXt${LPW;6yHmFBLa%i6l(eLjuLE0Qf2x43zTgZe`bnT)fkRJuSqJsA8LFvaq2U zLB>5uTs6)2BEA!52z)oH1>tI*d25H4{+rXp{_2>28(5j8xWNr80ZJ;pL?CNnMypHu`EQv71A8an!2gJt zhhfI6m~=RV^oKlB)nPxu@D=snoNSi2$rszNwJZS}1IHLWWi5WitR2 zd$?qc$nyWf3t0@P%RbQh9?t#1@;3s7t~Ij%)C#n?24>!5o8gab$zfZwmx_&3^PFum zKZi|v#M-!AS*f+%9N7Mql3IXINh_dG(&>HM^3(od+AVp{sXy! zZhOq1JfQv5C%lswFh?Rc;%PVz9AE?4&#?nz|H$}%rqR6N#@=nLZL1@H0mAG5k+pRG z!=X-fG9~JH3o=Qo$=pmSJ|YQqbqqBiYNiu^O3gHvtkebl$X@7}V)osnnl`!4eyj*# z*e{!)Ffs+4Nln3I$ENhAAKi);3DPiFsS>Po2mNR^+U!)oE_DG+#62D~+Ee2{HMxw2 z|F^x~3vQ2xjxCq1dn8P*uo`Wq@hffkMqDrHjzrc7W$ z4fodHqfvoz=-~1O#=V}Xd;K!@>IQPvIjKe-A$RY;d5-bFWXm~F?3wg9Kb{o=mImXzf!7$eWAM1tcgmxXU)FO~CR*-j)36l~!$E$dX z3S-txy5G#$jlL$??0=BFm+wjoOQ8K?GwO`rG<6v3vb9L+B<2*} zW{uMd@={?^f@hpgEg*gy-19cB;QZ}wSo*9H?%VuMcrL)hH<^3}c<#NAp7?Kxe;3dD zZEiVU&I!6{4V<>@nZNea>96%y0?IvHBX8v`YXG?k@R_a%+Eu(5+H4ccZHm`Dkeu3v z7ZD^V#6pI+W0>cLXnjFr8lndAs9sQHPgB#0AVwEae4x=wbcmDoidLHEGg5%J*oj)F zJ;|9@rFlz8PGFBP)BBo`ek6|MsWDMl)Yl08*~6I^qK*~Qyr9v~#ar0Pl7Oe`E?7eJ zlGk(KbSBQ?^vIJmuO}~9O#4y<)%$qlnK|C%#0u%q+7lm^Sqhn*EPK1@iR}MnM`^7C zZyb_Bf)%q_KVwcM=5qjSMN-nF-s*BAeU_aJ5{pHe%R}sokYf+IKdaIgEA-0x;}+S( zhIHJjl31x_7fVC&lf>4~;JU$Q$B(POVV?N5G4*2wSARbeR(fP%S*NSH)068VAB$#d zfH7mXe3F9j8jLPy-ziXi%7yU!2e5)C)Z5O{W*w(|gFo zx8iIKHAMI8r%dOJGHvm)x#)AHcm`nDvDMsp$?y?oWa$R^#tPW)4Ag*!P2=DJ-fBTY zU9*}83@d=?z}ng94sezlvVyU!2r#K`~Y2D`~X8m;Q&)rv-Qx*JU@78 z@Dv3@NRi6(F*-t$L@2)SQleI}5TGgYlnenQQA#T-(&aGvNX6?ZiYddOk)#f=(WHtD z=`moUVXl(va#*WOLtsU}X_F!AK`aDBghNk?@klTrVga2%MoWc}4^Pfq`3Y`Qbs25< O$@oD12Gp?wlQ{ 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 Ez~snGSpWb4 literal 0 HcmV?d00001 diff --git a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.svg b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.svg new file mode 100644 index 00000000..bd2894d6 --- /dev/null +++ b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.svg @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.ttf b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a83bbf9fc8935b8187f289299a802aa01ca008f7 GIT binary patch literal 29288 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 E0c9`PF#rGn literal 0 HcmV?d00001 diff --git a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..17c85006d0de2c50a19dd67150ef4d825c92fb9c GIT binary patch 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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 literal 0 HcmV?d00001 diff --git a/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff2 b/docs/assets/fonts/Noto-Sans-regular/Noto-Sans-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..a87d9cd7c6124a9fb103fe349dd91f55eed52c5b GIT binary patch literal 9932 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 K;{%RVQL6!h1TU%p literal 0 HcmV?d00001 diff --git a/docs/assets/js/scale.fix.js b/docs/assets/js/scale.fix.js new file mode 100644 index 00000000..911d33c3 --- /dev/null +++ b/docs/assets/js/scale.fix.js @@ -0,0 +1,27 @@ +(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 new file mode 100644 index 00000000..cda68f5b --- /dev/null +++ b/docs/index.html @@ -0,0 +1,204 @@ + + + + + + + + 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.

+
+ +
A number of 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.

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

Collections of related tokens as 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 got you covered!

+ +

Includes improved versions of the PHPCS native utility functions and plenty 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.
+ Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 8.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.

+
+ +
Fully documented
+
+

To see detailed information about all 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 may want to 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 unsure whether the changes you are proposing would be welcome, 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

+
+
+ + + + + + + From 86b523afefd916074f052dc2b380a045e2a9eb59 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 16 Feb 2020 06:05:36 +0100 Subject: [PATCH 46/48] Readme: minor tweaks ... to be in line with the documentation homepage. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7ab40b3..887e33c3 100644 --- a/README.md +++ b/README.md @@ -228,14 +228,14 @@ PHPCS 3.x uses namespaces, while PHPCS 2.x does not. The `phpcsutils-autoload.ph #### Q: Why is PHP_CodeSniffer 3.5.3 not supported ? -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. +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. Just clone the repo, branch off from `develop`, make your changes, commit them and send in a pull request. +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. From f448e9da1273d2b2ff00471a8474a6bba0fecf7e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 12 Feb 2020 23:40:18 +0100 Subject: [PATCH 47/48] CI: Various minor tweaks --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a8d5b380..4af3e6a3 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name" : "phpcsstandards/phpcsutils", "description" : "A suite of utility functions for use with PHP_CodeSniffer", "type" : "phpcodesniffer-standard", - "keywords" : [ "phpcs", "standards", "php_codesniffer", "phpcs2", "phpcs3", "tokens", "utility" ], + "keywords" : [ "phpcs", "phpcbf", "standards", "php_codesniffer", "phpcs2", "phpcs3", "tokens", "utility", "phpcodesniffer-standard" ], "license" : "LGPL-3.0-or-later", "homepage": "https://phpcsutils.com/", "authors" : [ @@ -24,7 +24,7 @@ "require" : { "php" : ">=5.4", "squizlabs/php_codesniffer" : "^2.6.0 || ^3.1.0", - "dealerdirect/phpcodesniffer-composer-installer" : "^0.3 || ^0.4.1 || ^0.5 || ^0.6" + "dealerdirect/phpcodesniffer-composer-installer" : "^0.3 || ^0.4.1 || ^0.5 || ^0.6.2" }, "require-dev" : { "jakub-onderka/php-parallel-lint": "^1.0", From ca72c7f9b8cf886c7088f87198aca163047bfff8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 14 Feb 2020 19:34:09 +0100 Subject: [PATCH 48/48] Add a changelog --- CHANGELOG.md | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..41de1e10 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,119 @@ +# Change Log for PHPCSUtils for PHP Codesniffer + +All notable changes to this project will be documented in this file. + +This projects adheres to [Keep a CHANGELOG](http://keepachangelog.com/) and uses [Semantic Versioning](http://semver.org/). + + +## [Unreleased] + +_Nothing yet._ + + +## [1.0.0-alpha2] - 2020-02-16 + +### Added + +* New `PHPCSUtils\Utils\ControlStructures` class: Utility functions for use when examining control structures. [#70](https://github.com/PHPCSStandards/PHPCSUtils/pull/70) +* New `PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction()` method. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) +* New `PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose()` method. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) + +#### PHPCS Backcompat +* `BCFile::isReference()`: support for arrow functions returning by reference. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) +* `BCFile::getMethodParameters()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) +* `BCFile::getMethodProperties()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79), [#89](https://github.com/PHPCSStandards/PHPCSUtils/pull/89) +* `BCFile::getDeclarationName()`: allow functions to be called "fn". [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) +* `BCFile::findEndOfStatement()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) +* `BCFile::findStartOfStatement()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) + +#### Tokens +* New `Collections::$alternativeControlStructureSyntaxTokens` property. [#70](https://github.com/PHPCSStandards/PHPCSUtils/pull/70) +* New `Collections::$alternativeControlStructureSyntaxCloserTokens` property. [#68](https://github.com/PHPCSStandards/PHPCSUtils/pull/68), [#69](https://github.com/PHPCSStandards/PHPCSUtils/pull/69) +* New `Collections::$controlStructureTokens` property. [#70](https://github.com/PHPCSStandards/PHPCSUtils/pull/70) +* New `Collections::arrowFunctionTokensBC()` method. [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) + +#### Utils +* `Arrays::getDoubleArrowPtr()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79), [#84](https://github.com/PHPCSStandards/PHPCSUtils/pull/84) +* `FunctionDeclarations::getParameters()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) +* `FunctionDeclarations::getProperties()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) +* `Operators::isReference()`: support for arrow functions returning by reference. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) +* `Parentheses::getOwner()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) +* `Parentheses::isOwnerIn()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) + +#### Other +* Documentation website at https://phpcsutils.com/ + +### Changed + +#### PHPCS Backcompat +* `BCFile::getCondition()`: sync with PHPCS 3.5.4 - added support for new `$first` parameter. [#73](https://github.com/PHPCSStandards/PHPCSUtils/pull/73) + +#### Tokens +* The `Collections::$returnTypeTokens` property now includes `T_ARRAY` to allow for supporting arrow functions in PHPCS < 3.5.3. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) + +#### Utils +* :warning: `Conditions::getCondition()`: sync with PHPCS 3.5.4 - renamed the existing `$reverse` parameter to `$first` and reversing the meaning of the boolean values, to stay in line with PHPCS itself. [#73](https://github.com/PHPCSStandards/PHPCSUtils/pull/73) +* :warning: `Numbers`: the `$unsupportedPHPCSVersions` property has been replaced with an `UNSUPPORTED_PHPCS_VERSION` constant. + +#### Other +* Various housekeeping. + + +## 1.0.0-alpha1 - 2020-01-23 + +Initial alpha release containing: +* A `PHPCS23Utils` standard which can be used to allow an external PHPCS standard to be compatible with both PHPCS 2.x as well as 3.x. +* A `PHPCSUtils` standard which contains generic utilities which can be used when writing sniffs. + **_This standard does not contain any sniffs!_** + To use these utilities in PHPCS 3.x, all that is needed is for this package to be installed and registered with PHPCS using `installed_paths`. If the package is requested via Composer, this will automatically be handled by the [DealerDirect Composer PHPCS plugin]. + To use these utilities in PHPCS 2.x, make sure the external standard includes the `PHPCS23Utils` standard in the `ruleset.xml` file like so: ``. + +All utilities offered are compatible with PHP_CodeSniffer 2.6.0 up to the latest stable release. + +This initial alpha release contains the following utility classes: + +### Abstract Sniffs +* `AbstractArrayDeclarationSniff`: to examine array declarations. + +### Backcompat +* `BCFile`: Backport of the latest versions of PHPCS native utility functions from the `PHP_CodeSniffer\Files\File` class to make them available in older PHPCS versions without the bugs and other quirks that the older versions of the native functions had. +* `BCTokens`: Backport of the latest versions of PHPCS native token arrays from the `PHP_CodeSniffer\Util\Tokens` class to make them available in older PHPCS versions. +* `Helper`: Utility methods to retrieve (configuration) information from PHP_CodeSniffer 2.x as well as 3.x. + +### Fixers +* `SpacesFixer`: Utility to check and, if necessary, fix the whitespace between two tokens. + +### TestUtils +* `UtilityMethodTestCase`: Base class for use when testing utility methods for PHP_CodeSniffer. + Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 8.x. + See the usage instructions in the class docblock. + +### Tokens +* `Collections`: Collections of related tokens as 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. + +### Utils +* `Arrays`: Utility functions for use when examining arrays. +* `Conditions`: Utility functions for use when examining token conditions. +* `FunctionDeclarations`: Utility functions for use when examining function declaration statements. +* `GetTokensAsString`: Utility functions to retrieve the content of a set of tokens as a string. +* `Lists`: Utility functions to retrieve information when working with lists. +* `Namespaces`: Utility functions for use when examining T_NAMESPACE tokens and to determine the namespace of arbitrary tokens. +* `Numbers`: Utility functions for working with integer/float tokens. +* `ObjectDeclarations`: Utility functions for use when examining object declaration statements. +* `Operators`: Utility functions for use when working with operators. +* `Orthography`: Utility functions for checking the orthography of arbitrary text strings. +* `Parentheses`: Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped in parentheses. +* `PassedParameters`: Utility functions to retrieve information about parameters passed to function calls, array declarations, isset and unset constructs. +* `Scopes`: Utility functions for use when examining token scopes. +* `TextStrings`: Utility functions for working with text string tokens. +* `UseStatements`: Utility functions for examining use statements. +* `Variables`: Utility functions for use when examining variables. + + +[DealerDirect Composer PHPCS plugin]: https://github.com/Dealerdirect/phpcodesniffer-composer-installer/ + + +[Unreleased]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.0-alpha2...HEAD +[1.0.0-alpha2]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.0-alpha1...1.0.0-alpha2 +