PHPParserVersion56   F
last analyzed

Complexity

Total Complexity 127

Size/Duplication

Total Lines 377
Duplicated Lines 0 %

Test Coverage

Coverage 76.25%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 127
eloc 231
dl 0
loc 377
c 3
b 0
f 0
ccs 151
cts 198
cp 0.7625
rs 2

9 Methods

Rating   Name   Duplication   Size   Complexity  
A parseArgumentExpression() 0 3 1
A parseConstantDeclaratorValue() 0 11 2
D isFollowedByStaticValueOrStaticArray() 0 40 24
A parseOptionalExpressionForVersion() 0 6 2
F parseStaticValueVersionSpecific() 0 181 86
A parseArgumentList() 0 21 6
A parseConstantArgument() 0 3 1
A parseExpressionVersion56() 0 21 2
A parseUseDeclarations() 0 23 3

How to fix   Complexity   

Complex Class

Complex classes like PHPParserVersion56 often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PHPParserVersion56, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * This file is part of PDepend.
4
 *
5
 * PHP Version 5
6
 *
7
 * Copyright (c) 2008-2017 Manuel Pichler <[email protected]>.
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 *
14
 *   * Redistributions of source code must retain the above copyright
15
 *     notice, this list of conditions and the following disclaimer.
16
 *
17
 *   * Redistributions in binary form must reproduce the above copyright
18
 *     notice, this list of conditions and the following disclaimer in
19
 *     the documentation and/or other materials provided with the
20
 *     distribution.
21
 *
22
 *   * Neither the name of Manuel Pichler nor the names of his
23
 *     contributors may be used to endorse or promote products derived
24
 *     from this software without specific prior written permission.
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37
 * POSSIBILITY OF SUCH DAMAGE.
38
 *
39
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
40
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
41
 *
42
 * @since 2.3
43
 */
44
45
namespace PDepend\Source\Language\PHP;
46
47
use PDepend\Source\AST\ASTArguments;
48
use PDepend\Source\AST\ASTConstant;
49
use PDepend\Source\AST\ASTNamedArgument;
50
use PDepend\Source\AST\ASTNode;
51
use PDepend\Source\AST\ASTValue;
52
use PDepend\Source\Parser\UnexpectedTokenException;
53
use PDepend\Source\Tokenizer\FullTokenizer;
54
use PDepend\Source\Tokenizer\Tokenizer;
55
use PDepend\Source\Tokenizer\Tokens;
56
57
/**
58
 * Concrete parser implementation that supports features up to PHP version 5.6.
59
 *
60
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
61
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
62
 *
63
 * @since 2.3
64
 */
65
abstract class PHPParserVersion56 extends PHPParserVersion55
66
{
67
    /**
68
     * Parses additional static values that are valid in the supported php version.
69
     *
70
     * @throws UnexpectedTokenException
71
     *
72
     * @return ASTValue|null
73
     */
74 4
    protected function parseStaticValueVersionSpecific(ASTValue $value)
75
    {
76 4
        $expressions = array();
77
78 4
        while (($tokenType = $this->tokenizer->peek()) != Tokenizer::T_EOF) {
79 4
            switch ($tokenType) {
80
                case Tokens::T_COMMA:
81
                case Tokens::T_CLOSE_TAG:
82
                case Tokens::T_COLON:
83
                case Tokens::T_DOUBLE_ARROW:
84
                case Tokens::T_END_HEREDOC:
85
                case Tokens::T_PARENTHESIS_CLOSE:
86
                case Tokens::T_SEMICOLON:
87
                case Tokens::T_SQUARED_BRACKET_CLOSE:
88 3
                    break 2;
89
                case Tokens::T_SELF:
90
                case Tokens::T_STRING:
91
                case Tokens::T_PARENT:
92
                case Tokens::T_STATIC:
93
                case Tokens::T_DOLLAR:
94
                case Tokens::T_VARIABLE:
95
                case Tokens::T_BACKSLASH:
96
                case Tokens::T_NAMESPACE:
97 1
                    $expressions[] = $this->parseVariableOrConstantOrPrimaryPrefix();
98 1
                    break;
99 4
                case ($this->isArrayStartDelimiter()):
100
                    $expressions[] = $this->doParseArray(true);
101
                    break;
102 4
                case Tokens::T_NULL:
103 4
                case Tokens::T_TRUE:
104 4
                case Tokens::T_FALSE:
105 4
                case Tokens::T_LNUMBER:
106 4
                case Tokens::T_DNUMBER:
107 4
                case Tokens::T_BACKTICK:
108 4
                case Tokens::T_DOUBLE_QUOTE:
109 4
                case Tokens::T_CONSTANT_ENCAPSED_STRING:
110 3
                    $expressions[] = $this->parseLiteralOrString();
111 3
                    break;
112 4
                case Tokens::T_QUESTION_MARK:
113
                    $expressions[] = $this->parseConditionalExpression();
114
                    break;
115 4
                case Tokens::T_BOOLEAN_AND:
116
                    $expressions[] = $this->parseBooleanAndExpression();
117
                    break;
118 4
                case Tokens::T_BOOLEAN_OR:
119
                    $expressions[] = $this->parseBooleanOrExpression();
120
                    break;
121 4
                case Tokens::T_LOGICAL_AND:
122
                    $expressions[] = $this->parseLogicalAndExpression();
123
                    break;
124 4
                case Tokens::T_LOGICAL_OR:
125
                    $expressions[] = $this->parseLogicalOrExpression();
126
                    break;
127 4
                case Tokens::T_LOGICAL_XOR:
128
                    $expressions[] = $this->parseLogicalXorExpression();
129
                    break;
130 4
                case Tokens::T_PARENTHESIS_OPEN:
131
                    $expressions[] = $this->parseParenthesisExpressionOrPrimaryPrefix();
132
                    break;
133 4
                case Tokens::T_START_HEREDOC:
134
                    $expressions[] = $this->parseHeredoc();
135
                    break;
136 4
                case Tokens::T_SL:
137
                    $expressions[] = $this->parseShiftLeftExpression();
138
                    break;
139 4
                case Tokens::T_SR:
140
                    $expressions[] = $this->parseShiftRightExpression();
141
                    break;
142 4
                case Tokens::T_ELLIPSIS:
143
                    $this->checkEllipsisInExpressionSupport();
144
                    // no break
145 4
                case Tokens::T_STRING_VARNAME: // TODO: Implement this
146 4
                case Tokens::T_PLUS: // TODO: Make this a arithmetic expression
147 4
                case Tokens::T_MINUS:
148 4
                case Tokens::T_MUL:
149 3
                case Tokens::T_DIV:
150 3
                case Tokens::T_MOD:
151 3
                case Tokens::T_POW:
152 2
                case Tokens::T_IS_EQUAL: // TODO: Implement compare expressions
153 2
                case Tokens::T_IS_NOT_EQUAL:
154 2
                case Tokens::T_IS_IDENTICAL:
155 2
                case Tokens::T_IS_NOT_IDENTICAL:
156 2
                case Tokens::T_BITWISE_OR:
157 2
                case Tokens::T_BITWISE_AND:
158 2
                case Tokens::T_BITWISE_NOT:
159 2
                case Tokens::T_BITWISE_XOR:
160 2
                case Tokens::T_IS_GREATER_OR_EQUAL:
161 2
                case Tokens::T_IS_SMALLER_OR_EQUAL:
162 2
                case Tokens::T_ANGLE_BRACKET_OPEN:
163 2
                case Tokens::T_ANGLE_BRACKET_CLOSE:
164 2
                case Tokens::T_EMPTY:
165 2
                case Tokens::T_CONCAT:
166 3
                    $token = $this->consumeToken($tokenType);
167
168 3
                    $expr = $this->builder->buildAstExpression($token->image);
169 3
                    $expr->configureLinesAndColumns(
170 3
                        $token->startLine,
171 3
                        $token->endLine,
172 3
                        $token->startColumn,
173 3
                        $token->endColumn
174
                    );
175
176 3
                    $expressions[] = $expr;
177 3
                    break;
178 1
                case Tokens::T_EQUAL:
179 1
                case Tokens::T_OR_EQUAL:
180 1
                case Tokens::T_SL_EQUAL:
181 1
                case Tokens::T_SR_EQUAL:
182 1
                case Tokens::T_AND_EQUAL:
183 1
                case Tokens::T_DIV_EQUAL:
184 1
                case Tokens::T_MOD_EQUAL:
185 1
                case Tokens::T_MUL_EQUAL:
186 1
                case Tokens::T_XOR_EQUAL:
187 1
                case Tokens::T_PLUS_EQUAL:
188 1
                case Tokens::T_MINUS_EQUAL:
189 1
                case Tokens::T_CONCAT_EQUAL:
190 1
                case Tokens::T_COALESCE_EQUAL:
191
                    $expressions[] = $this->parseAssignmentExpression(
192
                        array_pop($expressions)
193
                    );
194
                    break;
195 1
                case Tokens::T_DIR:
196 1
                case Tokens::T_FILE:
197 1
                case Tokens::T_LINE:
198 1
                case Tokens::T_NS_C:
199 1
                case Tokens::T_FUNC_C:
200 1
                case Tokens::T_CLASS_C:
201 1
                case Tokens::T_METHOD_C:
202
                    $expressions[] = $this->parseConstant();
203
                    break;
204
                // TODO: Handle comments here
205 1
                case Tokens::T_COMMENT:
206 1
                case Tokens::T_DOC_COMMENT:
207
                    $this->consumeToken($tokenType);
208
                    break;
209 1
                case Tokens::T_AT:
210 1
                case Tokens::T_EXCLAMATION_MARK:
211
                    $token = $this->consumeToken($tokenType);
212
213
                    $expr = $this->builder->buildAstUnaryExpression($token->image);
214
                    $expr->configureLinesAndColumns(
215
                        $token->startLine,
216
                        $token->endLine,
217
                        $token->startColumn,
218
                        $token->endColumn
219
                    );
220
221
                    $expressions[] = $expr;
222
                    break;
223
                default:
224 1
                    throw $this->getUnexpectedNextTokenException();
225
            }
226
        }
227
228 3
        $expressions = $this->reduce($expressions);
229
230 3
        $count = count($expressions);
231 3
        if ($count == 0) {
232
            return null;
233 3
        } elseif ($count == 1) {
234
            // @todo ASTValue must be a valid node.
235
            $value->setValue($expressions[0]);
236
237
            return $value;
238
        }
239
240 3
        $expr = $this->builder->buildAstExpression();
241 3
        foreach ($expressions as $node) {
242 3
            $expr->addChild($node);
243
        }
244 3
        $expr->configureLinesAndColumns(
245 3
            $expressions[0]->getStartLine(),
246 3
            $expressions[$count - 1]->getEndLine(),
247 3
            $expressions[0]->getStartColumn(),
248 3
            $expressions[$count - 1]->getEndColumn()
249
        );
250
251
        // @todo ASTValue must be a valid node.
252 3
        $value->setValue($expr);
253
254 3
        return $value;
255
    }
256
257
    /**
258
     * Parses use declarations that are valid in the supported php version.
259
     *
260
     * @return void
261
     */
262 2
    protected function parseUseDeclarations()
263
    {
264
        // Consume use keyword
265 2
        $this->consumeToken(Tokens::T_USE);
266 2
        $this->consumeComments();
267
268
        // Consume const and function tokens
269 2
        $nextToken = $this->tokenizer->peek();
270 2
        switch ($nextToken) {
271
            case Tokens::T_CONST:
272
            case Tokens::T_FUNCTION:
273 1
                $this->consumeToken($nextToken);
274
        }
275
276
        // Parse all use declarations
277 2
        $this->parseUseDeclaration();
278 1
        $this->consumeComments();
279
280
        // Consume closing semicolon
281 1
        $this->consumeToken(Tokens::T_SEMICOLON);
282
283
        // Reset any previous state
284 1
        $this->reset();
285 1
    }
286
287
    /**
288
     * This method will be called when the base parser cannot handle an expression
289
     * in the base version. In this method you can implement version specific
290
     * expressions.
291
     *
292
     * @throws UnexpectedTokenException
293
     *
294
     * @return ASTNode
295
     *
296
     * @since 2.2
297
     */
298 2
    protected function parseOptionalExpressionForVersion()
299
    {
300 2
        if ($expression = $this->parseExpressionVersion56()) {
301 1
            return $expression;
302
        }
303 1
        return parent::parseOptionalExpressionForVersion();
304
    }
305
306
    /**
307
     * In this method we implement parsing of PHP 5.6 specific expressions.
308
     *
309
     * @return ASTNode|null
310
     *
311
     * @since 2.3
312
     */
313 2
    protected function parseExpressionVersion56()
314
    {
315 2
        $this->consumeComments();
316 2
        $nextTokenType = $this->tokenizer->peek();
317
318 2
        switch ($nextTokenType) {
319
            case Tokens::T_POW:
320 1
                $token = $this->consumeToken($nextTokenType);
321
322 1
                $expr = $this->builder->buildAstExpression($token->image);
323 1
                $expr->configureLinesAndColumns(
324 1
                    $token->startLine,
325 1
                    $token->endLine,
326 1
                    $token->startColumn,
327 1
                    $token->endColumn
328
                );
329
330 1
                return $expr;
331
        }
332
333 1
        return null;
334
    }
335
336
    /**
337
     * @return ASTConstant|ASTNamedArgument
338
     */
339
    protected function parseConstantArgument(ASTConstant $constant, ASTArguments $arguments)
0 ignored issues
show
Unused Code introduced by
The parameter $arguments is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

339
    protected function parseConstantArgument(ASTConstant $constant, /** @scrutinizer ignore-unused */ ASTArguments $arguments)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
340
    {
341
        return $constant;
342
    }
343
344
    /**
345
     * @return ASTArguments
346
     */
347 1
    protected function parseArgumentList(ASTArguments $arguments)
348
    {
349 1
        while (true) {
350 1
            $this->consumeComments();
351
352 1
            if (Tokens::T_ELLIPSIS === $this->tokenizer->peek()) {
353 1
                $this->consumeToken(Tokens::T_ELLIPSIS);
354
            }
355
356 1
            $expr = $this->parseArgumentExpression();
357
358 1
            if ($expr instanceof ASTConstant) {
359
                $expr = $this->parseConstantArgument($expr, $arguments);
360
            }
361
362 1
            if (!$expr || !$this->addChildToList($arguments, $expr)) {
363 1
                break;
364
            }
365
        }
366
367 1
        return $arguments;
368
    }
369
370
    /**
371
     * @return ASTNode|null
372
     */
373 1
    protected function parseArgumentExpression()
374
    {
375 1
        return $this->parseOptionalExpression();
376
    }
377
378
    /**
379
     * Parses the value of a php constant. By default this can be only static
380
     * values that were allowed in the oldest supported PHP version.
381
     *
382
     * @return ASTValue
383
     */
384 2
    protected function parseConstantDeclaratorValue()
385
    {
386 2
        if ($this->isFollowedByStaticValueOrStaticArray()) {
387 2
            return $this->parseVariableDefaultValue();
388
        }
389
390
        // Else it would be provided as ASTLiteral or expressions object.
391 2
        $value = new ASTValue();
392 2
        $value->setValue($this->parseOptionalExpression());
393
394 2
        return $value;
395
    }
396
397
    /**
398
     * Determines if the following expression can be stored as a static value.
399
     *
400
     * @return bool
401
     */
402 2
    protected function isFollowedByStaticValueOrStaticArray()
403
    {
404
        // If we can't anticipate, we should assume it can be a dynamic value
405 2
        if (!($this->tokenizer instanceof FullTokenizer)) {
406
            return false;
407
        }
408
409 2
        for ($i = 0; $type = $this->tokenizer->peekAt($i); $i++) {
410 2
            switch ($type) {
411
                case Tokens::T_COMMENT:
412
                case Tokens::T_DOC_COMMENT:
413
                case Tokens::T_ARRAY:
414
                case Tokens::T_SQUARED_BRACKET_OPEN:
415
                case Tokens::T_SQUARED_BRACKET_CLOSE:
416
                case Tokens::T_PARENTHESIS_OPEN:
417
                case Tokens::T_PARENTHESIS_CLOSE:
418
                case Tokens::T_COMMA:
419
                case Tokens::T_DOUBLE_ARROW:
420
                case Tokens::T_NULL:
421
                case Tokens::T_TRUE:
422
                case Tokens::T_FALSE:
423
                case Tokens::T_LNUMBER:
424
                case Tokens::T_DNUMBER:
425
                case Tokens::T_STRING:
426
                case Tokens::T_EQUAL:
427
                case Tokens::T_START_HEREDOC:
428
                case Tokens::T_END_HEREDOC:
429
                case Tokens::T_ENCAPSED_AND_WHITESPACE:
430 2
                    break;
431
432
                case Tokens::T_SEMICOLON:
433
                case Tokenizer::T_EOF:
434 2
                    return true;
435
436
                default:
437 2
                    return false;
438
            }
439
        }
440
441
        return false;
442
    }
443
}
444