Completed
Push — php-5.4-7.0/new-class-member-a... ( d25e45 )
by Juliette
01:50
created

NewClassMemberAccessSniff::process()   C

Complexity

Conditions 9
Paths 7

Size

Total Lines 50
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 50
rs 6
c 0
b 0
f 0
cc 9
eloc 27
nc 7
nop 2
1
<?php
2
/**
3
 * \PHPCompatibility\Sniffs\PHP\NewClassMemberAccessSniff.
4
 *
5
 * PHP version 5.4
6
 * PHP version 7.0
7
 *
8
 * @category PHP
9
 * @package  PHPCompatibility
10
 * @author   Juliette Reinders Folmer <[email protected]>
11
 */
12
13
namespace PHPCompatibility\Sniffs\PHP;
14
15
use PHPCompatibility\Sniff;
16
17
/**
18
 * \PHPCompatibility\Sniffs\PHP\NewClassMemberAccessSniff.
19
 *
20
 * PHP 5.4: Class member access on instantiation has been added, e.g. (new Foo)->bar().
21
 * PHP 7.0: Class member access on cloning has been added, e.g. (clone $foo)->bar().
22
 *
23
 * PHP version 5.4
24
 * PHP version 7.0
25
 *
26
 * @category PHP
27
 * @package  PHPCompatibility
28
 * @author   Juliette Reinders Folmer <[email protected]>
29
 */
30
class NewClassMemberAccessSniff extends Sniff
31
{
32
33
    /**
34
     * Returns an array of tokens this test wants to listen for.
35
     *
36
     * @return array
37
     */
38
    public function register()
39
    {
40
        $targets = array();
41
42
        if ($this->supportsBelow('5.3') === true) {
43
            $targets[] = T_NEW;
44
        }
45
46
        if ($this->supportsBelow('5.6') === true) {
47
            $targets[] = T_CLONE;
48
        }
49
50
        return $targets;
51
    }
52
53
    /**
54
     * Processes this test, when one of its tokens is encountered.
55
     *
56
     * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
57
     * @param int                   $stackPtr  The position of the current token in the
58
     *                                         stack passed in $tokens.
59
     *
60
     * @return void
61
     */
62
    public function process(\PHP_CodeSniffer_File $phpcsFile, $stackPtr)
63
    {
64
        $tokens = $phpcsFile->getTokens();
65
66
        if (isset($tokens[$stackPtr]['nested_parenthesis']) === false) {
67
            // The `new className/clone $a` has to be in parentheses, without is not supported.
68
            return;
69
        }
70
71
        $parenthesisCloser = end($tokens[$stackPtr]['nested_parenthesis']);
72
        $parenthesisOpener = key($tokens[$stackPtr]['nested_parenthesis']);
73
74
        if (isset($tokens[$parenthesisOpener]['parenthesis_owner']) === true) {
75
            // If there is an owner, these parentheses are for a different purpose.
76
            return;
77
        }
78
79
        $prevBeforeParenthesis = $phpcsFile->findPrevious(\PHP_CodeSniffer_Tokens::$emptyTokens, ($parenthesisOpener - 1), null, true);
80
        if ($prevBeforeParenthesis !== false && $tokens[$prevBeforeParenthesis]['code'] === T_STRING) {
81
            // This is most likely a function call with the new/cloned object as a parameter.
82
            return;
83
        }
84
85
        $nextAfterParenthesis = $phpcsFile->findNext(\PHP_CodeSniffer_Tokens::$emptyTokens, ($parenthesisCloser + 1), null, true);
86
        if ($nextAfterParenthesis === false) {
87
            // Live coding.
88
            return;
89
        }
90
91
        if ($tokens[$nextAfterParenthesis]['code'] !== T_OBJECT_OPERATOR
92
            && $tokens[$nextAfterParenthesis]['code'] !== T_OPEN_SQUARE_BRACKET
93
        ) {
94
            return;
95
        }
96
97
        $data = array('instantiation', '5.3');
98
        $errorCode = 'Found';
99
100
        if ($tokens[$stackPtr]['code'] === T_CLONE) {
101
            $data = array('cloning', '5.6');
102
            $errorCode = 'Found';
103
        }
104
105
        $phpcsFile->addError(
106
            'Class member access on object %s was not supported in PHP %s or earlier',
107
            $parenthesisCloser,
108
            $errorCode,
109
            $data
110
        );
111
    }
112
}
113