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