annotate vendor/drupal/coder/coder_sniffer/Drupal/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@17 3 * \Drupal\Sniffs\WhiteSpace\ScopeClosingBraceSniff.
Chris@0 4 *
Chris@0 5 * @category PHP
Chris@0 6 * @package PHP_CodeSniffer
Chris@0 7 * @link http://Drupal.php.net/package/PHP_CodeSniffer
Chris@0 8 */
Chris@0 9
Chris@17 10 namespace Drupal\Sniffs\WhiteSpace;
Chris@17 11
Chris@17 12 use PHP_CodeSniffer\Files\File;
Chris@17 13 use PHP_CodeSniffer\Sniffs\Sniff;
Chris@17 14 use PHP_CodeSniffer\Util\Tokens;
Chris@17 15
Chris@0 16 /**
Chris@17 17 * Copied from \PHP_CodeSniffer\Standards\PEAR\Sniffs\WhiteSpace\ScopeClosingBraceSniff to allow empty methods
Chris@0 18 * and classes.
Chris@0 19 *
Chris@0 20 * Checks that the closing braces of scopes are aligned correctly.
Chris@0 21 *
Chris@0 22 * @category PHP
Chris@0 23 * @package PHP_CodeSniffer
Chris@0 24 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 25 */
Chris@17 26 class ScopeClosingBraceSniff implements Sniff
Chris@0 27 {
Chris@0 28
Chris@0 29 /**
Chris@0 30 * The number of spaces code should be indented.
Chris@0 31 *
Chris@0 32 * @var int
Chris@0 33 */
Chris@0 34 public $indent = 2;
Chris@0 35
Chris@0 36
Chris@0 37 /**
Chris@0 38 * Returns an array of tokens this test wants to listen for.
Chris@0 39 *
Chris@0 40 * @return array
Chris@0 41 */
Chris@0 42 public function register()
Chris@0 43 {
Chris@17 44 return Tokens::$scopeOpeners;
Chris@0 45
Chris@0 46 }//end register()
Chris@0 47
Chris@0 48
Chris@0 49 /**
Chris@0 50 * Processes this test, when one of its tokens is encountered.
Chris@0 51 *
Chris@17 52 * @param \PHP_CodeSniffer\Files\File $phpcsFile All the tokens found in the document.
Chris@17 53 * @param int $stackPtr The position of the current token
Chris@17 54 * in the stack passed in $tokens.
Chris@0 55 *
Chris@0 56 * @return void
Chris@0 57 */
Chris@17 58 public function process(File $phpcsFile, $stackPtr)
Chris@0 59 {
Chris@0 60 $tokens = $phpcsFile->getTokens();
Chris@0 61
Chris@0 62 // If this is an inline condition (ie. there is no scope opener), then
Chris@0 63 // return, as this is not a new scope.
Chris@0 64 if (isset($tokens[$stackPtr]['scope_closer']) === false) {
Chris@0 65 return;
Chris@0 66 }
Chris@0 67
Chris@0 68 $scopeStart = $tokens[$stackPtr]['scope_opener'];
Chris@0 69 $scopeEnd = $tokens[$stackPtr]['scope_closer'];
Chris@0 70
Chris@0 71 // If the scope closer doesn't think it belongs to this scope opener
Chris@0 72 // then the opener is sharing its closer with other tokens. We only
Chris@0 73 // want to process the closer once, so skip this one.
Chris@0 74 if (isset($tokens[$scopeEnd]['scope_condition']) === false
Chris@0 75 || $tokens[$scopeEnd]['scope_condition'] !== $stackPtr
Chris@0 76 ) {
Chris@0 77 return;
Chris@0 78 }
Chris@0 79
Chris@0 80 // We need to actually find the first piece of content on this line,
Chris@0 81 // because if this is a method with tokens before it (public, static etc)
Chris@0 82 // or an if with an else before it, then we need to start the scope
Chris@0 83 // checking from there, rather than the current token.
Chris@0 84 $lineStart = ($stackPtr - 1);
Chris@0 85 for ($lineStart; $lineStart > 0; $lineStart--) {
Chris@0 86 if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) {
Chris@0 87 break;
Chris@0 88 }
Chris@0 89 }
Chris@0 90
Chris@0 91 $lineStart++;
Chris@0 92
Chris@0 93 $startColumn = 1;
Chris@0 94 if ($tokens[$lineStart]['code'] === T_WHITESPACE) {
Chris@0 95 $startColumn = $tokens[($lineStart + 1)]['column'];
Chris@0 96 } else if ($tokens[$lineStart]['code'] === T_INLINE_HTML) {
Chris@0 97 $trimmed = ltrim($tokens[$lineStart]['content']);
Chris@0 98 if ($trimmed === '') {
Chris@0 99 $startColumn = $tokens[($lineStart + 1)]['column'];
Chris@0 100 } else {
Chris@0 101 $startColumn = (strlen($tokens[$lineStart]['content']) - strlen($trimmed));
Chris@0 102 }
Chris@0 103 }
Chris@0 104
Chris@0 105 // Check that the closing brace is on it's own line.
Chris@0 106 $lastContent = $phpcsFile->findPrevious(
Chris@0 107 array(
Chris@0 108 T_WHITESPACE,
Chris@0 109 T_INLINE_HTML,
Chris@0 110 T_OPEN_TAG,
Chris@0 111 ),
Chris@0 112 ($scopeEnd - 1),
Chris@0 113 $scopeStart,
Chris@0 114 true
Chris@0 115 );
Chris@0 116
Chris@0 117 if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) {
Chris@0 118 // Only allow empty classes and methods.
Chris@0 119 if (($tokens[$tokens[$scopeEnd]['scope_condition']]['code'] !== T_CLASS
Chris@0 120 && $tokens[$tokens[$scopeEnd]['scope_condition']]['code'] !== T_INTERFACE
Chris@0 121 && in_array(T_CLASS, $tokens[$scopeEnd]['conditions']) === false
Chris@0 122 && in_array(T_INTERFACE, $tokens[$scopeEnd]['conditions']) === false)
Chris@0 123 || $tokens[$lastContent]['code'] !== T_OPEN_CURLY_BRACKET
Chris@0 124 ) {
Chris@0 125 $error = 'Closing brace must be on a line by itself';
Chris@0 126 $fix = $phpcsFile->addFixableError($error, $scopeEnd, 'Line');
Chris@0 127 if ($fix === true) {
Chris@0 128 $phpcsFile->fixer->addNewlineBefore($scopeEnd);
Chris@0 129 }
Chris@0 130 }
Chris@0 131
Chris@0 132 return;
Chris@0 133 }
Chris@0 134
Chris@0 135 // Check now that the closing brace is lined up correctly.
Chris@0 136 $lineStart = ($scopeEnd - 1);
Chris@0 137 for ($lineStart; $lineStart > 0; $lineStart--) {
Chris@0 138 if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) {
Chris@0 139 break;
Chris@0 140 }
Chris@0 141 }
Chris@0 142
Chris@0 143 $lineStart++;
Chris@0 144
Chris@0 145 $braceIndent = 0;
Chris@0 146 if ($tokens[$lineStart]['code'] === T_WHITESPACE) {
Chris@0 147 $braceIndent = ($tokens[($lineStart + 1)]['column'] - 1);
Chris@0 148 } else if ($tokens[$lineStart]['code'] === T_INLINE_HTML) {
Chris@0 149 $trimmed = ltrim($tokens[$lineStart]['content']);
Chris@0 150 if ($trimmed === '') {
Chris@0 151 $braceIndent = ($tokens[($lineStart + 1)]['column'] - 1);
Chris@0 152 } else {
Chris@0 153 $braceIndent = (strlen($tokens[$lineStart]['content']) - strlen($trimmed) - 1);
Chris@0 154 }
Chris@0 155 }
Chris@0 156
Chris@0 157 $fix = false;
Chris@0 158 if ($tokens[$stackPtr]['code'] === T_CASE
Chris@0 159 || $tokens[$stackPtr]['code'] === T_DEFAULT
Chris@0 160 ) {
Chris@0 161 // BREAK statements should be indented n spaces from the
Chris@0 162 // CASE or DEFAULT statement.
Chris@0 163 $expectedIndent = ($startColumn + $this->indent - 1);
Chris@0 164 if ($braceIndent !== $expectedIndent) {
Chris@0 165 $error = 'Case breaking statement indented incorrectly; expected %s spaces, found %s';
Chris@0 166 $data = array(
Chris@0 167 $expectedIndent,
Chris@0 168 $braceIndent,
Chris@0 169 );
Chris@0 170 $fix = $phpcsFile->addFixableError($error, $scopeEnd, 'BreakIndent', $data);
Chris@0 171 }
Chris@0 172 } else {
Chris@0 173 $expectedIndent = ($startColumn - 1);
Chris@0 174 if ($braceIndent !== $expectedIndent) {
Chris@0 175 $error = 'Closing brace indented incorrectly; expected %s spaces, found %s';
Chris@0 176 $data = array(
Chris@0 177 $expectedIndent,
Chris@0 178 $braceIndent,
Chris@0 179 );
Chris@0 180 $fix = $phpcsFile->addFixableError($error, $scopeEnd, 'Indent', $data);
Chris@0 181 }
Chris@0 182 }//end if
Chris@0 183
Chris@0 184 if ($fix === true) {
Chris@0 185 $spaces = str_repeat(' ', $expectedIndent);
Chris@0 186 if ($braceIndent === 0) {
Chris@0 187 $phpcsFile->fixer->addContentBefore($lineStart, $spaces);
Chris@0 188 } else {
Chris@0 189 $phpcsFile->fixer->replaceToken($lineStart, ltrim($tokens[$lineStart]['content']));
Chris@0 190 $phpcsFile->fixer->addContentBefore($lineStart, $spaces);
Chris@0 191 }
Chris@0 192 }
Chris@0 193
Chris@0 194 }//end process()
Chris@0 195
Chris@0 196
Chris@0 197 }//end class