Skip to content

Commit e46e694

Browse files
gharlanondrejmirtes
authored andcommitted
bleedingEdge: use rawMessage in baseline generators
1 parent 480d60c commit e46e694

File tree

8 files changed

+224
-27
lines changed

8 files changed

+224
-27
lines changed

conf/bleedingEdge.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ parameters:
1111
newStaticInAbstractClassStaticMethod: true
1212
checkExtensionsForComparisonOperators: true
1313
reportTooWideBool: true
14+
rawMessageInBaseline: true

conf/config.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ parameters:
3535
newStaticInAbstractClassStaticMethod: false
3636
checkExtensionsForComparisonOperators: false
3737
reportTooWideBool: false
38+
rawMessageInBaseline: false
3839
fileExtensions:
3940
- php
4041
checkAdvancedIsset: false

conf/parametersSchema.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ parametersSchema:
3838
newStaticInAbstractClassStaticMethod: bool()
3939
checkExtensionsForComparisonOperators: bool()
4040
reportTooWideBool: bool()
41+
rawMessageInBaseline: bool()
4142
])
4243
fileExtensions: listOf(string())
4344
checkAdvancedIsset: bool()

src/Command/AnalyseCommand.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -733,12 +733,13 @@ private function generateBaseline(string $generateBaselineFile, InceptionResult
733733
$baselineOutput = new SymfonyOutput($streamOutput, new SymfonyStyle($errorConsoleStyle));
734734
$baselineFileDirectory = dirname($generateBaselineFile);
735735
$baselinePathHelper = new ParentDirectoryRelativePathHelper($baselineFileDirectory);
736+
$rawMessageInBaseline = $inceptionResult->getContainer()->getParameter('featureToggles')['rawMessageInBaseline'];
736737

737738
if ($baselineExtension === 'php') {
738-
$baselineErrorFormatter = new BaselinePhpErrorFormatter($baselinePathHelper);
739+
$baselineErrorFormatter = new BaselinePhpErrorFormatter($baselinePathHelper, $rawMessageInBaseline);
739740
$baselineErrorFormatter->formatErrors($analysisResult, $baselineOutput);
740741
} else {
741-
$baselineErrorFormatter = new BaselineNeonErrorFormatter($baselinePathHelper);
742+
$baselineErrorFormatter = new BaselineNeonErrorFormatter($baselinePathHelper, $rawMessageInBaseline);
742743
$existingBaselineContent = is_file($generateBaselineFile) ? FileReader::read($generateBaselineFile) : '';
743744
$baselineErrorFormatter->formatErrors($analysisResult, $baselineOutput, $existingBaselineContent);
744745
}

src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
final class BaselineNeonErrorFormatter
1919
{
2020

21-
public function __construct(private RelativePathHelper $relativePathHelper)
21+
public function __construct(private RelativePathHelper $relativePathHelper, private bool $useRawMessage)
2222
{
2323
}
2424

@@ -42,6 +42,7 @@ public function formatErrors(
4242
}
4343
ksort($fileErrors, SORT_STRING);
4444

45+
$messageKey = $this->useRawMessage ? 'rawMessage' : 'message';
4546
$errorsToOutput = [];
4647
foreach ($fileErrors as $file => $errors) {
4748
$fileErrorsByMessage = [];
@@ -72,19 +73,23 @@ public function formatErrors(
7273
ksort($fileErrorsByMessage, SORT_STRING);
7374

7475
foreach ($fileErrorsByMessage as $message => [$totalCount, $identifiers]) {
76+
if (!$this->useRawMessage) {
77+
$message = '#^' . preg_quote($message, '#') . '$#';
78+
}
79+
7580
ksort($identifiers, SORT_STRING);
7681
if (count($identifiers) > 0) {
7782
foreach ($identifiers as $identifier => $identifierCount) {
7883
$errorsToOutput[] = [
79-
'message' => Helpers::escape('#^' . preg_quote($message, '#') . '$#'),
84+
$messageKey => Helpers::escape($message),
8085
'identifier' => $identifier,
8186
'count' => $identifierCount,
8287
'path' => Helpers::escape($file),
8388
];
8489
}
8590
} else {
8691
$errorsToOutput[] = [
87-
'message' => Helpers::escape('#^' . preg_quote($message, '#') . '$#'),
92+
$messageKey => Helpers::escape($message),
8893
'count' => $totalCount,
8994
'path' => Helpers::escape($file),
9095
];
@@ -98,7 +103,7 @@ public function formatErrors(
98103
}
99104

100105
/**
101-
* @param array<int, array{message: string, count: int, path: string}> $ignoreErrors
106+
* @param array<int, array<string, string|int>> $ignoreErrors
102107
*/
103108
private function getNeon(array $ignoreErrors, string $existingBaselineContent): string
104109
{

src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
final class BaselinePhpErrorFormatter
1717
{
1818

19-
public function __construct(private RelativePathHelper $relativePathHelper)
19+
public function __construct(private RelativePathHelper $relativePathHelper, private bool $useRawMessage)
2020
{
2121
}
2222

@@ -76,21 +76,30 @@ public function formatErrors(
7676
ksort($fileErrorsByMessage, SORT_STRING);
7777

7878
foreach ($fileErrorsByMessage as $message => [$totalCount, $identifiers]) {
79+
if ($this->useRawMessage) {
80+
$messageKey = 'rawMessage';
81+
} else {
82+
$messageKey = 'message';
83+
$message = '#^' . preg_quote($message, '#') . '$#';
84+
}
85+
7986
ksort($identifiers, SORT_STRING);
8087
if (count($identifiers) > 0) {
8188
foreach ($identifiers as $identifier => $identifierCount) {
8289
$php .= sprintf(
83-
"\$ignoreErrors[] = [\n\t'message' => %s,\n\t'identifier' => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n",
84-
var_export(Helpers::escape('#^' . preg_quote($message, '#') . '$#'), true),
90+
"\$ignoreErrors[] = [\n\t%s => %s,\n\t'identifier' => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n",
91+
var_export($messageKey, true),
92+
var_export(Helpers::escape($message), true),
8593
var_export(Helpers::escape($identifier), true),
8694
var_export($identifierCount, true),
8795
var_export(Helpers::escape($file), true),
8896
);
8997
}
9098
} else {
9199
$php .= sprintf(
92-
"\$ignoreErrors[] = [\n\t'message' => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n",
93-
var_export(Helpers::escape('#^' . preg_quote($message, '#') . '$#'), true),
100+
"\$ignoreErrors[] = [\n\t%s => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n",
101+
var_export($messageKey, true),
102+
var_export(Helpers::escape($message), true),
94103
var_export($totalCount, true),
95104
var_export(Helpers::escape($file), true),
96105
);

tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php

Lines changed: 130 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public static function dataFormatterOutputProvider(): iterable
3636
0,
3737
0,
3838
0,
39+
false,
3940
[],
4041
];
4142

@@ -44,6 +45,7 @@ public static function dataFormatterOutputProvider(): iterable
4445
1,
4546
1,
4647
0,
48+
false,
4749
[
4850
[
4951
'message' => '#^Foo$#',
@@ -58,6 +60,7 @@ public static function dataFormatterOutputProvider(): iterable
5860
1,
5961
4,
6062
0,
63+
false,
6164
[
6265
[
6366
'message' => "#^Bar\nBar2$#",
@@ -87,6 +90,7 @@ public static function dataFormatterOutputProvider(): iterable
8790
1,
8891
4,
8992
2,
93+
false,
9094
[
9195
[
9296
'message' => "#^Bar\nBar2$#",
@@ -110,6 +114,36 @@ public static function dataFormatterOutputProvider(): iterable
110114
],
111115
],
112116
];
117+
118+
yield [
119+
'Multiple file, multiple generic errors (raw messages)',
120+
1,
121+
4,
122+
2,
123+
true,
124+
[
125+
[
126+
'rawMessage' => "Bar\nBar2",
127+
'count' => 1,
128+
'path' => 'folder with unicode 😃/file name with "spaces" and unicode 😃.php',
129+
],
130+
[
131+
'rawMessage' => 'Foo',
132+
'count' => 1,
133+
'path' => 'folder with unicode 😃/file name with "spaces" and unicode 😃.php',
134+
],
135+
[
136+
'rawMessage' => "Bar\nBar2",
137+
'count' => 1,
138+
'path' => 'foo.php',
139+
],
140+
[
141+
'rawMessage' => 'Foo<Bar>',
142+
'count' => 1,
143+
'path' => 'foo.php',
144+
],
145+
],
146+
];
113147
}
114148

115149
/**
@@ -121,10 +155,11 @@ public function testFormatErrors(
121155
int $exitCode,
122156
int $numFileErrors,
123157
int $numGenericErrors,
158+
bool $useRawMessage,
124159
array $expected,
125160
): void
126161
{
127-
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH));
162+
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH), $useRawMessage);
128163

129164
$this->assertSame($exitCode, $formatter->formatErrors(
130165
$this->getAnalysisResult($numFileErrors, $numGenericErrors),
@@ -137,7 +172,7 @@ public function testFormatErrors(
137172

138173
public function testFormatErrorMessagesRegexEscape(): void
139174
{
140-
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH));
175+
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH), false);
141176

142177
$result = new AnalysisResult(
143178
[new Error('Escape Regex with file # ~ \' ()', 'Testfile')],
@@ -176,11 +211,51 @@ public function testFormatErrorMessagesRegexEscape(): void
176211
);
177212
}
178213

179-
public function testEscapeDiNeon(): void
214+
/**
215+
* @return iterable<int, array{Error, bool, array<string, string|int>}>
216+
*/
217+
public static function dataEscapeDiNeon(): iterable
218+
{
219+
yield [
220+
new Error('Test %value%', 'Testfile'),
221+
false,
222+
[
223+
'message' => '#^Test %%value%%$#',
224+
'count' => 1,
225+
'path' => 'Testfile',
226+
],
227+
];
228+
229+
yield [
230+
new Error('Test %value%', 'Testfile'),
231+
true,
232+
[
233+
'rawMessage' => 'Test %%value%%',
234+
'count' => 1,
235+
'path' => 'Testfile',
236+
],
237+
];
238+
239+
yield [
240+
new Error('@Foo', 'Testfile'),
241+
true,
242+
[
243+
'rawMessage' => '@@Foo',
244+
'count' => 1,
245+
'path' => 'Testfile',
246+
],
247+
];
248+
}
249+
250+
/**
251+
* @param array<string, string|int> $expected
252+
*/
253+
#[DataProvider('dataEscapeDiNeon')]
254+
public function testEscapeDiNeon(Error $error, bool $useRawMessage, array $expected): void
180255
{
181-
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH));
256+
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH), $useRawMessage);
182257
$result = new AnalysisResult(
183-
[new Error('Test %value%', 'Testfile')],
258+
[$error],
184259
[],
185260
[],
186261
[],
@@ -203,11 +278,7 @@ public function testEscapeDiNeon(): void
203278
Neon::encode([
204279
'parameters' => [
205280
'ignoreErrors' => [
206-
[
207-
'message' => '#^Test %%value%%$#',
208-
'count' => 1,
209-
'path' => 'Testfile',
210-
],
281+
$expected,
211282
],
212283
],
213284
], Neon::BLOCK),
@@ -245,7 +316,7 @@ public static function outputOrderingProvider(): Generator
245316
#[DataProvider('outputOrderingProvider')]
246317
public function testOutputOrdering(array $errors): void
247318
{
248-
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH));
319+
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH), false);
249320
$result = new AnalysisResult(
250321
$errors,
251322
[],
@@ -404,7 +475,7 @@ public function testEndOfFileNewlines(
404475
int $expectedNewlinesCount,
405476
): void
406477
{
407-
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH));
478+
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(self::DIRECTORY_PATH), false);
408479
$result = new AnalysisResult(
409480
$errors,
410481
[],
@@ -468,6 +539,7 @@ public static function dataFormatErrorsWithIdentifiers(): iterable
468539
6,
469540
))->withIdentifier('argument.type'),
470541
],
542+
false,
471543
[
472544
'parameters' => [
473545
'ignoreErrors' => [
@@ -515,6 +587,7 @@ public static function dataFormatErrorsWithIdentifiers(): iterable
515587
5,
516588
))->withIdentifier('argument.type'),
517589
],
590+
false,
518591
[
519592
'parameters' => [
520593
'ignoreErrors' => [
@@ -545,16 +618,59 @@ public static function dataFormatErrorsWithIdentifiers(): iterable
545618
],
546619
],
547620
];
621+
622+
yield [
623+
[
624+
new Error(
625+
'Foo',
626+
__DIR__ . '/Foo.php',
627+
5,
628+
),
629+
new Error(
630+
'Foo',
631+
__DIR__ . '/Foo.php',
632+
5,
633+
),
634+
(new Error(
635+
'Foo with identifier',
636+
__DIR__ . '/Foo.php',
637+
5,
638+
))->withIdentifier('argument.type'),
639+
(new Error(
640+
'Foo with identifier',
641+
__DIR__ . '/Foo.php',
642+
6,
643+
))->withIdentifier('argument.type'),
644+
],
645+
true,
646+
[
647+
'parameters' => [
648+
'ignoreErrors' => [
649+
[
650+
'rawMessage' => 'Foo',
651+
'count' => 2,
652+
'path' => 'Foo.php',
653+
],
654+
[
655+
'rawMessage' => 'Foo with identifier',
656+
'identifier' => 'argument.type',
657+
'count' => 2,
658+
'path' => 'Foo.php',
659+
],
660+
],
661+
],
662+
],
663+
];
548664
}
549665

550666
/**
551667
* @param list<Error> $errors
552668
* @param mixed[] $expectedOutput
553669
*/
554670
#[DataProvider('dataFormatErrorsWithIdentifiers')]
555-
public function testFormatErrorsWithIdentifiers(array $errors, array $expectedOutput): void
671+
public function testFormatErrorsWithIdentifiers(array $errors, bool $useRawMessage, array $expectedOutput): void
556672
{
557-
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(__DIR__));
673+
$formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(__DIR__), $useRawMessage);
558674
$formatter->formatErrors(
559675
new AnalysisResult(
560676
$errors,

0 commit comments

Comments
 (0)