Completed
Push — master ( 9b18dc...e19264 )
by Tomáš
18s
created

getNextLineTokenByScopeCloser()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.016

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 9
cts 10
cp 0.9
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 4
nop 1
crap 4.016
1
<?php
2
3
declare(strict_types = 1);
4
5
/*
6
 * This file is part of Zenify
7
 * Copyright (c) 2012 Tomas Votruba (http://tomasvotruba.cz)
8
 */
9
10
namespace ZenifyCodingStandard\Sniffs\Whitespace;
11
12
use PHP_CodeSniffer_File;
13
use Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff;
14
15
16
/**
17
 * Rules:
18
 * - Method should have X empty line(s) after itself.
19
 *
20
 * Exceptions:
21
 * - Method is the first in the class, preceded by open bracket.
22
 * - Method is the last in the class, followed by close bracket.
23
 */
24
final class InBetweenMethodSpacingSniff extends Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff
25
{
26
27
	/**
28
	 * @var int
29
	 */
30
	public $blankLinesBetweenMethods = 2;
31
32
	/**
33
	 * @var int
34
	 */
35
	private $position;
36
37
	/**
38
	 * @var array
39
	 */
40
	private $tokens;
41
42
	/**
43
	 * @var PHP_CodeSniffer_File
44
	 */
45
	private $file;
46
47
48
	/**
49
	 * {@inheritdoc}
50
	 */
51 1
	public function register()
52
	{
53 1
		return [T_FUNCTION];
54
	}
55
56
57
	/**
58
	 * {@inheritdoc}
59
	 */
60 1
	public function process(PHP_CodeSniffer_File $file, $position)
61
	{
62
		// Fix type
63 1
		$this->blankLinesBetweenMethods = (int) $this->blankLinesBetweenMethods;
64
65 1
		$this->file = $file;
66 1
		$this->position = $position;
67 1
		$this->tokens = $file->getTokens();
68
69 1
		$blankLinesCountAfterFunction = $this->getBlankLineCountAfterFunction();
70 1
		if ($blankLinesCountAfterFunction !== $this->blankLinesBetweenMethods) {
71 1
			if ($this->isLastMethod()) {
72 1
				return;
73
74
			} else {
75 1
				$error = 'Method should have %s empty line(s) after itself, %s found.';
76 1
				$data = [$this->blankLinesBetweenMethods, $blankLinesCountAfterFunction];
77 1
				$this->file->addError($error, $position, '', $data);
78
			}
79
		}
80 1
	}
81
82
83 1
	private function getBlankLineCountAfterFunction() : int
84
	{
85 1
		$closer = $this->getScopeCloser();
86 1
		$nextLineToken = $this->getNextLineTokenByScopeCloser($closer);
0 ignored issues
show
Bug introduced by
It seems like $closer defined by $this->getScopeCloser() on line 85 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...
87
88 1
		$nextContent = $this->getNextLineContent($nextLineToken);
89 1
		if ($nextContent !== FALSE) {
90 1
			$foundLines = ($this->tokens[$nextContent]['line'] - $this->tokens[$nextLineToken]['line']);
91
92
		} else {
93
			// We are at the end of the file.
94
			$foundLines = $this->blankLinesBetweenMethods;
95
		}
96
97 1
		return $foundLines;
98
	}
99
100
101 1
	private function isLastMethod() : bool
102
	{
103 1
		$closer = $this->getScopeCloser();
104 1
		$nextLineToken = $this->getNextLineTokenByScopeCloser($closer);
0 ignored issues
show
Bug introduced by
It seems like $closer defined by $this->getScopeCloser() on line 103 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...
105 1
		if ($this->tokens[$nextLineToken + 1]['code'] === T_CLOSE_CURLY_BRACKET) {
106 1
			return TRUE;
107
		}
108 1
		return FALSE;
109
	}
110
111
112
	/**
113
	 * @return bool|int
114
	 */
115 1
	private function getScopeCloser()
116
	{
117 1
		if (isset($this->tokens[$this->position]['scope_closer']) === FALSE) {
118
			// Must be an interface method, so the closer is the semi-colon.
119
			return $this->file->findNext(T_SEMICOLON, $this->position);
120
		}
121
122 1
		return $this->tokens[$this->position]['scope_closer'];
123
	}
124
125
126
	/**
127
	 * @return int|NULL
128
	 */
129 1
	private function getNextLineTokenByScopeCloser(int $closer)
130
	{
131 1
		$nextLineToken = NULL;
132 1
		for ($i = $closer; $i < $this->file->numTokens; $i++) {
133 1
			if (strpos($this->tokens[$i]['content'], $this->file->eolChar) === FALSE) {
134 1
				continue;
135
136
			} else {
137 1
				$nextLineToken = ($i + 1);
138 1
				if ( ! isset($this->tokens[$nextLineToken])) {
139
					$nextLineToken = NULL;
140
				}
141
142 1
				break;
143
			}
144
		}
145 1
		return $nextLineToken;
146
	}
147
148
149
	/**
150
	 * @return bool|int
151
	 */
152 1
	private function getNextLineContent(int $nextLineToken)
153
	{
154 1
		if ($nextLineToken !== NULL) {
155 1
			return $this->file->findNext(T_WHITESPACE, ($nextLineToken + 1), NULL, TRUE);
156
		}
157
		return FALSE;
158
	}
159
160
}
161