1<?php 2/** 3 * Generic_Sniffs_Methods_OpeningMethodBraceBsdAllmanSniff. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @author Marc McIntyre <mmcintyre@squiz.net> 11 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 12 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 13 * @link http://pear.php.net/package/PHP_CodeSniffer 14 */ 15 16/** 17 * Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff. 18 * 19 * Checks that the opening brace of a function is on the line after the 20 * function declaration. 21 * 22 * @category PHP 23 * @package PHP_CodeSniffer 24 * @author Greg Sherwood <gsherwood@squiz.net> 25 * @author Marc McIntyre <mmcintyre@squiz.net> 26 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 27 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 28 * @version Release: @package_version@ 29 * @link http://pear.php.net/package/PHP_CodeSniffer 30 */ 31class Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff implements PHP_CodeSniffer_Sniff 32{ 33 34 /** 35 * Should this sniff check function braces? 36 * 37 * @var bool 38 */ 39 public $checkFunctions = true; 40 41 /** 42 * Should this sniff check closure braces? 43 * 44 * @var bool 45 */ 46 public $checkClosures = false; 47 48 49 /** 50 * Registers the tokens that this sniff wants to listen for. 51 * 52 * @return void 53 */ 54 public function register() 55 { 56 return array( 57 T_FUNCTION, 58 T_CLOSURE, 59 ); 60 61 }//end register() 62 63 64 /** 65 * Processes this test, when one of its tokens is encountered. 66 * 67 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 68 * @param int $stackPtr The position of the current token in the 69 * stack passed in $tokens. 70 * 71 * @return void 72 */ 73 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 74 { 75 $tokens = $phpcsFile->getTokens(); 76 77 if (isset($tokens[$stackPtr]['scope_opener']) === false) { 78 return; 79 } 80 81 if (($tokens[$stackPtr]['code'] === T_FUNCTION 82 && (bool) $this->checkFunctions === false) 83 || ($tokens[$stackPtr]['code'] === T_CLOSURE 84 && (bool) $this->checkClosures === false) 85 ) { 86 return; 87 } 88 89 $openingBrace = $tokens[$stackPtr]['scope_opener']; 90 $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; 91 if ($tokens[$stackPtr]['code'] === T_CLOSURE) { 92 $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']); 93 if ($use !== false) { 94 $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1)); 95 $closeBracket = $tokens[$openBracket]['parenthesis_closer']; 96 } 97 } 98 99 $functionLine = $tokens[$closeBracket]['line']; 100 $braceLine = $tokens[$openingBrace]['line']; 101 102 $lineDifference = ($braceLine - $functionLine); 103 104 if ($lineDifference === 0) { 105 $error = 'Opening brace should be on a new line'; 106 $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceOnSameLine'); 107 if ($fix === true) { 108 $phpcsFile->fixer->beginChangeset(); 109 $indent = $phpcsFile->findFirstOnLine(array(), $openingBrace); 110 if ($tokens[$indent]['code'] === T_WHITESPACE) { 111 $phpcsFile->fixer->addContentBefore($openingBrace, $tokens[$indent]['content']); 112 } 113 114 $phpcsFile->fixer->addNewlineBefore($openingBrace); 115 $phpcsFile->fixer->endChangeset(); 116 } 117 118 $phpcsFile->recordMetric($stackPtr, 'Function opening brace placement', 'same line'); 119 } else if ($lineDifference > 1) { 120 $error = 'Opening brace should be on the line after the declaration; found %s blank line(s)'; 121 $data = array(($lineDifference - 1)); 122 $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceSpacing', $data); 123 if ($fix === true) { 124 for ($i = ($tokens[$stackPtr]['parenthesis_closer'] + 1); $i < $openingBrace; $i++) { 125 if ($tokens[$i]['line'] === $braceLine) { 126 $phpcsFile->fixer->addNewLineBefore($i); 127 break; 128 } 129 130 $phpcsFile->fixer->replaceToken($i, ''); 131 } 132 } 133 }//end if 134 135 $next = $phpcsFile->findNext(T_WHITESPACE, ($openingBrace + 1), null, true); 136 if ($tokens[$next]['line'] === $tokens[$openingBrace]['line']) { 137 if ($next === $tokens[$stackPtr]['scope_closer']) { 138 // Ignore empty functions. 139 return; 140 } 141 142 $error = 'Opening brace must be the last content on the line'; 143 $fix = $phpcsFile->addFixableError($error, $openingBrace, 'ContentAfterBrace'); 144 if ($fix === true) { 145 $phpcsFile->fixer->addNewline($openingBrace); 146 } 147 } 148 149 // Only continue checking if the opening brace looks good. 150 if ($lineDifference !== 1) { 151 return; 152 } 153 154 // We need to actually find the first piece of content on this line, 155 // as if this is a method with tokens before it (public, static etc) 156 // or an if with an else before it, then we need to start the scope 157 // checking from there, rather than the current token. 158 $lineStart = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr, true); 159 160 // The opening brace is on the correct line, now it needs to be 161 // checked to be correctly indented. 162 $startColumn = $tokens[$lineStart]['column']; 163 $braceIndent = $tokens[$openingBrace]['column']; 164 165 if ($braceIndent !== $startColumn) { 166 $expected = ($startColumn - 1); 167 $found = ($braceIndent - 1); 168 169 $error = 'Opening brace indented incorrectly; expected %s spaces, found %s'; 170 $data = array( 171 $expected, 172 $found, 173 ); 174 175 $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceIndent', $data); 176 if ($fix === true) { 177 $indent = str_repeat(' ', $expected); 178 if ($found === 0) { 179 $phpcsFile->fixer->addContentBefore($openingBrace, $indent); 180 } else { 181 $phpcsFile->fixer->replaceToken(($openingBrace - 1), $indent); 182 } 183 } 184 }//end if 185 186 $phpcsFile->recordMetric($stackPtr, 'Function opening brace placement', 'new line'); 187 188 }//end process() 189 190 191}//end class 192