Completed
Pull Request — master (#291)
by Juliette
02:26
created

getErrorInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
1
<?php
2
/**
3
 * PHPCompatibility_Sniffs_PHP_NewKeywordsSniff.
4
 *
5
 * PHP version 5.5
6
 *
7
 * @category  PHP
8
 * @package   PHPCompatibility
9
 * @author    Wim Godden <[email protected]>
10
 * @copyright 2013 Cu.be Solutions bvba
11
 */
12
13
/**
14
 * PHPCompatibility_Sniffs_PHP_NewClassesSniff.
15
 *
16
 * @category  PHP
17
 * @package   PHPCompatibility
18
 * @author    Wim Godden <[email protected]>
19
 * @version   1.0.0
20
 * @copyright 2013 Cu.be Solutions bvba
21
 */
22
class PHPCompatibility_Sniffs_PHP_NewKeywordsSniff
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
23
    extends PHPCompatibility_AbstractNewFeatureSniff
0 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
24
{
25
26
    /**
27
     * A list of new keywords, not present in older versions.
28
     *
29
     * The array lists : version number with false (not present) or true (present).
30
     * If's sufficient to list the last version which did not contain the keyword.
31
     *
32
     * Description will be used as part of the error message.
33
     * Condition is an array of valid scope conditions to check for.
34
     * If you need a condition of a different type, make sure to add the appropriate
35
     * logic for it as well as this will not resolve itself automatically.
36
     *
37
     * @var array(string => array(string => int|string|null))
38
     */
39
    protected $newKeywords = array(
40
                                        'T_HALT_COMPILER' => array(
41
                                            '5.0' => false,
42
                                            '5.1' => true,
43
                                            'description' => '"__halt_compiler" keyword'
44
                                        ),
45
                                        'T_CONST' => array(
46
                                            '5.2' => false,
47
                                            '5.3' => true,
48
                                            'description' => '"const" keyword',
49
                                            'condition' => array(T_CLASS), // Keyword is only new when not in class context.
50
                                        ),
51
                                        'T_CALLABLE' => array(
52
                                            '5.3' => false,
53
                                            '5.4' => true,
54
                                            'description' => '"callable" keyword',
55
                                            'content' => 'callable',
56
                                        ),
57
                                        'T_DIR' => array(
58
                                            '5.2' => false,
59
                                            '5.3' => true,
60
                                            'description' => '__DIR__ magic constant',
61
                                            'content' => '__DIR__',
62
                                        ),
63
                                        'T_GOTO' => array(
64
                                            '5.2' => false,
65
                                            '5.3' => true,
66
                                            'description' => '"goto" keyword',
67
                                            'content' => 'goto',
68
                                        ),
69
                                        'T_INSTEADOF' => array(
70
                                            '5.3' => false,
71
                                            '5.4' => true,
72
                                            'description' => '"insteadof" keyword (for traits)',
73
                                            'content' => 'insteadof',
74
                                        ),
75
                                        'T_NAMESPACE' => array(
76
                                            '5.2' => false,
77
                                            '5.3' => true,
78
                                            'description' => '"namespace" keyword',
79
                                            'content' => 'namespace',
80
                                        ),
81
                                        'T_NS_C' => array(
82
                                            '5.2' => false,
83
                                            '5.3' => true,
84
                                            'description' => '__NAMESPACE__ magic constant',
85
                                            'content' => '__NAMESPACE__',
86
                                        ),
87
                                        'T_USE' => array(
88
                                            '5.2' => false,
89
                                            '5.3' => true,
90
                                            'description' => '"use" keyword (for traits/namespaces/anonymous functions)'
91
                                        ),
92
                                        'T_TRAIT' => array(
93
                                            '5.3' => false,
94
                                            '5.4' => true,
95
                                            'description' => '"trait" keyword',
96
                                            'content' => 'trait',
97
                                        ),
98
                                        'T_TRAIT_C' => array(
99
                                            '5.3' => false,
100
                                            '5.4' => true,
101
                                            'description' => '__TRAIT__ magic constant',
102
                                            'content' => '__TRAIT__',
103
                                        ),
104
                                        'T_YIELD' => array(
105
                                            '5.4' => false,
106
                                            '5.5' => true,
107
                                            'description' => '"yield" keyword (for generators)',
108
                                            'content' => 'yield',
109
                                        ),
110
                                        'T_FINALLY' => array(
111
                                            '5.4' => false,
112
                                            '5.5' => true,
113
                                            'description' => '"finally" keyword (in exception handling)',
114
                                            'content' => 'finally',
115
                                        ),
116
                                        'T_START_NOWDOC' => array(
117
                                            '5.2' => false,
118
                                            '5.3' => true,
119
                                            'description' => 'nowdoc functionality',
120
                                        ),
121
                                        'T_END_NOWDOC' => array(
122
                                            '5.2' => false,
123
                                            '5.3' => true,
124
                                            'description' => 'nowdoc functionality',
125
                                        ),
126
                                    );
127
128
    /**
129
     * Translation table for T_STRING tokens.
130
     *
131
     * Will be set up from the register() method.
132
     *
133
     * @var array(string => string)
134
     */
135
    protected $translateContentToToken = array();
136
137
138
    /**
139
     * Returns an array of tokens this test wants to listen for.
140
     *
141
     * @return array
142
     */
143
    public function register()
144
    {
145
        $tokens    = array();
146
        $translate = array();
147
        foreach ($this->newKeywords as $token => $versions) {
148
            if (defined($token)) {
149
                $tokens[] = constant($token);
150
            }
151
            if (isset($versions['content'])) {
152
                $translate[$versions['content']] = $token;
153
            }
154
        }
155
156
        /*
157
         * Deal with tokens not recognized by the PHP version the sniffer is run
158
         * under and (not correctly) compensated for by PHPCS.
159
         */
160
        if (empty($translate) === false) {
161
            $this->translateContentToToken = $translate;
162
            $tokens[] = T_STRING;
163
        }
164
165
        return $tokens;
166
167
    }//end register()
168
169
170
    /**
171
     * Processes this test, when one of its tokens is encountered.
172
     *
173
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
174
     * @param int                  $stackPtr  The position of the current token in
175
     *                                        the stack passed in $tokens.
176
     *
177
     * @return void
178
     */
179
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
180
    {
181
        $tokens    = $phpcsFile->getTokens();
182
        $tokenType = $tokens[$stackPtr]['type'];
183
184
        // Translate T_STRING token if necessary.
185
        if ($tokens[$stackPtr]['type'] === 'T_STRING') {
186
            $content = $tokens[$stackPtr]['content'];
187
            if (isset($this->translateContentToToken[$content]) === false) {
188
                // Not one of the tokens we're looking for.
189
                return;
190
            }
191
192
            $tokenType = $this->translateContentToToken[$content];
193
        }
194
195
        if (isset($this->newKeywords[$tokenType]) === false) {
196
            return;
197
        }
198
199
        $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
200
        $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
201
202
203
        // Skip attempts to use keywords as functions or class names - the former
204
        // will be reported by ForbiddenNamesAsInvokedFunctionsSniff, whilst the
205
        // latter will be (partially) reported by the ForbiddenNames sniff.
206
        // Either type will result in false-positives when targetting lower versions
207
        // of PHP where the name was not reserved, unless we explicitly check for
208
        // them.
209
        if (
210
            ($nextToken === false || $tokens[$nextToken]['type'] !== 'T_OPEN_PARENTHESIS')
211
            &&
212
            ($prevToken === false || $tokens[$prevToken]['type'] !== 'T_CLASS' || $tokens[$prevToken]['type'] !== 'T_INTERFACE')
213
        ) {
214
            // Skip based on token scope condition.
215
            if (isset($this->newKeywords[$tokenType]['condition'])) {
216
                $condition = $this->newKeywords[$tokenType]['condition'];
217
                if ($this->tokenHasScope($phpcsFile, $stackPtr, $condition) === true) {
218
                    return;
219
                }
220
            }
221
222
            $itemInfo = array(
223
                'name'   => $tokenType,
224
            );
225
            $this->handleFeature($phpcsFile, $stackPtr, $itemInfo);
226
        }
227
228
    }//end process()
229
230
231
    /**
232
     * Get the relevant sub-array for a specific item from a multi-dimensional array.
233
     *
234
     * @param array $itemInfo Base information about the item.
235
     *
236
     * @return array Version and other information about the item.
237
     */
238
    public function getItemArray(array $itemInfo)
239
    {
240
        return $this->newKeywords[$itemInfo['name']];
241
    }
242
243
244
    /**
245
     * Get an array of the non-PHP-version array keys used in a sub-array.
246
     *
247
     * @return array
248
     */
249
    protected function getNonVersionArrayKeys()
250
    {
251
        return array(
252
            'description',
253
            'condition',
254
            'content',
255
        );
256
    }
257
258
259
    /**
260
     * Retrieve the relevant detail (version) information for use in an error message.
261
     *
262
     * @param array $itemArray Version and other information about the item.
263
     * @param array $itemInfo  Base information about the item.
264
     *
265
     * @return array
266
     */
267
    public function getErrorInfo(array $itemArray, array $itemInfo)
268
    {
269
        $errorInfo = parent::getErrorInfo($itemArray, $itemInfo);
270
        $errorInfo['description'] = $itemArray['description'];
271
272
        return $errorInfo;
273
274
    }
275
276
277
    /**
278
     * Allow for concrete child classes to filter the error data before it's passed to PHPCS.
279
     *
280
     * @param array $data      The error data array which was created.
281
     * @param array $itemInfo  Base information about the item this error message applied to.
282
     * @param array $errorInfo Detail information about an item this error message applied to.
283
     *
284
     * @return array
285
     */
286
    protected function filterErrorData(array $data, array $itemInfo, array $errorInfo)
287
    {
288
        $data[0] = $errorInfo['description'];
289
        return $data;
290
    }
291
292
293
}//end class
294