Completed
Pull Request — master (#41)
by Tomáš
03:11
created

ensureSingleSpaceAfterKeyword()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5.009

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
ccs 13
cts 14
cp 0.9286
rs 8.5125
cc 5
eloc 15
nc 8
nop 0
crap 5.009
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\ControlStructures;
11
12
use PHP_CodeSniffer_File;
13
use PHP_CodeSniffer_Sniff;
14
15
16
/**
17
 * Rules:
18
 * - Same as @see Squiz_Sniffs_ControlStructures_ControlSignatureSniff
19
 * - This modification allows comments
20
 */
21
final class ControlSignatureSniff implements PHP_CodeSniffer_Sniff
22
{
23
24
	/**
25
	 * @var PHP_CodeSniffer_File
26
	 */
27
	private $file;
28
29
	/**
30
	 * @var int
31
	 */
32
	private $position;
33
34
	/**
35
	 * @var array
36
	 */
37
	private $tokens;
38
39
40
	/**
41
	 * {@inheritdoc}
42
	 */
43 1
	public function register()
44
	{
45 1
		return [T_TRY, T_CATCH, T_DO, T_WHILE, T_FOR, T_IF, T_FOREACH, T_ELSE, T_ELSEIF];
46
	}
47
48
49
	/**
50
	 * {@inheritdoc}
51
	 */
52 1
	public function process(PHP_CodeSniffer_File $file, $position)
53
	{
54 1
		$this->file = $file;
55 1
		$this->position = $position;
56 1
		$this->tokens = $tokens = $file->getTokens();
57
58 1
		$this->ensureSingleSpaceAfterKeyword();
59 1
		$this->ensureSingleSpaceAfterClosingParenthesis();
60 1
		$this->ensureNewlineAfterOpeningBrace();
61
62
		// Only want to check multi-keyword structures from here on.
63 1
		if ($tokens[$position]['code'] === T_TRY || $tokens[$position]['code'] === T_DO) {
64 1
			$closer = $tokens[$position]['scope_closer'];
65
66 1
		} elseif ($tokens[$position]['code'] === T_ELSE || $tokens[$position]['code'] === T_ELSEIF) {
67 1
			$closer = $file->findPrevious(T_CLOSE_CURLY_BRACKET, ($position - 1));
68
69
		} else {
70 1
			return;
71
		}
72
73
		// Single space after closing brace.
74 1
		$found = 1;
75 1
		if ($tokens[($closer + 1)]['code'] !== T_WHITESPACE) {
76 1
			$found = 0;
77
78
		} else {
79 1
			if ($tokens[($closer + 1)]['content'] !== ' ') {
80
				if (strpos($tokens[($closer + 1)]['content'], $file->eolChar) !== FALSE) {
81
					$found = 'newline';
82
83
				} else {
84
					$found = strlen($tokens[($closer + 1)]['content']);
85
				}
86
			}
87
		}
88
89 1
		if ($found !== 1) {
90 1
			$error = 'Expected 1 space after closing brace; %s found';
91 1
			$data = [$found];
92 1
			$file->addError($error, $closer, 'SpaceAfterCloseBrace', $data);
93
		}
94 1
	}
95
96
97 1
	private function ensureSingleSpaceAfterKeyword()
98
	{
99 1
		$found = 1;
100 1
		if ($this->tokens[($this->position + 1)]['code'] !== T_WHITESPACE) {
101 1
			$found = 0;
102
103 1
		} elseif ($this->tokens[($this->position + 1)]['content'] !== ' ') {
104 1
			if (strpos($this->tokens[($this->position + 1)]['content'], $this->file->eolChar) !== FALSE) {
105
				$found = 'newline';
106
107
			} else {
108 1
				$found = strlen($this->tokens[($this->position + 1)]['content']);
109
			}
110
		}
111
112 1
		if ($found !== 1) {
113 1
			$error = 'Expected 1 space after %s keyword; %s found';
114
			$data = [
115 1
				strtoupper($this->tokens[$this->position]['content']),
116 1
				$found,
117
			];
118 1
			$this->file->addError($error, $this->position, 'SpaceAfterKeyword', $data);
119
		}
120 1
	}
121
122
123 1
	private function ensureSingleSpaceAfterClosingParenthesis()
124
	{
125 1
		if (isset($this->tokens[$this->position]['parenthesis_closer']) === TRUE
126 1
			&& isset($this->tokens[$this->position]['scope_opener']) === TRUE
127
		) {
128 1
			$closer = $this->tokens[$this->position]['parenthesis_closer'];
129 1
			$opener = $this->tokens[$this->position]['scope_opener'];
130 1
			$content = $this->file->getTokensAsString(($closer + 1), ($opener - $closer - 1));
131 1
			if ($content !== ' ') {
132 1
				$error = 'Expected 1 space after closing parenthesis; found "%s"';
133 1
				$data = [str_replace($this->file->eolChar, '\n', $content)];
134 1
				$this->file->addError($error, $closer, 'SpaceAfterCloseParenthesis', $data);
135
			}
136
		}
137 1
	}
138
139
140 1
	private function ensureNewlineAfterOpeningBrace()
141
	{
142 1
		if (isset($this->tokens[$this->position]['scope_opener']) === TRUE) {
143 1
			$opener = $this->tokens[$this->position]['scope_opener'];
144 1
			$next = $this->file->findNext(T_WHITESPACE, ($opener + 1), NULL, TRUE);
145 1
			$found = ($this->tokens[$next]['line'] - $this->tokens[$opener]['line']);
146 1
			if ($found !== 1) {
147 1
				if ( ! $this->isCommentOnTheSameLine($this->file, $opener)) {
148 1
					$error = 'Expected 1 newline after opening brace; %s found';
149 1
					$data = [$found];
150 1
					$this->file->addError($error, $opener, 'NewlineAfterOpenBrace', $data);
151
				}
152
			}
153
154 1
		} elseif ($this->tokens[$this->position]['code'] === T_WHILE) {
155 1
			$closerPosition = $this->tokens[$this->position]['parenthesis_closer'];
156 1
			$this->ensureZeroSpacesAfterParenthesisCloser($closerPosition);
157
		}
158 1
	}
159
160
161 1
	private function isCommentOnTheSameLine(PHP_CodeSniffer_File $file, int $position) : bool
162
	{
163 1
		$isComment = $file->findNext(T_COMMENT, ($position + 1), NULL);
164 1
		if ($this->tokens[$isComment]['line'] === $this->tokens[$position]['line']) {
165 1
			return TRUE;
166
		}
167 1
		return FALSE;
168
	}
169
170
171 1
	private function ensureZeroSpacesAfterParenthesisCloser(int $closerPosition)
172
	{
173 1
		$found = 0;
174 1
		if ($this->tokens[($closerPosition + 1)]['code'] === T_WHITESPACE) {
175
			if (strpos($this->tokens[($closerPosition + 1)]['content'], $this->file->eolChar) !== FALSE) {
176
				$found = 'newline';
177
178
			} else {
179
				$found = strlen($this->tokens[($closerPosition + 1)]['content']);
180
			}
181
		}
182 1
		if ($found !== 0) {
183
			$error = 'Expected 0 spaces before semicolon; %s found';
184
			$data = [$found];
185
			$this->file->addError($error, $closerPosition, 'SpaceBeforeSemicolon', $data);
186
		}
187 1
	}
188
189
}
190