@@ -17,7 +17,7 @@ class VariableAnalysisSniff implements Sniff
1717/**
1818 * The current phpcsFile being checked.
1919 *
20- * @var File|null phpcsFile
20+ * @var File|null
2121 */
2222protected $ currentFile = null ;
2323
@@ -33,6 +33,13 @@ class VariableAnalysisSniff implements Sniff
3333 */
3434private $ forLoops = [];
3535
36+ /**
37+ * A list of enum blocks, keyed by the index of their first token in this file.
38+ *
39+ * @var array<int, \VariableAnalysis\Lib\EnumInfo>
40+ */
41+ private $ enums = [];
42+
3643/**
3744 * A list of custom functions which pass in variables to be initialized by
3845 * reference (eg `preg_match()`) and therefore should not require those
@@ -175,6 +182,9 @@ public function register()
175182if (defined ('T_FN ' )) {
176183$ types [] = T_FN ;
177184}
185+ if (defined ('T_ENUM ' )) {
186+ $ types [] = T_ENUM ;
187+ }
178188return $ types ;
179189}
180190
@@ -226,6 +236,7 @@ public function process(File $phpcsFile, $stackPtr)
226236if ($ this ->currentFile !== $ phpcsFile ) {
227237$ this ->currentFile = $ phpcsFile ;
228238$ this ->forLoops = [];
239+ $ this ->enums = [];
229240}
230241
231242// Add the global scope for the current file to our scope indexes.
@@ -265,6 +276,12 @@ public function process(File $phpcsFile, $stackPtr)
265276return ;
266277}
267278
279+ // Record enums so we can detect them even before phpcs was able to.
280+ if ($ token ['content ' ] === 'enum ' ) {
281+ $ this ->recordEnum ($ phpcsFile , $ stackPtr );
282+ return ;
283+ }
284+
268285// If the current token is a call to `get_defined_vars()`, consider that a
269286// usage of all variables in the current scope.
270287if ($ this ->isGetDefinedVars ($ phpcsFile , $ stackPtr )) {
@@ -286,6 +303,19 @@ public function process(File $phpcsFile, $stackPtr)
286303}
287304}
288305
306+ /**
307+ * Record the boundaries of an enum.
308+ *
309+ * @param File $phpcsFile
310+ * @param int $stackPtr
311+ *
312+ * @return void
313+ */
314+ private function recordEnum ($ phpcsFile , $ stackPtr )
315+ {
316+ $ this ->enums [$ stackPtr ] = Helpers::makeEnumInfo ($ phpcsFile , $ stackPtr );
317+ }
318+
289319/**
290320 * Record the boundaries of a for loop.
291321 *
@@ -857,9 +887,11 @@ protected function processVariableAsClassProperty(File $phpcsFile, $stackPtr)
857887// define variables, so make sure we are not in a function before
858888// assuming it's a property.
859889$ tokens = $ phpcsFile ->getTokens ();
860- $ token = $ tokens [$ stackPtr ];
861- if ($ token && !empty ($ token ['conditions ' ]) && !Helpers::areConditionsWithinFunctionBeforeClass ($ token ['conditions ' ])) {
862- return Helpers::areAnyConditionsAClass ($ token ['conditions ' ]);
890+
891+ /** @var array{conditions?: (int|string)[], content?: string}|null */
892+ $ token = $ tokens [$ stackPtr ];
893+ if ($ token && !empty ($ token ['conditions ' ]) && !empty ($ token ['content ' ]) && !Helpers::areConditionsWithinFunctionBeforeClass ($ token )) {
894+ return Helpers::areAnyConditionsAClass ($ token );
863895}
864896return false ;
865897}
@@ -925,13 +957,30 @@ protected function processVariableAsThisWithinClass(File $phpcsFile, $stackPtr,
925957return false ;
926958}
927959
960+ // Handle enums specially since their condition may not exist in old phpcs.
961+ $ inEnum = false ;
962+ foreach ($ this ->enums as $ enum ) {
963+ if ($ stackPtr > $ enum ->blockStart && $ stackPtr < $ enum ->blockEnd ) {
964+ $ inEnum = true ;
965+ }
966+ }
967+
928968$ inFunction = false ;
929969foreach (array_reverse ($ token ['conditions ' ], true ) as $ scopeCode ) {
930970// $this within a closure is valid
931971if ($ scopeCode === T_CLOSURE && $ inFunction === false ) {
932972return true ;
933973}
934- if ($ scopeCode === T_CLASS || $ scopeCode === T_ANON_CLASS || $ scopeCode === T_TRAIT ) {
974+
975+ $ classlikeCodes = [T_CLASS , T_ANON_CLASS , T_TRAIT ];
976+ if (defined ('T_ENUM ' )) {
977+ $ classlikeCodes [] = T_ENUM ;
978+ }
979+ if (in_array ($ scopeCode , $ classlikeCodes , true )) {
980+ return true ;
981+ }
982+
983+ if ($ scopeCode === T_FUNCTION && $ inEnum ) {
935984return true ;
936985}
937986
@@ -1033,7 +1082,9 @@ protected function processVariableAsStaticOutsideClass(File $phpcsFile, $stackPt
10331082// Are we refering to self:: outside a class?
10341083
10351084$ tokens = $ phpcsFile ->getTokens ();
1036- $ token = $ tokens [$ stackPtr ];
1085+
1086+ /** @var array{conditions?: (int|string)[], content?: string}|null */
1087+ $ token = $ tokens [$ stackPtr ];
10371088
10381089$ doubleColonPtr = $ phpcsFile ->findPrevious (Tokens::$ emptyTokens , $ stackPtr - 1 , null , true );
10391090if ($ doubleColonPtr === false || $ tokens [$ doubleColonPtr ]['code ' ] !== T_DOUBLE_COLON ) {
@@ -1053,7 +1104,7 @@ protected function processVariableAsStaticOutsideClass(File $phpcsFile, $stackPt
10531104}
10541105$ errorClass = $ code === T_SELF ? 'SelfOutsideClass ' : 'StaticOutsideClass ' ;
10551106$ staticRefType = $ code === T_SELF ? 'self:: ' : 'static:: ' ;
1056- if (!empty ($ token ['conditions ' ]) && Helpers:: areAnyConditionsAClass ($ token ['conditions ' ] )) {
1107+ if (!empty ($ token ['conditions ' ]) && ! empty ($ token ['content ' ]) && Helpers:: areAnyConditionsAClass ( $ token )) {
10571108return false ;
10581109}
10591110$ phpcsFile ->addError (
0 commit comments