annotate vendor/squizlabs/php_codesniffer/CodeSniffer/Fixer.php @ 2:5311817fb629

Theme updates
author Chris Cannam
date Tue, 10 Jul 2018 13:19:18 +0000
parents c75dbcec494b
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@0 3 * A helper class for fixing errors.
Chris@0 4 *
Chris@0 5 * PHP version 5
Chris@0 6 *
Chris@0 7 * @category PHP
Chris@0 8 * @package PHP_CodeSniffer
Chris@0 9 * @author Greg Sherwood <gsherwood@squiz.net>
Chris@0 10 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
Chris@0 11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
Chris@0 12 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 13 */
Chris@0 14
Chris@0 15 /**
Chris@0 16 * A helper class for fixing errors.
Chris@0 17 *
Chris@0 18 * Provides helper functions that act upon a token array and modify the file
Chris@0 19 * content.
Chris@0 20 *
Chris@0 21 * @category PHP
Chris@0 22 * @package PHP_CodeSniffer
Chris@0 23 * @author Greg Sherwood <gsherwood@squiz.net>
Chris@0 24 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
Chris@0 25 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
Chris@0 26 * @version Release: @package_version@
Chris@0 27 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 28 */
Chris@0 29 class PHP_CodeSniffer_Fixer
Chris@0 30 {
Chris@0 31
Chris@0 32 /**
Chris@0 33 * Is the fixer enabled and fixing a file?
Chris@0 34 *
Chris@0 35 * Sniffs should check this value to ensure they are not
Chris@0 36 * doing extra processing to prepare for a fix when fixing is
Chris@0 37 * not required.
Chris@0 38 *
Chris@0 39 * @var boolean
Chris@0 40 */
Chris@0 41 public $enabled = false;
Chris@0 42
Chris@0 43 /**
Chris@0 44 * The number of times we have looped over a file.
Chris@0 45 *
Chris@0 46 * @var int
Chris@0 47 */
Chris@0 48 public $loops = 0;
Chris@0 49
Chris@0 50 /**
Chris@0 51 * The file being fixed.
Chris@0 52 *
Chris@0 53 * @var PHP_CodeSniffer_File
Chris@0 54 */
Chris@0 55 private $_currentFile = null;
Chris@0 56
Chris@0 57 /**
Chris@0 58 * The list of tokens that make up the file contents.
Chris@0 59 *
Chris@0 60 * This is a simplified list which just contains the token content and nothing
Chris@0 61 * else. This is the array that is updated as fixes are made, not the file's
Chris@0 62 * token array. Imploding this array will give you the file content back.
Chris@0 63 *
Chris@0 64 * @var array(int => string)
Chris@0 65 */
Chris@0 66 private $_tokens = array();
Chris@0 67
Chris@0 68 /**
Chris@0 69 * A list of tokens that have already been fixed.
Chris@0 70 *
Chris@0 71 * We don't allow the same token to be fixed more than once each time
Chris@0 72 * through a file as this can easily cause conflicts between sniffs.
Chris@0 73 *
Chris@0 74 * @var array(int)
Chris@0 75 */
Chris@0 76 private $_fixedTokens = array();
Chris@0 77
Chris@0 78 /**
Chris@0 79 * The last value of each fixed token.
Chris@0 80 *
Chris@0 81 * If a token is being "fixed" back to its last value, the fix is
Chris@0 82 * probably conflicting with another.
Chris@0 83 *
Chris@0 84 * @var array(int => string)
Chris@0 85 */
Chris@0 86 private $_oldTokenValues = array();
Chris@0 87
Chris@0 88 /**
Chris@0 89 * A list of tokens that have been fixed during a changeset.
Chris@0 90 *
Chris@0 91 * All changes in changeset must be able to be applied, or else
Chris@0 92 * the entire changeset is rejected.
Chris@0 93 *
Chris@0 94 * @var array()
Chris@0 95 */
Chris@0 96 private $_changeset = array();
Chris@0 97
Chris@0 98 /**
Chris@0 99 * Is there an open changeset.
Chris@0 100 *
Chris@0 101 * @var boolean
Chris@0 102 */
Chris@0 103 private $_inChangeset = false;
Chris@0 104
Chris@0 105 /**
Chris@0 106 * Is the current fixing loop in conflict?
Chris@0 107 *
Chris@0 108 * @var boolean
Chris@0 109 */
Chris@0 110 private $_inConflict = false;
Chris@0 111
Chris@0 112 /**
Chris@0 113 * The number of fixes that have been performed.
Chris@0 114 *
Chris@0 115 * @var int
Chris@0 116 */
Chris@0 117 private $_numFixes = 0;
Chris@0 118
Chris@0 119
Chris@0 120 /**
Chris@0 121 * Starts fixing a new file.
Chris@0 122 *
Chris@0 123 * @param PHP_CodeSniffer_File $phpcsFile The file being fixed.
Chris@0 124 *
Chris@0 125 * @return void
Chris@0 126 */
Chris@0 127 public function startFile($phpcsFile)
Chris@0 128 {
Chris@0 129 $this->_currentFile = $phpcsFile;
Chris@0 130 $this->_numFixes = 0;
Chris@0 131 $this->_fixedTokens = array();
Chris@0 132
Chris@0 133 $tokens = $phpcsFile->getTokens();
Chris@0 134 $this->_tokens = array();
Chris@0 135 foreach ($tokens as $index => $token) {
Chris@0 136 if (isset($token['orig_content']) === true) {
Chris@0 137 $this->_tokens[$index] = $token['orig_content'];
Chris@0 138 } else {
Chris@0 139 $this->_tokens[$index] = $token['content'];
Chris@0 140 }
Chris@0 141 }
Chris@0 142
Chris@0 143 }//end startFile()
Chris@0 144
Chris@0 145
Chris@0 146 /**
Chris@0 147 * Attempt to fix the file by processing it until no fixes are made.
Chris@0 148 *
Chris@0 149 * @return boolean
Chris@0 150 */
Chris@0 151 public function fixFile()
Chris@0 152 {
Chris@0 153 $fixable = $this->_currentFile->getFixableCount();
Chris@0 154 if ($fixable === 0) {
Chris@0 155 // Nothing to fix.
Chris@0 156 return false;
Chris@0 157 }
Chris@0 158
Chris@0 159 $stdin = false;
Chris@0 160 $cliValues = $this->_currentFile->phpcs->cli->getCommandLineValues();
Chris@0 161 if (empty($cliValues['files']) === true) {
Chris@0 162 $stdin = true;
Chris@0 163 }
Chris@0 164
Chris@0 165 $this->enabled = true;
Chris@0 166
Chris@0 167 $this->loops = 0;
Chris@0 168 while ($this->loops < 50) {
Chris@0 169 ob_start();
Chris@0 170
Chris@0 171 // Only needed once file content has changed.
Chris@0 172 $contents = $this->getContents();
Chris@0 173
Chris@0 174 if (PHP_CODESNIFFER_VERBOSITY > 2) {
Chris@0 175 @ob_end_clean();
Chris@0 176 echo '---START FILE CONTENT---'.PHP_EOL;
Chris@0 177 $lines = explode($this->_currentFile->eolChar, $contents);
Chris@0 178 $max = strlen(count($lines));
Chris@0 179 foreach ($lines as $lineNum => $line) {
Chris@0 180 $lineNum++;
Chris@0 181 echo str_pad($lineNum, $max, ' ', STR_PAD_LEFT).'|'.$line.PHP_EOL;
Chris@0 182 }
Chris@0 183
Chris@0 184 echo '--- END FILE CONTENT ---'.PHP_EOL;
Chris@0 185 ob_start();
Chris@0 186 }
Chris@0 187
Chris@0 188 $this->_inConflict = false;
Chris@0 189 $this->_currentFile->refreshTokenListeners();
Chris@0 190 $this->_currentFile->start($contents);
Chris@0 191 ob_end_clean();
Chris@0 192
Chris@0 193 $this->loops++;
Chris@0 194
Chris@0 195 if (PHP_CODESNIFFER_CBF === true && $stdin === false) {
Chris@0 196 echo "\r".str_repeat(' ', 80)."\r";
Chris@0 197 echo "\t=> Fixing file: $this->_numFixes/$fixable violations remaining [made $this->loops pass";
Chris@0 198 if ($this->loops > 1) {
Chris@0 199 echo 'es';
Chris@0 200 }
Chris@0 201
Chris@0 202 echo ']... ';
Chris@0 203 }
Chris@0 204
Chris@0 205 if ($this->_numFixes === 0 && $this->_inConflict === false) {
Chris@0 206 // Nothing left to do.
Chris@0 207 break;
Chris@0 208 } else if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 209 echo "\t* fixed $this->_numFixes violations, starting loop ".($this->loops + 1).' *'.PHP_EOL;
Chris@0 210 }
Chris@0 211 }//end while
Chris@0 212
Chris@0 213 $this->enabled = false;
Chris@0 214
Chris@0 215 if ($this->_numFixes > 0) {
Chris@0 216 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 217 @ob_end_clean();
Chris@0 218 echo "\t*** Reached maximum number of loops with $this->_numFixes violations left unfixed ***".PHP_EOL;
Chris@0 219 ob_start();
Chris@0 220 }
Chris@0 221
Chris@0 222 return false;
Chris@0 223 }
Chris@0 224
Chris@0 225 return true;
Chris@0 226
Chris@0 227 }//end fixFile()
Chris@0 228
Chris@0 229
Chris@0 230 /**
Chris@0 231 * Generates a text diff of the original file and the new content.
Chris@0 232 *
Chris@0 233 * @param string $filePath Optional file path to diff the file against.
Chris@0 234 * If not specified, the original version of the
Chris@0 235 * file will be used.
Chris@0 236 * @param boolean $colors Print colored output or not.
Chris@0 237 *
Chris@0 238 * @return string
Chris@0 239 */
Chris@0 240 public function generateDiff($filePath=null, $colors=true)
Chris@0 241 {
Chris@0 242 if ($filePath === null) {
Chris@0 243 $filePath = $this->_currentFile->getFilename();
Chris@0 244 }
Chris@0 245
Chris@0 246 $cwd = getcwd().DIRECTORY_SEPARATOR;
Chris@0 247 if (strpos($filePath, $cwd) === 0) {
Chris@0 248 $filename = substr($filePath, strlen($cwd));
Chris@0 249 } else {
Chris@0 250 $filename = $filePath;
Chris@0 251 }
Chris@0 252
Chris@0 253 $contents = $this->getContents();
Chris@0 254
Chris@0 255 if (function_exists('sys_get_temp_dir') === true) {
Chris@0 256 // This is needed for HHVM support, but only available from 5.2.1.
Chris@0 257 $tempName = tempnam(sys_get_temp_dir(), 'phpcs-fixer');
Chris@0 258 $fixedFile = fopen($tempName, 'w');
Chris@0 259 } else {
Chris@0 260 $fixedFile = tmpfile();
Chris@0 261 $data = stream_get_meta_data($fixedFile);
Chris@0 262 $tempName = $data['uri'];
Chris@0 263 }
Chris@0 264
Chris@0 265 fwrite($fixedFile, $contents);
Chris@0 266
Chris@0 267 // We must use something like shell_exec() because whitespace at the end
Chris@0 268 // of lines is critical to diff files.
Chris@0 269 $filename = escapeshellarg($filename);
Chris@0 270 $cmd = "diff -u -L$filename -LPHP_CodeSniffer $filename \"$tempName\"";
Chris@0 271
Chris@0 272 $diff = shell_exec($cmd);
Chris@0 273
Chris@0 274 fclose($fixedFile);
Chris@0 275 if (is_file($tempName) === true) {
Chris@0 276 unlink($tempName);
Chris@0 277 }
Chris@0 278
Chris@0 279 if ($colors === false) {
Chris@0 280 return $diff;
Chris@0 281 }
Chris@0 282
Chris@0 283 $diffLines = explode(PHP_EOL, $diff);
Chris@0 284 if (count($diffLines) === 1) {
Chris@0 285 // Seems to be required for cygwin.
Chris@0 286 $diffLines = explode("\n", $diff);
Chris@0 287 }
Chris@0 288
Chris@0 289 $diff = array();
Chris@0 290 foreach ($diffLines as $line) {
Chris@0 291 if (isset($line[0]) === true) {
Chris@0 292 switch ($line[0]) {
Chris@0 293 case '-':
Chris@0 294 $diff[] = "\033[31m$line\033[0m";
Chris@0 295 break;
Chris@0 296 case '+':
Chris@0 297 $diff[] = "\033[32m$line\033[0m";
Chris@0 298 break;
Chris@0 299 default:
Chris@0 300 $diff[] = $line;
Chris@0 301 }
Chris@0 302 }
Chris@0 303 }
Chris@0 304
Chris@0 305 $diff = implode(PHP_EOL, $diff);
Chris@0 306
Chris@0 307 return $diff;
Chris@0 308
Chris@0 309 }//end generateDiff()
Chris@0 310
Chris@0 311
Chris@0 312 /**
Chris@0 313 * Get a count of fixes that have been performed on the file.
Chris@0 314 *
Chris@0 315 * This value is reset every time a new file is started, or an existing
Chris@0 316 * file is restarted.
Chris@0 317 *
Chris@0 318 * @return int
Chris@0 319 */
Chris@0 320 public function getFixCount()
Chris@0 321 {
Chris@0 322 return $this->_numFixes;
Chris@0 323
Chris@0 324 }//end getFixCount()
Chris@0 325
Chris@0 326
Chris@0 327 /**
Chris@0 328 * Get the current content of the file, as a string.
Chris@0 329 *
Chris@0 330 * @return string
Chris@0 331 */
Chris@0 332 public function getContents()
Chris@0 333 {
Chris@0 334 $contents = implode($this->_tokens);
Chris@0 335 return $contents;
Chris@0 336
Chris@0 337 }//end getContents()
Chris@0 338
Chris@0 339
Chris@0 340 /**
Chris@0 341 * Get the current fixed content of a token.
Chris@0 342 *
Chris@0 343 * This function takes changesets into account so should be used
Chris@0 344 * instead of directly accessing the token array.
Chris@0 345 *
Chris@0 346 * @param int $stackPtr The position of the token in the token stack.
Chris@0 347 *
Chris@0 348 * @return string
Chris@0 349 */
Chris@0 350 public function getTokenContent($stackPtr)
Chris@0 351 {
Chris@0 352 if ($this->_inChangeset === true
Chris@0 353 && isset($this->_changeset[$stackPtr]) === true
Chris@0 354 ) {
Chris@0 355 return $this->_changeset[$stackPtr];
Chris@0 356 } else {
Chris@0 357 return $this->_tokens[$stackPtr];
Chris@0 358 }
Chris@0 359
Chris@0 360 }//end getTokenContent()
Chris@0 361
Chris@0 362
Chris@0 363 /**
Chris@0 364 * Start recording actions for a changeset.
Chris@0 365 *
Chris@0 366 * @return void
Chris@0 367 */
Chris@0 368 public function beginChangeset()
Chris@0 369 {
Chris@0 370 if ($this->_inConflict === true) {
Chris@0 371 return false;
Chris@0 372 }
Chris@0 373
Chris@0 374 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 375 $bt = debug_backtrace();
Chris@0 376 $sniff = $bt[1]['class'];
Chris@0 377 $line = $bt[0]['line'];
Chris@0 378
Chris@0 379 @ob_end_clean();
Chris@0 380 echo "\t=> Changeset started by $sniff (line $line)".PHP_EOL;
Chris@0 381 ob_start();
Chris@0 382 }
Chris@0 383
Chris@0 384 $this->_changeset = array();
Chris@0 385 $this->_inChangeset = true;
Chris@0 386
Chris@0 387 }//end beginChangeset()
Chris@0 388
Chris@0 389
Chris@0 390 /**
Chris@0 391 * Stop recording actions for a changeset, and apply logged changes.
Chris@0 392 *
Chris@0 393 * @return boolean
Chris@0 394 */
Chris@0 395 public function endChangeset()
Chris@0 396 {
Chris@0 397 if ($this->_inConflict === true) {
Chris@0 398 return false;
Chris@0 399 }
Chris@0 400
Chris@0 401 $this->_inChangeset = false;
Chris@0 402
Chris@0 403 $success = true;
Chris@0 404 $applied = array();
Chris@0 405 foreach ($this->_changeset as $stackPtr => $content) {
Chris@0 406 $success = $this->replaceToken($stackPtr, $content);
Chris@0 407 if ($success === false) {
Chris@0 408 break;
Chris@0 409 } else {
Chris@0 410 $applied[] = $stackPtr;
Chris@0 411 }
Chris@0 412 }
Chris@0 413
Chris@0 414 if ($success === false) {
Chris@0 415 // Rolling back all changes.
Chris@0 416 foreach ($applied as $stackPtr) {
Chris@0 417 $this->revertToken($stackPtr);
Chris@0 418 }
Chris@0 419
Chris@0 420 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 421 @ob_end_clean();
Chris@0 422 echo "\t=> Changeset failed to apply".PHP_EOL;
Chris@0 423 ob_start();
Chris@0 424 }
Chris@0 425 } else if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 426 $fixes = count($this->_changeset);
Chris@0 427 @ob_end_clean();
Chris@0 428 echo "\t=> Changeset ended: $fixes changes applied".PHP_EOL;
Chris@0 429 ob_start();
Chris@0 430 }
Chris@0 431
Chris@0 432 $this->_changeset = array();
Chris@0 433
Chris@0 434 }//end endChangeset()
Chris@0 435
Chris@0 436
Chris@0 437 /**
Chris@0 438 * Stop recording actions for a changeset, and discard logged changes.
Chris@0 439 *
Chris@0 440 * @return void
Chris@0 441 */
Chris@0 442 public function rollbackChangeset()
Chris@0 443 {
Chris@0 444 $this->_inChangeset = false;
Chris@0 445 $this->_inConflict = false;
Chris@0 446
Chris@0 447 if (empty($this->_changeset) === false) {
Chris@0 448 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 449 $bt = debug_backtrace();
Chris@0 450 if ($bt[1]['class'] === 'PHP_CodeSniffer_Fixer') {
Chris@0 451 $sniff = $bt[2]['class'];
Chris@0 452 $line = $bt[1]['line'];
Chris@0 453 } else {
Chris@0 454 $sniff = $bt[1]['class'];
Chris@0 455 $line = $bt[0]['line'];
Chris@0 456 }
Chris@0 457
Chris@0 458 $numChanges = count($this->_changeset);
Chris@0 459
Chris@0 460 @ob_end_clean();
Chris@0 461 echo "\t\tR: $sniff (line $line) rolled back the changeset ($numChanges changes)".PHP_EOL;
Chris@0 462 echo "\t=> Changeset rolled back".PHP_EOL;
Chris@0 463 ob_start();
Chris@0 464 }
Chris@0 465
Chris@0 466 $this->_changeset = array();
Chris@0 467 }//end if
Chris@0 468
Chris@0 469 }//end rollbackChangeset()
Chris@0 470
Chris@0 471
Chris@0 472 /**
Chris@0 473 * Replace the entire contents of a token.
Chris@0 474 *
Chris@0 475 * @param int $stackPtr The position of the token in the token stack.
Chris@0 476 * @param string $content The new content of the token.
Chris@0 477 *
Chris@0 478 * @return bool If the change was accepted.
Chris@0 479 */
Chris@0 480 public function replaceToken($stackPtr, $content)
Chris@0 481 {
Chris@0 482 if ($this->_inConflict === true) {
Chris@0 483 return false;
Chris@0 484 }
Chris@0 485
Chris@0 486 if ($this->_inChangeset === false
Chris@0 487 && isset($this->_fixedTokens[$stackPtr]) === true
Chris@0 488 ) {
Chris@0 489 $indent = "\t";
Chris@0 490 if (empty($this->_changeset) === false) {
Chris@0 491 $indent .= "\t";
Chris@0 492 }
Chris@0 493
Chris@0 494 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 495 @ob_end_clean();
Chris@0 496 echo "$indent* token $stackPtr has already been modified, skipping *".PHP_EOL;
Chris@0 497 ob_start();
Chris@0 498 }
Chris@0 499
Chris@0 500 return false;
Chris@0 501 }
Chris@0 502
Chris@0 503 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 504 $bt = debug_backtrace();
Chris@0 505 if ($bt[1]['class'] === 'PHP_CodeSniffer_Fixer') {
Chris@0 506 $sniff = $bt[2]['class'];
Chris@0 507 $line = $bt[1]['line'];
Chris@0 508 } else {
Chris@0 509 $sniff = $bt[1]['class'];
Chris@0 510 $line = $bt[0]['line'];
Chris@0 511 }
Chris@0 512
Chris@0 513 $tokens = $this->_currentFile->getTokens();
Chris@0 514 $type = $tokens[$stackPtr]['type'];
Chris@0 515 $oldContent = PHP_CodeSniffer::prepareForOutput($this->_tokens[$stackPtr]);
Chris@0 516 $newContent = PHP_CodeSniffer::prepareForOutput($content);
Chris@0 517 if (trim($this->_tokens[$stackPtr]) === '' && isset($this->_tokens[($stackPtr + 1)]) === true) {
Chris@0 518 // Add some context for whitespace only changes.
Chris@0 519 $append = PHP_CodeSniffer::prepareForOutput($this->_tokens[($stackPtr + 1)]);
Chris@0 520 $oldContent .= $append;
Chris@0 521 $newContent .= $append;
Chris@0 522 }
Chris@0 523 }//end if
Chris@0 524
Chris@0 525 if ($this->_inChangeset === true) {
Chris@0 526 $this->_changeset[$stackPtr] = $content;
Chris@0 527
Chris@0 528 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 529 @ob_end_clean();
Chris@0 530 echo "\t\tQ: $sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
Chris@0 531 ob_start();
Chris@0 532 }
Chris@0 533
Chris@0 534 return true;
Chris@0 535 }
Chris@0 536
Chris@0 537 if (isset($this->_oldTokenValues[$stackPtr]) === false) {
Chris@0 538 $this->_oldTokenValues[$stackPtr] = array(
Chris@0 539 'curr' => $content,
Chris@0 540 'prev' => $this->_tokens[$stackPtr],
Chris@0 541 'loop' => $this->loops,
Chris@0 542 );
Chris@0 543 } else {
Chris@0 544 if ($this->_oldTokenValues[$stackPtr]['prev'] === $content
Chris@0 545 && $this->_oldTokenValues[$stackPtr]['loop'] === ($this->loops - 1)
Chris@0 546 ) {
Chris@0 547 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 548 $indent = "\t";
Chris@0 549 if (empty($this->_changeset) === false) {
Chris@0 550 $indent .= "\t";
Chris@0 551 }
Chris@0 552
Chris@0 553 $loop = $this->_oldTokenValues[$stackPtr]['loop'];
Chris@0 554
Chris@0 555 @ob_end_clean();
Chris@0 556 echo "$indent**** $sniff (line $line) has possible conflict with another sniff on loop $loop; caused by the following change ****".PHP_EOL;
Chris@0 557 echo "$indent**** replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\" ****".PHP_EOL;
Chris@0 558 }
Chris@0 559
Chris@0 560 if ($this->_oldTokenValues[$stackPtr]['loop'] >= ($this->loops - 1)) {
Chris@0 561 $this->_inConflict = true;
Chris@0 562 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 563 echo "$indent**** ignoring all changes until next loop ****".PHP_EOL;
Chris@0 564 }
Chris@0 565 }
Chris@0 566
Chris@0 567 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 568 ob_start();
Chris@0 569 }
Chris@0 570
Chris@0 571 return false;
Chris@0 572 }//end if
Chris@0 573
Chris@0 574 $this->_oldTokenValues[$stackPtr]['prev'] = $this->_oldTokenValues[$stackPtr]['curr'];
Chris@0 575 $this->_oldTokenValues[$stackPtr]['curr'] = $content;
Chris@0 576 $this->_oldTokenValues[$stackPtr]['loop'] = $this->loops;
Chris@0 577 }//end if
Chris@0 578
Chris@0 579 $this->_fixedTokens[$stackPtr] = $this->_tokens[$stackPtr];
Chris@0 580 $this->_tokens[$stackPtr] = $content;
Chris@0 581 $this->_numFixes++;
Chris@0 582
Chris@0 583 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 584 $indent = "\t";
Chris@0 585 if (empty($this->_changeset) === false) {
Chris@0 586 $indent .= "\tA: ";
Chris@0 587 }
Chris@0 588
Chris@0 589 @ob_end_clean();
Chris@0 590 echo "$indent$sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
Chris@0 591 ob_start();
Chris@0 592 }
Chris@0 593
Chris@0 594 return true;
Chris@0 595
Chris@0 596 }//end replaceToken()
Chris@0 597
Chris@0 598
Chris@0 599 /**
Chris@0 600 * Reverts the previous fix made to a token.
Chris@0 601 *
Chris@0 602 * @param int $stackPtr The position of the token in the token stack.
Chris@0 603 *
Chris@0 604 * @return bool If a change was reverted.
Chris@0 605 */
Chris@0 606 public function revertToken($stackPtr)
Chris@0 607 {
Chris@0 608 if (isset($this->_fixedTokens[$stackPtr]) === false) {
Chris@0 609 return false;
Chris@0 610 }
Chris@0 611
Chris@0 612 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 613 $bt = debug_backtrace();
Chris@0 614 if ($bt[1]['class'] === 'PHP_CodeSniffer_Fixer') {
Chris@0 615 $sniff = $bt[2]['class'];
Chris@0 616 $line = $bt[1]['line'];
Chris@0 617 } else {
Chris@0 618 $sniff = $bt[1]['class'];
Chris@0 619 $line = $bt[0]['line'];
Chris@0 620 }
Chris@0 621
Chris@0 622 $tokens = $this->_currentFile->getTokens();
Chris@0 623 $type = $tokens[$stackPtr]['type'];
Chris@0 624 $oldContent = PHP_CodeSniffer::prepareForOutput($this->_tokens[$stackPtr]);
Chris@0 625 $newContent = PHP_CodeSniffer::prepareForOutput($this->_fixedTokens[$stackPtr]);
Chris@0 626 if (trim($this->_tokens[$stackPtr]) === '' && isset($tokens[($stackPtr + 1)]) === true) {
Chris@0 627 // Add some context for whitespace only changes.
Chris@0 628 $append = PHP_CodeSniffer::prepareForOutput($this->_tokens[($stackPtr + 1)]);
Chris@0 629 $oldContent .= $append;
Chris@0 630 $newContent .= $append;
Chris@0 631 }
Chris@0 632 }//end if
Chris@0 633
Chris@0 634 $this->_tokens[$stackPtr] = $this->_fixedTokens[$stackPtr];
Chris@0 635 unset($this->_fixedTokens[$stackPtr]);
Chris@0 636 $this->_numFixes--;
Chris@0 637
Chris@0 638 if (PHP_CODESNIFFER_VERBOSITY > 1) {
Chris@0 639 $indent = "\t";
Chris@0 640 if (empty($this->_changeset) === false) {
Chris@0 641 $indent .= "\tR: ";
Chris@0 642 }
Chris@0 643
Chris@0 644 @ob_end_clean();
Chris@0 645 echo "$indent$sniff (line $line) reverted token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
Chris@0 646 ob_start();
Chris@0 647 }
Chris@0 648
Chris@0 649 return true;
Chris@0 650
Chris@0 651 }//end revertToken()
Chris@0 652
Chris@0 653
Chris@0 654 /**
Chris@0 655 * Replace the content of a token with a part of its current content.
Chris@0 656 *
Chris@0 657 * @param int $stackPtr The position of the token in the token stack.
Chris@0 658 * @param int $start The first character to keep.
Chris@0 659 * @param int $length The number of chacters to keep. If NULL, the content of
Chris@0 660 * the token from $start to the end of the content is kept.
Chris@0 661 *
Chris@0 662 * @return bool If the change was accepted.
Chris@0 663 */
Chris@0 664 public function substrToken($stackPtr, $start, $length=null)
Chris@0 665 {
Chris@0 666 $current = $this->getTokenContent($stackPtr);
Chris@0 667
Chris@0 668 if ($length === null) {
Chris@0 669 $newContent = substr($current, $start);
Chris@0 670 } else {
Chris@0 671 $newContent = substr($current, $start, $length);
Chris@0 672 }
Chris@0 673
Chris@0 674 return $this->replaceToken($stackPtr, $newContent);
Chris@0 675
Chris@0 676 }//end substrToken()
Chris@0 677
Chris@0 678
Chris@0 679 /**
Chris@0 680 * Adds a newline to end of a token's content.
Chris@0 681 *
Chris@0 682 * @param int $stackPtr The position of the token in the token stack.
Chris@0 683 *
Chris@0 684 * @return bool If the change was accepted.
Chris@0 685 */
Chris@0 686 public function addNewline($stackPtr)
Chris@0 687 {
Chris@0 688 $current = $this->getTokenContent($stackPtr);
Chris@0 689 return $this->replaceToken($stackPtr, $current.$this->_currentFile->eolChar);
Chris@0 690
Chris@0 691 }//end addNewline()
Chris@0 692
Chris@0 693
Chris@0 694 /**
Chris@0 695 * Adds a newline to the start of a token's content.
Chris@0 696 *
Chris@0 697 * @param int $stackPtr The position of the token in the token stack.
Chris@0 698 *
Chris@0 699 * @return bool If the change was accepted.
Chris@0 700 */
Chris@0 701 public function addNewlineBefore($stackPtr)
Chris@0 702 {
Chris@0 703 $current = $this->getTokenContent($stackPtr);
Chris@0 704 return $this->replaceToken($stackPtr, $this->_currentFile->eolChar.$current);
Chris@0 705
Chris@0 706 }//end addNewlineBefore()
Chris@0 707
Chris@0 708
Chris@0 709 /**
Chris@0 710 * Adds content to the end of a token's current content.
Chris@0 711 *
Chris@0 712 * @param int $stackPtr The position of the token in the token stack.
Chris@0 713 * @param string $content The content to add.
Chris@0 714 *
Chris@0 715 * @return bool If the change was accepted.
Chris@0 716 */
Chris@0 717 public function addContent($stackPtr, $content)
Chris@0 718 {
Chris@0 719 $current = $this->getTokenContent($stackPtr);
Chris@0 720 return $this->replaceToken($stackPtr, $current.$content);
Chris@0 721
Chris@0 722 }//end addContent()
Chris@0 723
Chris@0 724
Chris@0 725 /**
Chris@0 726 * Adds content to the start of a token's current content.
Chris@0 727 *
Chris@0 728 * @param int $stackPtr The position of the token in the token stack.
Chris@0 729 * @param string $content The content to add.
Chris@0 730 *
Chris@0 731 * @return bool If the change was accepted.
Chris@0 732 */
Chris@0 733 public function addContentBefore($stackPtr, $content)
Chris@0 734 {
Chris@0 735 $current = $this->getTokenContent($stackPtr);
Chris@0 736 return $this->replaceToken($stackPtr, $content.$current);
Chris@0 737
Chris@0 738 }//end addContentBefore()
Chris@0 739
Chris@0 740
Chris@0 741 }//end class