@@ -370,33 +370,36 @@ protected function getVariableInfo($varName, $currScope) {
370370 * @return VariableInfo
371371 */
372372 protected function getOrCreateVariableInfo ($ varName , $ currScope ) {
373+ Helpers::debug ("getOrCreateVariableInfo: starting for ' {$ varName }' " );
373374 $ scopeInfo = $ this ->getOrCreateScopeInfo ($ currScope );
374- if (!isset ($ scopeInfo ->variables [$ varName ])) {
375- Helpers::debug ("creating a new variable for ' {$ varName }' in scope " , $ scopeInfo );
376- $ scopeInfo ->variables [$ varName ] = new VariableInfo ($ varName );
377- $ validUnusedVariableNames = (empty ($ this ->validUnusedVariableNames ))
378- ? []
379- : Helpers::splitStringToArray ('/\s+/ ' , trim ($ this ->validUnusedVariableNames ));
380- $ validUndefinedVariableNames = (empty ($ this ->validUndefinedVariableNames ))
381- ? []
382- : Helpers::splitStringToArray ('/\s+/ ' , trim ($ this ->validUndefinedVariableNames ));
383- if (in_array ($ varName , $ validUnusedVariableNames )) {
384- $ scopeInfo ->variables [$ varName ]->ignoreUnused = true ;
385- }
386- if (isset ($ this ->ignoreUnusedRegexp ) && preg_match ($ this ->ignoreUnusedRegexp , $ varName ) === 1 ) {
387- $ scopeInfo ->variables [$ varName ]->ignoreUnused = true ;
388- }
389- if ($ scopeInfo ->scopeStartIndex === 0 && $ this ->allowUndefinedVariablesInFileScope ) {
390- $ scopeInfo ->variables [$ varName ]->ignoreUndefined = true ;
391- }
392- if (in_array ($ varName , $ validUndefinedVariableNames )) {
393- $ scopeInfo ->variables [$ varName ]->ignoreUndefined = true ;
394- }
395- if (isset ($ this ->validUndefinedVariableRegexp ) && preg_match ($ this ->validUndefinedVariableRegexp , $ varName ) === 1 ) {
396- $ scopeInfo ->variables [$ varName ]->ignoreUndefined = true ;
397- }
398- }
399- Helpers::debug ("scope for ' {$ varName }' is now " , $ scopeInfo );
375+ if (isset ($ scopeInfo ->variables [$ varName ])) {
376+ Helpers::debug ("getOrCreateVariableInfo: found scope for ' {$ varName }' " , $ scopeInfo );
377+ return $ scopeInfo ->variables [$ varName ];
378+ }
379+ Helpers::debug ("getOrCreateVariableInfo: creating a new variable for ' {$ varName }' in scope " , $ scopeInfo );
380+ $ scopeInfo ->variables [$ varName ] = new VariableInfo ($ varName );
381+ $ validUnusedVariableNames = (empty ($ this ->validUnusedVariableNames ))
382+ ? []
383+ : Helpers::splitStringToArray ('/\s+/ ' , trim ($ this ->validUnusedVariableNames ));
384+ $ validUndefinedVariableNames = (empty ($ this ->validUndefinedVariableNames ))
385+ ? []
386+ : Helpers::splitStringToArray ('/\s+/ ' , trim ($ this ->validUndefinedVariableNames ));
387+ if (in_array ($ varName , $ validUnusedVariableNames )) {
388+ $ scopeInfo ->variables [$ varName ]->ignoreUnused = true ;
389+ }
390+ if (isset ($ this ->ignoreUnusedRegexp ) && preg_match ($ this ->ignoreUnusedRegexp , $ varName ) === 1 ) {
391+ $ scopeInfo ->variables [$ varName ]->ignoreUnused = true ;
392+ }
393+ if ($ scopeInfo ->scopeStartIndex === 0 && $ this ->allowUndefinedVariablesInFileScope ) {
394+ $ scopeInfo ->variables [$ varName ]->ignoreUndefined = true ;
395+ }
396+ if (in_array ($ varName , $ validUndefinedVariableNames )) {
397+ $ scopeInfo ->variables [$ varName ]->ignoreUndefined = true ;
398+ }
399+ if (isset ($ this ->validUndefinedVariableRegexp ) && preg_match ($ this ->validUndefinedVariableRegexp , $ varName ) === 1 ) {
400+ $ scopeInfo ->variables [$ varName ]->ignoreUndefined = true ;
401+ }
402+ Helpers::debug ("getOrCreateVariableInfo: scope for ' {$ varName }' is now " , $ scopeInfo );
400403 return $ scopeInfo ->variables [$ varName ];
401404 }
402405
@@ -408,10 +411,12 @@ protected function getOrCreateVariableInfo($varName, $currScope) {
408411 * @return void
409412 */
410413 protected function markVariableAssignment ($ varName , $ stackPtr , $ currScope ) {
414+ Helpers::debug ('markVariableAssignment: starting for ' , $ varName );
411415 $ this ->markVariableAssignmentWithoutInitialization ($ varName , $ stackPtr , $ currScope );
416+ Helpers::debug ('markVariableAssignment: marked as assigned without initialization ' , $ varName );
412417 $ varInfo = $ this ->getOrCreateVariableInfo ($ varName , $ currScope );
413418 if (isset ($ varInfo ->firstInitialized ) && ($ varInfo ->firstInitialized <= $ stackPtr )) {
414- Helpers::debug ('markVariableAssignment variable is already initialized ' , $ varName );
419+ Helpers::debug ('markVariableAssignment: variable is already initialized ' , $ varName );
415420 return ;
416421 }
417422 $ varInfo ->firstInitialized = $ stackPtr ;
@@ -429,7 +434,11 @@ protected function markVariableAssignmentWithoutInitialization($varName, $stackP
429434
430435 // Is the variable referencing another variable? If so, mark that variable used also.
431436 if ($ varInfo ->referencedVariableScope !== null && $ varInfo ->referencedVariableScope !== $ currScope ) {
432- $ this ->markVariableAssignment ($ varInfo ->name , $ stackPtr , $ varInfo ->referencedVariableScope );
437+ // Don't do this if the referenced variable does not exist; eg: if it's going to be bound at runtime like in array_walk
438+ if ($ this ->getVariableInfo ($ varInfo ->name , $ varInfo ->referencedVariableScope )) {
439+ Helpers::debug ('markVariableAssignmentWithoutInitialization: marking referenced variable as assigned also ' , $ varName );
440+ $ this ->markVariableAssignment ($ varInfo ->name , $ stackPtr , $ varInfo ->referencedVariableScope );
441+ }
433442 }
434443
435444 if (!isset ($ varInfo ->scopeType )) {
@@ -622,12 +631,14 @@ protected function processVariableAsFunctionDefinitionArgument(File $phpcsFile,
622631 // Are we pass-by-reference?
623632 $ referencePtr = $ phpcsFile ->findPrevious (Tokens::$ emptyTokens , $ stackPtr - 1 , null , true , null , true );
624633 if (($ referencePtr !== false ) && ($ tokens [$ referencePtr ]['code ' ] === T_BITWISE_AND )) {
634+ Helpers::debug ("processVariableAsFunctionDefinitionArgument found pass-by-reference to scope " , $ outerScope );
625635 $ varInfo = $ this ->getOrCreateVariableInfo ($ varName , $ functionPtr );
626636 $ varInfo ->referencedVariableScope = $ outerScope ;
627637 }
628638
629639 // Are we optional with a default?
630640 if (Helpers::getNextAssignPointer ($ phpcsFile , $ stackPtr ) !== null ) {
641+ Helpers::debug ("processVariableAsFunctionDefinitionArgument optional with default " );
631642 $ this ->markVariableAssignment ($ varName , $ stackPtr , $ functionPtr );
632643 }
633644 }
@@ -898,19 +909,13 @@ protected function processVariableAsStaticOutsideClass(File $phpcsFile, $stackPt
898909 * @param string $varName
899910 * @param int $currScope
900911 *
901- * @return bool
912+ * @return void
902913 */
903914 protected function processVariableAsAssignment (File $ phpcsFile , $ stackPtr , $ varName , $ currScope ) {
904- // Is the next non-whitespace an assignment?
915+ Helpers:: debug ( " processVariableAsAssignment: starting for ' $ {varName} ' " );
905916 $ assignPtr = Helpers::getNextAssignPointer ($ phpcsFile , $ stackPtr );
906917 if (! is_int ($ assignPtr )) {
907- return false ;
908- }
909-
910- // Is this a variable variable? If so, it's not an assignment to the current variable.
911- if ($ this ->processVariableAsVariableVariable ($ phpcsFile , $ stackPtr )) {
912- Helpers::debug ('found variable variable ' );
913- return false ;
918+ return ;
914919 }
915920
916921 // If the right-hand-side of the assignment to this variable is a reference
@@ -922,12 +927,12 @@ protected function processVariableAsAssignment(File $phpcsFile, $stackPtr, $varN
922927 $ tokens = $ phpcsFile ->getTokens ();
923928 $ referencePtr = $ phpcsFile ->findNext (Tokens::$ emptyTokens , $ assignPtr + 1 , null , true , null , true );
924929 if (is_int ($ referencePtr ) && $ tokens [$ referencePtr ]['code ' ] === T_BITWISE_AND ) {
930+ Helpers::debug ('processVariableAsAssignment: found reference variable ' );
925931 $ varInfo = $ this ->getOrCreateVariableInfo ($ varName , $ currScope );
926932 // If the variable was already declared, but was not yet read, it is
927933 // unused because we're about to change the binding.
928934 $ scopeInfo = $ this ->getOrCreateScopeInfo ($ currScope );
929935 $ this ->processScopeCloseForVariable ($ phpcsFile , $ varInfo , $ scopeInfo );
930- Helpers::debug ('found reference variable ' );
931936 // The referenced variable may have a different name, but we don't
932937 // actually need to mark it as used in this case because the act of this
933938 // assignment will mark it used on the next token.
@@ -936,39 +941,11 @@ protected function processVariableAsAssignment(File $phpcsFile, $stackPtr, $varN
936941 // An assignment to a reference is a binding and should not count as
937942 // initialization since it doesn't change any values.
938943 $ this ->markVariableAssignmentWithoutInitialization ($ varName , $ stackPtr , $ currScope );
939- return true ;
944+ return ;
940945 }
941946
947+ Helpers::debug ('processVariableAsAssignment: marking as assignment in scope ' , $ currScope );
942948 $ this ->markVariableAssignment ($ varName , $ stackPtr , $ currScope );
943-
944- return true ;
945- }
946-
947- /**
948- * @param File $phpcsFile
949- * @param int $stackPtr
950- *
951- * @return bool
952- */
953- protected function processVariableAsVariableVariable (File $ phpcsFile , $ stackPtr ) {
954- $ tokens = $ phpcsFile ->getTokens ();
955-
956- $ prev = $ phpcsFile ->findPrevious (Tokens::$ emptyTokens , ($ stackPtr - 1 ), null , true );
957- if ($ prev === false ) {
958- return false ;
959- }
960- if ($ tokens [$ prev ]['code ' ] === T_DOLLAR ) {
961- return true ;
962- }
963- if ($ tokens [$ prev ]['code ' ] !== T_OPEN_CURLY_BRACKET ) {
964- return false ;
965- }
966-
967- $ prevPrev = $ phpcsFile ->findPrevious (Tokens::$ emptyTokens , ($ prev - 1 ), null , true );
968- if ($ prevPrev !== false && $ tokens [$ prevPrev ]['code ' ] === T_DOLLAR ) {
969- return true ;
970- }
971- return false ;
972949 }
973950
974951 /**
@@ -1398,13 +1375,14 @@ protected function processVariable(File $phpcsFile, $stackPtr) {
13981375 }
13991376
14001377 // Is the next non-whitespace an assignment?
1401- if ($ this ->processVariableAsAssignment ($ phpcsFile , $ stackPtr , $ varName , $ currScope )) {
1378+ if (Helpers::isTokenInsideAssignmentLHS ($ phpcsFile , $ stackPtr )) {
1379+ Helpers::debug ('found assignment ' );
1380+ $ this ->processVariableAsAssignment ($ phpcsFile , $ stackPtr , $ varName , $ currScope );
14021381 if (Helpers::isTokenInsideAssignmentRHS ($ phpcsFile , $ stackPtr ) || Helpers::isTokenInsideFunctionCall ($ phpcsFile , $ stackPtr )) {
14031382 Helpers::debug ("found assignment that's also inside an expression " );
14041383 $ this ->markVariableRead ($ varName , $ stackPtr , $ currScope );
14051384 return ;
14061385 }
1407- Helpers::debug ('found assignment ' );
14081386 return ;
14091387 }
14101388
0 commit comments