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

keradus / PHP-CS-Fixer / 17678835382

12 Sep 2025 03:24PM UTC coverage: 94.69% (-0.06%) from 94.75%
17678835382

push

github

keradus
fix typo

1 of 1 new or added line in 1 file covered. (100.0%)

1042 existing lines in 177 files now uncovered.

28424 of 30018 relevant lines covered (94.69%)

45.5 hits per line

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

90.79
/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
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
29
 */
30
final class DocBlock
31
{
32
    /**
33
     * @var list<Line>
34
     */
35
    private array $lines = [];
36

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

42
    private ?NamespaceAnalysis $namespace;
43

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

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

58
        $this->namespace = $namespace;
21✔
59
        $this->namespaceUses = $namespaceUses;
21✔
60
    }
61

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

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

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

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

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

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

114
        return $this->annotations;
5✔
115
    }
116

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

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

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

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

UNCOV
140
            return;
×
141
        }
142

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

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

156
        $usefulLines = array_filter(
5✔
157
            $this->lines,
5✔
158
            static fn (Line $line): bool => $line->containsUsefulContent()
5✔
159
        );
5✔
160

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

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

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

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

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

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

191
        $annotations = [];
4✔
192

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

200
        return $annotations;
4✔
201
    }
202

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

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

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

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

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

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

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

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

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

251
        return trim($lineString);
6✔
252
    }
253
}
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

© 2026 Coveralls, Inc