@@ -526,8 +526,9 @@ protected function tokenize($string)
526
526
$ numTokens = count ($ tokens );
527
527
$ lastNotEmptyToken = 0 ;
528
528
529
- $ insideInlineIf = [];
530
- $ insideUseGroup = false ;
529
+ $ insideInlineIf = [];
530
+ $ insideUseGroup = false ;
531
+ $ insideConstDeclaration = false ;
531
532
532
533
$ commentTokenizer = new Comment ();
533
534
@@ -608,7 +609,8 @@ protected function tokenize($string)
608
609
if ($ tokenIsArray === true
609
610
&& isset (Util \Tokens::$ contextSensitiveKeywords [$ token [0 ]]) === true
610
611
&& (isset ($ this ->tstringContexts [$ finalTokens [$ lastNotEmptyToken ]['code ' ]]) === true
611
- || $ finalTokens [$ lastNotEmptyToken ]['content ' ] === '& ' )
612
+ || $ finalTokens [$ lastNotEmptyToken ]['content ' ] === '& '
613
+ || $ insideConstDeclaration === true )
612
614
) {
613
615
if (isset ($ this ->tstringContexts [$ finalTokens [$ lastNotEmptyToken ]['code ' ]]) === true ) {
614
616
$ preserveKeyword = false ;
@@ -665,6 +667,30 @@ protected function tokenize($string)
665
667
}
666
668
}//end if
667
669
670
+ // Types in typed constants should not be touched, but the constant name should be.
671
+ if ((isset ($ this ->tstringContexts [$ finalTokens [$ lastNotEmptyToken ]['code ' ]]) === true
672
+ && $ finalTokens [$ lastNotEmptyToken ]['code ' ] === T_CONST )
673
+ || $ insideConstDeclaration === true
674
+ ) {
675
+ $ preserveKeyword = true ;
676
+
677
+ // Find the next non-empty token.
678
+ for ($ i = ($ stackPtr + 1 ); $ i < $ numTokens ; $ i ++) {
679
+ if (is_array ($ tokens [$ i ]) === true
680
+ && isset (Util \Tokens::$ emptyTokens [$ tokens [$ i ][0 ]]) === true
681
+ ) {
682
+ continue ;
683
+ }
684
+
685
+ break ;
686
+ }
687
+
688
+ if ($ tokens [$ i ] === '= ' || $ tokens [$ i ] === '; ' ) {
689
+ $ preserveKeyword = false ;
690
+ $ insideConstDeclaration = false ;
691
+ }
692
+ }//end if
693
+
668
694
if ($ finalTokens [$ lastNotEmptyToken ]['content ' ] === '& ' ) {
669
695
$ preserveKeyword = true ;
670
696
@@ -698,6 +724,26 @@ protected function tokenize($string)
698
724
}
699
725
}//end if
700
726
727
+ /*
728
+ Mark the start of a constant declaration to allow for handling keyword to T_STRING
729
+ convertion for constant names using reserved keywords.
730
+ */
731
+
732
+ if ($ tokenIsArray === true && $ token [0 ] === T_CONST ) {
733
+ $ insideConstDeclaration = true ;
734
+ }
735
+
736
+ /*
737
+ Close an open "inside constant declaration" marker when no keyword convertion was needed.
738
+ */
739
+
740
+ if ($ insideConstDeclaration === true
741
+ && $ tokenIsArray === false
742
+ && ($ token [0 ] === '= ' || $ token [0 ] === '; ' )
743
+ ) {
744
+ $ insideConstDeclaration = false ;
745
+ }
746
+
701
747
/*
702
748
Special case for `static` used as a function name, i.e. `static()`.
703
749
*/
@@ -1869,6 +1915,20 @@ protected function tokenize($string)
1869
1915
$ newToken = [];
1870
1916
$ newToken ['content ' ] = '? ' ;
1871
1917
1918
+ // For typed constants, we only need to check the token before the ? to be sure.
1919
+ if ($ finalTokens [$ lastNotEmptyToken ]['code ' ] === T_CONST ) {
1920
+ $ newToken ['code ' ] = T_NULLABLE ;
1921
+ $ newToken ['type ' ] = 'T_NULLABLE ' ;
1922
+
1923
+ if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
1924
+ echo "\t\t* token $ stackPtr changed from ? to T_NULLABLE " .PHP_EOL ;
1925
+ }
1926
+
1927
+ $ finalTokens [$ newStackPtr ] = $ newToken ;
1928
+ $ newStackPtr ++;
1929
+ continue ;
1930
+ }
1931
+
1872
1932
/*
1873
1933
* Check if the next non-empty token is one of the tokens which can be used
1874
1934
* in type declarations. If not, it's definitely a ternary.
@@ -2236,7 +2296,30 @@ function return types. We want to keep the parenthesis map clean,
2236
2296
if ($ tokenIsArray === true && $ token [0 ] === T_STRING ) {
2237
2297
$ preserveTstring = false ;
2238
2298
2239
- if (isset ($ this ->tstringContexts [$ finalTokens [$ lastNotEmptyToken ]['code ' ]]) === true ) {
2299
+ // True/false/parent/self/static in typed constants should be fixed to their own token,
2300
+ // but the constant name should not be.
2301
+ if ((isset ($ this ->tstringContexts [$ finalTokens [$ lastNotEmptyToken ]['code ' ]]) === true
2302
+ && $ finalTokens [$ lastNotEmptyToken ]['code ' ] === T_CONST )
2303
+ || $ insideConstDeclaration === true
2304
+ ) {
2305
+ // Find the next non-empty token.
2306
+ for ($ i = ($ stackPtr + 1 ); $ i < $ numTokens ; $ i ++) {
2307
+ if (is_array ($ tokens [$ i ]) === true
2308
+ && isset (Util \Tokens::$ emptyTokens [$ tokens [$ i ][0 ]]) === true
2309
+ ) {
2310
+ continue ;
2311
+ }
2312
+
2313
+ break ;
2314
+ }
2315
+
2316
+ if ($ tokens [$ i ] === '= ' ) {
2317
+ $ preserveTstring = true ;
2318
+ $ insideConstDeclaration = false ;
2319
+ }
2320
+ } else if (isset ($ this ->tstringContexts [$ finalTokens [$ lastNotEmptyToken ]['code ' ]]) === true
2321
+ && $ finalTokens [$ lastNotEmptyToken ]['code ' ] !== T_CONST
2322
+ ) {
2240
2323
$ preserveTstring = true ;
2241
2324
2242
2325
// Special case for syntax like: return new self/new parent
@@ -3008,6 +3091,12 @@ protected function processAdditional()
3008
3091
$ suspectedType = 'return ' ;
3009
3092
}
3010
3093
3094
+ if ($ this ->tokens [$ x ]['code ' ] === T_EQUAL ) {
3095
+ // Possible constant declaration, the `T_STRING` name will have been skipped over already.
3096
+ $ suspectedType = 'constant ' ;
3097
+ break ;
3098
+ }
3099
+
3011
3100
break ;
3012
3101
}//end for
3013
3102
@@ -3049,6 +3138,11 @@ protected function processAdditional()
3049
3138
break ;
3050
3139
}
3051
3140
3141
+ if ($ suspectedType === 'constant ' && $ this ->tokens [$ x ]['code ' ] === T_CONST ) {
3142
+ $ confirmed = true ;
3143
+ break ;
3144
+ }
3145
+
3052
3146
if ($ suspectedType === 'property or parameter '
3053
3147
&& (isset (Util \Tokens::$ scopeModifiers [$ this ->tokens [$ x ]['code ' ]]) === true
3054
3148
|| $ this ->tokens [$ x ]['code ' ] === T_VAR
0 commit comments