| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 | 
							- <?php
 
- /**
 
-  * Copyright © Magento, Inc. All rights reserved.
 
-  * See COPYING.txt for license details.
 
-  */
 
- declare(strict_types=1);
 
- namespace Magento\Sniffs\Annotation;
 
- use PHP_CodeSniffer\Sniffs\Sniff;
 
- use PHP_CodeSniffer\Files\File;
 
- /**
 
-  * Sniff to validate method arguments annotations
 
-  */
 
- class MethodArgumentsSniff implements Sniff
 
- {
 
-     /**
 
-      * @var array
 
-      */
 
-     private $validTokensBeforeClosingCommentTag = [
 
-         'T_WHITESPACE',
 
-         'T_PUBLIC',
 
-         'T_PRIVATE',
 
-         'T_PROTECTED',
 
-         'T_STATIC',
 
-         'T_ABSTRACT',
 
-         'T_FINAL'
 
-     ];
 
-     /**
 
-      * @var array
 
-      */
 
-     private $invalidTypes = [
 
-         'null',
 
-         'false',
 
-         'true',
 
-         'self'
 
-     ];
 
-     /**
 
-      * @inheritdoc
 
-      */
 
-     public function register() : array
 
-     {
 
-         return [
 
-             T_FUNCTION
 
-         ];
 
-     }
 
-     /**
 
-      * Validates whether valid token exists before closing comment tag
 
-      *
 
-      * @param string $type
 
-      * @return bool
 
-      */
 
-     private function isTokenBeforeClosingCommentTagValid(string $type) : bool
 
-     {
 
-         return in_array($type, $this->validTokensBeforeClosingCommentTag);
 
-     }
 
-     /**
 
-      * Validates whether comment block exists
 
-      *
 
-      * @param File $phpcsFile
 
-      * @param int $previousCommentClosePtr
 
-      * @param int $stackPtr
 
-      * @return bool
 
-      */
 
-     private function validateCommentBlockExists(File $phpcsFile, int $previousCommentClosePtr, int $stackPtr) : bool
 
-     {
 
-         $tokens = $phpcsFile->getTokens();
 
-         for ($tempPtr = $previousCommentClosePtr + 1; $tempPtr < $stackPtr; $tempPtr++) {
 
-             if (!$this->isTokenBeforeClosingCommentTagValid($tokens[$tempPtr]['type'])) {
 
-                 return false;
 
-             }
 
-         }
 
-         return true;
 
-     }
 
-     /**
 
-      * Checks whether the parameter type is invalid
 
-      *
 
-      * @param string $type
 
-      * @return bool
 
-      */
 
-     private function isInvalidType(string $type) : bool
 
-     {
 
-         return in_array(strtolower($type), $this->invalidTypes);
 
-     }
 
-     /**
 
-      * Get arguments from method signature
 
-      *
 
-      * @param File $phpcsFile
 
-      * @param int $openParenthesisPtr
 
-      * @param int $closedParenthesisPtr
 
-      * @return array
 
-      */
 
-     private function getMethodArguments(File $phpcsFile, int $openParenthesisPtr, int $closedParenthesisPtr) : array
 
-     {
 
-         $tokens = $phpcsFile->getTokens();
 
-         $methodArguments = [];
 
-         for ($i = $openParenthesisPtr; $i < $closedParenthesisPtr; $i++) {
 
-             $argumentsPtr = $phpcsFile->findNext(T_VARIABLE, $i + 1, $closedParenthesisPtr);
 
-             if ($argumentsPtr === false) {
 
-                 break;
 
-             } elseif ($argumentsPtr < $closedParenthesisPtr) {
 
-                 $arguments = $tokens[$argumentsPtr]['content'];
 
-                 $methodArguments[] = $arguments;
 
-                 $i = $argumentsPtr - 1;
 
-             }
 
-         }
 
-         return $methodArguments;
 
-     }
 
-     /**
 
-      * Get parameters from method annotation
 
-      *
 
-      * @param array $paramDefinitions
 
-      * @return array
 
-      */
 
-     private function getMethodParameters(array $paramDefinitions) : array
 
-     {
 
-         $paramName = [];
 
-         for ($i = 0; $i < count($paramDefinitions); $i++) {
 
-             if (isset($paramDefinitions[$i]['paramName'])) {
 
-                 $paramName[] = $paramDefinitions[$i]['paramName'];
 
-             }
 
-         }
 
-         return $paramName;
 
-     }
 
-     /**
 
-      * Validates whether @inheritdoc without braces [@inheritdoc] exists or not
 
-      *
 
-      * @param File $phpcsFile
 
-      * @param int $previousCommentOpenPtr
 
-      * @param int $previousCommentClosePtr
 
-      */
 
-     private function validateInheritdocAnnotationWithoutBracesExists(
 
-         File $phpcsFile,
 
-         int $previousCommentOpenPtr,
 
-         int $previousCommentClosePtr
 
-     ) : bool {
 
-         return $this->validateInheritdocAnnotationExists(
 
-             $phpcsFile,
 
-             $previousCommentOpenPtr,
 
-             $previousCommentClosePtr,
 
-             '@inheritdoc'
 
-         );
 
-     }
 
-     /**
 
-      * Validates whether @inheritdoc with braces [{@inheritdoc}] exists or not
 
-      *
 
-      * @param File $phpcsFile
 
-      * @param int $previousCommentOpenPtr
 
-      * @param int $previousCommentClosePtr
 
-      */
 
-     private function validateInheritdocAnnotationWithBracesExists(
 
-         File $phpcsFile,
 
-         int $previousCommentOpenPtr,
 
-         int $previousCommentClosePtr
 
-     ) : bool {
 
-         return $this->validateInheritdocAnnotationExists(
 
-             $phpcsFile,
 
-             $previousCommentOpenPtr,
 
-             $previousCommentClosePtr,
 
-             '{@inheritdoc}'
 
-         );
 
-     }
 
-     /**
 
-      * Validates inheritdoc annotation exists
 
-      *
 
-      * @param File $phpcsFile
 
-      * @param int $previousCommentOpenPtr
 
-      * @param int $previousCommentClosePtr
 
-      * @param string $inheritdocAnnotation
 
-      * @return bool
 
-      */
 
-     private function validateInheritdocAnnotationExists(
 
-         File $phpcsFile,
 
-         int $previousCommentOpenPtr,
 
-         int $previousCommentClosePtr,
 
-         string $inheritdocAnnotation
 
-     ) : bool {
 
-         $tokens = $phpcsFile->getTokens();
 
-         for ($ptr = $previousCommentOpenPtr; $ptr < $previousCommentClosePtr; $ptr++) {
 
-             if (strtolower($tokens[$ptr]['content']) === $inheritdocAnnotation) {
 
-                 return true;
 
-             }
 
-         }
 
-         return false;
 
-     }
 
-     /**
 
-      * Validates if annotation exists for parameter in method annotation
 
-      *
 
-      * @param File $phpcsFile
 
-      * @param int $argumentsCount
 
-      * @param int $parametersCount
 
-      * @param int $previousCommentOpenPtr
 
-      * @param int $previousCommentClosePtr
 
-      * @param int $stackPtr
 
-      */
 
-     private function validateParameterAnnotationForArgumentExists(
 
-         File $phpcsFile,
 
-         int $argumentsCount,
 
-         int $parametersCount,
 
-         int $previousCommentOpenPtr,
 
-         int $previousCommentClosePtr,
 
-         int $stackPtr
 
-     ) : void {
 
-         if ($argumentsCount > 0 && $parametersCount === 0) {
 
-             $inheritdocAnnotationWithoutBracesExists = $this->validateInheritdocAnnotationWithoutBracesExists(
 
-                 $phpcsFile,
 
-                 $previousCommentOpenPtr,
 
-                 $previousCommentClosePtr
 
-             );
 
-             $inheritdocAnnotationWithBracesExists = $this->validateInheritdocAnnotationWithBracesExists(
 
-                 $phpcsFile,
 
-                 $previousCommentOpenPtr,
 
-                 $previousCommentClosePtr
 
-             );
 
-             if ($inheritdocAnnotationWithBracesExists) {
 
-                 $phpcsFile->addFixableError(
 
-                     '{@inheritdoc} does not import parameter annotation',
 
-                     $stackPtr,
 
-                     'MethodArguments'
 
-                 );
 
-             } elseif ($this->validateCommentBlockExists($phpcsFile, $previousCommentClosePtr, $stackPtr)
 
-                 && !$inheritdocAnnotationWithoutBracesExists
 
-             ) {
 
-                 $phpcsFile->addFixableError(
 
-                     'Missing @param for argument in method annotation',
 
-                     $stackPtr,
 
-                     'MethodArguments'
 
-                 );
 
-             }
 
-         }
 
-     }
 
-     /**
 
-      * Validates whether comment block have extra the parameters listed in method annotation
 
-      *
 
-      * @param File $phpcsFile
 
-      * @param int $argumentsCount
 
-      * @param int $parametersCount
 
-      * @param int $stackPtr
 
-      */
 
-     private function validateCommentBlockDoesnotHaveExtraParameterAnnotation(
 
-         File $phpcsFile,
 
-         int $argumentsCount,
 
-         int $parametersCount,
 
-         int $stackPtr
 
-     ) : void {
 
-         if ($argumentsCount < $parametersCount && $argumentsCount > 0) {
 
-             $phpcsFile->addFixableError(
 
-                 'Extra @param found in method annotation',
 
-                 $stackPtr,
 
-                 'MethodArguments'
 
-             );
 
-         } elseif ($argumentsCount > 0 && $argumentsCount != $parametersCount && $parametersCount != 0) {
 
-             $phpcsFile->addFixableError(
 
-                 '@param is not found for one or more params in method annotation',
 
-                 $stackPtr,
 
-                 'MethodArguments'
 
-             );
 
-         }
 
-     }
 
-     /**
 
-      * Validates whether the argument name exists in method parameter annotation
 
-      *
 
-      * @param int $stackPtr
 
-      * @param int $ptr
 
-      * @param File $phpcsFile
 
-      * @param array $methodArguments
 
-      * @param array $paramDefinitions
 
-      */
 
-     private function validateArgumentNameInParameterAnnotationExists(
 
-         int $stackPtr,
 
-         int $ptr,
 
-         File $phpcsFile,
 
-         array $methodArguments,
 
-         array $paramDefinitions
 
-     ) : void {
 
-         $parameterNames = $this->getMethodParameters($paramDefinitions);
 
-         if (!in_array($methodArguments[$ptr], $parameterNames)) {
 
-             $error = $methodArguments[$ptr]. ' parameter is missing in method annotation';
 
-             $phpcsFile->addFixableError($error, $stackPtr, 'MethodArguments');
 
-         }
 
-     }
 
-     /**
 
-      * Validates whether parameter present in method signature
 
-      *
 
-      * @param int $ptr
 
-      * @param int $paramDefinitionsArguments
 
-      * @param array $methodArguments
 
-      * @param File $phpcsFile
 
-      * @param array $paramPointers
 
-      */
 
-     private function validateParameterPresentInMethodSignature(
 
-         int $ptr,
 
-         string $paramDefinitionsArguments,
 
-         array $methodArguments,
 
-         File $phpcsFile,
 
-         array $paramPointers
 
-     ) : void {
 
-         if (!in_array($paramDefinitionsArguments, $methodArguments)) {
 
-             $phpcsFile->addFixableError(
 
-                 $paramDefinitionsArguments . ' parameter is missing in method arguments signature',
 
-                 $paramPointers[$ptr],
 
-                 'MethodArguments'
 
-             );
 
-         }
 
-     }
 
-     /**
 
-      * Validates whether the parameters are in order or not in method annotation
 
-      *
 
-      * @param array $paramDefinitions
 
-      * @param array $methodArguments
 
-      * @param File $phpcsFile
 
-      * @param array $paramPointers
 
-      */
 
-     private function validateParameterOrderIsCorrect(
 
-         array $paramDefinitions,
 
-         array $methodArguments,
 
-         File $phpcsFile,
 
-         array $paramPointers
 
-     ) : void {
 
-         $parameterNames = $this->getMethodParameters($paramDefinitions);
 
-         $paramDefinitionsCount = count($paramDefinitions);
 
-         for ($ptr = 0; $ptr < $paramDefinitionsCount; $ptr++) {
 
-             if (isset($methodArguments[$ptr]) && isset($parameterNames[$ptr])
 
-                 && in_array($methodArguments[$ptr], $parameterNames)
 
-             ) {
 
-                 if ($methodArguments[$ptr] != $parameterNames[$ptr]) {
 
-                     $phpcsFile->addFixableError(
 
-                         $methodArguments[$ptr].' parameter is not in order',
 
-                         $paramPointers[$ptr],
 
-                         'MethodArguments'
 
-                     );
 
-                 }
 
-             }
 
-         }
 
-     }
 
-     /**
 
-      * Validate whether duplicate annotation present in method annotation
 
-      *
 
-      * @param int $stackPtr
 
-      * @param array $paramDefinitions
 
-      * @param array $paramPointers
 
-      * @param File $phpcsFile
 
-      * @param array $methodArguments
 
-      */
 
-     private function validateDuplicateAnnotationDoesnotExists(
 
-         int $stackPtr,
 
-         array $paramDefinitions,
 
-         array $paramPointers,
 
-         File $phpcsFile,
 
-         array $methodArguments
 
-     ) : void {
 
-         $argumentsCount = count($methodArguments);
 
-         $parametersCount = count($paramPointers);
 
-         if ($argumentsCount <= $parametersCount && $argumentsCount > 0) {
 
-             $duplicateParameters = [];
 
-             for ($i = 0; $i < sizeof($paramDefinitions); $i++) {
 
-                 if (isset($paramDefinitions[$i]['paramName'])) {
 
-                     $parameterContent = $paramDefinitions[$i]['paramName'];
 
-                     for ($j = $i + 1; $j < count($paramDefinitions); $j++) {
 
-                         if (isset($paramDefinitions[$j]['paramName'])
 
-                             && $parameterContent === $paramDefinitions[$j]['paramName']
 
-                         ) {
 
-                             $duplicateParameters[] = $parameterContent;
 
-                         }
 
-                     }
 
-                 }
 
-             }
 
-             foreach ($duplicateParameters as $value) {
 
-                 $phpcsFile->addFixableError(
 
-                     $value . ' duplicate found in method annotation',
 
-                     $stackPtr,
 
-                     'MethodArguments'
 
-                 );
 
-             }
 
-         }
 
-     }
 
-     /**
 
-      * Validate parameter annotation format is correct or not
 
-      *
 
-      * @param int $ptr
 
-      * @param File $phpcsFile
 
-      * @param array $methodArguments
 
-      * @param array $paramDefinitions
 
-      * @param array $paramPointers
 
-      */
 
-     private function validateParameterAnnotationFormatIsCorrect(
 
-         int $ptr,
 
-         File $phpcsFile,
 
-         array $methodArguments,
 
-         array $paramDefinitions,
 
-         array $paramPointers
 
-     ) : void {
 
-         switch (count($paramDefinitions)) {
 
-             case 0:
 
-                 $phpcsFile->addFixableError(
 
-                     'Missing both type and parameter',
 
-                     $paramPointers[$ptr],
 
-                     'MethodArguments'
 
-                 );
 
-                 break;
 
-             case 1:
 
-                 if (preg_match('/^\$.*/', $paramDefinitions[0])) {
 
-                     $phpcsFile->addError(
 
-                         'Type is not specified',
 
-                         $paramPointers[$ptr],
 
-                         'MethodArguments'
 
-                     );
 
-                 }
 
-                 break;
 
-             case 2:
 
-                 if ($this->isInvalidType($paramDefinitions[0])) {
 
-                     $phpcsFile->addFixableError(
 
-                         $paramDefinitions[0].' is not a valid PHP type',
 
-                         $paramPointers[$ptr],
 
-                         'MethodArguments'
 
-                     );
 
-                 }
 
-                 $this->validateParameterPresentInMethodSignature(
 
-                     $ptr,
 
-                     ltrim($paramDefinitions[1], '&'),
 
-                     $methodArguments,
 
-                     $phpcsFile,
 
-                     $paramPointers
 
-                 );
 
-                 break;
 
-             default:
 
-                 if (preg_match('/^\$.*/', $paramDefinitions[0])) {
 
-                     $phpcsFile->addError(
 
-                         'Type is not specified',
 
-                         $paramPointers[$ptr],
 
-                         'MethodArguments'
 
-                     );
 
-                     if ($this->isInvalidType($paramDefinitions[0])) {
 
-                         $phpcsFile->addFixableError(
 
-                             $paramDefinitions[0].' is not a valid PHP type',
 
-                             $paramPointers[$ptr],
 
-                             'MethodArguments'
 
-                         );
 
-                     }
 
-                 }
 
-                 break;
 
-         }
 
-     }
 
-     /**
 
-      * Validate method parameter annotations
 
-      *
 
-      * @param int $stackPtr
 
-      * @param array $paramDefinitions
 
-      * @param array $paramPointers
 
-      * @param File $phpcsFile
 
-      * @param array $methodArguments
 
-      * @param int $previousCommentOpenPtr
 
-      * @param int $previousCommentClosePtr
 
-      */
 
-     private function validateMethodParameterAnnotations(
 
-         int $stackPtr,
 
-         array $paramDefinitions,
 
-         array $paramPointers,
 
-         File $phpcsFile,
 
-         array $methodArguments,
 
-         int $previousCommentOpenPtr,
 
-         int $previousCommentClosePtr
 
-     ) : void {
 
-         $argumentCount = count($methodArguments);
 
-         $paramCount = count($paramPointers);
 
-         $this->validateParameterAnnotationForArgumentExists(
 
-             $phpcsFile,
 
-             $argumentCount,
 
-             $paramCount,
 
-             $previousCommentOpenPtr,
 
-             $previousCommentClosePtr,
 
-             $stackPtr
 
-         );
 
-         $this->validateCommentBlockDoesnotHaveExtraParameterAnnotation(
 
-             $phpcsFile,
 
-             $argumentCount,
 
-             $paramCount,
 
-             $stackPtr
 
-         );
 
-         $this->validateDuplicateAnnotationDoesnotExists(
 
-             $stackPtr,
 
-             $paramDefinitions,
 
-             $paramPointers,
 
-             $phpcsFile,
 
-             $methodArguments
 
-         );
 
-         $this->validateParameterOrderIsCorrect(
 
-             $paramDefinitions,
 
-             $methodArguments,
 
-             $phpcsFile,
 
-             $paramPointers
 
-         );
 
-         for ($ptr = 0; $ptr < count($methodArguments); $ptr++) {
 
-             $tokens = $phpcsFile->getTokens();
 
-             if (isset($paramPointers[$ptr])) {
 
-                 $this->validateArgumentNameInParameterAnnotationExists(
 
-                     $stackPtr,
 
-                     $ptr,
 
-                     $phpcsFile,
 
-                     $methodArguments,
 
-                     $paramDefinitions
 
-                 );
 
-                 $paramContent = $tokens[$paramPointers[$ptr]+2]['content'];
 
-                 $paramContentExplode = explode(' ', $paramContent);
 
-                 $this->validateParameterAnnotationFormatIsCorrect(
 
-                     $ptr,
 
-                     $phpcsFile,
 
-                     $methodArguments,
 
-                     $paramContentExplode,
 
-                     $paramPointers
 
-                 );
 
-             }
 
-         }
 
-     }
 
-     /**
 
-      * @inheritdoc
 
-      */
 
-     public function process(File $phpcsFile, $stackPtr)
 
-     {
 
-         $tokens = $phpcsFile->getTokens();
 
-         $numTokens = count($tokens);
 
-         $previousCommentOpenPtr = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr-1, 0);
 
-         $previousCommentClosePtr = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, $stackPtr-1, 0);
 
-         if (!$this->validateCommentBlockExists($phpcsFile, $previousCommentClosePtr, $stackPtr)) {
 
-             $phpcsFile->addError('Comment block is missing', $stackPtr, 'MethodArguments');
 
-             return;
 
-         }
 
-         $openParenthesisPtr = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr+1, $numTokens);
 
-         $closedParenthesisPtr = $phpcsFile->findNext(T_CLOSE_PARENTHESIS, $stackPtr+1, $numTokens);
 
-         $methodArguments = $this->getMethodArguments($phpcsFile, $openParenthesisPtr, $closedParenthesisPtr);
 
-         $paramPointers = $paramDefinitions = [];
 
-         for ($tempPtr = $previousCommentOpenPtr; $tempPtr < $previousCommentClosePtr; $tempPtr++) {
 
-             if (strtolower($tokens[$tempPtr]['content']) === '@param') {
 
-                 $paramPointers[] = $tempPtr;
 
-                 $paramAnnotationParts = explode(' ', $tokens[$tempPtr+2]['content']);
 
-                 if (count($paramAnnotationParts) === 1) {
 
-                     if ((preg_match('/^\$.*/', $paramAnnotationParts[0]))) {
 
-                         $paramDefinitions[] = [
 
-                             'type' => null,
 
-                             'paramName' => rtrim(ltrim($tokens[$tempPtr+2]['content'], '&'), ',')
 
-                         ];
 
-                     } else {
 
-                         $paramDefinitions[] = [
 
-                             'type' => $tokens[$tempPtr+2]['content'],
 
-                             'paramName' => null
 
-                         ];
 
-                     }
 
-                 } else {
 
-                     $paramDefinitions[] = [
 
-                         'type' => $paramAnnotationParts[0],
 
-                         'paramName' => rtrim(ltrim($paramAnnotationParts[1], '&'), ',')
 
-                     ];
 
-                 }
 
-             }
 
-         }
 
-         $this->validateMethodParameterAnnotations(
 
-             $stackPtr,
 
-             $paramDefinitions,
 
-             $paramPointers,
 
-             $phpcsFile,
 
-             $methodArguments,
 
-             $previousCommentOpenPtr,
 
-             $previousCommentClosePtr
 
-         );
 
-     }
 
- }
 
 
  |