Subversion Repositories Applications.framework

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 aurelien 1
<?php
2
/**
3
 * This file is part of the CodeAnalysis addon for PHP_CodeSniffer.
4
 *
5
 * PHP version 5
6
 *
7
 * @category  PHP
8
 * @package   PHP_CodeSniffer
9
 * @author    Greg Sherwood <gsherwood@squiz.net>
10
 * @author    Manuel Pichler <mapi@manuel-pichler.de>
11
 * @copyright 2007-2008 Manuel Pichler. All rights reserved.
12
 * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
13
 * @version   CVS: $Id: JumbledIncrementerSniff.php,v 1.1 2008/02/06 02:38:36 squiz Exp $
14
 * @link      http://pear.php.net/package/PHP_CodeSniffer
15
 */
16
 
17
/**
18
 * Detects incrementer jumbling in for loops.
19
 *
20
 * This rule is based on the PMD rule catalog. The jumbling incrementer sniff
21
 * detects the usage of one and the same incrementer into an outer and an inner
22
 * loop. Even it is intended this is confusing code.
23
 *
24
 * <code>
25
 * class Foo
26
 * {
27
 *     public function bar($x)
28
 *     {
29
 *         for ($i = 0; $i < 10; $i++)
30
 *         {
31
 *             for ($k = 0; $k < 20; $i++)
32
 *             {
33
 *                 echo 'Hello';
34
 *             }
35
 *         }
36
 *     }
37
 * }
38
 * </code>
39
 *
40
 * @category  PHP
41
 * @package   PHP_CodeSniffer
42
 * @author    Manuel Pichler <mapi@manuel-pichler.de>
43
 * @copyright 2007-2008 Manuel Pichler. All rights reserved.
44
 * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
45
 * @version   Release: 1.2.0RC1
46
 * @link      http://pear.php.net/package/PHP_CodeSniffer
47
 */
48
class Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff implements PHP_CodeSniffer_Sniff
49
{
50
 
51
 
52
    /**
53
     * Registers the tokens that this sniff wants to listen for.
54
     *
55
     * @return array(integer)
56
     */
57
    public function register()
58
    {
59
        return array(T_FOR);
60
 
61
    }//end register()
62
 
63
 
64
    /**
65
     * Processes this test, when one of its tokens is encountered.
66
     *
67
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
68
     * @param int                  $stackPtr  The position of the current token
69
     *                                        in the stack passed in $tokens.
70
     *
71
     * @return void
72
     */
73
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
74
    {
75
        $tokens = $phpcsFile->getTokens();
76
        $token  = $tokens[$stackPtr];
77
 
78
        // Skip for-loop without body.
79
        if (isset($token['scope_opener']) === false) {
80
            return;
81
        }
82
 
83
        // Find incrementors for outer loop.
84
        $outer = $this->findIncrementers($tokens, $token);
85
 
86
        // Skip if empty.
87
        if (count($outer) === 0) {
88
            return;
89
        }
90
 
91
        // Find nested for loops.
92
        $start = ++$token['scope_opener'];
93
        $end   = --$token['scope_closer'];
94
 
95
        for (; $start <= $end; ++$start) {
96
            if ($tokens[$start]['code'] !== T_FOR) {
97
                continue;
98
            }
99
 
100
            $inner = $this->findIncrementers($tokens, $tokens[$start]);
101
            $diff  = array_intersect($outer, $inner);
102
 
103
            if (count($diff) !== 0) {
104
                $error = sprintf('Loop incrementor (%s) jumbling with inner loop', join(', ', $diff));
105
                $phpcsFile->addWarning($error, $stackPtr);
106
            }
107
        }
108
 
109
    }//end process()
110
 
111
 
112
    /**
113
     * Get all used variables in the incrementer part of a for statement.
114
     *
115
     * @param array(integer=>array) $tokens Array with all code sniffer tokens.
116
     * @param array(string=>mixed)  $token  Current for loop token
117
     *
118
     * @return array(string) List of all found incrementer variables.
119
     */
120
    protected function findIncrementers(array $tokens, array $token)
121
    {
122
        // Skip invalid statement.
123
        if (isset($token['parenthesis_opener']) === false) {
124
            return array();
125
        }
126
 
127
        $start = ++$token['parenthesis_opener'];
128
        $end   = --$token['parenthesis_closer'];
129
 
130
        $incrementers = array();
131
        $semicolons   = 0;
132
        for ($next = $start; $next <= $end; ++$next) {
133
            $code = $tokens[$next]['code'];
134
            if ($code === T_SEMICOLON) {
135
                ++$semicolons;
136
            } else if ($semicolons === 2 && $code === T_VARIABLE) {
137
                $incrementers[] = $tokens[$next]['content'];
138
            }
139
        }
140
 
141
        return $incrementers;
142
 
143
    }//end findIncrementers()
144
 
145
 
146
}//end class
147
 
148
?>