annotate vendor/drupal/coder/coder_sniffer/Drupal/Sniffs/ControlStructures/ControlSignatureSniff.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 129ea1e6d783
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@0 3 * Verifies that control statements conform to their coding standards.
Chris@0 4 *
Chris@0 5 * @category PHP
Chris@0 6 * @package PHP_CodeSniffer
Chris@0 7 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 8 */
Chris@0 9
Chris@0 10 /**
Chris@0 11 * Verifies that control statements conform to their coding standards.
Chris@0 12 *
Chris@0 13 * Largely copied from Squiz_Sniffs_ControlStructures_ControlSignatureSniff and
Chris@0 14 * adapted for Drupal's else on new lines.
Chris@0 15 *
Chris@0 16 * @category PHP
Chris@0 17 * @package PHP_CodeSniffer
Chris@0 18 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 19 */
Chris@0 20 class Drupal_Sniffs_ControlStructures_ControlSignatureSniff implements PHP_CodeSniffer_Sniff
Chris@0 21 {
Chris@0 22
Chris@0 23 /**
Chris@0 24 * A list of tokenizers this sniff supports.
Chris@0 25 *
Chris@0 26 * @var array
Chris@0 27 */
Chris@0 28 public $supportedTokenizers = array(
Chris@0 29 'PHP',
Chris@0 30 'JS',
Chris@0 31 );
Chris@0 32
Chris@0 33
Chris@0 34 /**
Chris@0 35 * Returns an array of tokens this test wants to listen for.
Chris@0 36 *
Chris@0 37 * @return int[]
Chris@0 38 */
Chris@0 39 public function register()
Chris@0 40 {
Chris@0 41 return array(
Chris@0 42 T_TRY,
Chris@0 43 T_CATCH,
Chris@0 44 T_DO,
Chris@0 45 T_WHILE,
Chris@0 46 T_FOR,
Chris@0 47 T_IF,
Chris@0 48 T_FOREACH,
Chris@0 49 T_ELSE,
Chris@0 50 T_ELSEIF,
Chris@0 51 T_SWITCH,
Chris@0 52 );
Chris@0 53
Chris@0 54 }//end register()
Chris@0 55
Chris@0 56
Chris@0 57 /**
Chris@0 58 * Processes this test, when one of its tokens is encountered.
Chris@0 59 *
Chris@0 60 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
Chris@0 61 * @param int $stackPtr The position of the current token in the
Chris@0 62 * stack passed in $tokens.
Chris@0 63 *
Chris@0 64 * @return void
Chris@0 65 */
Chris@0 66 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
Chris@0 67 {
Chris@0 68 $tokens = $phpcsFile->getTokens();
Chris@0 69
Chris@0 70 if (isset($tokens[($stackPtr + 1)]) === false) {
Chris@0 71 return;
Chris@0 72 }
Chris@0 73
Chris@0 74 // Single space after the keyword.
Chris@0 75 $found = 1;
Chris@0 76 if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) {
Chris@0 77 $found = 0;
Chris@0 78 } else if ($tokens[($stackPtr + 1)]['content'] !== ' ') {
Chris@0 79 if (strpos($tokens[($stackPtr + 1)]['content'], $phpcsFile->eolChar) !== false) {
Chris@0 80 $found = 'newline';
Chris@0 81 } else {
Chris@0 82 $found = strlen($tokens[($stackPtr + 1)]['content']);
Chris@0 83 }
Chris@0 84 }
Chris@0 85
Chris@0 86 if ($found !== 1) {
Chris@0 87 $error = 'Expected 1 space after %s keyword; %s found';
Chris@0 88 $data = array(
Chris@0 89 strtoupper($tokens[$stackPtr]['content']),
Chris@0 90 $found,
Chris@0 91 );
Chris@0 92
Chris@0 93 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterKeyword', $data);
Chris@0 94 if ($fix === true) {
Chris@0 95 if ($found === 0) {
Chris@0 96 $phpcsFile->fixer->addContent($stackPtr, ' ');
Chris@0 97 } else {
Chris@0 98 $phpcsFile->fixer->replaceToken(($stackPtr + 1), ' ');
Chris@0 99 }
Chris@0 100 }
Chris@0 101 }
Chris@0 102
Chris@0 103 // Single space after closing parenthesis.
Chris@0 104 if (isset($tokens[$stackPtr]['parenthesis_closer']) === true
Chris@0 105 && isset($tokens[$stackPtr]['scope_opener']) === true
Chris@0 106 ) {
Chris@0 107 $closer = $tokens[$stackPtr]['parenthesis_closer'];
Chris@0 108 $opener = $tokens[$stackPtr]['scope_opener'];
Chris@0 109 $content = $phpcsFile->getTokensAsString(($closer + 1), ($opener - $closer - 1));
Chris@0 110
Chris@0 111 if ($content !== ' ') {
Chris@0 112 $error = 'Expected 1 space after closing parenthesis; found %s';
Chris@0 113 if (trim($content) === '') {
Chris@0 114 $found = strlen($content);
Chris@0 115 } else {
Chris@0 116 $found = '"'.str_replace($phpcsFile->eolChar, '\n', $content).'"';
Chris@0 117 }
Chris@0 118
Chris@0 119 $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceAfterCloseParenthesis', array($found));
Chris@0 120 if ($fix === true) {
Chris@0 121 if ($closer === ($opener - 1)) {
Chris@0 122 $phpcsFile->fixer->addContent($closer, ' ');
Chris@0 123 } else {
Chris@0 124 $phpcsFile->fixer->beginChangeset();
Chris@0 125 $phpcsFile->fixer->addContent($closer, ' '.$tokens[$opener]['content']);
Chris@0 126 $phpcsFile->fixer->replaceToken($opener, '');
Chris@0 127
Chris@0 128 if ($tokens[$opener]['line'] !== $tokens[$closer]['line']) {
Chris@0 129 $next = $phpcsFile->findNext(T_WHITESPACE, ($opener + 1), null, true);
Chris@0 130 if ($tokens[$next]['line'] !== $tokens[$opener]['line']) {
Chris@0 131 for ($i = ($opener + 1); $i < $next; $i++) {
Chris@0 132 $phpcsFile->fixer->replaceToken($i, '');
Chris@0 133 }
Chris@0 134 }
Chris@0 135 }
Chris@0 136
Chris@0 137 $phpcsFile->fixer->endChangeset();
Chris@0 138 }
Chris@0 139 }
Chris@0 140 }//end if
Chris@0 141 }//end if
Chris@0 142
Chris@0 143 // Single newline after opening brace.
Chris@0 144 if (isset($tokens[$stackPtr]['scope_opener']) === true) {
Chris@0 145 $opener = $tokens[$stackPtr]['scope_opener'];
Chris@0 146 for ($next = ($opener + 1); $next < $phpcsFile->numTokens; $next++) {
Chris@0 147 $code = $tokens[$next]['code'];
Chris@0 148
Chris@0 149 if ($code === T_WHITESPACE
Chris@0 150 || ($code === T_INLINE_HTML
Chris@0 151 && trim($tokens[$next]['content']) === '')
Chris@0 152 ) {
Chris@0 153 continue;
Chris@0 154 }
Chris@0 155
Chris@0 156 // Skip all empty tokens on the same line as the opener.
Chris@0 157 if ($tokens[$next]['line'] === $tokens[$opener]['line']
Chris@0 158 && (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$code]) === true
Chris@0 159 || $code === T_CLOSE_TAG)
Chris@0 160 ) {
Chris@0 161 continue;
Chris@0 162 }
Chris@0 163
Chris@0 164 // We found the first bit of a code, or a comment on the
Chris@0 165 // following line.
Chris@0 166 break;
Chris@0 167 }//end for
Chris@0 168
Chris@0 169 if ($tokens[$next]['line'] === $tokens[$opener]['line']) {
Chris@0 170 $error = 'Newline required after opening brace';
Chris@0 171 $fix = $phpcsFile->addFixableError($error, $opener, 'NewlineAfterOpenBrace');
Chris@0 172 if ($fix === true) {
Chris@0 173 $phpcsFile->fixer->beginChangeset();
Chris@0 174 for ($i = ($opener + 1); $i < $next; $i++) {
Chris@0 175 if (trim($tokens[$i]['content']) !== '') {
Chris@0 176 break;
Chris@0 177 }
Chris@0 178
Chris@0 179 // Remove whitespace.
Chris@0 180 $phpcsFile->fixer->replaceToken($i, '');
Chris@0 181 }
Chris@0 182
Chris@0 183 $phpcsFile->fixer->addContent($opener, $phpcsFile->eolChar);
Chris@0 184 $phpcsFile->fixer->endChangeset();
Chris@0 185 }
Chris@0 186 }//end if
Chris@0 187 } else if ($tokens[$stackPtr]['code'] === T_WHILE) {
Chris@0 188 // Zero spaces after parenthesis closer.
Chris@0 189 $closer = $tokens[$stackPtr]['parenthesis_closer'];
Chris@0 190 $found = 0;
Chris@0 191 if ($tokens[($closer + 1)]['code'] === T_WHITESPACE) {
Chris@0 192 if (strpos($tokens[($closer + 1)]['content'], $phpcsFile->eolChar) !== false) {
Chris@0 193 $found = 'newline';
Chris@0 194 } else {
Chris@0 195 $found = strlen($tokens[($closer + 1)]['content']);
Chris@0 196 }
Chris@0 197 }
Chris@0 198
Chris@0 199 if ($found !== 0) {
Chris@0 200 $error = 'Expected 0 spaces before semicolon; %s found';
Chris@0 201 $data = array($found);
Chris@0 202 $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceBeforeSemicolon', $data);
Chris@0 203 if ($fix === true) {
Chris@0 204 $phpcsFile->fixer->replaceToken(($closer + 1), '');
Chris@0 205 }
Chris@0 206 }
Chris@0 207 }//end if
Chris@0 208
Chris@0 209 // Only want to check multi-keyword structures from here on.
Chris@0 210 if ($tokens[$stackPtr]['code'] === T_DO) {
Chris@0 211 $closer = false;
Chris@0 212 if (isset($tokens[$stackPtr]['scope_closer']) === true) {
Chris@0 213 $closer = $tokens[$stackPtr]['scope_closer'];
Chris@0 214 }
Chris@0 215
Chris@0 216 // Do-while loops should have curly braces. This is optional in
Chris@0 217 // Javascript.
Chris@0 218 if ($closer === false && $tokens[$stackPtr]['code'] === T_DO && $phpcsFile->tokenizerType === 'JS') {
Chris@0 219 $error = 'The code block in a do-while loop should be surrounded by curly braces';
Chris@0 220 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'DoWhileCurlyBraces');
Chris@0 221 $closer = $phpcsFile->findNext(T_WHILE, $stackPtr);
Chris@0 222 if ($fix === true) {
Chris@0 223 $phpcsFile->fixer->beginChangeset();
Chris@0 224 // Append an opening curly brace followed by a newline after
Chris@0 225 // the DO.
Chris@0 226 $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
Chris@0 227 if ($next !== ($stackPtr + 1)) {
Chris@0 228 $phpcsFile->fixer->replaceToken(($stackPtr + 1), '');
Chris@0 229 }
Chris@0 230
Chris@0 231 $phpcsFile->fixer->addContent($stackPtr, ' {'.$phpcsFile->eolChar);
Chris@0 232
Chris@0 233 // Prepend a closing curly brace before the WHILE and ensure
Chris@0 234 // it is on a new line.
Chris@0 235 $prepend = $phpcsFile->eolChar;
Chris@0 236 if ($tokens[($closer - 1)]['code'] === T_WHITESPACE) {
Chris@0 237 $prepend = '';
Chris@0 238 if ($tokens[($closer - 1)]['content'] !== $phpcsFile->eolChar) {
Chris@0 239 $phpcsFile->fixer->replaceToken(($closer - 1), $phpcsFile->eolChar);
Chris@0 240 }
Chris@0 241 }
Chris@0 242
Chris@0 243 $phpcsFile->fixer->addContentBefore($closer, $prepend.'} ');
Chris@0 244 $phpcsFile->fixer->endChangeset();
Chris@0 245 }//end if
Chris@0 246 }//end if
Chris@0 247 } else if ($tokens[$stackPtr]['code'] === T_ELSE
Chris@0 248 || $tokens[$stackPtr]['code'] === T_ELSEIF
Chris@0 249 || $tokens[$stackPtr]['code'] === T_CATCH
Chris@0 250 ) {
Chris@0 251 $closer = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
Chris@0 252 if ($closer === false || $tokens[$closer]['code'] !== T_CLOSE_CURLY_BRACKET) {
Chris@0 253 return;
Chris@0 254 }
Chris@0 255 } else {
Chris@0 256 return;
Chris@0 257 }//end if
Chris@0 258
Chris@0 259 if ($tokens[$stackPtr]['code'] === T_DO) {
Chris@0 260 // Single space after closing brace.
Chris@0 261 $found = 1;
Chris@0 262 if ($tokens[($closer + 1)]['code'] !== T_WHITESPACE) {
Chris@0 263 $found = 0;
Chris@0 264 } else if ($tokens[($closer + 1)]['content'] !== ' ') {
Chris@0 265 if (strpos($tokens[($closer + 1)]['content'], $phpcsFile->eolChar) !== false) {
Chris@0 266 $found = 'newline';
Chris@0 267 } else {
Chris@0 268 $found = strlen($tokens[($closer + 1)]['content']);
Chris@0 269 }
Chris@0 270 }
Chris@0 271
Chris@0 272 if ($found !== 1) {
Chris@0 273 $error = 'Expected 1 space after closing brace; %s found';
Chris@0 274 $data = array($found);
Chris@0 275 $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceAfterCloseBrace', $data);
Chris@0 276 if ($fix === true) {
Chris@0 277 if ($found === 0) {
Chris@0 278 $phpcsFile->fixer->addContent($closer, ' ');
Chris@0 279 } else {
Chris@0 280 $phpcsFile->fixer->replaceToken(($closer + 1), ' ');
Chris@0 281 }
Chris@0 282 }
Chris@0 283 }
Chris@0 284 } else {
Chris@0 285 // New line after closing brace.
Chris@0 286 $found = 'newline';
Chris@0 287 if ($tokens[($closer + 1)]['code'] !== T_WHITESPACE) {
Chris@0 288 $found = 'none';
Chris@0 289 } else if (strpos($tokens[($closer + 1)]['content'], "\n") === false) {
Chris@0 290 $found = 'spaces';
Chris@0 291 }
Chris@0 292
Chris@0 293 if ($found !== 'newline') {
Chris@0 294 $error = 'Expected newline after closing brace';
Chris@0 295 $fix = $phpcsFile->addFixableError($error, $closer, 'NewlineAfterCloseBrace');
Chris@0 296 if ($fix === true) {
Chris@0 297 if ($found === 'none') {
Chris@0 298 $phpcsFile->fixer->addContent($closer, "\n");
Chris@0 299 } else {
Chris@0 300 $phpcsFile->fixer->replaceToken(($closer + 1), "\n");
Chris@0 301 }
Chris@0 302 }
Chris@0 303 }
Chris@0 304 }//end if
Chris@0 305
Chris@0 306 }//end process()
Chris@0 307
Chris@0 308
Chris@0 309 }//end class