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

« back to all changes in this revision

Viewing changes to PHP_CodeSniffer-1.5.4/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.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_FunctionCallSignatureSniff.
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-2014 Squiz Pty Ltd (ABN 77 084 670 600)
12
 
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13
 
 * @link      http://pear.php.net/package/PHP_CodeSniffer
14
 
 */
15
 
 
16
 
/**
17
 
 * PEAR_Sniffs_Functions_FunctionCallSignatureSniff.
18
 
 *
19
 
 * @category  PHP
20
 
 * @package   PHP_CodeSniffer
21
 
 * @author    Greg Sherwood <gsherwood@squiz.net>
22
 
 * @author    Marc McIntyre <mmcintyre@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.4
26
 
 * @link      http://pear.php.net/package/PHP_CodeSniffer
27
 
 */
28
 
class PEAR_Sniffs_Functions_FunctionCallSignatureSniff 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
 
     * If TRUE, multiple arguments can be defined per line in a multi-line call.
40
 
     *
41
 
     * @var bool
42
 
     */
43
 
    public $allowMultipleArguments = true;
44
 
 
45
 
    /**
46
 
     * How many spaces should follow the opening bracket.
47
 
     *
48
 
     * @var int
49
 
     */
50
 
    public $requiredSpacesAfterOpen = 0;
51
 
 
52
 
    /**
53
 
     * How many spaces should precede the closing bracket.
54
 
     *
55
 
     * @var int
56
 
     */
57
 
    public $requiredSpacesBeforeClose = 0;
58
 
 
59
 
 
60
 
    /**
61
 
     * Returns an array of tokens this test wants to listen for.
62
 
     *
63
 
     * @return array
64
 
     */
65
 
    public function register()
66
 
    {
67
 
        return array(T_STRING);
68
 
 
69
 
    }//end register()
70
 
 
71
 
 
72
 
    /**
73
 
     * Processes this test, when one of its tokens is encountered.
74
 
     *
75
 
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
76
 
     * @param int                  $stackPtr  The position of the current token
77
 
     *                                        in the stack passed in $tokens.
78
 
     *
79
 
     * @return void
80
 
     */
81
 
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
82
 
    {
83
 
        $this->requiredSpacesAfterOpen   = (int) $this->requiredSpacesAfterOpen;
84
 
        $this->requiredSpacesBeforeClose = (int) $this->requiredSpacesBeforeClose;
85
 
        $tokens = $phpcsFile->getTokens();
86
 
 
87
 
        // Find the next non-empty token.
88
 
        $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
89
 
 
90
 
        if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) {
91
 
            // Not a function call.
92
 
            return;
93
 
        }
94
 
 
95
 
        if (isset($tokens[$openBracket]['parenthesis_closer']) === false) {
96
 
            // Not a function call.
97
 
            return;
98
 
        }
99
 
 
100
 
        // Find the previous non-empty token.
101
 
        $search   = PHP_CodeSniffer_Tokens::$emptyTokens;
102
 
        $search[] = T_BITWISE_AND;
103
 
        $previous = $phpcsFile->findPrevious($search, ($stackPtr - 1), null, true);
104
 
        if ($tokens[$previous]['code'] === T_FUNCTION) {
105
 
            // It's a function definition, not a function call.
106
 
            return;
107
 
        }
108
 
 
109
 
        $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
110
 
 
111
 
        if (($stackPtr + 1) !== $openBracket) {
112
 
            // Checking this: $value = my_function[*](...).
113
 
            $error = 'Space before opening parenthesis of function call prohibited';
114
 
            $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeOpenBracket');
115
 
        }
116
 
 
117
 
        $next = $phpcsFile->findNext(T_WHITESPACE, ($closeBracket + 1), null, true);
118
 
        if ($tokens[$next]['code'] === T_SEMICOLON) {
119
 
            if (in_array($tokens[($closeBracket + 1)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) {
120
 
                $error = 'Space after closing parenthesis of function call prohibited';
121
 
                $phpcsFile->addError($error, $closeBracket, 'SpaceAfterCloseBracket');
122
 
            }
123
 
        }
124
 
 
125
 
        // Check if this is a single line or multi-line function call.
126
 
        if ($this->isMultiLineCall($phpcsFile, $stackPtr, $openBracket, $tokens) === true) {
127
 
            $this->processMultiLineCall($phpcsFile, $stackPtr, $openBracket, $tokens);
128
 
        } else {
129
 
            $this->processSingleLineCall($phpcsFile, $stackPtr, $openBracket, $tokens);
130
 
        }
131
 
 
132
 
    }//end process()
133
 
 
134
 
 
135
 
    /**
136
 
     * Processes single-line calls.
137
 
     *
138
 
     * @param PHP_CodeSniffer_File $phpcsFile   The file being scanned.
139
 
     * @param int                  $stackPtr    The position of the current token
140
 
     *                                          in the stack passed in $tokens.
141
 
     * @param int                  $openBracket The position of the opening bracket
142
 
     *                                          in the stack passed in $tokens.
143
 
     * @param array                $tokens      The stack of tokens that make up
144
 
     *                                          the file.
145
 
     *
146
 
     * @return void
147
 
     */
148
 
    public function isMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens)
149
 
    {
150
 
        $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
151
 
        if ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']) {
152
 
            return true;
153
 
        }
154
 
 
155
 
        return false;
156
 
 
157
 
    }//end isMultiLineCall()
158
 
 
159
 
 
160
 
    /**
161
 
     * Processes single-line calls.
162
 
     *
163
 
     * @param PHP_CodeSniffer_File $phpcsFile   The file being scanned.
164
 
     * @param int                  $stackPtr    The position of the current token
165
 
     *                                          in the stack passed in $tokens.
166
 
     * @param int                  $openBracket The position of the opening bracket
167
 
     *                                          in the stack passed in $tokens.
168
 
     * @param array                $tokens      The stack of tokens that make up
169
 
     *                                          the file.
170
 
     *
171
 
     * @return void
172
 
     */
173
 
    public function processSingleLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens)
174
 
    {
175
 
 
176
 
        $closer = $tokens[$openBracket]['parenthesis_closer'];
177
 
        if ($openBracket === ($closer - 1)) {
178
 
            return;
179
 
        }
180
 
 
181
 
        if ($this->requiredSpacesAfterOpen === 0 && $tokens[($openBracket + 1)]['code'] === T_WHITESPACE) {
182
 
            // Checking this: $value = my_function([*]...).
183
 
            $error = 'Space after opening parenthesis of function call prohibited';
184
 
            $phpcsFile->addError($error, $stackPtr, 'SpaceAfterOpenBracket');
185
 
        } else if ($this->requiredSpacesAfterOpen > 0) {
186
 
            $spaceAfterOpen = 0;
187
 
            if ($tokens[($openBracket + 1)]['code'] === T_WHITESPACE) {
188
 
                $spaceAfterOpen = strlen($tokens[($openBracket + 1)]['content']);
189
 
            }
190
 
 
191
 
            if ($spaceAfterOpen !== $this->requiredSpacesAfterOpen) {
192
 
                $error = 'Expected %s spaces after opening bracket; %s found';
193
 
                $data  = array(
194
 
                          $this->requiredSpacesAfterOpen,
195
 
                          $spaceAfterOpen,
196
 
                         );
197
 
                $phpcsFile->addError($error, $stackPtr, 'SpaceAfterOpenBracket', $data);
198
 
            }
199
 
        }
200
 
 
201
 
        // Checking this: $value = my_function(...[*]).
202
 
        $spaceBeforeClose = 0;
203
 
        if ($tokens[($closer - 1)]['code'] === T_WHITESPACE) {
204
 
            $spaceBeforeClose = strlen($tokens[($closer - 1)]['content']);
205
 
        }
206
 
 
207
 
        if ($spaceBeforeClose !== $this->requiredSpacesBeforeClose) {
208
 
            $error = 'Expected %s spaces before closing bracket; %s found';
209
 
            $data  = array(
210
 
                      $this->requiredSpacesBeforeClose,
211
 
                      $spaceBeforeClose,
212
 
                     );
213
 
            $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeCloseBracket', $data);
214
 
        }
215
 
 
216
 
    }//end processSingleLineCall()
217
 
 
218
 
 
219
 
    /**
220
 
     * Processes multi-line calls.
221
 
     *
222
 
     * @param PHP_CodeSniffer_File $phpcsFile   The file being scanned.
223
 
     * @param int                  $stackPtr    The position of the current token
224
 
     *                                          in the stack passed in $tokens.
225
 
     * @param int                  $openBracket The position of the openning bracket
226
 
     *                                          in the stack passed in $tokens.
227
 
     * @param array                $tokens      The stack of tokens that make up
228
 
     *                                          the file.
229
 
     *
230
 
     * @return void
231
 
     */
232
 
    public function processMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens)
233
 
    {
234
 
        // We need to work out how far indented the function
235
 
        // call itself is, so we can work out how far to
236
 
        // indent the arguments.
237
 
        $functionIndent = 0;
238
 
        for ($i = ($stackPtr - 1); $i >= 0; $i--) {
239
 
            if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) {
240
 
                $i++;
241
 
                break;
242
 
            }
243
 
        }
244
 
 
245
 
        if ($i > 0 && $tokens[$i]['code'] === T_WHITESPACE) {
246
 
            $functionIndent = strlen($tokens[$i]['content']);
247
 
        }
248
 
 
249
 
        // Each line between the parenthesis should be indented n spaces.
250
 
        $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
251
 
        $lastLine     = $tokens[$openBracket]['line'];
252
 
        for ($i = ($openBracket + 1); $i < $closeBracket; $i++) {
253
 
            // Skip nested function calls.
254
 
            if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) {
255
 
                $i        = $tokens[$i]['parenthesis_closer'];
256
 
                $lastLine = $tokens[$i]['line'];
257
 
                continue;
258
 
            }
259
 
 
260
 
            if ($tokens[$i]['line'] !== $lastLine) {
261
 
                $lastLine = $tokens[$i]['line'];
262
 
 
263
 
                // Ignore heredoc indentation.
264
 
                if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$heredocTokens) === true) {
265
 
                    continue;
266
 
                }
267
 
 
268
 
                // Ignore multi-line string indentation.
269
 
                if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) {
270
 
                    if ($tokens[$i]['code'] === $tokens[($i - 1)]['code']) {
271
 
                        continue;
272
 
                    }
273
 
                }
274
 
 
275
 
                // We changed lines, so this should be a whitespace indent token, but first make
276
 
                // sure it isn't a blank line because we don't need to check indent unless there
277
 
                // is actually some code to indent.
278
 
                if ($tokens[$i]['code'] === T_WHITESPACE) {
279
 
                    $nextCode = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), ($closeBracket + 1), true);
280
 
                    if ($tokens[$nextCode]['line'] !== $lastLine) {
281
 
                        $error = 'Empty lines are not allowed in multi-line function calls';
282
 
                        $phpcsFile->addError($error, $i, 'EmptyLine');
283
 
                        continue;
284
 
                    }
285
 
                } else {
286
 
                    $nextCode = $i;
287
 
                }
288
 
 
289
 
                // Check if the next line contains an object operator, if so rely on
290
 
                // the ObjectOperatorIndentSniff to test the indent.
291
 
                if ($tokens[$nextCode]['type'] === 'T_OBJECT_OPERATOR') {
292
 
                    continue;
293
 
                }
294
 
 
295
 
                if ($nextCode === $closeBracket) {
296
 
                    // Closing brace needs to be indented to the same level
297
 
                    // as the function call.
298
 
                    $expectedIndent = $functionIndent;
299
 
                } else {
300
 
                    $expectedIndent = ($functionIndent + $this->indent);
301
 
                }
302
 
 
303
 
                if ($tokens[$i]['code'] !== T_WHITESPACE) {
304
 
                    // Just check if it is a multi-line block comment. If so, we can
305
 
                    // calculate the indent from the whitespace before the content.
306
 
                    if ($tokens[$i]['code'] === T_COMMENT
307
 
                        && $tokens[($i - 1)]['code'] === T_COMMENT
308
 
                    ) {
309
 
                        $trimmed     = ltrim($tokens[$i]['content']);
310
 
                        $foundIndent = (strlen($tokens[$i]['content']) - strlen($trimmed));
311
 
                    } else {
312
 
                        $foundIndent = 0;
313
 
                    }
314
 
                } else {
315
 
                    $foundIndent = strlen($tokens[$i]['content']);
316
 
                }
317
 
 
318
 
                if ($expectedIndent !== $foundIndent) {
319
 
                    $error = 'Multi-line function call not indented correctly; expected %s spaces but found %s';
320
 
                    $data  = array(
321
 
                              $expectedIndent,
322
 
                              $foundIndent,
323
 
                             );
324
 
                    $phpcsFile->addError($error, $i, 'Indent', $data);
325
 
                }
326
 
            }//end if
327
 
 
328
 
            // Skip the rest of a closure.
329
 
            if ($tokens[$i]['code'] === T_CLOSURE) {
330
 
                $i        = $tokens[$i]['scope_closer'];
331
 
                $lastLine = $tokens[$i]['line'];
332
 
                continue;
333
 
            }
334
 
 
335
 
            // Skip the rest of a short array.
336
 
            if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) {
337
 
                $i        = $tokens[$i]['bracket_closer'];
338
 
                $lastLine = $tokens[$i]['line'];
339
 
                continue;
340
 
            }
341
 
 
342
 
            if ($this->allowMultipleArguments === false && $tokens[$i]['code'] === T_COMMA) {
343
 
                // Comma has to be the last token on the line.
344
 
                $next = $phpcsFile->findNext(array(T_WHITESPACE, T_COMMENT), ($i + 1), $closeBracket, true);
345
 
                if ($next !== false
346
 
                    && $tokens[$i]['line'] === $tokens[$next]['line']
347
 
                ) {
348
 
                    $error = 'Only one argument is allowed per line in a multi-line function call';
349
 
                    $phpcsFile->addError($error, $next, 'MultipleArguments');
350
 
                }
351
 
            }
352
 
        }//end for
353
 
 
354
 
        if ($tokens[($openBracket + 1)]['content'] !== $phpcsFile->eolChar) {
355
 
            $error = 'Opening parenthesis of a multi-line function call must be the last content on the line';
356
 
            $phpcsFile->addError($error, $stackPtr, 'ContentAfterOpenBracket');
357
 
        }
358
 
 
359
 
        $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBracket - 1), null, true);
360
 
        if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
361
 
            $error = 'Closing parenthesis of a multi-line function call must be on a line by itself';
362
 
            $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine');
363
 
        }
364
 
 
365
 
    }//end processMultiLineCall()
366
 
 
367
 
 
368
 
}//end class