1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Symfony\CS\Fixer\PSR2;
use Symfony\CS\AbstractFixer;
use Symfony\CS\Tokenizer\Tokens;
/**
* Fixer for rules defined in PSR2 generally (¶1 and ¶6).
*
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
class FunctionDeclarationFixer extends AbstractFixer
{
private $singleLineWhitespaceOptions = array('whitespaces' => " \t");
/**
* {@inheritdoc}
*/
public function fix(\SplFileInfo $file, $content)
{
$tokens = Tokens::fromCode($content);
for ($index = $tokens->count() - 1; $index >= 0; --$index) {
$token = $tokens[$index];
if (!$token->isGivenKind(T_FUNCTION)) {
continue;
}
$startParenthesisIndex = $tokens->getNextTokenOfKind($index, array('(', ';', array(T_CLOSE_TAG)));
if (!$tokens[$startParenthesisIndex]->equals('(')) {
continue;
}
$endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
$startBraceIndex = $tokens->getNextTokenOfKind($endParenthesisIndex, array(';', '{'));
// fix single-line whitespace before {
// eg: `function foo(){}` => `function foo() {}`
// eg: `function foo() {}` => `function foo() {}`
if (
$tokens[$tokens->getPrevNonWhitespace($startBraceIndex)]->equals(')') &&
$tokens[$startBraceIndex]->equals('{') &&
(
!$tokens[$startBraceIndex - 1]->isWhitespace() ||
$tokens[$startBraceIndex - 1]->isWhitespace($this->singleLineWhitespaceOptions)
)
) {
$tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' ');
}
$afterParenthesisIndex = $tokens->getNextNonWhitespace($endParenthesisIndex);
$afterParenthesisToken = $tokens[$afterParenthesisIndex];
if ($afterParenthesisToken->isGivenKind(T_USE)) {
// fix whitespace after T_USE (we might add a token, so do this before determining start and end parenthesis)
$tokens->ensureWhitespaceAtIndex($afterParenthesisIndex + 1, 0, ' ');
$useStartParenthesisIndex = $tokens->getNextTokenOfKind($afterParenthesisIndex, array('('));
$useEndParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $useStartParenthesisIndex);
// remove single-line edge whitespaces inside use parentheses
$this->fixParenthesisInnerEdge($tokens, $useStartParenthesisIndex, $useEndParenthesisIndex);
// fix whitespace before T_USE
$tokens->ensureWhitespaceAtIndex($afterParenthesisIndex - 1, 1, ' ');
}
// remove single-line edge whitespaces inside parameters list parentheses
$this->fixParenthesisInnerEdge($tokens, $startParenthesisIndex, $endParenthesisIndex);
// remove whitespace before (
// eg: `function foo () {}` => `function foo() {}`
if ($tokens[$startParenthesisIndex - 1]->isWhitespace()) {
$tokens[$startParenthesisIndex - 1]->clear();
}
// fix whitespace after T_FUNCTION
// eg: `function foo() {}` => `function foo() {}`
$tokens->ensureWhitespaceAtIndex($index + 1, 0, ' ');
}
return $tokens->generateCode();
}
/**
* {@inheritdoc}
*/
public function getDescription()
{
return 'Spaces should be properly placed in a function declaration.';
}
private function fixParenthesisInnerEdge(Tokens $tokens, $start, $end)
{
// remove single-line whitespace before )
if ($tokens[$end - 1]->isWhitespace($this->singleLineWhitespaceOptions)) {
$tokens[$end - 1]->clear();
}
// remove single-line whitespace after (
if ($tokens[$start + 1]->isWhitespace($this->singleLineWhitespaceOptions)) {
$tokens[$start + 1]->clear();
}
}
}