• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PHP-CS-Fixer / PHP-CS-Fixer / 3721300657

pending completion
3721300657

push

github

GitHub
minor: Follow PSR12 ordered imports in Symfony ruleset (#6712)

9 of 9 new or added lines in 2 files covered. (100.0%)

22674 of 24281 relevant lines covered (93.38%)

39.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/src/DocBlock/DocBlock.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of PHP CS Fixer.
7
 *
8
 * (c) Fabien Potencier <fabien@symfony.com>
9
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14

15
namespace PhpCsFixer\DocBlock;
16

17
use PhpCsFixer\Preg;
18
use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
19
use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
20

21
/**
22
 * This class represents a docblock.
23
 *
24
 * It internally splits it up into "lines" that we can manipulate.
25
 *
26
 * @author Graham Campbell <hello@gjcampbell.co.uk>
27
 */
28
final class DocBlock
29
{
30
    /**
31
     * @var list<Line>
32
     */
33
    private array $lines = [];
34

35
    /**
36
     * @var null|list<Annotation>
37
     */
38
    private ?array $annotations = null;
39

40
    private ?NamespaceAnalysis $namespace;
41

42
    /**
43
     * @var list<NamespaceUseAnalysis>
44
     */
45
    private array $namespaceUses;
46

47
    /**
48
     * @param list<NamespaceUseAnalysis> $namespaceUses
49
     */
50
    public function __construct(string $content, ?NamespaceAnalysis $namespace = null, array $namespaceUses = [])
51
    {
52
        foreach (Preg::split('/([^\n\r]+\R*)/', $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $line) {
21✔
53
            $this->lines[] = new Line($line);
20✔
54
        }
55

56
        $this->namespace = $namespace;
21✔
57
        $this->namespaceUses = $namespaceUses;
21✔
58
    }
59

60
    public function __toString(): string
61
    {
62
        return $this->getContent();
1✔
63
    }
64

65
    /**
66
     * Get this docblock's lines.
67
     *
68
     * @return list<Line>
69
     */
70
    public function getLines(): array
71
    {
72
        return $this->lines;
1✔
73
    }
74

75
    /**
76
     * Get a single line.
77
     */
78
    public function getLine(int $pos): ?Line
79
    {
80
        return $this->lines[$pos] ?? null;
6✔
81
    }
82

83
    /**
84
     * Get this docblock's annotations.
85
     *
86
     * @return list<Annotation>
87
     */
88
    public function getAnnotations(): array
89
    {
90
        if (null !== $this->annotations) {
5✔
91
            return $this->annotations;
1✔
92
        }
93

94
        $this->annotations = [];
5✔
95
        $total = \count($this->lines);
5✔
96

97
        for ($index = 0; $index < $total; ++$index) {
5✔
98
            if ($this->lines[$index]->containsATag()) {
5✔
99
                // get all the lines that make up the annotation
100
                $lines = \array_slice($this->lines, $index, $this->findAnnotationLength($index), true);
5✔
101
                $annotation = new Annotation($lines, $this->namespace, $this->namespaceUses);
5✔
102
                // move the index to the end of the annotation to avoid
103
                // checking it again because we know the lines inside the
104
                // current annotation cannot be part of another annotation
105
                $index = $annotation->getEnd();
5✔
106
                // add the current annotation to the list of annotations
107
                $this->annotations[] = $annotation;
5✔
108
            }
109
        }
110

111
        return $this->annotations;
5✔
112
    }
113

114
    public function isMultiLine(): bool
115
    {
116
        return 1 !== \count($this->lines);
13✔
117
    }
118

119
    /**
120
     * Take a one line doc block, and turn it into a multi line doc block.
121
     */
122
    public function makeMultiLine(string $indent, string $lineEnd): void
123
    {
124
        if ($this->isMultiLine()) {
6✔
125
            return;
3✔
126
        }
127

128
        $lineContent = $this->getSingleLineDocBlockEntry($this->lines[0]);
3✔
129

130
        if ('' === $lineContent) {
3✔
131
            $this->lines = [
×
132
                new Line('/**'.$lineEnd),
×
133
                new Line($indent.' *'.$lineEnd),
×
134
                new Line($indent.' */'),
×
135
            ];
×
136

137
            return;
×
138
        }
139

140
        $this->lines = [
3✔
141
            new Line('/**'.$lineEnd),
3✔
142
            new Line($indent.' * '.$lineContent.$lineEnd),
3✔
143
            new Line($indent.' */'),
3✔
144
        ];
3✔
145
    }
146

147
    public function makeSingleLine(): void
148
    {
149
        if (!$this->isMultiLine()) {
6✔
150
            return;
1✔
151
        }
152

153
        $usefulLines = array_filter(
5✔
154
            $this->lines,
5✔
155
            static function (Line $line): bool {
5✔
156
                return $line->containsUsefulContent();
5✔
157
            }
5✔
158
        );
5✔
159

160
        if (1 < \count($usefulLines)) {
5✔
161
            return;
1✔
162
        }
163

164
        $lineContent = '';
4✔
165
        if (\count($usefulLines) > 0) {
4✔
166
            $lineContent = $this->getSingleLineDocBlockEntry(array_shift($usefulLines));
3✔
167
        }
168

169
        $this->lines = [new Line('/** '.$lineContent.' */')];
4✔
170
    }
171

172
    public function getAnnotation(int $pos): ?Annotation
173
    {
174
        $annotations = $this->getAnnotations();
1✔
175

176
        return $annotations[$pos] ?? null;
1✔
177
    }
178

179
    /**
180
     * Get specific types of annotations only.
181
     *
182
     * @param list<string>|string $types
183
     *
184
     * @return list<Annotation>
185
     */
186
    public function getAnnotationsOfType($types): array
187
    {
188
        $typesToSearchFor = (array) $types;
4✔
189

190
        $annotations = [];
4✔
191

192
        foreach ($this->getAnnotations() as $annotation) {
4✔
193
            $tagName = $annotation->getTag()->getName();
4✔
194
            if (\in_array($tagName, $typesToSearchFor, true)) {
4✔
195
                $annotations[] = $annotation;
3✔
196
            }
197
        }
198

199
        return $annotations;
4✔
200
    }
201

202
    /**
203
     * Get the actual content of this docblock.
204
     */
205
    public function getContent(): string
206
    {
207
        return implode('', $this->lines);
14✔
208
    }
209

210
    private function findAnnotationLength(int $start): int
211
    {
212
        $index = $start;
5✔
213

214
        while ($line = $this->getLine(++$index)) {
5✔
215
            if ($line->containsATag()) {
5✔
216
                // we've 100% reached the end of the description if we get here
217
                break;
5✔
218
            }
219

220
            if (!$line->containsUsefulContent()) {
5✔
221
                // if next line is also non-useful, or contains a tag, then we're done here
222
                $next = $this->getLine($index + 1);
5✔
223
                if (null === $next || !$next->containsUsefulContent() || $next->containsATag()) {
5✔
224
                    break;
5✔
225
                }
226
                // otherwise, continue, the annotation must have contained a blank line in its description
227
            }
228
        }
229

230
        return $index - $start;
5✔
231
    }
232

233
    private function getSingleLineDocBlockEntry(Line $line): string
234
    {
235
        $lineString = $line->getContent();
6✔
236

237
        if ('' === $lineString) {
6✔
238
            return $lineString;
×
239
        }
240

241
        $lineString = str_replace('*/', '', $lineString);
6✔
242
        $lineString = trim($lineString);
6✔
243

244
        if (str_starts_with($lineString, '/**')) {
6✔
245
            $lineString = substr($lineString, 3);
3✔
246
        } elseif (str_starts_with($lineString, '*')) {
3✔
247
            $lineString = substr($lineString, 1);
3✔
248
        }
249

250
        return trim($lineString);
6✔
251
    }
252
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc