Completed
Pull Request — master (#41)
by Tomáš
07:50 queued 04:44
created

InBetweenMethodSpacingSniff::process()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 13
cts 13
cp 1
rs 9.3142
c 0
b 0
f 0
cc 3
eloc 13
nc 3
nop 2
crap 3
1
<?php
2
3
/*
4
 * This file is part of Zenify
5
 * Copyright (c) 2012 Tomas Votruba (http://tomasvotruba.cz)
6
 */
7
8
namespace ZenifyCodingStandard\Sniffs\Whitespace;
9
10
use PHP_CodeSniffer_File;
11
use Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff;
12
13
14
/**
15
 * Rules:
16
 * - Method should have X empty line(s) after itself.
17
 *
18
 * Exceptions:
19
 * - Method is the first in the class, preceded by open bracket.
20
 * - Method is the last in the class, followed by close bracket.
21
 */
22
class InBetweenMethodSpacingSniff extends Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff
23
{
24
25
	/**
26
	 * @var int
27
	 */
28
	public $blankLinesBetweenMethods = 2;
29
30
	/**
31
	 * @var int
32
	 */
33
	private $position;
34
35
	/**
36
	 * @var array
37
	 */
38
	private $tokens;
39
40
	/**
41
	 * @var PHP_CodeSniffer_File
42
	 */
43
	private $file;
44
45
46
	/**
47
	 * {@inheritdoc}
48
	 */
49 1
	public function register()
50
	{
51 1
		return [T_FUNCTION];
52
	}
53
54
55
	/**
56
	 * {@inheritdoc}
57
	 */
58 1
	public function process(PHP_CodeSniffer_File $file, $position)
59
	{
60
		// Fix type
61 1
		$this->blankLinesBetweenMethods = (int) $this->blankLinesBetweenMethods;
62
63 1
		$this->file = $file;
64 1
		$this->position = $position;
65 1
		$this->tokens = $file->getTokens();
66
67 1
		$blankLinesCountAfterFunction = $this->getBlankLineCountAfterFunction();
68 1
		if ($blankLinesCountAfterFunction !== $this->blankLinesBetweenMethods) {
69 1
			if ($this->isLastMethod()) {
70 1
				return;
71
72
			} else {
73 1
				$error = 'Method should have %s empty line(s) after itself, %s found.';
74 1
				$data = [$this->blankLinesBetweenMethods, $blankLinesCountAfterFunction];
75 1
				$this->file->addError($error, $position, '', $data);
76
			}
77
		}
78 1
	}
79
80
81
	/**
82
	 * @return int
83
	 */
84 1
	private function getBlankLineCountAfterFunction()
85
	{
86 1
		$closer = $this->getScopeCloser();
87 1
		$nextLineToken = $this->getNextLineTokenByScopeCloser($closer);
0 ignored issues
show
Bug introduced by
It seems like $closer defined by $this->getScopeCloser() on line 86 can also be of type boolean; however, ZenifyCodingStandard\Sni...ineTokenByScopeCloser() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
88
89 1
		$nextContent = $this->getNextLineContent($nextLineToken);
90 1
		if ($nextContent !== FALSE) {
91 1
			$foundLines = ($this->tokens[$nextContent]['line'] - $this->tokens[$nextLineToken]['line']);
92
93
		} else {
94
			// We are at the end of the file.
95
			$foundLines = $this->blankLinesBetweenMethods;
96
		}
97
98 1
		return $foundLines;
99
	}
100
101
102
	/**
103
	 * @return bool
104
	 */
105 1
	private function isLastMethod()
106
	{
107 1
		$closer = $this->getScopeCloser();
108 1
		$nextLineToken = $this->getNextLineTokenByScopeCloser($closer);
0 ignored issues
show
Bug introduced by
It seems like $closer defined by $this->getScopeCloser() on line 107 can also be of type boolean; however, ZenifyCodingStandard\Sni...ineTokenByScopeCloser() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
109 1
		if ($this->tokens[$nextLineToken + 1]['code'] === T_CLOSE_CURLY_BRACKET) {
110 1
			return TRUE;
111
		}
112 1
		return FALSE;
113
	}
114
115
116
	/**
117
	 * @return bool|int
118
	 */
119 1
	private function getScopeCloser()
120
	{
121 1
		if (isset($this->tokens[$this->position]['scope_closer']) === FALSE) {
122
			// Must be an interface method, so the closer is the semi-colon.
123
			return $this->file->findNext(T_SEMICOLON, $this->position);
124
125
		} else {
126 1
			return $this->tokens[$this->position]['scope_closer'];
127
		}
128
	}
129
130
131
	/**
132
	 * @param int $closer
133
	 * @return int|NULL
134
	 */
135 1
	private function getNextLineTokenByScopeCloser($closer)
136
	{
137 1
		$nextLineToken = NULL;
138 1
		for ($i = $closer; $i < $this->file->numTokens; $i++) {
139 1
			if (strpos($this->tokens[$i]['content'], $this->file->eolChar) === FALSE) {
140 1
				continue;
141
142
			} else {
143 1
				$nextLineToken = ($i + 1);
144 1
				if ( ! isset($this->tokens[$nextLineToken])) {
145
					$nextLineToken = NULL;
146
				}
147
148 1
				break;
149
			}
150
		}
151 1
		return $nextLineToken;
152
	}
153
154
155
	/**
156
	 * @param int $nextLineToken
157
	 * @return bool|int
158
	 */
159 1
	private function getNextLineContent($nextLineToken)
160
	{
161 1
		if ($nextLineToken !== NULL) {
162 1
			return $this->file->findNext(T_WHITESPACE, ($nextLineToken + 1), NULL, TRUE);
163
		}
164
		return FALSE;
165
	}
166
167
}
168