~ubuntu-branches/ubuntu/vivid/php-codesniffer/vivid

« back to all changes in this revision

Viewing changes to PHP_CodeSniffer-1.3.4/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php

  • Committer: Package Import Robot
  • Author(s): Thomas Goirand
  • Date: 2012-05-31 16:37:24 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20120531163724-u6aiaubu8ks5dh5z
Tags: 1.3.4-0.1
* Non-maintainer upload.
* New upstream release (Closes: #599617, #634825).
* Swtiched debian/copyright to format 1.0 (rewrite was needed anyway, as the
upstream license changed).
* Switched package to pkg-php-tools and debhelper 8 sequencer.
* Now running unit tests at build time (so depends on phpunit (>= 3.6)).
* Section is now PHP.
* Added missing Build-Depends-Indep: php-pear.
* Added missing ${misc:Depends}.
* Added Vcs fields.
* Added homepage field.
* Reviewed short and long description.
* Added dependency on php-timer.
* Standards-Version: is now 3.9.3 (lots of changes, see above...).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff.
 
4
 *
 
5
 * PHP version 5
 
6
 *
 
7
 * @category  PHP
 
8
 * @package   PHP_CodeSniffer
 
9
 * @author    Greg Sherwood <gsherwood@squiz.net>
 
10
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 
11
 * @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
 
12
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 
13
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 
14
 */
 
15
 
 
16
/**
 
17
 * Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff.
 
18
 *
 
19
 * Ensures all the breaks and cases are aligned correctly according to their
 
20
 * parent switch's alignment and enforces other switch formatting.
 
21
 *
 
22
 * @category  PHP
 
23
 * @package   PHP_CodeSniffer
 
24
 * @author    Greg Sherwood <gsherwood@squiz.net>
 
25
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 
26
 * @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
 
27
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 
28
 * @version   Release: 1.3.4
 
29
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 
30
 */
 
31
class Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff implements PHP_CodeSniffer_Sniff
 
32
{
 
33
 
 
34
    /**
 
35
     * A list of tokenizers this sniff supports.
 
36
     *
 
37
     * @var array
 
38
     */
 
39
    public $supportedTokenizers = array(
 
40
                                   'PHP',
 
41
                                   'JS',
 
42
                                  );
 
43
 
 
44
 
 
45
    /**
 
46
     * Returns an array of tokens this test wants to listen for.
 
47
     *
 
48
     * @return array
 
49
     */
 
50
    public function register()
 
51
    {
 
52
        return array(T_SWITCH);
 
53
 
 
54
    }//end register()
 
55
 
 
56
 
 
57
    /**
 
58
     * Processes this test, when one of its tokens is encountered.
 
59
     *
 
60
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
 
61
     * @param int                  $stackPtr  The position of the current token in the
 
62
     *                                        stack passed in $tokens.
 
63
     *
 
64
     * @return void
 
65
     */
 
66
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 
67
    {
 
68
        $tokens = $phpcsFile->getTokens();
 
69
 
 
70
        // We can't process SWITCH statements unless we know where they start and end.
 
71
        if (isset($tokens[$stackPtr]['scope_opener']) === false
 
72
            || isset($tokens[$stackPtr]['scope_closer']) === false
 
73
        ) {
 
74
            return;
 
75
        }
 
76
 
 
77
        $switch        = $tokens[$stackPtr];
 
78
        $nextCase      = $stackPtr;
 
79
        $caseAlignment = ($switch['column'] + 4);
 
80
        $caseCount     = 0;
 
81
        $foundDefault  = false;
 
82
 
 
83
        while (($nextCase = $phpcsFile->findNext(array(T_CASE, T_DEFAULT, T_SWITCH), ($nextCase + 1), $switch['scope_closer'])) !== false) {
 
84
            // Skip nested SWITCH statements; they are handled on their own.
 
85
            if ($tokens[$nextCase]['code'] === T_SWITCH) {
 
86
                $nextCase = $tokens[$nextCase]['scope_closer'];
 
87
                continue;
 
88
            }
 
89
 
 
90
            if ($tokens[$nextCase]['code'] === T_DEFAULT) {
 
91
                $type         = 'Default';
 
92
                $foundDefault = true;
 
93
            } else {
 
94
                $type = 'Case';
 
95
                $caseCount++;
 
96
            }
 
97
 
 
98
            if ($tokens[$nextCase]['content'] !== strtolower($tokens[$nextCase]['content'])) {
 
99
                $expected = strtolower($tokens[$nextCase]['content']);
 
100
                $error    = strtoupper($type).' keyword must be lowercase; expected "%s" but found "%s"';
 
101
                $data     = array(
 
102
                             $expected,
 
103
                             $tokens[$nextCase]['content'],
 
104
                            );
 
105
                $phpcsFile->addError($error, $nextCase, $type.'NotLower', $data);
 
106
            }
 
107
 
 
108
            if ($tokens[$nextCase]['column'] !== $caseAlignment) {
 
109
                $error = strtoupper($type).' keyword must be indented 4 spaces from SWITCH keyword';
 
110
                $phpcsFile->addError($error, $nextCase, $type.'Indent');
 
111
            }
 
112
 
 
113
            if ($type === 'Case'
 
114
                && ($tokens[($nextCase + 1)]['type'] !== 'T_WHITESPACE'
 
115
                || $tokens[($nextCase + 1)]['content'] !== ' ')
 
116
            ) {
 
117
                $error = 'CASE keyword must be followed by a single space';
 
118
                $phpcsFile->addError($error, $nextCase, 'SpacingAfterCase');
 
119
            }
 
120
 
 
121
            $opener = $tokens[$nextCase]['scope_opener'];
 
122
            if ($tokens[($opener - 1)]['type'] === 'T_WHITESPACE') {
 
123
                $error = 'There must be no space before the colon in a '.strtoupper($type).' statement';
 
124
                $phpcsFile->addError($error, $nextCase, 'SpaceBeforeColon'.$type);
 
125
            }
 
126
 
 
127
            $nextBreak = $tokens[$nextCase]['scope_closer'];
 
128
            if ($tokens[$nextBreak]['code'] === T_BREAK) {
 
129
                if ($tokens[$nextBreak]['scope_condition'] === $nextCase) {
 
130
                    // Only need to check a couple of things once, even if the
 
131
                    // break is shared between multiple case statements, or even
 
132
                    // the default case.
 
133
                    if ($tokens[$nextBreak]['column'] !== $caseAlignment) {
 
134
                        $error = 'BREAK statement must be indented 4 spaces from SWITCH keyword';
 
135
                        $phpcsFile->addError($error, $nextBreak, 'BreakIndent');
 
136
                    }
 
137
 
 
138
                    $breakLine = $tokens[$nextBreak]['line'];
 
139
                    $prevLine  = 0;
 
140
                    for ($i = ($nextBreak - 1); $i > $stackPtr; $i--) {
 
141
                        if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
 
142
                            $prevLine = $tokens[$i]['line'];
 
143
                            break;
 
144
                        }
 
145
                    }
 
146
 
 
147
                    if ($prevLine !== ($breakLine - 1)) {
 
148
                        $error = 'Blank lines are not allowed before BREAK statements';
 
149
                        $phpcsFile->addError($error, $nextBreak, 'SpacingBeforeBreak');
 
150
                    }
 
151
 
 
152
                    $breakLine = $tokens[$nextBreak]['line'];
 
153
                    $nextLine  = $tokens[$tokens[$stackPtr]['scope_closer']]['line'];
 
154
                    $semicolon = $phpcsFile->findNext(T_SEMICOLON, $nextBreak);
 
155
                    for ($i = ($semicolon + 1); $i < $tokens[$stackPtr]['scope_closer']; $i++) {
 
156
                        if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
 
157
                            $nextLine = $tokens[$i]['line'];
 
158
                            break;
 
159
                        }
 
160
                    }
 
161
 
 
162
                    if ($type === 'Case') {
 
163
                        // Ensure the BREAK statement is followed by
 
164
                        // a single blank line, or the end switch brace.
 
165
                        if ($nextLine !== ($breakLine + 2) && $i !== $tokens[$stackPtr]['scope_closer']) {
 
166
                            $error = 'BREAK statements must be followed by a single blank line';
 
167
                            $phpcsFile->addError($error, $nextBreak, 'SpacingAfterBreak');
 
168
                        }
 
169
                    } else {
 
170
                        // Ensure the BREAK statement is not followed by a blank line.
 
171
                        if ($nextLine !== ($breakLine + 1)) {
 
172
                            $error = 'Blank lines are not allowed after the DEFAULT case\'s BREAK statement';
 
173
                            $phpcsFile->addError($error, $nextBreak, 'SpacingAfterDefaultBreak');
 
174
                        }
 
175
                    }
 
176
 
 
177
                    $caseLine = $tokens[$nextCase]['line'];
 
178
                    $nextLine = $tokens[$nextBreak]['line'];
 
179
                    for ($i = ($opener + 1); $i < $nextBreak; $i++) {
 
180
                        if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
 
181
                            $nextLine = $tokens[$i]['line'];
 
182
                            break;
 
183
                        }
 
184
                    }
 
185
 
 
186
                    if ($nextLine !== ($caseLine + 1)) {
 
187
                        $error = 'Blank lines are not allowed after '.strtoupper($type).' statements';
 
188
                        $phpcsFile->addError($error, $nextCase, 'SpacingAfter'.$type);
 
189
                    }
 
190
                }//end if
 
191
 
 
192
                if ($type === 'Case') {
 
193
                    // Ensure empty CASE statements are not allowed.
 
194
                    // They must have some code content in them. A comment is not enough.
 
195
                    $foundContent = false;
 
196
                    for ($i = ($tokens[$nextCase]['scope_opener'] + 1); $i < $nextBreak; $i++) {
 
197
                        if ($tokens[$i]['code'] === T_CASE) {
 
198
                            $i = $tokens[$i]['scope_opener'];
 
199
                            continue;
 
200
                        }
 
201
 
 
202
                        if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
 
203
                            $foundContent = true;
 
204
                            break;
 
205
                        }
 
206
                    }
 
207
 
 
208
                    if ($foundContent === false) {
 
209
                        $error = 'Empty CASE statements are not allowed';
 
210
                        $phpcsFile->addError($error, $nextCase, 'EmptyCase');
 
211
                    }
 
212
                } else {
 
213
                    // Ensure empty DEFAULT statements are not allowed.
 
214
                    // They must (at least) have a comment describing why
 
215
                    // the default case is being ignored.
 
216
                    $foundContent = false;
 
217
                    for ($i = ($tokens[$nextCase]['scope_opener'] + 1); $i < $nextBreak; $i++) {
 
218
                        if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
 
219
                            $foundContent = true;
 
220
                            break;
 
221
                        }
 
222
                    }
 
223
 
 
224
                    if ($foundContent === false) {
 
225
                        $error = 'Comment required for empty DEFAULT case';
 
226
                        $phpcsFile->addError($error, $nextCase, 'EmptyDefault');
 
227
                    }
 
228
                }//end if
 
229
            } else if ($type === 'Default') {
 
230
                $error = 'DEFAULT case must have a BREAK statement';
 
231
                $phpcsFile->addError($error, $nextCase, 'DefaultNoBreak');
 
232
            }//end if
 
233
        }//end while
 
234
 
 
235
        if ($foundDefault === false) {
 
236
            $error = 'All SWITCH statements must contain a DEFAULT case';
 
237
            $phpcsFile->addError($error, $stackPtr, 'MissingDefault');
 
238
        }
 
239
 
 
240
        if ($tokens[$switch['scope_closer']]['column'] !== $switch['column']) {
 
241
            $error = 'Closing brace of SWITCH statement must be aligned with SWITCH keyword';
 
242
            $phpcsFile->addError($error, $switch['scope_closer'], 'CloseBraceAlign');
 
243
        }
 
244
 
 
245
        if ($caseCount === 0) {
 
246
            $error = 'SWITCH statements must contain at least one CASE statement';
 
247
            $phpcsFile->addError($error, $stackPtr, 'MissingCase');
 
248
        }
 
249
 
 
250
    }//end process()
 
251
 
 
252
 
 
253
}//end class
 
254
 
 
255
?>