1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of Symplify |
5
|
|
|
* Copyright (c) 2016 Tomas Votruba (http://tomasvotruba.cz). |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace Symplify\PHP7_CodeSniffer; |
9
|
|
|
|
10
|
|
|
use Symplify\PHP7_CodeSniffer\File\File; |
11
|
|
|
|
12
|
|
|
final class Fixer |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* @var File |
16
|
|
|
*/ |
17
|
|
|
private $currentFile; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* The list of tokens that make up the file contents. |
21
|
|
|
* |
22
|
|
|
* This is a simplified list which just contains the token content and nothing |
23
|
|
|
* else. This is the array that is updated as fixes are made, not the file's |
24
|
|
|
* token array. Imploding this array will give you the file content back. |
25
|
|
|
* |
26
|
|
|
* @var array<int, string> |
27
|
|
|
*/ |
28
|
|
|
private $tokens = array(); |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* A list of tokens that have already been fixed. |
32
|
|
|
* |
33
|
|
|
* We don't allow the same token to be fixed more than once each time |
34
|
|
|
* through a file as this can easily cause conflicts between sniffs. |
35
|
|
|
* |
36
|
|
|
* @var int[] |
37
|
|
|
*/ |
38
|
|
|
private $fixedTokens = []; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* A list of tokens that have been fixed during a changeset. |
42
|
|
|
* |
43
|
|
|
* @var array |
44
|
|
|
*/ |
45
|
|
|
private $changeset = []; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var bool |
49
|
|
|
*/ |
50
|
|
|
private $inChangeset = false; |
51
|
|
|
|
52
|
|
|
public function startFile(File $file) |
53
|
|
|
{ |
54
|
|
|
$this->currentFile = $file; |
55
|
|
|
$this->fixedTokens = []; |
56
|
|
|
|
57
|
|
|
$tokens = $file->getTokens(); |
58
|
|
|
|
59
|
|
|
$this->tokens = []; |
60
|
|
|
foreach ($tokens as $index => $token) { |
61
|
|
|
if (isset($token['orig_content']) === true) { |
62
|
|
|
$this->tokens[$index] = $token['orig_content']; |
63
|
|
|
} else { |
64
|
|
|
$this->tokens[$index] = $token['content']; |
65
|
|
|
} |
66
|
|
|
} |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
public function getContents() : string |
70
|
|
|
{ |
71
|
|
|
return implode($this->tokens); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
View Code Duplication |
public function getTokenContent(int $stackPtr) : string |
|
|
|
|
75
|
|
|
{ |
76
|
|
|
if ($this->inChangeset === true |
77
|
|
|
&& isset($this->changeset[$stackPtr]) === true |
78
|
|
|
) { |
79
|
|
|
return $this->changeset[$stackPtr]; |
80
|
|
|
} else { |
81
|
|
|
return $this->tokens[$stackPtr]; |
82
|
|
|
} |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
public function beginChangeset() |
86
|
|
|
{ |
87
|
|
|
$this->changeset = []; |
88
|
|
|
$this->inChangeset = true; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* @return bool|null |
93
|
|
|
*/ |
94
|
|
|
public function endChangeset() |
95
|
|
|
{ |
96
|
|
|
$this->inChangeset = false; |
97
|
|
|
|
98
|
|
|
$success = true; |
99
|
|
|
$applied = []; |
100
|
|
|
|
101
|
|
|
foreach ($this->changeset as $stackPtr => $content) { |
102
|
|
|
$success = $this->replaceToken($stackPtr, $content); |
103
|
|
|
if ($success === false) { |
104
|
|
|
break; |
105
|
|
|
} else { |
106
|
|
|
$applied[] = $stackPtr; |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
if ($success === false) { |
111
|
|
|
// Rolling back all changes. |
112
|
|
|
foreach ($applied as $stackPtr) { |
113
|
|
|
$this->revertToken($stackPtr); |
114
|
|
|
} |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
$this->changeset = []; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Replace the entire contents of a token. |
122
|
|
|
* |
123
|
|
|
* @return bool If the change was accepted. |
124
|
|
|
*/ |
125
|
|
|
public function replaceToken(int $stackPtr, string $content) : bool |
126
|
|
|
{ |
127
|
|
|
if ($this->inChangeset === false |
128
|
|
|
&& isset($this->fixedTokens[$stackPtr]) === true |
129
|
|
|
) { |
130
|
|
|
$indent = "\t"; |
131
|
|
|
if (empty($this->changeset) === false) { |
132
|
|
|
$indent .= "\t"; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
return false; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
if ($this->inChangeset === true) { |
139
|
|
|
$this->changeset[$stackPtr] = $content; |
140
|
|
|
return true; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
$this->fixedTokens[$stackPtr] = $this->tokens[$stackPtr]; |
144
|
|
|
$this->tokens[$stackPtr] = $content; |
145
|
|
|
|
146
|
|
|
return true; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* @return bool If a change was reverted. |
151
|
|
|
*/ |
152
|
|
View Code Duplication |
public function revertToken(int $stackPtr) : bool |
|
|
|
|
153
|
|
|
{ |
154
|
|
|
if (isset($this->fixedTokens[$stackPtr]) === false) { |
155
|
|
|
return false; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
$this->tokens[$stackPtr] = $this->fixedTokens[$stackPtr]; |
159
|
|
|
unset($this->fixedTokens[$stackPtr]); |
160
|
|
|
|
161
|
|
|
return true; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
public function substrToken(int $stackPtr, int $start, int $length = null) : bool |
165
|
|
|
{ |
166
|
|
|
$current = $this->getTokenContent($stackPtr); |
167
|
|
|
|
168
|
|
|
if ($length === null) { |
169
|
|
|
$newContent = substr($current, $start); |
170
|
|
|
} else { |
171
|
|
|
$newContent = substr($current, $start, $length); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
return $this->replaceToken($stackPtr, $newContent); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
public function addNewline(int $stackPtr) : bool |
178
|
|
|
{ |
179
|
|
|
$current = $this->getTokenContent($stackPtr); |
180
|
|
|
return $this->replaceToken($stackPtr, $current.$this->currentFile->eolChar); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
public function addNewlineBefore(int $stackPtr) : bool |
184
|
|
|
{ |
185
|
|
|
$current = $this->getTokenContent($stackPtr); |
186
|
|
|
return $this->replaceToken($stackPtr, $this->currentFile->eolChar.$current); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
public function addContent(int $stackPtr, string $content) : bool |
190
|
|
|
{ |
191
|
|
|
$current = $this->getTokenContent($stackPtr); |
192
|
|
|
return $this->replaceToken($stackPtr, $current.$content); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
public function addContentBefore(int $stackPtr, string $content) : bool |
196
|
|
|
{ |
197
|
|
|
$current = $this->getTokenContent($stackPtr); |
198
|
|
|
return $this->replaceToken($stackPtr, $content.$current); |
199
|
|
|
} |
200
|
|
|
} |
201
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.