NoWhitespaceInBlankLineFixer.php 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Fixer\Whitespace;
  13. use PhpCsFixer\AbstractFixer;
  14. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  15. use PhpCsFixer\FixerDefinition\CodeSample;
  16. use PhpCsFixer\FixerDefinition\FixerDefinition;
  17. use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
  18. use PhpCsFixer\Preg;
  19. use PhpCsFixer\Tokenizer\Tokens;
  20. /**
  21. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  22. */
  23. final class NoWhitespaceInBlankLineFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
  24. {
  25. public function getDefinition(): FixerDefinitionInterface
  26. {
  27. return new FixerDefinition(
  28. 'Remove trailing whitespace at the end of blank lines.',
  29. [new CodeSample("<?php\n \n\$a = 1;\n")]
  30. );
  31. }
  32. /**
  33. * {@inheritdoc}
  34. *
  35. * Must run after AssignNullCoalescingToCoalesceEqualFixer, CombineConsecutiveIssetsFixer, CombineConsecutiveUnsetsFixer, FunctionToConstantFixer, NoEmptyCommentFixer, NoEmptyPhpdocFixer, NoEmptyStatementFixer, NoUselessElseFixer, NoUselessReturnFixer, YieldFromArrayToYieldsFixer.
  36. */
  37. public function getPriority(): int
  38. {
  39. return -99;
  40. }
  41. public function isCandidate(Tokens $tokens): bool
  42. {
  43. return true;
  44. }
  45. protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
  46. {
  47. // skip first as it cannot be a white space token
  48. for ($i = 1, $count = \count($tokens); $i < $count; ++$i) {
  49. if ($tokens[$i]->isWhitespace()) {
  50. $this->fixWhitespaceToken($tokens, $i);
  51. }
  52. }
  53. }
  54. private function fixWhitespaceToken(Tokens $tokens, int $index): void
  55. {
  56. $content = $tokens[$index]->getContent();
  57. $lines = Preg::split("/(\r\n|\n)/", $content);
  58. $lineCount = \count($lines);
  59. if (
  60. // fix T_WHITESPACES with at least 3 lines (eg `\n \n`)
  61. $lineCount > 2
  62. // and T_WHITESPACES with at least 2 lines at the end of file or after open tag with linebreak
  63. || ($lineCount > 0 && (!isset($tokens[$index + 1]) || $tokens[$index - 1]->isGivenKind(T_OPEN_TAG)))
  64. ) {
  65. $lMax = isset($tokens[$index + 1]) ? $lineCount - 1 : $lineCount;
  66. $lStart = 1;
  67. if ($tokens[$index - 1]->isGivenKind(T_OPEN_TAG) && "\n" === substr($tokens[$index - 1]->getContent(), -1)) {
  68. $lStart = 0;
  69. }
  70. for ($l = $lStart; $l < $lMax; ++$l) {
  71. $lines[$l] = Preg::replace('/^\h+$/', '', $lines[$l]);
  72. }
  73. $content = implode($this->whitespacesConfig->getLineEnding(), $lines);
  74. $tokens->ensureWhitespaceAtIndex($index, 0, $content);
  75. }
  76. }
  77. }