1<?php 2/** 3 * This file is part of the CodeAnalysis add-on for PHP_CodeSniffer. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @author Manuel Pichler <mapi@manuel-pichler.de> 11 * @copyright 2007-2014 Manuel Pichler. All rights reserved. 12 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 13 * @link http://pear.php.net/package/PHP_CodeSniffer 14 */ 15 16/** 17 * Detects unnecessary overridden methods that simply call their parent. 18 * 19 * This rule is based on the PMD rule catalog. The Useless Overriding Method 20 * sniff detects the use of methods that only call their parent classes's method 21 * with the same name and arguments. These methods are not required. 22 * 23 * <code> 24 * class FooBar { 25 * public function __construct($a, $b) { 26 * parent::__construct($a, $b); 27 * } 28 * } 29 * </code> 30 * 31 * @category PHP 32 * @package PHP_CodeSniffer 33 * @author Manuel Pichler <mapi@manuel-pichler.de> 34 * @copyright 2007-2014 Manuel Pichler. All rights reserved. 35 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 36 * @version Release: @package_version@ 37 * @link http://pear.php.net/package/PHP_CodeSniffer 38 */ 39class Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff implements PHP_CodeSniffer_Sniff 40{ 41 42 43 /** 44 * Registers the tokens that this sniff wants to listen for. 45 * 46 * @return int[] 47 */ 48 public function register() 49 { 50 return array(T_FUNCTION); 51 52 }//end register() 53 54 55 /** 56 * Processes this test, when one of its tokens is encountered. 57 * 58 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 59 * @param int $stackPtr The position of the current token 60 * in the stack passed in $tokens. 61 * 62 * @return void 63 */ 64 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 65 { 66 $tokens = $phpcsFile->getTokens(); 67 $token = $tokens[$stackPtr]; 68 69 // Skip function without body. 70 if (isset($token['scope_opener']) === false) { 71 return; 72 } 73 74 // Get function name. 75 $methodName = $phpcsFile->getDeclarationName($stackPtr); 76 77 // Get all parameters from method signature. 78 $signature = array(); 79 foreach ($phpcsFile->getMethodParameters($stackPtr) as $param) { 80 $signature[] = $param['name']; 81 } 82 83 $next = ++$token['scope_opener']; 84 $end = --$token['scope_closer']; 85 86 for (; $next <= $end; ++$next) { 87 $code = $tokens[$next]['code']; 88 89 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$code]) === true) { 90 continue; 91 } else if ($code === T_RETURN) { 92 continue; 93 } 94 95 break; 96 } 97 98 // Any token except 'parent' indicates correct code. 99 if ($tokens[$next]['code'] !== T_PARENT) { 100 return; 101 } 102 103 // Find next non empty token index, should be double colon. 104 $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); 105 106 // Skip for invalid code. 107 if ($next === false || $tokens[$next]['code'] !== T_DOUBLE_COLON) { 108 return; 109 } 110 111 // Find next non empty token index, should be the function name. 112 $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); 113 114 // Skip for invalid code or other method. 115 if ($next === false || $tokens[$next]['content'] !== $methodName) { 116 return; 117 } 118 119 // Find next non empty token index, should be the open parenthesis. 120 $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); 121 122 // Skip for invalid code. 123 if ($next === false || $tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { 124 return; 125 } 126 127 $parameters = array(''); 128 $parenthesisCount = 1; 129 $count = count($tokens); 130 for (++$next; $next < $count; ++$next) { 131 $code = $tokens[$next]['code']; 132 133 if ($code === T_OPEN_PARENTHESIS) { 134 ++$parenthesisCount; 135 } else if ($code === T_CLOSE_PARENTHESIS) { 136 --$parenthesisCount; 137 } else if ($parenthesisCount === 1 && $code === T_COMMA) { 138 $parameters[] = ''; 139 } else if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$code]) === false) { 140 $parameters[(count($parameters) - 1)] .= $tokens[$next]['content']; 141 } 142 143 if ($parenthesisCount === 0) { 144 break; 145 } 146 }//end for 147 148 $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($next + 1), null, true); 149 if ($next === false || $tokens[$next]['code'] !== T_SEMICOLON) { 150 return; 151 } 152 153 // Check rest of the scope. 154 for (++$next; $next <= $end; ++$next) { 155 $code = $tokens[$next]['code']; 156 // Skip for any other content. 157 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$code]) === false) { 158 return; 159 } 160 } 161 162 $parameters = array_map('trim', $parameters); 163 $parameters = array_filter($parameters); 164 165 if (count($parameters) === count($signature) && $parameters === $signature) { 166 $phpcsFile->addWarning('Possible useless method overriding detected', $stackPtr, 'Found'); 167 } 168 169 }//end process() 170 171 172}//end class 173