Skip to content

Commit ff83d52

Browse files
authored
Merge pull request #674 from PHPCSStandards/feature/update-for-new-upstream-4-branch
Update for new upstream PHPCS 4.x branch
2 parents 59d93d7 + 2adfb12 commit ff83d52

File tree

57 files changed

+1339
-278
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1339
-278
lines changed

.github/workflows/test.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,13 @@ jobs:
108108
experimental: true
109109

110110
- php: '7.4'
111-
phpcs_version: '4.0.x-dev'
111+
phpcs_version: '4.x-dev'
112112
risky: false
113113
experimental: true
114114

115115
# Run risky tests separately.
116116
- php: '7.4'
117-
phpcs_version: '4.0.x-dev'
117+
phpcs_version: '4.x-dev'
118118
risky: true
119119
experimental: true
120120

@@ -151,7 +151,7 @@ jobs:
151151
- name: Setup ini config
152152
id: set_ini
153153
run: |
154-
if [[ "${{ matrix.phpcs_version }}" != "dev-master" && "${{ matrix.phpcs_version }}" != "4.0.x-dev" ]]; then
154+
if [[ "${{ matrix.phpcs_version }}" != "dev-master" && "${{ matrix.phpcs_version }}" != "4.x-dev" ]]; then
155155
echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> "$GITHUB_OUTPUT"
156156
else
157157
echo 'PHP_INI=error_reporting=-1, display_errors=On' >> "$GITHUB_OUTPUT"
@@ -214,7 +214,7 @@ jobs:
214214
if: ${{ matrix.risky == false }}
215215
run: vendor/bin/phpunit -c ${{ steps.phpunit_config.outputs.FILE }} --no-coverage
216216
env:
217-
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }}
217+
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.x-dev' && '4.0.0' || matrix.phpcs_version }}
218218
PHPCSUTILS_USE_CACHE: false
219219

220220
- name: Run the unit tests with caching (non-risky)
@@ -223,7 +223,7 @@ jobs:
223223
vendor/bin/phpunit -c ${{ steps.phpunit_config.outputs.FILE }}
224224
--testsuite PHPCSUtils --no-coverage ${{ steps.phpunit_config.outputs.EXTRA_ARGS }}
225225
env:
226-
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }}
226+
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.x-dev' && '4.0.0' || matrix.phpcs_version }}
227227
PHPCSUTILS_USE_CACHE: true
228228

229229
# Only run the "compare with PHPCS" group against dev-master as it ensures that PHPCSUtils
@@ -233,15 +233,15 @@ jobs:
233233
# "nothing" is excluded to force PHPUnit to ignore the <exclude> settings in phpunit.xml.dist.
234234
run: vendor/bin/phpunit -c ${{ steps.phpunit_config.outputs.FILE }} --no-coverage --group compareWithPHPCS --exclude-group nothing
235235
env:
236-
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }}
236+
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.x-dev' && '4.0.0' || matrix.phpcs_version }}
237237

238238
# Run the "xtra" group against high and low PHPCS as these are tests safeguarding PHPCS itself.
239239
- name: Run the unit tests (risky, xtra)
240240
if: ${{ matrix.risky }}
241241
# "nothing" is excluded to force PHPUnit to ignore the <exclude> settings in phpunit.xml.dist.
242242
run: vendor/bin/phpunit -c ${{ steps.phpunit_config.outputs.FILE }} --no-coverage --group xtra --exclude-group nothing
243243
env:
244-
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }}
244+
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.x-dev' && '4.0.0' || matrix.phpcs_version }}
245245

246246

247247
#### CODE COVERAGE STAGE ####

PHPCSUtils/BackCompat/BCFile.php

Lines changed: 254 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ final class BCFile
7676
*
7777
* Changelog for the PHPCS native function:
7878
* - Introduced in PHPCS 0.0.5.
79-
* - The upstream method has received no significant updates since PHPCS 3.13.0.
79+
* - PHPCS 4.0: The method no longer accepts `T_CLOSURE` and `T_ANON_CLASS` tokens.
80+
* - PHPCS 4.0: The method will now always return a string.
8081
*
8182
* @see \PHP_CodeSniffer\Files\File::getDeclarationName() Original source.
8283
* @see \PHPCSUtils\Utils\ObjectDeclarations::getName() PHPCSUtils native improved version.
@@ -88,17 +89,53 @@ final class BCFile
8889
* which declared the class, interface,
8990
* trait, enum or function.
9091
*
91-
* @return string|null The name of the class, interface, trait, enum, or function;
92-
* or `NULL` if the function or class is anonymous or
93-
* in case of a parse error/live coding.
92+
* @return string The name of the class, interface, trait, or function or an empty string
93+
* if the name could not be determined (live coding).
9494
*
9595
* @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified token is not of type
96-
* `T_FUNCTION`, `T_CLASS`, `T_ANON_CLASS`,
97-
* `T_CLOSURE`, `T_TRAIT`, `T_ENUM` or `T_INTERFACE`.
96+
* `T_FUNCTION`, `T_CLASS`, `T_TRAIT`, `T_ENUM`, or `T_INTERFACE`.
9897
*/
9998
public static function getDeclarationName(File $phpcsFile, $stackPtr)
10099
{
101-
return $phpcsFile->getDeclarationName($stackPtr);
100+
$tokens = $phpcsFile->getTokens();
101+
102+
$tokenCode = $tokens[$stackPtr]['code'];
103+
104+
if ($tokenCode !== T_FUNCTION
105+
&& $tokenCode !== T_CLASS
106+
&& $tokenCode !== T_INTERFACE
107+
&& $tokenCode !== T_TRAIT
108+
&& $tokenCode !== T_ENUM
109+
) {
110+
throw new RuntimeException('Token type "' . $tokens[$stackPtr]['type'] . '" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM');
111+
}
112+
113+
if ($tokenCode === T_FUNCTION
114+
&& strtolower($tokens[$stackPtr]['content']) !== 'function'
115+
) {
116+
// This is a function declared without the "function" keyword.
117+
// So this token is the function name.
118+
return $tokens[$stackPtr]['content'];
119+
}
120+
121+
$stopPoint = $phpcsFile->numTokens;
122+
if (isset($tokens[$stackPtr]['parenthesis_opener']) === true) {
123+
// For functions, stop searching at the parenthesis opener.
124+
$stopPoint = $tokens[$stackPtr]['parenthesis_opener'];
125+
} elseif (isset($tokens[$stackPtr]['scope_opener']) === true) {
126+
// For OO tokens, stop searching at the open curly.
127+
$stopPoint = $tokens[$stackPtr]['scope_opener'];
128+
}
129+
130+
$content = '';
131+
for ($i = $stackPtr; $i < $stopPoint; $i++) {
132+
if ($tokens[$i]['code'] === T_STRING) {
133+
$content = $tokens[$i]['content'];
134+
break;
135+
}
136+
}
137+
138+
return $content;
102139
}
103140

104141
/**
@@ -512,7 +549,8 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr)
512549
*
513550
* Changelog for the PHPCS native function:
514551
* - Introduced in PHPCS 0.0.5.
515-
* - The upstream method has received no significant updates since PHPCS 3.13.0.
552+
* - PHPCS 4.0: properties in interfaces (PHP 8.4+) are accepted.
553+
* - PHPCS 4.0: will no longer throw a parse error warning.
516554
*
517555
* @see \PHP_CodeSniffer\Files\File::getMemberProperties() Original source.
518556
* @see \PHPCSUtils\Utils\Variables::getMemberProperties() PHPCSUtils native improved version.
@@ -531,7 +569,137 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr)
531569
*/
532570
public static function getMemberProperties(File $phpcsFile, $stackPtr)
533571
{
534-
return $phpcsFile->getMemberProperties($stackPtr);
572+
$tokens = $phpcsFile->getTokens();
573+
574+
if ($tokens[$stackPtr]['code'] !== T_VARIABLE) {
575+
throw new RuntimeException('$stackPtr must be of type T_VARIABLE');
576+
}
577+
578+
$conditions = $tokens[$stackPtr]['conditions'];
579+
$conditions = array_keys($conditions);
580+
$ptr = array_pop($conditions);
581+
if (isset($tokens[$ptr]) === false
582+
|| isset(Tokens::$ooScopeTokens[$tokens[$ptr]['code']]) === false
583+
|| $tokens[$ptr]['code'] === T_ENUM
584+
) {
585+
throw new RuntimeException('$stackPtr is not a class member var');
586+
}
587+
588+
// Make sure it's not a method parameter.
589+
if (empty($tokens[$stackPtr]['nested_parenthesis']) === false) {
590+
$parenthesis = array_keys($tokens[$stackPtr]['nested_parenthesis']);
591+
$deepestOpen = array_pop($parenthesis);
592+
if ($deepestOpen > $ptr
593+
&& isset($tokens[$deepestOpen]['parenthesis_owner']) === true
594+
&& $tokens[$tokens[$deepestOpen]['parenthesis_owner']]['code'] === T_FUNCTION
595+
) {
596+
throw new RuntimeException('$stackPtr is not a class member var');
597+
}
598+
}
599+
600+
$valid = [
601+
T_PUBLIC => T_PUBLIC,
602+
T_PRIVATE => T_PRIVATE,
603+
T_PROTECTED => T_PROTECTED,
604+
T_STATIC => T_STATIC,
605+
T_VAR => T_VAR,
606+
T_READONLY => T_READONLY,
607+
T_FINAL => T_FINAL,
608+
];
609+
610+
$valid += Tokens::$emptyTokens;
611+
612+
$scope = 'public';
613+
$scopeSpecified = false;
614+
$isStatic = false;
615+
$isReadonly = false;
616+
$isFinal = false;
617+
618+
$startOfStatement = $phpcsFile->findPrevious(
619+
[
620+
T_SEMICOLON,
621+
T_OPEN_CURLY_BRACKET,
622+
T_CLOSE_CURLY_BRACKET,
623+
T_ATTRIBUTE_END,
624+
],
625+
($stackPtr - 1)
626+
);
627+
628+
for ($i = ($startOfStatement + 1); $i < $stackPtr; $i++) {
629+
if (isset($valid[$tokens[$i]['code']]) === false) {
630+
break;
631+
}
632+
633+
switch ($tokens[$i]['code']) {
634+
case T_PUBLIC:
635+
$scope = 'public';
636+
$scopeSpecified = true;
637+
break;
638+
case T_PRIVATE:
639+
$scope = 'private';
640+
$scopeSpecified = true;
641+
break;
642+
case T_PROTECTED:
643+
$scope = 'protected';
644+
$scopeSpecified = true;
645+
break;
646+
case T_STATIC:
647+
$isStatic = true;
648+
break;
649+
case T_READONLY:
650+
$isReadonly = true;
651+
break;
652+
case T_FINAL:
653+
$isFinal = true;
654+
break;
655+
}
656+
}
657+
658+
$type = '';
659+
$typeToken = false;
660+
$typeEndToken = false;
661+
$nullableType = false;
662+
663+
if ($i < $stackPtr) {
664+
// We've found a type.
665+
$valid = Collections::propertyTypeTokens();
666+
667+
for ($i; $i < $stackPtr; $i++) {
668+
if ($tokens[$i]['code'] === T_VARIABLE) {
669+
// Hit another variable in a group definition.
670+
break;
671+
}
672+
673+
if ($tokens[$i]['code'] === T_NULLABLE) {
674+
$nullableType = true;
675+
}
676+
677+
if (isset($valid[$tokens[$i]['code']]) === true) {
678+
$typeEndToken = $i;
679+
if ($typeToken === false) {
680+
$typeToken = $i;
681+
}
682+
683+
$type .= $tokens[$i]['content'];
684+
}
685+
}
686+
687+
if ($type !== '' && $nullableType === true) {
688+
$type = '?' . $type;
689+
}
690+
}
691+
692+
return [
693+
'scope' => $scope,
694+
'scope_specified' => $scopeSpecified,
695+
'is_static' => $isStatic,
696+
'is_readonly' => $isReadonly,
697+
'is_final' => $isFinal,
698+
'type' => $type,
699+
'type_token' => $typeToken,
700+
'type_end_token' => $typeEndToken,
701+
'nullable_type' => $nullableType,
702+
];
535703
}
536704

537705
/**
@@ -737,7 +905,7 @@ public static function getCondition(File $phpcsFile, $stackPtr, $type, $first =
737905
*
738906
* Changelog for the PHPCS native function:
739907
* - Introduced in PHPCS 1.2.0.
740-
* - The upstream method has received no significant updates since PHPCS 3.13.0.
908+
* - PHPCS 4.0.0: Handling of the namespace relative parent class using the namespace keyword as operator.
741909
*
742910
* @see \PHP_CodeSniffer\Files\File::findExtendedClassName() Original source.
743911
* @see \PHPCSUtils\Utils\ObjectDeclarations::findExtendedClassName() PHPCSUtils native improved version.
@@ -752,7 +920,42 @@ public static function getCondition(File $phpcsFile, $stackPtr, $type, $first =
752920
*/
753921
public static function findExtendedClassName(File $phpcsFile, $stackPtr)
754922
{
755-
return $phpcsFile->findExtendedClassName($stackPtr);
923+
$tokens = $phpcsFile->getTokens();
924+
925+
// Check for the existence of the token.
926+
if (isset($tokens[$stackPtr]) === false) {
927+
return false;
928+
}
929+
930+
if ($tokens[$stackPtr]['code'] !== T_CLASS
931+
&& $tokens[$stackPtr]['code'] !== T_ANON_CLASS
932+
&& $tokens[$stackPtr]['code'] !== T_INTERFACE
933+
) {
934+
return false;
935+
}
936+
937+
if (isset($tokens[$stackPtr]['scope_opener']) === false) {
938+
return false;
939+
}
940+
941+
$classOpenerIndex = $tokens[$stackPtr]['scope_opener'];
942+
$extendsIndex = $phpcsFile->findNext(T_EXTENDS, $stackPtr, $classOpenerIndex);
943+
if ($extendsIndex === false) {
944+
return false;
945+
}
946+
947+
$find = Collections::namespacedNameTokens();
948+
$find[] = T_WHITESPACE;
949+
950+
$end = $phpcsFile->findNext($find, ($extendsIndex + 1), ($classOpenerIndex + 1), true);
951+
$name = $phpcsFile->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1));
952+
$name = trim($name);
953+
954+
if ($name === '') {
955+
return false;
956+
}
957+
958+
return $name;
756959
}
757960

758961
/**
@@ -762,7 +965,7 @@ public static function findExtendedClassName(File $phpcsFile, $stackPtr)
762965
*
763966
* Changelog for the PHPCS native function:
764967
* - Introduced in PHPCS 2.7.0.
765-
* - The upstream method has received no significant updates since PHPCS 3.13.0.
968+
* - PHPCS 4.0.0: Handling of the namespace relative parent class using the namespace keyword as operator.
766969
*
767970
* @see \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames() Original source.
768971
* @see \PHPCSUtils\Utils\ObjectDeclarations::findImplementedInterfaceNames() PHPCSUtils native improved version.
@@ -777,6 +980,44 @@ public static function findExtendedClassName(File $phpcsFile, $stackPtr)
777980
*/
778981
public static function findImplementedInterfaceNames(File $phpcsFile, $stackPtr)
779982
{
780-
return $phpcsFile->findImplementedInterfaceNames($stackPtr);
983+
$tokens = $phpcsFile->getTokens();
984+
985+
// Check for the existence of the token.
986+
if (isset($tokens[$stackPtr]) === false) {
987+
return false;
988+
}
989+
990+
if ($tokens[$stackPtr]['code'] !== T_CLASS
991+
&& $tokens[$stackPtr]['code'] !== T_ANON_CLASS
992+
&& $tokens[$stackPtr]['code'] !== T_ENUM
993+
) {
994+
return false;
995+
}
996+
997+
if (isset($tokens[$stackPtr]['scope_closer']) === false) {
998+
return false;
999+
}
1000+
1001+
$classOpenerIndex = $tokens[$stackPtr]['scope_opener'];
1002+
$implementsIndex = $phpcsFile->findNext(T_IMPLEMENTS, $stackPtr, $classOpenerIndex);
1003+
if ($implementsIndex === false) {
1004+
return false;
1005+
}
1006+
1007+
$find = Collections::namespacedNameTokens();
1008+
$find[] = T_WHITESPACE;
1009+
$find[] = T_COMMA;
1010+
1011+
$end = $phpcsFile->findNext($find, ($implementsIndex + 1), ($classOpenerIndex + 1), true);
1012+
$name = $phpcsFile->getTokensAsString(($implementsIndex + 1), ($end - $implementsIndex - 1));
1013+
$name = trim($name);
1014+
1015+
if ($name === '') {
1016+
return false;
1017+
} else {
1018+
$names = explode(',', $name);
1019+
$names = array_map('trim', $names);
1020+
return $names;
1021+
}
7811022
}
7821023
}

0 commit comments

Comments
 (0)