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

« back to all changes in this revision

Viewing changes to PHP_CodeSniffer-1.5.5/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php

  • Committer: Package Import Robot
  • Author(s): David Prévot, Greg Sherwood, Alexey, Emily, David Prévot
  • Date: 2014-09-26 13:44:35 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20140926134435-wvjq16miqq4d60y0
Tags: 1.5.5-1
[ Greg Sherwood ]
* Improved closure support in Generic ScopeIndentSniff
* Improved indented PHP tag support in Generic ScopeIndentSniff
* Standards can now be located within hidden directories
 (further fix for bug #20323)
* Fixed bug #20373 : Inline comment sniff tab handling way
* Fixed bug #20378 : Report appended to existing file if no errors
  found in run
* Fixed bug #20381 : Invalid "Comment closer must be on a new line"
* PHP tokenizer no longer converts class/function names to special
  tokens types
* Fixed bug #20386 : Squiz.Commenting.ClassComment.SpacingBefore
  thrown if first block comment
* Squiz and PEAR FunctionCommentSnif now support _()
* PEAR ValidFunctionNameSniff no longer throws an error for _()
* Fixed bug #248 : FunctionCommentSniff expects ampersand on param name
* Fixed bug #248 in Squiz sniff as well
* Fixed bug #265 : False positives with type hints in ForbiddenFunctionsSniff
* Prepare for 1.5.5 release

[ Alexey ]
* Allowed single undersored methods and functions

[ Emily ]
* Added var_dump to discouraged functions sniff

[ David Prévot ]
* Revert "Add XS-Testsuite still needed for ci.d.n"
* Add self to uploaders
* Bump standards version to 3.9.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * PEAR_Sniffs_Functions_FunctionDeclarationSniff.
 
4
 *
 
5
 * PHP version 5
 
6
 *
 
7
 * @category  PHP
 
8
 * @package   PHP_CodeSniffer
 
9
 * @author    Greg Sherwood <gsherwood@squiz.net>
 
10
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
 
11
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 
12
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 
13
 */
 
14
 
 
15
/**
 
16
 * PEAR_Sniffs_Functions_FunctionDeclarationSniff.
 
17
 *
 
18
 * Ensure single and multi-line function declarations are defined correctly.
 
19
 *
 
20
 * @category  PHP
 
21
 * @package   PHP_CodeSniffer
 
22
 * @author    Greg Sherwood <gsherwood@squiz.net>
 
23
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
 
24
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 
25
 * @version   Release: 1.5.5
 
26
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 
27
 */
 
28
class PEAR_Sniffs_Functions_FunctionDeclarationSniff implements PHP_CodeSniffer_Sniff
 
29
{
 
30
 
 
31
    /**
 
32
     * The number of spaces code should be indented.
 
33
     *
 
34
     * @var int
 
35
     */
 
36
    public $indent = 4;
 
37
 
 
38
 
 
39
    /**
 
40
     * Returns an array of tokens this test wants to listen for.
 
41
     *
 
42
     * @return array
 
43
     */
 
44
    public function register()
 
45
    {
 
46
        return array(
 
47
                T_FUNCTION,
 
48
                T_CLOSURE,
 
49
               );
 
50
 
 
51
    }//end register()
 
52
 
 
53
 
 
54
    /**
 
55
     * Processes this test, when one of its tokens is encountered.
 
56
     *
 
57
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
 
58
     * @param int                  $stackPtr  The position of the current token
 
59
     *                                        in the stack passed in $tokens.
 
60
     *
 
61
     * @return void
 
62
     */
 
63
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 
64
    {
 
65
        $tokens = $phpcsFile->getTokens();
 
66
 
 
67
        $spaces = 0;
 
68
        if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) {
 
69
            $spaces = strlen($tokens[($stackPtr + 1)]['content']);
 
70
        }
 
71
 
 
72
        if ($spaces !== 1) {
 
73
            $error = 'Expected 1 space after FUNCTION keyword; %s found';
 
74
            $data  = array($spaces);
 
75
            $phpcsFile->addError($error, $stackPtr, 'SpaceAfterFunction', $data);
 
76
        }
 
77
 
 
78
        // Must be one space before and after USE keyword for closures.
 
79
        $openBracket  = $tokens[$stackPtr]['parenthesis_opener'];
 
80
        $closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
 
81
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
 
82
            $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']);
 
83
            if ($use !== false) {
 
84
                if ($tokens[($use + 1)]['code'] !== T_WHITESPACE) {
 
85
                    $length = 0;
 
86
                } else if ($tokens[($use + 1)]['content'] === "\t") {
 
87
                    $length = '\t';
 
88
                } else {
 
89
                    $length = strlen($tokens[($use + 1)]['content']);
 
90
                }
 
91
 
 
92
                if ($length !== 1) {
 
93
                    $error = 'Expected 1 space after USE keyword; found %s';
 
94
                    $data  = array($length);
 
95
                    $phpcsFile->addError($error, $use, 'SpaceAfterUse', $data);
 
96
                }
 
97
 
 
98
                if ($tokens[($use - 1)]['code'] !== T_WHITESPACE) {
 
99
                    $length = 0;
 
100
                } else if ($tokens[($use - 1)]['content'] === "\t") {
 
101
                    $length = '\t';
 
102
                } else {
 
103
                    $length = strlen($tokens[($use - 1)]['content']);
 
104
                }
 
105
 
 
106
                if ($length !== 1) {
 
107
                    $error = 'Expected 1 space before USE keyword; found %s';
 
108
                    $data  = array($length);
 
109
                    $phpcsFile->addError($error, $use, 'SpaceBeforeUse', $data);
 
110
                }
 
111
            }//end if
 
112
        }//end if
 
113
 
 
114
        // Check if this is a single line or multi-line declaration.
 
115
        $singleLine = true;
 
116
        if ($tokens[$openBracket]['line'] === $tokens[$closeBracket]['line']) {
 
117
            // Closures may use the USE keyword and so be multi-line in this way.
 
118
            if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
 
119
                if ($use !== false) {
 
120
                    // If the opening and closing parenthesis of the use statement
 
121
                    // are also on the same line, this is a single line declaration.
 
122
                    $open  = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1));
 
123
                    $close = $tokens[$open]['parenthesis_closer'];
 
124
                    if ($tokens[$open]['line'] !== $tokens[$close]['line']) {
 
125
                        $singleLine = false;
 
126
                    }
 
127
                }
 
128
            }
 
129
        } else {
 
130
            $singleLine = false;
 
131
        }
 
132
 
 
133
        if ($singleLine === true) {
 
134
            $this->processSingleLineDeclaration($phpcsFile, $stackPtr, $tokens);
 
135
        } else {
 
136
            $this->processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens);
 
137
        }
 
138
 
 
139
    }//end process()
 
140
 
 
141
 
 
142
    /**
 
143
     * Processes single-line declarations.
 
144
     *
 
145
     * Just uses the Generic BSD-Allman brace sniff.
 
146
     *
 
147
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
 
148
     * @param int                  $stackPtr  The position of the current token
 
149
     *                                        in the stack passed in $tokens.
 
150
     * @param array                $tokens    The stack of tokens that make up
 
151
     *                                        the file.
 
152
     *
 
153
     * @return void
 
154
     */
 
155
    public function processSingleLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens)
 
156
    {
 
157
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
 
158
            if (class_exists('Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff', true) === false) {
 
159
                throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff not found');
 
160
            }
 
161
 
 
162
            $sniff = new Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff();
 
163
        } else {
 
164
            if (class_exists('Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff', true) === false) {
 
165
                throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff not found');
 
166
            }
 
167
 
 
168
            $sniff = new Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff();
 
169
        }
 
170
 
 
171
        $sniff->process($phpcsFile, $stackPtr);
 
172
 
 
173
    }//end processSingleLineDeclaration()
 
174
 
 
175
 
 
176
    /**
 
177
     * Processes mutli-line declarations.
 
178
     *
 
179
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
 
180
     * @param int                  $stackPtr  The position of the current token
 
181
     *                                        in the stack passed in $tokens.
 
182
     * @param array                $tokens    The stack of tokens that make up
 
183
     *                                        the file.
 
184
     *
 
185
     * @return void
 
186
     */
 
187
    public function processMultiLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens)
 
188
    {
 
189
        // We need to work out how far indented the function
 
190
        // declaration itself is, so we can work out how far to
 
191
        // indent parameters.
 
192
        $functionIndent = 0;
 
193
        for ($i = ($stackPtr - 1); $i >= 0; $i--) {
 
194
            if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) {
 
195
                $i++;
 
196
                break;
 
197
            }
 
198
        }
 
199
 
 
200
        if ($tokens[$i]['code'] === T_WHITESPACE) {
 
201
            $functionIndent = strlen($tokens[$i]['content']);
 
202
        }
 
203
 
 
204
        // The closing parenthesis must be on a new line, even
 
205
        // when checking abstract function definitions.
 
206
        $closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
 
207
        $prev = $phpcsFile->findPrevious(
 
208
            T_WHITESPACE,
 
209
            ($closeBracket - 1),
 
210
            null,
 
211
            true
 
212
        );
 
213
 
 
214
        if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) {
 
215
            if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
 
216
                $error = 'The closing parenthesis of a multi-line function declaration must be on a new line';
 
217
                $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine');
 
218
            }
 
219
        }
 
220
 
 
221
        // If this is a closure and is using a USE statement, the closing
 
222
        // parenthesis we need to look at from now on is the closing parenthesis
 
223
        // of the USE statement.
 
224
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
 
225
            $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']);
 
226
            if ($use !== false) {
 
227
                $open         = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1));
 
228
                $closeBracket = $tokens[$open]['parenthesis_closer'];
 
229
 
 
230
                $prev = $phpcsFile->findPrevious(
 
231
                    T_WHITESPACE,
 
232
                    ($closeBracket - 1),
 
233
                    null,
 
234
                    true
 
235
                );
 
236
 
 
237
                if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) {
 
238
                    if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
 
239
                        $error = 'The closing parenthesis of a multi-line use declaration must be on a new line';
 
240
                        $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine');
 
241
                    }
 
242
                }
 
243
            }//end if
 
244
        }//end if
 
245
 
 
246
        // Each line between the parenthesis should be indented 4 spaces.
 
247
        $openBracket  = $tokens[$stackPtr]['parenthesis_opener'];
 
248
        $lastLine     = $tokens[$openBracket]['line'];
 
249
        for ($i = ($openBracket + 1); $i < $closeBracket; $i++) {
 
250
            if ($tokens[$i]['line'] !== $lastLine) {
 
251
                if ($i === $tokens[$stackPtr]['parenthesis_closer']
 
252
                    || ($tokens[$i]['code'] === T_WHITESPACE
 
253
                    && (($i + 1) === $closeBracket
 
254
                    || ($i + 1) === $tokens[$stackPtr]['parenthesis_closer']))
 
255
                ) {
 
256
                    // Closing braces need to be indented to the same level
 
257
                    // as the function.
 
258
                    $expectedIndent = $functionIndent;
 
259
                } else {
 
260
                    $expectedIndent = ($functionIndent + $this->indent);
 
261
                }
 
262
 
 
263
                // We changed lines, so this should be a whitespace indent token.
 
264
                if ($tokens[$i]['code'] !== T_WHITESPACE) {
 
265
                    $foundIndent = 0;
 
266
                } else {
 
267
                    $foundIndent = strlen($tokens[$i]['content']);
 
268
                }
 
269
 
 
270
                if ($expectedIndent !== $foundIndent) {
 
271
                    $error = 'Multi-line function declaration not indented correctly; expected %s spaces but found %s';
 
272
                    $data  = array(
 
273
                              $expectedIndent,
 
274
                              $foundIndent,
 
275
                             );
 
276
                    $phpcsFile->addError($error, $i, 'Indent', $data);
 
277
                }
 
278
 
 
279
                $lastLine = $tokens[$i]['line'];
 
280
            }//end if
 
281
 
 
282
            if ($tokens[$i]['code'] === T_ARRAY || $tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) {
 
283
                // Skip arrays as they have their own indentation rules.
 
284
                if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) {
 
285
                    $i = $tokens[$i]['bracket_closer'];
 
286
                } else {
 
287
                    $i = $tokens[$i]['parenthesis_closer'];
 
288
                }
 
289
 
 
290
                $lastLine = $tokens[$i]['line'];
 
291
                continue;
 
292
            }
 
293
        }//end for
 
294
 
 
295
        if (isset($tokens[$stackPtr]['scope_opener']) === true) {
 
296
            // The openning brace needs to be one space away
 
297
            // from the closing parenthesis.
 
298
            $next = $tokens[($closeBracket + 1)];
 
299
            if ($next['code'] !== T_WHITESPACE) {
 
300
                $length = 0;
 
301
            } else if ($next['content'] === $phpcsFile->eolChar) {
 
302
                $length = -1;
 
303
            } else {
 
304
                $length = strlen($next['content']);
 
305
            }
 
306
 
 
307
            if ($length !== 1) {
 
308
                $data = array($length);
 
309
                $code = 'SpaceBeforeOpenBrace';
 
310
 
 
311
                $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found ';
 
312
                if ($length === -1) {
 
313
                    $error .= 'newline';
 
314
                    $code   = 'NewlineBeforeOpenBrace';
 
315
                } else {
 
316
                    $error .= '%s spaces';
 
317
                }
 
318
 
 
319
                $phpcsFile->addError($error, ($closeBracket + 1), $code, $data);
 
320
                return;
 
321
            }
 
322
 
 
323
            // And just in case they do something funny before the brace...
 
324
            $next = $phpcsFile->findNext(
 
325
                T_WHITESPACE,
 
326
                ($closeBracket + 1),
 
327
                null,
 
328
                true
 
329
            );
 
330
 
 
331
            if ($next !== false && $tokens[$next]['code'] !== T_OPEN_CURLY_BRACKET) {
 
332
                $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration';
 
333
                $phpcsFile->addError($error, $next, 'NoSpaceBeforeOpenBrace');
 
334
            }
 
335
        }//end if
 
336
 
 
337
    }//end processMultiLineDeclaration()
 
338
 
 
339
 
 
340
}//end class
 
341
 
 
342
?>