Skip to content

Commit 2471ac6

Browse files
authored
Merge pull request #45 from viktorkulahin/3.0.2
3.0.2
2 parents 2181e77 + 2bebb44 commit 2471ac6

File tree

8 files changed

+276
-74
lines changed

8 files changed

+276
-74
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ Semantic Versioning is maintained only for the following:
1111
The fixers themselves can change their behavior on any update.
1212
New fixers could be added with minor releases, this would require changes in configuration if migration mode is used.
1313

14+
## 3.0.2
15+
16+
### Changed
17+
- ChainedMethodCallsFixer refactored for the proper whitespaces, new lines etc.
18+
- DefaultValuesInConstructorFixer refactored
19+
- ConditionResultsFixer fixed a bug when trying to get not existed token index+1
20+
- TypeHintingArgumentsFixer to work correctly with nullable (?type) and other arguments.
21+
- ChainedMethodCallsFixerTest - testcases added
22+
- DefaultValuesInConstructorFixerTest - testcases added
23+
1424
## 3.0.1
1525

1626
### Changed

src/Fixer/PhpBasic/CodeStyle/ChainedMethodCallsFixer.php

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,27 @@ public function isCandidate(Tokens $tokens): bool
5050
return $tokens->isTokenKindFound(T_OBJECT_OPERATOR);
5151
}
5252

53+
public function getPriority(): int
54+
{
55+
return 10;
56+
}
57+
5358
protected function applyFix(SplFileInfo $file, Tokens $tokens): void
5459
{
5560
for ($key = 0; $key < $tokens->count(); $key++) {
5661
if (!$tokens[$key]->isGivenKind(T_OBJECT_OPERATOR)) {
5762
continue;
5863
}
5964

60-
$semicolonIndex = $tokens->getNextTokenOfKind($key, [';']);
65+
$endIndex = $tokens->getNextTokenOfKind($key, [';', '{']);
6166
$indent = $this->checkForMethodSplits(
6267
$tokens,
6368
$key,
64-
$semicolonIndex,
69+
$endIndex,
6570
);
6671

6772
if ($indent !== null) {
68-
$key = $this->validateMethodSplits($tokens, $key, $semicolonIndex, $indent);
73+
$key = $this->validateMethodSplits($tokens, $key, $endIndex, $indent);
6974
}
7075
}
7176
}
@@ -85,7 +90,15 @@ private function validateMethodSplits(Tokens $tokens, int $startIndex, int $endI
8590
}
8691
}
8792

88-
if (!$tokens[$i - 1]->isWhitespace() && strpos($tokens[$i - 2]->getContent(), "\n") === false) {
93+
if ($tokens[$i]->isWhitespace() && !str_contains($tokens[$i - 2]->getContent(), "\n")) {
94+
$tokens->clearAt($i);
95+
}
96+
97+
if (
98+
!$tokens[$i - 1]->isWhitespace()
99+
&& !str_contains($tokens[$i - 2]->getContent(), "\n")
100+
&& !str_contains($tokens[$i]->getContent(), "\n")
101+
) {
89102
$tokens->insertSlices([
90103
$i => [
91104
new Token([
@@ -110,6 +123,7 @@ private function checkForMethodSplits(Tokens $tokens, int $startIndex, int $endI
110123
if ($tokens[$i]->equals('(')) {
111124
$blockEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $i);
112125
$i = $blockEndIndex;
126+
continue;
113127
}
114128

115129
if (

src/Fixer/PhpBasic/CodeStyle/DefaultValuesInConstructorFixer.php

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void
7070
$parentConstructNeeded = false;
7171
$isConstructorPresent = false;
7272
$propertiesWithDefaultValues = [];
73-
$endOfPropertyDeclarationSemicolon = 0;
7473

7574
foreach ($tokens as $key => $token) {
7675
if ($this->isConstructor($key, $tokens, $token)) {
@@ -89,6 +88,7 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void
8988
if ($extends !== false) {
9089
$parentConstructNeeded = true;
9190
}
91+
9292
$subsequentDeclarativeToken = $tokens->getNextMeaningfulToken($key);
9393

9494
// @TODO: PHP 7.4 support, drop condition when there will be no PHP 7.4 support.
@@ -150,13 +150,13 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void
150150
&& !$isConstructorPresent
151151
&& count($propertiesWithDefaultValues) > 0
152152
) {
153-
$endOfDeclarationNewLine = $tokens[$endOfPropertyDeclarationSemicolon + 1];
153+
$endOfDeclarationNewLine = $tokens[$key + 1];
154154

155155
$closingCurlyBrace = $tokens->getNextTokenOfKind($key, ['}']);
156156
$indentation = $tokens[$closingCurlyBrace - 1]->getContent();
157157
$index = $this->insertConstructTokensAndReturnOpeningBraceIndex(
158158
$tokens,
159-
$endOfPropertyDeclarationSemicolon + 1,
159+
$key + 1,
160160
$indentation,
161161
);
162162
$tokens->insertSlices([
@@ -211,18 +211,25 @@ private function insertDefaultPropertiesInConstruct(
211211

212212
private function isEndOfPropertiesDeclaration(int $key, Tokens $tokens, Token $token): bool
213213
{
214+
if (!$token->equals(';')) {
215+
return false;
216+
}
217+
214218
$nextMeaningfulToken = $tokens->getNextMeaningfulToken($key);
215-
$subsequentToken = $nextMeaningfulToken ? $tokens->getNextNonWhitespace($nextMeaningfulToken) : null;
216-
217-
return (
218-
$token->equals(';')
219-
&& $tokens[$nextMeaningfulToken]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE])
220-
&& !$tokens[$subsequentToken]->isGivenKind(T_VARIABLE)
221-
|| (
222-
$token->equals(';')
223-
&& !$tokens[$nextMeaningfulToken]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE])
224-
)
225-
);
219+
220+
if (!$tokens[$nextMeaningfulToken]->isGivenKind([T_PUBLIC, T_PROTECTED, T_PRIVATE])) {
221+
return true;
222+
}
223+
224+
for ($i = 0; $i < 2; $i++) {
225+
$nextMeaningfulToken = $tokens->getNextNonWhitespace($nextMeaningfulToken);
226+
227+
if ($tokens[$nextMeaningfulToken]->isGivenKind(T_FUNCTION)) {
228+
return true;
229+
}
230+
}
231+
232+
return false;
226233
}
227234

228235
private function isConstructor(int $key, Tokens $tokens, Token $token): bool

src/Fixer/PhpBasic/Feature/ConditionResultsFixer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ private function validateShortIfStatement(Tokens $tokens, int $key, bool $assign
9595
}
9696
$index = $key + 2;
9797
while (!$tokens[$index]->equals(';')) {
98+
if (!isset($tokens[$index + 1])) {
99+
return;
100+
}
101+
98102
if (!$tokens[$index + 1]->equals('?') && !$tokens[$index]->equals('?')) {
99103
$ifStatementConditionTokens[] = $tokens[$index];
100104
}

src/Fixer/PhpBasic/Feature/TypeHintingArgumentsFixer.php

Lines changed: 108 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,11 @@ public function __construct()
3131

3232
$this->inheritanceHelper = new InheritanceHelper();
3333
$this->unavailableTypeHints = [
34-
'array',
3534
'void',
3635
'self',
3736
'$this',
3837
'mixed',
3938
'callable',
40-
'bool',
41-
'boolean',
42-
'float',
43-
'int',
44-
'integer',
45-
'string',
4639
'resource',
4740
];
4841
}
@@ -159,85 +152,145 @@ private function validateObjectArguments(
159152
int $docBlockIndex,
160153
int $parenthesesStartIndex,
161154
int $parenthesesEndIndex
162-
) {
155+
): void {
163156
$currentParenthesesEndIndex = $parenthesesEndIndex;
164157
$docBlock = new DocBlock($tokens[$docBlockIndex]->getContent());
165158
for ($i = $parenthesesEndIndex; $i > $parenthesesStartIndex; $i--) {
166159
if (!$tokens[$i]->isGivenKind(T_VARIABLE)) {
167160
continue;
168161
}
162+
169163
$previousTokenIndex = $tokens->getPrevMeaningfulToken($i);
170164
if (!$tokens[$previousTokenIndex]->isGivenKind(T_STRING)) {
171165
foreach ($docBlock->getAnnotationsOfType('param') as $annotation) {
172166
$variable = $tokens[$i]->getContent();
173167
if (
174-
!preg_match(
175-
'#^[^$]+@param\s([^$].*?[^\s])\s\\' . $variable . '#m',
176-
$annotation->getContent(),
177-
)
178-
|| preg_match(
179-
'#^[^$]+@param\s(.*?\[\])\s\\' . $variable . '#m',
180-
$annotation->getContent(),
181-
)
168+
$this->isAnnotationWrongFormat($variable, $annotation->getContent())
169+
|| $this->isAnnotationArray($variable, $annotation->getContent())
182170
) {
183171
continue;
184172
}
185173

186174
$argumentTypes = $annotation->getTypes();
187175
$argumentTypeCount = count($argumentTypes);
176+
177+
$argumentTypesNotNullable = [];
178+
foreach ($argumentTypes as $argumentType) {
179+
$argumentTypesNotNullable[] = str_replace('?', '', $argumentType);
180+
}
181+
182+
$nullableFound = false;
188183
$nullFound = in_array('null', $argumentTypes, true);
184+
if (!$nullFound) {
185+
$nullableFound = $this->isNullableFound($argumentTypes);
186+
}
187+
189188
if (
190-
!array_intersect($argumentTypes, $this->unavailableTypeHints)
191-
&& (($argumentTypeCount === 2 && $nullFound) || ($argumentTypeCount === 1) && !$nullFound)
189+
!array_intersect($argumentTypesNotNullable, $this->unavailableTypeHints)
190+
&& (
191+
($argumentTypeCount === 2 && $nullFound)
192+
|| ($argumentTypeCount === 1 && !$nullFound)
193+
)
194+
|| ($argumentTypeCount === 2 && $nullableFound)
192195
) {
193196
$argumentType = trim(implode('', array_diff($argumentTypes, ['null'])));
194-
$tokens->insertSlices([
195-
$i => [
196-
new Token([T_STRING, $argumentType]),
197-
new Token([T_WHITESPACE, ' ']),
198-
],
199-
]);
200-
$currentParenthesesEndIndex += 2;
197+
if (
198+
$tokens[$i]->isGivenKind(T_VARIABLE)
199+
&& !$tokens[$previousTokenIndex]->isGivenKind(10005)
200+
) {
201+
$tokens->insertSlices([
202+
$i => [
203+
new Token([T_STRING, $argumentType]),
204+
new Token([T_WHITESPACE, ' ']),
205+
],
206+
]);
207+
$currentParenthesesEndIndex += 2;
208+
}
201209
}
202210

203211
if ($nullFound) {
204-
/** @var Token[] $variables */
205-
$variables = (clone $tokens)->findGivenKind(
206-
T_VARIABLE,
212+
$this->processIfNullFound(
213+
$tokens,
207214
$parenthesesStartIndex,
208215
$currentParenthesesEndIndex,
216+
$variable
209217
);
210-
$variablePosition = null;
211-
foreach ($variables as $key => $variableToken) {
212-
$expectedEqual = $tokens->getNextMeaningfulToken($key);
213-
$expectedNull = $tokens->getNextMeaningfulToken($expectedEqual);
214-
if (
215-
$tokens[$expectedEqual]->getContent() === '='
216-
&& $tokens[$expectedNull]->getContent() === 'null'
217-
) {
218-
continue;
219-
}
220-
221-
if ($variableToken->getContent() === $variable) {
222-
$variablePosition = $key;
223-
break;
224-
}
225-
}
226-
227-
if ($variablePosition !== null) {
228-
$tokens->insertSlices([
229-
++$variablePosition => [
230-
new Token([T_WHITESPACE, ' ']),
231-
new Token('='),
232-
new Token([T_WHITESPACE, ' ']),
233-
new Token([T_STRING, 'null']),
234-
],
235-
]);
236-
}
237218
}
238219
break;
239220
}
240221
}
241222
}
242223
}
224+
225+
private function isAnnotationWrongFormat(string $variable, string $content): bool
226+
{
227+
return preg_match(
228+
'#^[^$]+@param\s([^$].*?[^\s])\s\\' . $variable . '#m',
229+
$content,
230+
) !== 1;
231+
}
232+
233+
private function isAnnotationArray(string $variable, string $content): bool
234+
{
235+
return preg_match(
236+
'#^[^$]+@param\s(.*?\[\])\s\\' . $variable . '#m',
237+
$content,
238+
) === 1;
239+
}
240+
241+
private function processIfNullFound(
242+
Tokens $tokens,
243+
int $parenthesesStartIndex,
244+
int $currentParenthesesEndIndex,
245+
string $variable
246+
) {
247+
/** @var Token[] $variables */
248+
$variables = (clone $tokens)->findGivenKind(
249+
T_VARIABLE,
250+
$parenthesesStartIndex,
251+
$currentParenthesesEndIndex,
252+
);
253+
$variablePosition = null;
254+
foreach ($variables as $key => $variableToken) {
255+
$expectedEqual = $tokens->getNextMeaningfulToken($key);
256+
$expectedNull = $tokens->getNextMeaningfulToken($expectedEqual);
257+
if (
258+
$tokens[$expectedEqual]->getContent() === '='
259+
&& $tokens[$expectedNull]->getContent() === 'null'
260+
) {
261+
continue;
262+
}
263+
264+
if ($variableToken->getContent() === $variable) {
265+
$variablePosition = $key;
266+
break;
267+
}
268+
}
269+
270+
if ($variablePosition !== null) {
271+
$tokens->insertSlices([
272+
++$variablePosition => [
273+
new Token([T_WHITESPACE, ' ']),
274+
new Token('='),
275+
new Token([T_WHITESPACE, ' ']),
276+
new Token([T_STRING, 'null']),
277+
],
278+
]);
279+
}
280+
}
281+
282+
/**
283+
* @param string[] $argumentTypes
284+
* @return bool
285+
*/
286+
private function isNullableFound(array $argumentTypes): bool
287+
{
288+
foreach ($argumentTypes as $argumentType) {
289+
if (str_contains($argumentType, '?')) {
290+
return true;
291+
}
292+
}
293+
294+
return false;
295+
}
243296
}

0 commit comments

Comments
 (0)