Skip to content

Commit 27f28bb

Browse files
committed
Merge branch '1.11'
Conflicts: README.rst Symfony/CS/Console/Command/FixCommand.php Symfony/CS/Test/AbstractIntegrationTestCase.php Symfony/CS/Tests/FixerTest.php Symfony/CS/Tokenizer/Token.php
2 parents 2ab47d4 + 38a14bd commit 27f28bb

20 files changed

+870
-64
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
.php_cs
22
composer.lock
3-
vendor
43
phpunit.xml
4+
vendor

COOKBOOK-FIXERS.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use Symfony\CS\Tokenizer\Tokens;
6767
/**
6868
* @author Your name <your@email.com>
6969
*/
70-
class RemoveCommentsFixer extends AbstractFixer
70+
final class RemoveCommentsFixer extends AbstractFixer
7171
{
7272
}
7373
```
@@ -99,8 +99,10 @@ use Symfony\CS\Tests\Fixer\AbstractFixerTestBase;
9999

100100
/**
101101
* @author Your name <your@email.com>
102+
*
103+
* @internal
102104
*/
103-
class RemoveCommentsFixerTest extends AbstractFixerTestBase
105+
final class RemoveCommentsFixerTest extends AbstractFixerTestBase
104106
{
105107
/**
106108
* @dataProvider provideFixCases
@@ -182,8 +184,10 @@ use Symfony\CS\Tests\Fixer\AbstractFixerTestBase;
182184

183185
/**
184186
* @author Your name <your@email.com>
187+
*
188+
* @internal
185189
*/
186-
class RemoveCommentsFixerTest extends AbstractFixerTestBase
190+
final class RemoveCommentsFixerTest extends AbstractFixerTestBase
187191
{
188192
/**
189193
* @dataProvider provideFixCases
@@ -214,7 +218,7 @@ implement it.
214218
We need first to create one method to describe what this fixer does:
215219
`Symfony/CS/Fixer/Contrib/RemoveCommentsFixer.php`:
216220
```php
217-
class RemoveCommentsFixer extends AbstractFixer
221+
final class RemoveCommentsFixer extends AbstractFixer
218222
{
219223
/**
220224
* {@inheritdoc}
@@ -229,7 +233,7 @@ class RemoveCommentsFixer extends AbstractFixer
229233
Next, we must filter what type of tokens we want to fix. Here, we are interested in code that contains `T_COMMENT` tokens:
230234
`Symfony/CS/Fixer/Contrib/RemoveCommentsFixer.php`:
231235
```php
232-
class RemoveCommentsFixer extends AbstractFixer
236+
final class RemoveCommentsFixer extends AbstractFixer
233237
{
234238
...
235239
/**
@@ -294,7 +298,7 @@ We do not want all symbols to be analysed. Only `T_COMMENT`. So let us
294298
iterate the token(s) we are interested in.
295299
`Symfony/CS/Fixer/Contrib/RemoveCommentsFixer.php`:
296300
```php
297-
class RemoveCommentsFixer extends AbstractFixer
301+
final class RemoveCommentsFixer extends AbstractFixer
298302
{
299303
/**
300304
* {@inheritdoc}
@@ -317,7 +321,7 @@ OK, now for each `T_COMMENT`, all we need to do is check if the previous
317321
token is a semicolon.
318322
`Symfony/CS/Fixer/Contrib/RemoveCommentsFixer.php`:
319323
```php
320-
class RemoveCommentsFixer extends AbstractFixer
324+
final class RemoveCommentsFixer extends AbstractFixer
321325
{
322326
/**
323327
* {@inheritdoc}
@@ -363,7 +367,7 @@ use Symfony\CS\Tokenizer\Tokens;
363367
/**
364368
* @author Your name <your@email.com>
365369
*/
366-
class RemoveCommentsFixer extends AbstractFixer {
370+
final class RemoveCommentsFixer extends AbstractFixer {
367371
/**
368372
* {@inheritdoc}
369373
*/

README.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ Choose from the list of available fixers:
224224
* **duplicate_semicolon** [@Symfony]
225225
Remove duplicated semicolons.
226226

227+
* **echo_to_print**
228+
Converts echo language
229+
construct to print if
230+
possible.
231+
227232
* **elseif** [@PSR2, @Symfony]
228233
The keyword elseif should be
229234
used instead of else if so
@@ -507,6 +512,10 @@ Choose from the list of available fixers:
507512
incrementation/decrementation
508513
should be used if possible.
509514

515+
* **print_to_echo**
516+
Converts print language
517+
construct to echo if possible.
518+
510519
* **psr0**
511520
Classes must be in a path that
512521
matches their namespace, be at

Symfony/CS/AbstractPhpdocTypesFixer.php

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
namespace Symfony\CS;
1313

14+
use Symfony\CS\DocBlock\Annotation;
1415
use Symfony\CS\DocBlock\DocBlock;
15-
use Symfony\CS\DocBlock\Line;
1616
use Symfony\CS\Tokenizer\Tokens;
1717

1818
/**
@@ -27,9 +27,19 @@ abstract class AbstractPhpdocTypesFixer extends AbstractFixer
2727
/**
2828
* The annotation tags search inside.
2929
*
30-
* @var string[]
30+
* @var string[]|null
3131
*/
32-
protected static $tags = array('param', 'property', 'property-read', 'property-write', 'return', 'type', 'var');
32+
protected static $tags;
33+
34+
/**
35+
* {@inheritdoc}
36+
*/
37+
public function __construct()
38+
{
39+
if (null === static::$tags) {
40+
static::$tags = Annotation::getTagsWithTypes();
41+
}
42+
}
3343

3444
/**
3545
* {@inheritdoc}
@@ -57,7 +67,7 @@ public function fix(\SplFileInfo $file, Tokens $tokens)
5767
}
5868

5969
foreach ($annotations as $annotation) {
60-
$this->fixTypes($doc->getLine($annotation->getStart()), $annotation->getTag()->getName());
70+
$this->fixTypes($annotation);
6171
}
6272

6373
$token->setContent($doc->getContent());
@@ -69,27 +79,18 @@ public function fix(\SplFileInfo $file, Tokens $tokens)
6979
*
7080
* We must be super careful not to modify parts of words.
7181
*
72-
* @param Line $line
73-
* @param string $tag
82+
* This will be nicely handled behind the scenes for us by the annotation class.
83+
*
84+
* @param Annotation $annotation
7485
*/
75-
private function fixTypes(Line $line, $tag)
86+
private function fixTypes(Annotation $annotation)
7687
{
77-
$content = $line->getContent();
78-
$tagSplit = preg_split('/\s*\@'.$tag.'\s*/', $content, 2);
79-
$spaceSplit = preg_split('/\s/', $tagSplit[1], 2);
80-
$usefulContent = $spaceSplit[0];
81-
82-
if (strpos($usefulContent, '|') !== false) {
83-
$newContent = implode('|', $this->normalizeTypes(explode('|', $usefulContent)));
84-
} else {
85-
$newContent = $this->normalizeType($usefulContent);
86-
}
88+
$types = $annotation->getTypes();
89+
90+
$new = $this->normalizeTypes($types);
8791

88-
if ($newContent !== $usefulContent) {
89-
// limiting to 1 replacement to prevent errors like
90-
// "integer $integer" being converted to "int $int"
91-
// when they should be converted to "int $integer"
92-
$line->setContent(preg_replace('/'.preg_quote($usefulContent).'/', $newContent, $content, 1));
92+
if ($types !== $new) {
93+
$annotation->setTypes($new);
9394
}
9495
}
9596

Symfony/CS/Console/Command/FixCommand.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Console\Input\InputArgument;
1616
use Symfony\Component\Console\Input\InputInterface;
1717
use Symfony\Component\Console\Input\InputOption;
18+
use Symfony\Component\Console\Output\ConsoleOutputInterface;
1819
use Symfony\Component\Console\Output\OutputInterface;
1920
use Symfony\Component\EventDispatcher\EventDispatcher;
2021
use Symfony\Component\Stopwatch\Stopwatch;
@@ -334,6 +335,11 @@ protected function execute(InputInterface $input, OutputInterface $output)
334335
}
335336
}
336337

338+
if ($output instanceof ConsoleOutputInterface && extension_loaded('xdebug')) {
339+
$stdErr = $output->getErrorOutput();
340+
$stdErr->writeln(sprintf($stdErr->isDecorated() ? '<bg=yellow;fg=black;>%s</>' : '%s', 'You are running composer with xdebug enabled. This has a major impact on runtime performance.'));
341+
}
342+
337343
$showProgress = $resolver->getProgress();
338344

339345
if ($showProgress) {

Symfony/CS/DocBlock/Annotation.php

Lines changed: 105 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,80 @@
1919
class Annotation
2020
{
2121
/**
22-
* The lines that make up the annotation.
22+
* All the annotation tag names with types.
2323
*
24-
* Note that the array indexes represent the position in the docblock.
24+
* @var string[]
25+
*/
26+
private static $tags = array(
27+
'method',
28+
'param',
29+
'property',
30+
'property-read',
31+
'property-write',
32+
'return',
33+
'throws',
34+
'type',
35+
'var',
36+
);
37+
38+
/**
39+
* The lines that make up the annotation.
2540
*
2641
* @var Line[]
2742
*/
2843
private $lines;
2944

45+
/**
46+
* The position of the first line of the annotation in the docblock.
47+
*
48+
* @var int
49+
*/
50+
private $start;
51+
52+
/**
53+
* The position of the last line of the annotation in the docblock.
54+
*
55+
* @var int
56+
*/
57+
private $end;
58+
3059
/**
3160
* The associated tag.
3261
*
3362
* @var Tag|null
3463
*/
3564
private $tag;
3665

66+
/**
67+
* The cached types content.
68+
*
69+
* @var string|null
70+
*/
71+
private $typesContent;
72+
3773
/**
3874
* Create a new line instance.
3975
*
4076
* @param Line[] $lines
4177
*/
4278
public function __construct(array $lines)
4379
{
44-
$this->lines = $lines;
80+
$this->lines = array_values($lines);
81+
82+
$keys = array_keys($lines);
83+
84+
$this->start = $keys[0];
85+
$this->end = end($keys);
86+
}
87+
88+
/**
89+
* Get all the annotation tag names with types.
90+
*
91+
* @var string[]
92+
*/
93+
public static function getTagsWithTypes()
94+
{
95+
return self::$tags;
4596
}
4697

4798
/**
@@ -51,9 +102,7 @@ public function __construct(array $lines)
51102
*/
52103
public function getStart()
53104
{
54-
$keys = array_keys($this->lines);
55-
56-
return $keys[0];
105+
return $this->start;
57106
}
58107

59108
/**
@@ -63,9 +112,7 @@ public function getStart()
63112
*/
64113
public function getEnd()
65114
{
66-
$keys = array_keys($this->lines);
67-
68-
return end($keys);
115+
return $this->end;
69116
}
70117

71118
/**
@@ -83,6 +130,55 @@ public function getTag()
83130
return $this->tag;
84131
}
85132

133+
/**
134+
* Get the current types content.
135+
*
136+
* Be careful modifying the underlying line as that won't flush the cache.
137+
*
138+
* @return string
139+
*/
140+
private function getTypesContent()
141+
{
142+
if (null === $this->typesContent) {
143+
$name = $this->getTag()->getName();
144+
145+
if (!in_array($name, self::$tags, true)) {
146+
throw new \RuntimeException('This tag does not support types');
147+
}
148+
149+
$tagSplit = preg_split('/\s*\@'.$name.'\s*/', $this->lines[0]->getContent(), 2);
150+
$spaceSplit = preg_split('/\s/', $tagSplit[1], 2);
151+
152+
$this->typesContent = $spaceSplit[0];
153+
}
154+
155+
return $this->typesContent;
156+
}
157+
158+
/**
159+
* Get the types associated with this annotation.
160+
*
161+
* @return string[]
162+
*/
163+
public function getTypes()
164+
{
165+
return explode('|', $this->getTypesContent());
166+
}
167+
168+
/**
169+
* Set the types associated with this annotation.
170+
*
171+
* @param string[] $types
172+
*/
173+
public function setTypes(array $types)
174+
{
175+
$pattern = '/'.preg_quote($this->getTypesContent()).'/';
176+
177+
$this->lines[0]->setContent(preg_replace($pattern, implode('|', $types), $this->lines[0]->getContent(), 1));
178+
179+
$this->typesContent = null;
180+
}
181+
86182
/**
87183
* Remove this annotation by removing all its lines.
88184
*/

0 commit comments

Comments
 (0)