@@ -462,7 +462,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
462462 *
463463 * Changelog for the PHPCS native function:
464464 * - Introduced in PHPCS 0.0.5.
465- * - The upstream method has received no significant updates since PHPCS 3.9.0 .
465+ * - PHPCS 3.9.2: skip over closure use statements. PHPCS #421 .
466466 *
467467 * @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source.
468468 * @see \PHPCSUtils\Utils\FunctionDeclarations::getProperties() PHPCSUtils native improved version.
@@ -480,7 +480,147 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
480480 */
481481 public static function getMethodProperties (File $ phpcsFile , $ stackPtr )
482482 {
483- return $ phpcsFile ->getMethodProperties ($ stackPtr );
483+ $ tokens = $ phpcsFile ->getTokens ();
484+
485+ if ($ tokens [$ stackPtr ]['code ' ] !== T_FUNCTION
486+ && $ tokens [$ stackPtr ]['code ' ] !== T_CLOSURE
487+ && $ tokens [$ stackPtr ]['code ' ] !== T_FN
488+ ) {
489+ throw new RuntimeException ('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN ' );
490+ }
491+
492+ if ($ tokens [$ stackPtr ]['code ' ] === T_FUNCTION ) {
493+ $ valid = [
494+ T_PUBLIC => T_PUBLIC ,
495+ T_PRIVATE => T_PRIVATE ,
496+ T_PROTECTED => T_PROTECTED ,
497+ T_STATIC => T_STATIC ,
498+ T_FINAL => T_FINAL ,
499+ T_ABSTRACT => T_ABSTRACT ,
500+ T_WHITESPACE => T_WHITESPACE ,
501+ T_COMMENT => T_COMMENT ,
502+ T_DOC_COMMENT => T_DOC_COMMENT ,
503+ ];
504+ } else {
505+ $ valid = [
506+ T_STATIC => T_STATIC ,
507+ T_WHITESPACE => T_WHITESPACE ,
508+ T_COMMENT => T_COMMENT ,
509+ T_DOC_COMMENT => T_DOC_COMMENT ,
510+ ];
511+ }
512+
513+ $ scope = 'public ' ;
514+ $ scopeSpecified = false ;
515+ $ isAbstract = false ;
516+ $ isFinal = false ;
517+ $ isStatic = false ;
518+
519+ for ($ i = ($ stackPtr - 1 ); $ i > 0 ; $ i --) {
520+ if (isset ($ valid [$ tokens [$ i ]['code ' ]]) === false ) {
521+ break ;
522+ }
523+
524+ switch ($ tokens [$ i ]['code ' ]) {
525+ case T_PUBLIC :
526+ $ scope = 'public ' ;
527+ $ scopeSpecified = true ;
528+ break ;
529+ case T_PRIVATE :
530+ $ scope = 'private ' ;
531+ $ scopeSpecified = true ;
532+ break ;
533+ case T_PROTECTED :
534+ $ scope = 'protected ' ;
535+ $ scopeSpecified = true ;
536+ break ;
537+ case T_ABSTRACT :
538+ $ isAbstract = true ;
539+ break ;
540+ case T_FINAL :
541+ $ isFinal = true ;
542+ break ;
543+ case T_STATIC :
544+ $ isStatic = true ;
545+ break ;
546+ }
547+ }
548+
549+ $ returnType = '' ;
550+ $ returnTypeToken = false ;
551+ $ returnTypeEndToken = false ;
552+ $ nullableReturnType = false ;
553+ $ hasBody = true ;
554+ $ returnTypeTokens = Collections::returnTypeTokens ();
555+
556+ if (isset ($ tokens [$ stackPtr ]['parenthesis_closer ' ]) === true ) {
557+ $ scopeOpener = null ;
558+ if (isset ($ tokens [$ stackPtr ]['scope_opener ' ]) === true ) {
559+ $ scopeOpener = $ tokens [$ stackPtr ]['scope_opener ' ];
560+ }
561+
562+ for ($ i = $ tokens [$ stackPtr ]['parenthesis_closer ' ]; $ i < $ phpcsFile ->numTokens ; $ i ++) {
563+ if (($ scopeOpener === null && $ tokens [$ i ]['code ' ] === T_SEMICOLON )
564+ || ($ scopeOpener !== null && $ i === $ scopeOpener )
565+ ) {
566+ // End of function definition.
567+ break ;
568+ }
569+
570+ if ($ tokens [$ i ]['code ' ] === T_USE ) {
571+ // Skip over closure use statements.
572+ for ($ j = ($ i + 1 ); $ j < $ phpcsFile ->numTokens && isset (Tokens::$ emptyTokens [$ tokens [$ j ]['code ' ]]) === true ; $ j ++);
573+ if ($ tokens [$ j ]['code ' ] === T_OPEN_PARENTHESIS ) {
574+ if (isset ($ tokens [$ j ]['parenthesis_closer ' ]) === false ) {
575+ // Live coding/parse error, stop parsing.
576+ break ;
577+ }
578+
579+ $ i = $ tokens [$ j ]['parenthesis_closer ' ];
580+ continue ;
581+ }
582+ }
583+
584+ if ($ tokens [$ i ]['code ' ] === T_NULLABLE ) {
585+ $ nullableReturnType = true ;
586+ }
587+
588+ if (isset ($ returnTypeTokens [$ tokens [$ i ]['code ' ]]) === true ) {
589+ if ($ returnTypeToken === false ) {
590+ $ returnTypeToken = $ i ;
591+ }
592+
593+ $ returnType .= $ tokens [$ i ]['content ' ];
594+ $ returnTypeEndToken = $ i ;
595+ }
596+ }
597+
598+ if ($ tokens [$ stackPtr ]['code ' ] === T_FN ) {
599+ $ bodyToken = T_FN_ARROW ;
600+ } else {
601+ $ bodyToken = T_OPEN_CURLY_BRACKET ;
602+ }
603+
604+ $ end = $ phpcsFile ->findNext ([$ bodyToken , T_SEMICOLON ], $ tokens [$ stackPtr ]['parenthesis_closer ' ]);
605+ $ hasBody = ($ end !== false && $ tokens [$ end ]['code ' ] === $ bodyToken );
606+ }
607+
608+ if ($ returnType !== '' && $ nullableReturnType === true ) {
609+ $ returnType = '? ' . $ returnType ;
610+ }
611+
612+ return [
613+ 'scope ' => $ scope ,
614+ 'scope_specified ' => $ scopeSpecified ,
615+ 'return_type ' => $ returnType ,
616+ 'return_type_token ' => $ returnTypeToken ,
617+ 'return_type_end_token ' => $ returnTypeEndToken ,
618+ 'nullable_return_type ' => $ nullableReturnType ,
619+ 'is_abstract ' => $ isAbstract ,
620+ 'is_final ' => $ isFinal ,
621+ 'is_static ' => $ isStatic ,
622+ 'has_body ' => $ hasBody ,
623+ ];
484624 }
485625
486626 /**
0 commit comments