From 6cf7b267708fec4ec1348c756e56a1752601420b Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 23 Apr 2022 11:44:14 +0200 Subject: [PATCH 01/46] disussion#7862: adds first test case --- tests/ReportOutputTest.php | 96 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 5fb82b594f4..3fabcad6a49 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -3,6 +3,7 @@ namespace Psalm\Tests; use DOMDocument; +use Generator; use Psalm\Config; use Psalm\Context; use Psalm\Internal\Analyzer\IssueData; @@ -17,6 +18,7 @@ use Psalm\Tests\Internal\Provider\FakeParserCacheProvider; use UnexpectedValueException; +use function explode; use function file_get_contents; use function json_decode; use function ob_end_clean; @@ -26,6 +28,8 @@ use const JSON_THROW_ON_ERROR; +use const PHP_EOL; + class ReportOutputTest extends TestCase { public function setUp(): void @@ -1323,4 +1327,96 @@ private function toUnixLineEndings(string $output): string { return preg_replace('~\r\n?~', "\n", $output); } + + /** + * @dataProvider outputProvider() + */ + public function testConsoleReportWithPrettyPrint(string $file_contents, $expected_output): void + { + $this->addFile( + 'somefile.php', + $file_contents + ); + + $this->analyzeFile('somefile.php', new Context()); + + $console_report_options = new ReportOptions(); + $console_report_options->use_color = false; + $console_report_options->show_info = false; + $console_report_options->pretty_print_array = true; + + $output = IssueBuffer::getOutput(IssueBuffer::getIssuesData(), $console_report_options); + foreach (explode(PHP_EOL, $expected_output) as $line) { + $this->assertStringContainsString($line, $output); + } + } + + /** + * @return Generator> + */ + public function outputProvider(): Generator + { + $file_contents = <<<'EOT' + + */ +function request(): array +{ + return [ "aa" => "bar"]; +} + +function accept(array $input): void +{ + $v = $input["foo"]; +} + +accept(request()); +'; +EOT; + + $exp = <<<"EOT" +| Expected | Provided +| --- | --- +| array { | array { +| array-key, | aa: 'bar' +| int | } +| } | +| | +EOT; + + yield 'C1' => [$file_contents, $exp]; + + + $file_contents = <<<'EOT' + + */ +function request(): array +{ + return [ "aa" => 111]; +} + +function accept(array $input): void +{ + $v = $input["foo"]; +} + +accept(request()); +'; +EOT; + + $exp = <<<"EOT" +| Expected | Provided +| --- | --- +| array { | array { +| array-key, | aa: 111 +| string | } +| } | +| | +EOT; + + yield 'C2' => [$file_contents, $exp]; + } } From d0f43112317bc0260d053c0788bff9df60cfffe7 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:42:36 +0200 Subject: [PATCH 02/46] adds pretty options --- src/Psalm/Report.php | 4 ++++ src/Psalm/Report/ReportOptions.php | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/Psalm/Report.php b/src/Psalm/Report.php index e1956d1991e..59541ceffa2 100644 --- a/src/Psalm/Report.php +++ b/src/Psalm/Report.php @@ -76,6 +76,9 @@ abstract class Report /** @var int */ protected $total_expression_count; + /** @var bool */ + protected $pretty_print_array = false; + /** * @param array $issues_data * @param array $fixable_issue_counts @@ -102,6 +105,7 @@ public function __construct( $this->show_info = $report_options->show_info; $this->pretty = $report_options->pretty; $this->in_ci = $report_options->in_ci; + $this->pretty_print_array = $report_options->pretty_print_array; $this->mixed_expression_count = $mixed_expression_count; $this->total_expression_count = $total_expression_count; diff --git a/src/Psalm/Report/ReportOptions.php b/src/Psalm/Report/ReportOptions.php index 242caf4884a..34d5152ac0a 100644 --- a/src/Psalm/Report/ReportOptions.php +++ b/src/Psalm/Report/ReportOptions.php @@ -43,4 +43,7 @@ final class ReportOptions /** @var bool */ public $in_ci = false; + + /** @var bool */ + public $pretty_print_array = false; } From e84df6506e7a670243f8e73deb77b54c850cebbf Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:42:48 +0200 Subject: [PATCH 03/46] fix test --- tests/ReportOutputTest.php | 199 +++++++++++++++++++++++++------------ 1 file changed, 133 insertions(+), 66 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 3fabcad6a49..ce6bc2dca44 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -27,7 +27,6 @@ use function unlink; use const JSON_THROW_ON_ERROR; - use const PHP_EOL; class ReportOutputTest extends TestCase @@ -1331,24 +1330,15 @@ private function toUnixLineEndings(string $output): string /** * @dataProvider outputProvider() */ - public function testConsoleReportWithPrettyPrint(string $file_contents, $expected_output): void + public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_contents, $expected_output): void { - $this->addFile( - 'somefile.php', - $file_contents - ); - + $this->addFile('somefile.php', $file_contents); $this->analyzeFile('somefile.php', new Context()); - $console_report_options = new ReportOptions(); - $console_report_options->use_color = false; - $console_report_options->show_info = false; - $console_report_options->pretty_print_array = true; - + $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); $output = IssueBuffer::getOutput(IssueBuffer::getIssuesData(), $console_report_options); - foreach (explode(PHP_EOL, $expected_output) as $line) { - $this->assertStringContainsString($line, $output); - } + + $this->assertOutputPrettyPrintEquals($expected_output, $output); } /** @@ -1357,66 +1347,143 @@ public function testConsoleReportWithPrettyPrint(string $file_contents, $expecte public function outputProvider(): Generator { $file_contents = <<<'EOT' - - */ -function request(): array -{ - return [ "aa" => "bar"]; -} + + */ + function request(): array + { + return [ "aa" => "bar"]; + } -function accept(array $input): void -{ - $v = $input["foo"]; -} + function accept(array $input): void + { + $v = $input["foo"]; + } -accept(request()); -'; -EOT; + accept(request()); + ; + EOT; - $exp = <<<"EOT" -| Expected | Provided -| --- | --- -| array { | array { -| array-key, | aa: 'bar' -| int | } -| } | -| | -EOT; - - yield 'C1' => [$file_contents, $exp]; + $expected_output = <<<'EOT' + | Expected | Provided + | --- | --- + | array { | array { + | array-key, | aa: 'bar' + | int | } + | } | + | | + EOT; + yield [$file_contents, $expected_output]; $file_contents = <<<'EOT' - - */ -function request(): array -{ - return [ "aa" => 111]; -} + + */ + function request(): array + { + return [ "aa" => 111]; + } -function accept(array $input): void -{ - $v = $input["foo"]; -} + function accept(array $input): void + { + $v = $input["foo"]; + } -accept(request()); -'; -EOT; + accept(request()); + ; + EOT; $exp = <<<"EOT" -| Expected | Provided -| --- | --- -| array { | array { -| array-key, | aa: 111 -| string | } -| } | -| | -EOT; - - yield 'C2' => [$file_contents, $exp]; + | Expected | Provided + | --- | --- + | array { | array { + | array-key, | aa: 111 + | string | } + | } | + | | + EOT; + + yield [$file_contents, $exp]; + } + + /** + * @dataProvider payloadProvider() + */ + public function testConsoleReportWithPrettyPrintFromPayload(string $payload, $expected_output): void + { + $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); + $issues_data = [ + 1 => new IssueData( + 'error', + 15, + 15, + 'InvalidReturnStatement', + $payload, + 'somefile.php', + 'somefile.php', + '', + '$a', + 201, + 203, + 196, + 203, + 6, + 8 + ), + ]; + + $consoleReport = new Report\ConsoleReport($issues_data, [], $console_report_options); + $output = $consoleReport->create(); + $this->assertOutputPrettyPrintEquals($expected_output, $output); + } + + /** + * @return Generator> + */ + public function payloadProvider(): Generator + { + $paylaod = <<<'EOT' + 'ERROR: InvalidReturnStatement - XXXX.php:66:16 - + The inferred type 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_ccccc: null|string, tid_bbbbb: null|string}' does not match the declared return type 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_aaaaaa: null|string, tid_bbbbb: null|string}' for YYYYY() (see https://psalm.dev/128) + EOT; + + $expected = <<<"EOT" + | + | Expected | Provided + | --- | --- + | array { | array { + | code_xxx: null|string, | code_xxx: null|string, + | datetime: null|string, | datetime: null|string, + | money: float|null, | money: float|null, + | id_yyyy: null|string, | id_yyyy: null|string, + | tid_ccccc: null|string, | tid_aaaaaa: null|string, + | tid_bbbbb: null|string | tid_bbbbb: null|string + | } | } + | + EOT; + + + yield [$paylaod, $expected]; + } + + private function prepareConsoleOptionsForPrettyPrint(): ReportOptions + { + $console_report_options = new ReportOptions(); + $console_report_options->use_color = false; + $console_report_options->show_info = false; + $console_report_options->pretty_print_array = true; + return $console_report_options; + } + + private function assertOutputPrettyPrintEquals($expected_output, string $output): void + { + $lines = explode(PHP_EOL, $expected_output); + + foreach ($lines as $line) { + $this->assertStringContainsString($line, $output); + } } } From 3c204d5420cf541bc3b15ac183ebd5a9c21b32dc Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:43:05 +0200 Subject: [PATCH 04/46] adds helper classes --- .../Report/PrettyPrintArray/PrettyCompare.php | 45 ++++++++++++ .../PrettyPrintArray/PrettyCursorBracket.php | 48 +++++++++++++ .../PrettyPrintArray/PrettyDetectArray.php | 72 +++++++++++++++++++ .../Report/PrettyPrintArray/PrettyFormat.php | 68 ++++++++++++++++++ .../Report/PrettyPrintArray/PrettyGeneric.php | 29 ++++++++ 5 files changed, 262 insertions(+) create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyCompare.php create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyFormat.php create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php new file mode 100644 index 00000000000..20def28a970 --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php @@ -0,0 +1,45 @@ + count($provided) ? count($requested) : count($provided); + $indexOne = 0; + $paired = []; + + for ($indexTwo = 0; $indexTwo <= $maxOf; $indexTwo++) + { + $rowProvided = $provided[$indexTwo] ?? ''; + + if (isset($requested[$indexOne]) && $requested[$indexOne] !== '') { + $paired[] = [$requested[$indexOne], $rowProvided]; //tuple + } else { + $paired[] = ['', $rowProvided]; //tuple + } + $indexOne++; + } + + if (!count($paired)) { + return ''; + } + + $pairedFormattedResult[] = '|'; + $pairedFormattedResult[] = sprintf($formatTable, 'Expected', 'Provided'); + $pairedFormattedResult[] = sprintf($formatTable, '---', '---'); + + foreach ($paired as $k => $rows) { + $pairedFormattedResult[] = sprintf($formatTable, ...$rows); + } + + return join(PHP_EOL, $pairedFormattedResult); + } + +} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php b/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php new file mode 100644 index 00000000000..ce1c4684b4c --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php @@ -0,0 +1,48 @@ +nBrackets = 0; + $this->char = ''; + } + + public function accept(string $char): void + { + $this->char = $char; + if (self::BRACKET_OPEN === $this->char) { + $this->openedBracket = true; + $this->nBrackets++; + } + + if (self::BRACKET_CLOSE === $char) { + $this->nBrackets--; + } + } + + public function closed(): bool + { + if ($this->openedBracket === true && self::BRACKET_CLOSE === $this->char) { + $this->nBrackets--; + if ($this->nBrackets <= 0) { + return true; + } + } + return false; + } + + public function getNumberBrackets(): int + { + return $this->nBrackets; + } +} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php new file mode 100644 index 00000000000..e2f3ac75e6e --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php @@ -0,0 +1,72 @@ +getFirstArrayPayload($workingPayload); + yield $arrayPayload['payload']; + + $arrayPayload = $this->getFirstArrayPayload($arrayPayload['nextPayload']); + yield $arrayPayload['payload']; + } + + private function getPositionOfEndArray(string $payload): ?int + { + $countChar = 0; + $prettyCursorBracket = new PrettyCursorBracket(); + + $positionArrayWord = strpos($payload, 'array'); + if ($positionArrayWord === false) { + return null; + } + + $arrayPayload = substr($payload, $positionArrayWord); + + foreach (str_split($arrayPayload) as $char) { + $countChar++; + + $prettyCursorBracket->accept($char); + if ($prettyCursorBracket->closed()) { + break; + } + } + + return $countChar; + } + + /** + * @return array { + * payload: string, + * start: int + * end: int, + * nextPayload: string + * } + */ + private function getFirstArrayPayload(string $payload): ?array + { + $posStart = strpos($payload, 'array'); + if ($posStart === false) { + return null; + } + $posEnd = $this->getPositionOfEndArray($payload); + + $payloadArray = substr($payload, $posStart,$posEnd); + $nextPayload = substr($payload, $posStart+$posEnd); + + return [ + 'payload' => $payloadArray, + 'start' => $posStart, + 'end' => $posEnd, + 'nextPayload' => $nextPayload + ]; + } +} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php new file mode 100644 index 00000000000..a10d9fce71d --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php @@ -0,0 +1,68 @@ +accept($char); + + if (self::CHAR_SPACE === $char) { + continue; + } + + $charAfter = ''; + $charBefore = ''; + + if (':' === $char) { + $charAfter = self::CHAR_SPACE; + } + + if (',' === $char) { + $charAfter = PHP_EOL; + } elseif (',' === $previousChar) { + $charBefore = $this->addIdentChar($prettyCursorBracket); + } + + if ('{' === $previousChar) { + $charBefore = $this->addIdentChar($prettyCursorBracket); + } elseif ('{' === $char) { + $charBefore = self::CHAR_SPACE; + $charAfter = PHP_EOL; + } + + if ('}' === $char) { + $charBefore = PHP_EOL .$this->addIdentChar($prettyCursorBracket); + } + + $buffer .= $charBefore + . $char + . $charAfter; + + $previousChar = $char; + if ($prettyCursorBracket->closed()) { + break; + } + } + return $buffer; + } + + private function addIdentChar(PrettyCursorBracket $prettyCursorBracket): string + { + return str_repeat(self::CHAR_SPACE, $prettyCursorBracket->getNumberBrackets()); + } +} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php b/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php new file mode 100644 index 00000000000..d4b82a6ec86 --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php @@ -0,0 +1,29 @@ +'], + ['{', '}'], + $payload + ); + } + + public static function normalizeTokens(string $payload): string + { + return str_replace('array-key', 'psalm-key', $payload); + } + + public static function revertNormalizedTokens(string $payload): string + { + return str_replace('psalm-key', 'array-key', $payload); + } + + +} From 4baa288d05a7160256dd6adada29bd36b5976e46 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:43:23 +0200 Subject: [PATCH 05/46] changes ConsoleReport.php to use pretty option --- src/Psalm/Report/ConsoleReport.php | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index f968326f1a0..4c71d9f09c6 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -6,14 +6,25 @@ use Psalm\Internal\Analyzer\DataFlowNodeData; use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; +use Psalm\Report\PrettyPrintArray\PrettyDetectArray; +use Psalm\Report\PrettyPrintArray\PrettyFormat; +use Psalm\Report\PrettyPrintArray\PrettyGeneric; +use Psalm\Report\PrettyPrintArray\PrettyCompare; +use Throwable; use function basename; +use function count; +use function explode; use function get_cfg_var; use function ini_get; +use function join; +use function sprintf; use function strlen; use function strtr; use function substr; +use const PHP_EOL; + final class ConsoleReport extends Report { /** @var string|null */ @@ -65,6 +76,10 @@ private function format(IssueData $issue_data): string } } + if ($this->pretty_print_array === true) { + $issue_string .= $this->prettyPrintArray($issue_data); + } + if ($issue_data->other_references) { if ($this->show_snippet) { $issue_string .= "\n"; @@ -76,6 +91,43 @@ private function format(IssueData $issue_data): string return $issue_string; } + private function prettyPrintArray(IssueData $issue_data): string + { + $prettyDetectArray = new PrettyDetectArray(); + $prettyFormat = new PrettyFormat(); + $prettyPaired = new PrettyCompare(); + $arrays = []; + $toIssue = ''; + $maxArray = 2; + + $workingPayload = PrettyGeneric::normalizeBracket($issue_data->message); + $workingPayload = PrettyGeneric::normalizeTokens($workingPayload); + + try { + foreach ($prettyDetectArray->detect($workingPayload) as $array) { + $arrays[] = $array; + } + + if (count($arrays) === $maxArray) { + $separator = '----'; + $arrayPrettyPrinted0 = $prettyFormat->format($arrays[0]); + $arrayPrettyPrinted1 = $prettyFormat->format($arrays[1]); + + $listOfArrays = []; + $listOfArrays[] = $arrayPrettyPrinted0; + $listOfArrays[] = $separator; + $listOfArrays[] = $arrayPrettyPrinted1; + + $toIssue = PHP_EOL.$prettyPaired->compare($listOfArrays); + } + + return PrettyGeneric::revertNormalizedTokens($toIssue); + } catch (Throwable $throwable) { + //todo: log ? + return 'Pretty Print Array failed for unexpected error. Error: ' . $throwable->getMessage(); + } + } + /** * @param non-empty-list $taint_trace */ From 10e4fba42500850a5d2d48df0bdbc429943b92a2 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:47:11 +0200 Subject: [PATCH 06/46] fix code style --- src/Psalm/Report/ConsoleReport.php | 5 +---- src/Psalm/Report/PrettyPrintArray/PrettyCompare.php | 11 ++++++++--- .../Report/PrettyPrintArray/PrettyDetectArray.php | 2 +- src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php | 2 -- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index 4c71d9f09c6..56e9e85254a 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -6,19 +6,16 @@ use Psalm\Internal\Analyzer\DataFlowNodeData; use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; +use Psalm\Report\PrettyPrintArray\PrettyCompare; use Psalm\Report\PrettyPrintArray\PrettyDetectArray; use Psalm\Report\PrettyPrintArray\PrettyFormat; use Psalm\Report\PrettyPrintArray\PrettyGeneric; -use Psalm\Report\PrettyPrintArray\PrettyCompare; use Throwable; use function basename; use function count; -use function explode; use function get_cfg_var; use function ini_get; -use function join; -use function sprintf; use function strlen; use function strtr; use function substr; diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php index 20def28a970..570fdf01de9 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php @@ -2,6 +2,13 @@ namespace Psalm\Report\PrettyPrintArray; +use function count; +use function explode; +use function join; +use function sprintf; + +use const PHP_EOL; + final class PrettyCompare { public function compare(array $arrays): string @@ -15,8 +22,7 @@ public function compare(array $arrays): string $indexOne = 0; $paired = []; - for ($indexTwo = 0; $indexTwo <= $maxOf; $indexTwo++) - { + for ($indexTwo = 0; $indexTwo <= $maxOf; $indexTwo++) { $rowProvided = $provided[$indexTwo] ?? ''; if (isset($requested[$indexOne]) && $requested[$indexOne] !== '') { @@ -41,5 +47,4 @@ public function compare(array $arrays): string return join(PHP_EOL, $pairedFormattedResult); } - } diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php index e2f3ac75e6e..411e45756c9 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php @@ -59,7 +59,7 @@ private function getFirstArrayPayload(string $payload): ?array } $posEnd = $this->getPositionOfEndArray($payload); - $payloadArray = substr($payload, $posStart,$posEnd); + $payloadArray = substr($payload, $posStart, $posEnd); $nextPayload = substr($payload, $posStart+$posEnd); return [ diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php b/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php index d4b82a6ec86..086c158a43d 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php @@ -24,6 +24,4 @@ public static function revertNormalizedTokens(string $payload): string { return str_replace('psalm-key', 'array-key', $payload); } - - } From 6c88ff9feba63376914dd00b9869574996264bac Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 23 Apr 2022 11:44:14 +0200 Subject: [PATCH 07/46] disussion#7862: adds first test case --- tests/ReportOutputTest.php | 96 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 5fb82b594f4..3fabcad6a49 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -3,6 +3,7 @@ namespace Psalm\Tests; use DOMDocument; +use Generator; use Psalm\Config; use Psalm\Context; use Psalm\Internal\Analyzer\IssueData; @@ -17,6 +18,7 @@ use Psalm\Tests\Internal\Provider\FakeParserCacheProvider; use UnexpectedValueException; +use function explode; use function file_get_contents; use function json_decode; use function ob_end_clean; @@ -26,6 +28,8 @@ use const JSON_THROW_ON_ERROR; +use const PHP_EOL; + class ReportOutputTest extends TestCase { public function setUp(): void @@ -1323,4 +1327,96 @@ private function toUnixLineEndings(string $output): string { return preg_replace('~\r\n?~', "\n", $output); } + + /** + * @dataProvider outputProvider() + */ + public function testConsoleReportWithPrettyPrint(string $file_contents, $expected_output): void + { + $this->addFile( + 'somefile.php', + $file_contents + ); + + $this->analyzeFile('somefile.php', new Context()); + + $console_report_options = new ReportOptions(); + $console_report_options->use_color = false; + $console_report_options->show_info = false; + $console_report_options->pretty_print_array = true; + + $output = IssueBuffer::getOutput(IssueBuffer::getIssuesData(), $console_report_options); + foreach (explode(PHP_EOL, $expected_output) as $line) { + $this->assertStringContainsString($line, $output); + } + } + + /** + * @return Generator> + */ + public function outputProvider(): Generator + { + $file_contents = <<<'EOT' + + */ +function request(): array +{ + return [ "aa" => "bar"]; +} + +function accept(array $input): void +{ + $v = $input["foo"]; +} + +accept(request()); +'; +EOT; + + $exp = <<<"EOT" +| Expected | Provided +| --- | --- +| array { | array { +| array-key, | aa: 'bar' +| int | } +| } | +| | +EOT; + + yield 'C1' => [$file_contents, $exp]; + + + $file_contents = <<<'EOT' + + */ +function request(): array +{ + return [ "aa" => 111]; +} + +function accept(array $input): void +{ + $v = $input["foo"]; +} + +accept(request()); +'; +EOT; + + $exp = <<<"EOT" +| Expected | Provided +| --- | --- +| array { | array { +| array-key, | aa: 111 +| string | } +| } | +| | +EOT; + + yield 'C2' => [$file_contents, $exp]; + } } From 5882b16062b892647f15a7c43c6fb6125501e9e4 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:42:36 +0200 Subject: [PATCH 08/46] adds pretty options --- src/Psalm/Report.php | 4 ++++ src/Psalm/Report/ReportOptions.php | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/Psalm/Report.php b/src/Psalm/Report.php index e1956d1991e..59541ceffa2 100644 --- a/src/Psalm/Report.php +++ b/src/Psalm/Report.php @@ -76,6 +76,9 @@ abstract class Report /** @var int */ protected $total_expression_count; + /** @var bool */ + protected $pretty_print_array = false; + /** * @param array $issues_data * @param array $fixable_issue_counts @@ -102,6 +105,7 @@ public function __construct( $this->show_info = $report_options->show_info; $this->pretty = $report_options->pretty; $this->in_ci = $report_options->in_ci; + $this->pretty_print_array = $report_options->pretty_print_array; $this->mixed_expression_count = $mixed_expression_count; $this->total_expression_count = $total_expression_count; diff --git a/src/Psalm/Report/ReportOptions.php b/src/Psalm/Report/ReportOptions.php index 242caf4884a..34d5152ac0a 100644 --- a/src/Psalm/Report/ReportOptions.php +++ b/src/Psalm/Report/ReportOptions.php @@ -43,4 +43,7 @@ final class ReportOptions /** @var bool */ public $in_ci = false; + + /** @var bool */ + public $pretty_print_array = false; } From 38e63e0dae33b828cc7dc23fa67de88e07e243d1 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:42:48 +0200 Subject: [PATCH 09/46] fix test --- tests/ReportOutputTest.php | 199 +++++++++++++++++++++++++------------ 1 file changed, 133 insertions(+), 66 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 3fabcad6a49..ce6bc2dca44 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -27,7 +27,6 @@ use function unlink; use const JSON_THROW_ON_ERROR; - use const PHP_EOL; class ReportOutputTest extends TestCase @@ -1331,24 +1330,15 @@ private function toUnixLineEndings(string $output): string /** * @dataProvider outputProvider() */ - public function testConsoleReportWithPrettyPrint(string $file_contents, $expected_output): void + public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_contents, $expected_output): void { - $this->addFile( - 'somefile.php', - $file_contents - ); - + $this->addFile('somefile.php', $file_contents); $this->analyzeFile('somefile.php', new Context()); - $console_report_options = new ReportOptions(); - $console_report_options->use_color = false; - $console_report_options->show_info = false; - $console_report_options->pretty_print_array = true; - + $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); $output = IssueBuffer::getOutput(IssueBuffer::getIssuesData(), $console_report_options); - foreach (explode(PHP_EOL, $expected_output) as $line) { - $this->assertStringContainsString($line, $output); - } + + $this->assertOutputPrettyPrintEquals($expected_output, $output); } /** @@ -1357,66 +1347,143 @@ public function testConsoleReportWithPrettyPrint(string $file_contents, $expecte public function outputProvider(): Generator { $file_contents = <<<'EOT' - - */ -function request(): array -{ - return [ "aa" => "bar"]; -} + + */ + function request(): array + { + return [ "aa" => "bar"]; + } -function accept(array $input): void -{ - $v = $input["foo"]; -} + function accept(array $input): void + { + $v = $input["foo"]; + } -accept(request()); -'; -EOT; + accept(request()); + ; + EOT; - $exp = <<<"EOT" -| Expected | Provided -| --- | --- -| array { | array { -| array-key, | aa: 'bar' -| int | } -| } | -| | -EOT; - - yield 'C1' => [$file_contents, $exp]; + $expected_output = <<<'EOT' + | Expected | Provided + | --- | --- + | array { | array { + | array-key, | aa: 'bar' + | int | } + | } | + | | + EOT; + yield [$file_contents, $expected_output]; $file_contents = <<<'EOT' - - */ -function request(): array -{ - return [ "aa" => 111]; -} + + */ + function request(): array + { + return [ "aa" => 111]; + } -function accept(array $input): void -{ - $v = $input["foo"]; -} + function accept(array $input): void + { + $v = $input["foo"]; + } -accept(request()); -'; -EOT; + accept(request()); + ; + EOT; $exp = <<<"EOT" -| Expected | Provided -| --- | --- -| array { | array { -| array-key, | aa: 111 -| string | } -| } | -| | -EOT; - - yield 'C2' => [$file_contents, $exp]; + | Expected | Provided + | --- | --- + | array { | array { + | array-key, | aa: 111 + | string | } + | } | + | | + EOT; + + yield [$file_contents, $exp]; + } + + /** + * @dataProvider payloadProvider() + */ + public function testConsoleReportWithPrettyPrintFromPayload(string $payload, $expected_output): void + { + $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); + $issues_data = [ + 1 => new IssueData( + 'error', + 15, + 15, + 'InvalidReturnStatement', + $payload, + 'somefile.php', + 'somefile.php', + '', + '$a', + 201, + 203, + 196, + 203, + 6, + 8 + ), + ]; + + $consoleReport = new Report\ConsoleReport($issues_data, [], $console_report_options); + $output = $consoleReport->create(); + $this->assertOutputPrettyPrintEquals($expected_output, $output); + } + + /** + * @return Generator> + */ + public function payloadProvider(): Generator + { + $paylaod = <<<'EOT' + 'ERROR: InvalidReturnStatement - XXXX.php:66:16 - + The inferred type 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_ccccc: null|string, tid_bbbbb: null|string}' does not match the declared return type 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_aaaaaa: null|string, tid_bbbbb: null|string}' for YYYYY() (see https://psalm.dev/128) + EOT; + + $expected = <<<"EOT" + | + | Expected | Provided + | --- | --- + | array { | array { + | code_xxx: null|string, | code_xxx: null|string, + | datetime: null|string, | datetime: null|string, + | money: float|null, | money: float|null, + | id_yyyy: null|string, | id_yyyy: null|string, + | tid_ccccc: null|string, | tid_aaaaaa: null|string, + | tid_bbbbb: null|string | tid_bbbbb: null|string + | } | } + | + EOT; + + + yield [$paylaod, $expected]; + } + + private function prepareConsoleOptionsForPrettyPrint(): ReportOptions + { + $console_report_options = new ReportOptions(); + $console_report_options->use_color = false; + $console_report_options->show_info = false; + $console_report_options->pretty_print_array = true; + return $console_report_options; + } + + private function assertOutputPrettyPrintEquals($expected_output, string $output): void + { + $lines = explode(PHP_EOL, $expected_output); + + foreach ($lines as $line) { + $this->assertStringContainsString($line, $output); + } } } From 4fd6c8a476dc6932474120d1e501ae747511f8a0 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:43:05 +0200 Subject: [PATCH 10/46] adds helper classes --- .../Report/PrettyPrintArray/PrettyCompare.php | 45 ++++++++++++ .../PrettyPrintArray/PrettyCursorBracket.php | 48 +++++++++++++ .../PrettyPrintArray/PrettyDetectArray.php | 72 +++++++++++++++++++ .../Report/PrettyPrintArray/PrettyFormat.php | 68 ++++++++++++++++++ .../Report/PrettyPrintArray/PrettyGeneric.php | 29 ++++++++ 5 files changed, 262 insertions(+) create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyCompare.php create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyFormat.php create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php new file mode 100644 index 00000000000..20def28a970 --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php @@ -0,0 +1,45 @@ + count($provided) ? count($requested) : count($provided); + $indexOne = 0; + $paired = []; + + for ($indexTwo = 0; $indexTwo <= $maxOf; $indexTwo++) + { + $rowProvided = $provided[$indexTwo] ?? ''; + + if (isset($requested[$indexOne]) && $requested[$indexOne] !== '') { + $paired[] = [$requested[$indexOne], $rowProvided]; //tuple + } else { + $paired[] = ['', $rowProvided]; //tuple + } + $indexOne++; + } + + if (!count($paired)) { + return ''; + } + + $pairedFormattedResult[] = '|'; + $pairedFormattedResult[] = sprintf($formatTable, 'Expected', 'Provided'); + $pairedFormattedResult[] = sprintf($formatTable, '---', '---'); + + foreach ($paired as $k => $rows) { + $pairedFormattedResult[] = sprintf($formatTable, ...$rows); + } + + return join(PHP_EOL, $pairedFormattedResult); + } + +} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php b/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php new file mode 100644 index 00000000000..ce1c4684b4c --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php @@ -0,0 +1,48 @@ +nBrackets = 0; + $this->char = ''; + } + + public function accept(string $char): void + { + $this->char = $char; + if (self::BRACKET_OPEN === $this->char) { + $this->openedBracket = true; + $this->nBrackets++; + } + + if (self::BRACKET_CLOSE === $char) { + $this->nBrackets--; + } + } + + public function closed(): bool + { + if ($this->openedBracket === true && self::BRACKET_CLOSE === $this->char) { + $this->nBrackets--; + if ($this->nBrackets <= 0) { + return true; + } + } + return false; + } + + public function getNumberBrackets(): int + { + return $this->nBrackets; + } +} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php new file mode 100644 index 00000000000..e2f3ac75e6e --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php @@ -0,0 +1,72 @@ +getFirstArrayPayload($workingPayload); + yield $arrayPayload['payload']; + + $arrayPayload = $this->getFirstArrayPayload($arrayPayload['nextPayload']); + yield $arrayPayload['payload']; + } + + private function getPositionOfEndArray(string $payload): ?int + { + $countChar = 0; + $prettyCursorBracket = new PrettyCursorBracket(); + + $positionArrayWord = strpos($payload, 'array'); + if ($positionArrayWord === false) { + return null; + } + + $arrayPayload = substr($payload, $positionArrayWord); + + foreach (str_split($arrayPayload) as $char) { + $countChar++; + + $prettyCursorBracket->accept($char); + if ($prettyCursorBracket->closed()) { + break; + } + } + + return $countChar; + } + + /** + * @return array { + * payload: string, + * start: int + * end: int, + * nextPayload: string + * } + */ + private function getFirstArrayPayload(string $payload): ?array + { + $posStart = strpos($payload, 'array'); + if ($posStart === false) { + return null; + } + $posEnd = $this->getPositionOfEndArray($payload); + + $payloadArray = substr($payload, $posStart,$posEnd); + $nextPayload = substr($payload, $posStart+$posEnd); + + return [ + 'payload' => $payloadArray, + 'start' => $posStart, + 'end' => $posEnd, + 'nextPayload' => $nextPayload + ]; + } +} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php new file mode 100644 index 00000000000..a10d9fce71d --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php @@ -0,0 +1,68 @@ +accept($char); + + if (self::CHAR_SPACE === $char) { + continue; + } + + $charAfter = ''; + $charBefore = ''; + + if (':' === $char) { + $charAfter = self::CHAR_SPACE; + } + + if (',' === $char) { + $charAfter = PHP_EOL; + } elseif (',' === $previousChar) { + $charBefore = $this->addIdentChar($prettyCursorBracket); + } + + if ('{' === $previousChar) { + $charBefore = $this->addIdentChar($prettyCursorBracket); + } elseif ('{' === $char) { + $charBefore = self::CHAR_SPACE; + $charAfter = PHP_EOL; + } + + if ('}' === $char) { + $charBefore = PHP_EOL .$this->addIdentChar($prettyCursorBracket); + } + + $buffer .= $charBefore + . $char + . $charAfter; + + $previousChar = $char; + if ($prettyCursorBracket->closed()) { + break; + } + } + return $buffer; + } + + private function addIdentChar(PrettyCursorBracket $prettyCursorBracket): string + { + return str_repeat(self::CHAR_SPACE, $prettyCursorBracket->getNumberBrackets()); + } +} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php b/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php new file mode 100644 index 00000000000..d4b82a6ec86 --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php @@ -0,0 +1,29 @@ +'], + ['{', '}'], + $payload + ); + } + + public static function normalizeTokens(string $payload): string + { + return str_replace('array-key', 'psalm-key', $payload); + } + + public static function revertNormalizedTokens(string $payload): string + { + return str_replace('psalm-key', 'array-key', $payload); + } + + +} From 749d4379d77086f512d6caafcf42b633af587d2b Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:43:23 +0200 Subject: [PATCH 11/46] changes ConsoleReport.php to use pretty option --- src/Psalm/Report/ConsoleReport.php | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index f968326f1a0..4c71d9f09c6 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -6,14 +6,25 @@ use Psalm\Internal\Analyzer\DataFlowNodeData; use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; +use Psalm\Report\PrettyPrintArray\PrettyDetectArray; +use Psalm\Report\PrettyPrintArray\PrettyFormat; +use Psalm\Report\PrettyPrintArray\PrettyGeneric; +use Psalm\Report\PrettyPrintArray\PrettyCompare; +use Throwable; use function basename; +use function count; +use function explode; use function get_cfg_var; use function ini_get; +use function join; +use function sprintf; use function strlen; use function strtr; use function substr; +use const PHP_EOL; + final class ConsoleReport extends Report { /** @var string|null */ @@ -65,6 +76,10 @@ private function format(IssueData $issue_data): string } } + if ($this->pretty_print_array === true) { + $issue_string .= $this->prettyPrintArray($issue_data); + } + if ($issue_data->other_references) { if ($this->show_snippet) { $issue_string .= "\n"; @@ -76,6 +91,43 @@ private function format(IssueData $issue_data): string return $issue_string; } + private function prettyPrintArray(IssueData $issue_data): string + { + $prettyDetectArray = new PrettyDetectArray(); + $prettyFormat = new PrettyFormat(); + $prettyPaired = new PrettyCompare(); + $arrays = []; + $toIssue = ''; + $maxArray = 2; + + $workingPayload = PrettyGeneric::normalizeBracket($issue_data->message); + $workingPayload = PrettyGeneric::normalizeTokens($workingPayload); + + try { + foreach ($prettyDetectArray->detect($workingPayload) as $array) { + $arrays[] = $array; + } + + if (count($arrays) === $maxArray) { + $separator = '----'; + $arrayPrettyPrinted0 = $prettyFormat->format($arrays[0]); + $arrayPrettyPrinted1 = $prettyFormat->format($arrays[1]); + + $listOfArrays = []; + $listOfArrays[] = $arrayPrettyPrinted0; + $listOfArrays[] = $separator; + $listOfArrays[] = $arrayPrettyPrinted1; + + $toIssue = PHP_EOL.$prettyPaired->compare($listOfArrays); + } + + return PrettyGeneric::revertNormalizedTokens($toIssue); + } catch (Throwable $throwable) { + //todo: log ? + return 'Pretty Print Array failed for unexpected error. Error: ' . $throwable->getMessage(); + } + } + /** * @param non-empty-list $taint_trace */ From d398f054f7eda14167475ebc1343784ac3db7712 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 11 May 2022 22:47:11 +0200 Subject: [PATCH 12/46] fix code style --- src/Psalm/Report/ConsoleReport.php | 5 +---- src/Psalm/Report/PrettyPrintArray/PrettyCompare.php | 11 ++++++++--- .../Report/PrettyPrintArray/PrettyDetectArray.php | 2 +- src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php | 2 -- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index 4c71d9f09c6..56e9e85254a 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -6,19 +6,16 @@ use Psalm\Internal\Analyzer\DataFlowNodeData; use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; +use Psalm\Report\PrettyPrintArray\PrettyCompare; use Psalm\Report\PrettyPrintArray\PrettyDetectArray; use Psalm\Report\PrettyPrintArray\PrettyFormat; use Psalm\Report\PrettyPrintArray\PrettyGeneric; -use Psalm\Report\PrettyPrintArray\PrettyCompare; use Throwable; use function basename; use function count; -use function explode; use function get_cfg_var; use function ini_get; -use function join; -use function sprintf; use function strlen; use function strtr; use function substr; diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php index 20def28a970..570fdf01de9 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php @@ -2,6 +2,13 @@ namespace Psalm\Report\PrettyPrintArray; +use function count; +use function explode; +use function join; +use function sprintf; + +use const PHP_EOL; + final class PrettyCompare { public function compare(array $arrays): string @@ -15,8 +22,7 @@ public function compare(array $arrays): string $indexOne = 0; $paired = []; - for ($indexTwo = 0; $indexTwo <= $maxOf; $indexTwo++) - { + for ($indexTwo = 0; $indexTwo <= $maxOf; $indexTwo++) { $rowProvided = $provided[$indexTwo] ?? ''; if (isset($requested[$indexOne]) && $requested[$indexOne] !== '') { @@ -41,5 +47,4 @@ public function compare(array $arrays): string return join(PHP_EOL, $pairedFormattedResult); } - } diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php index e2f3ac75e6e..411e45756c9 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php @@ -59,7 +59,7 @@ private function getFirstArrayPayload(string $payload): ?array } $posEnd = $this->getPositionOfEndArray($payload); - $payloadArray = substr($payload, $posStart,$posEnd); + $payloadArray = substr($payload, $posStart, $posEnd); $nextPayload = substr($payload, $posStart+$posEnd); return [ diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php b/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php index d4b82a6ec86..086c158a43d 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php @@ -24,6 +24,4 @@ public static function revertNormalizedTokens(string $payload): string { return str_replace('psalm-key', 'array-key', $payload); } - - } From 4f91c39611a7d353a9d200b91e1db0ac7d3562a9 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Tue, 17 May 2022 22:17:57 +0200 Subject: [PATCH 13/46] spyke commit use InvolvedTypes.php --- src/Psalm/Internal/Analyzer/IssueData.php | 10 ++- .../Analyzer/Statements/ReturnAnalyzer.php | 6 +- src/Psalm/Issue/CodeIssue.php | 9 ++- src/Psalm/Issue/InvolvedTypes.php | 26 +++++++ src/Psalm/Report/ConsoleReport.php | 26 ++++--- .../PrettyPrintArray/PrettyDetectArray.php | 72 ------------------- tests/ReportOutputTest.php | 21 ++++-- 7 files changed, 74 insertions(+), 96 deletions(-) create mode 100644 src/Psalm/Issue/InvolvedTypes.php delete mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php diff --git a/src/Psalm/Internal/Analyzer/IssueData.php b/src/Psalm/Internal/Analyzer/IssueData.php index 318afe57f6a..306bfe4a439 100644 --- a/src/Psalm/Internal/Analyzer/IssueData.php +++ b/src/Psalm/Internal/Analyzer/IssueData.php @@ -2,6 +2,7 @@ namespace Psalm\Internal\Analyzer; +use Psalm\Issue\InvolvedTypes; use function str_pad; use const STR_PAD_LEFT; @@ -127,6 +128,11 @@ class IssueData */ public $dupe_key; + /** + * @readonly + */ + public ?InvolvedTypes $involvedTypes; + /** * @param ?list $taint_trace * @param ?list $other_references @@ -151,7 +157,8 @@ public function __construct( int $error_level = -1, ?array $taint_trace = null, array $other_references = null, - ?string $dupe_key = null + ?string $dupe_key = null, + ?InvolvedTypes $involvedTypes = null ) { $this->severity = $severity; $this->line_from = $line_from; @@ -174,5 +181,6 @@ public function __construct( $this->taint_trace = $taint_trace; $this->other_references = $other_references; $this->dupe_key = $dupe_key; + $this->involvedTypes = $involvedTypes; } } diff --git a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php index 6ce6cdb1536..09a3dfa94ce 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php @@ -28,6 +28,7 @@ use Psalm\Issue\FalsableReturnStatement; use Psalm\Issue\InvalidDocblock; use Psalm\Issue\InvalidReturnStatement; +use Psalm\Issue\InvolvedTypes; use Psalm\Issue\LessSpecificReturnStatement; use Psalm\Issue\MixedReturnStatement; use Psalm\Issue\MixedReturnTypeCoercion; @@ -483,7 +484,10 @@ public static function analyze( 'The inferred type \'' . $inferred_type->getId() . '\' does not match the declared return ' . 'type \'' . $local_return_type->getId() . '\' for ' . $cased_method_id, - new CodeLocation($source, $stmt->expr) + new CodeLocation($source, $stmt->expr), + new InvolvedTypes( + $inferred_type->getId(), + $local_return_type->getId()) ), $statements_analyzer->getSuppressedIssues() ); diff --git a/src/Psalm/Issue/CodeIssue.php b/src/Psalm/Issue/CodeIssue.php index 0b8035efd09..e693101470c 100644 --- a/src/Psalm/Issue/CodeIssue.php +++ b/src/Psalm/Issue/CodeIssue.php @@ -32,12 +32,16 @@ abstract class CodeIssue */ public $dupe_key; + public ?InvolvedTypes $involvedTypes; + public function __construct( string $message, - CodeLocation $code_location + CodeLocation $code_location, + ?InvolvedTypes $involvedTypes = null ) { $this->code_location = $code_location; $this->message = $message; + $this->involvedTypes = $involvedTypes; } public function getShortLocationWithPrevious(): string @@ -103,7 +107,8 @@ public function toIssueData(string $severity): IssueData ) ] : null, - $this->dupe_key + $this->dupe_key, + $this->involvedTypes ?? null ); } } diff --git a/src/Psalm/Issue/InvolvedTypes.php b/src/Psalm/Issue/InvolvedTypes.php new file mode 100644 index 00000000000..f6f6ec17e53 --- /dev/null +++ b/src/Psalm/Issue/InvolvedTypes.php @@ -0,0 +1,26 @@ +inferedType = $inferedType; + $this->declaredType = $declaredType; + } + + public function getInferedType(): string + { + return $this->inferedType; + } + + public function getDeclaredType(): string + { + return $this->declaredType; + } + +} diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index 56e9e85254a..d1d217a6c30 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -90,25 +90,24 @@ private function format(IssueData $issue_data): string private function prettyPrintArray(IssueData $issue_data): string { - $prettyDetectArray = new PrettyDetectArray(); $prettyFormat = new PrettyFormat(); $prettyPaired = new PrettyCompare(); - $arrays = []; - $toIssue = ''; - $maxArray = 2; - - $workingPayload = PrettyGeneric::normalizeBracket($issue_data->message); - $workingPayload = PrettyGeneric::normalizeTokens($workingPayload); try { - foreach ($prettyDetectArray->detect($workingPayload) as $array) { - $arrays[] = $array; - } + if (!$issue_data->involvedTypes) { + return ''; + } - if (count($arrays) === $maxArray) { $separator = '----'; - $arrayPrettyPrinted0 = $prettyFormat->format($arrays[0]); - $arrayPrettyPrinted1 = $prettyFormat->format($arrays[1]); + $declaredType = $issue_data->involvedTypes->getDeclaredType(); + $declaredType = PrettyGeneric::normalizeBracket($declaredType); + $declaredType = PrettyGeneric::normalizeTokens($declaredType); + $arrayPrettyPrinted0 = $prettyFormat->format($declaredType); + + $inferedType = $issue_data->involvedTypes->getInferedType(); + $inferedType = PrettyGeneric::normalizeBracket($inferedType); + $inferedType = PrettyGeneric::normalizeTokens($inferedType); + $arrayPrettyPrinted1 = $prettyFormat->format($inferedType); $listOfArrays = []; $listOfArrays[] = $arrayPrettyPrinted0; @@ -116,7 +115,6 @@ private function prettyPrintArray(IssueData $issue_data): string $listOfArrays[] = $arrayPrettyPrinted1; $toIssue = PHP_EOL.$prettyPaired->compare($listOfArrays); - } return PrettyGeneric::revertNormalizedTokens($toIssue); } catch (Throwable $throwable) { diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php deleted file mode 100644 index 411e45756c9..00000000000 --- a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php +++ /dev/null @@ -1,72 +0,0 @@ -getFirstArrayPayload($workingPayload); - yield $arrayPayload['payload']; - - $arrayPayload = $this->getFirstArrayPayload($arrayPayload['nextPayload']); - yield $arrayPayload['payload']; - } - - private function getPositionOfEndArray(string $payload): ?int - { - $countChar = 0; - $prettyCursorBracket = new PrettyCursorBracket(); - - $positionArrayWord = strpos($payload, 'array'); - if ($positionArrayWord === false) { - return null; - } - - $arrayPayload = substr($payload, $positionArrayWord); - - foreach (str_split($arrayPayload) as $char) { - $countChar++; - - $prettyCursorBracket->accept($char); - if ($prettyCursorBracket->closed()) { - break; - } - } - - return $countChar; - } - - /** - * @return array { - * payload: string, - * start: int - * end: int, - * nextPayload: string - * } - */ - private function getFirstArrayPayload(string $payload): ?array - { - $posStart = strpos($payload, 'array'); - if ($posStart === false) { - return null; - } - $posEnd = $this->getPositionOfEndArray($payload); - - $payloadArray = substr($payload, $posStart, $posEnd); - $nextPayload = substr($payload, $posStart+$posEnd); - - return [ - 'payload' => $payloadArray, - 'start' => $posStart, - 'end' => $posEnd, - 'nextPayload' => $nextPayload - ]; - } -} diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index ce6bc2dca44..ac489ef17ec 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -11,6 +11,7 @@ use Psalm\Internal\Provider\FakeFileProvider; use Psalm\Internal\Provider\Providers; use Psalm\Internal\RuntimeCaches; +use Psalm\Issue\InvolvedTypes; use Psalm\IssueBuffer; use Psalm\Report; use Psalm\Report\JsonReport; @@ -1412,7 +1413,7 @@ function accept(array $input): void /** * @dataProvider payloadProvider() */ - public function testConsoleReportWithPrettyPrintFromPayload(string $payload, $expected_output): void + public function testConsoleReportWithPrettyPrintFromPayload(string $payload, string $infered, string $declared, $expected_output): void { $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); $issues_data = [ @@ -1431,7 +1432,13 @@ public function testConsoleReportWithPrettyPrintFromPayload(string $payload, $ex 196, 203, 6, - 8 + 8, + 0, + -1, + null, + null, + null, + new InvolvedTypes($infered, $declared) ), ]; @@ -1445,9 +1452,12 @@ public function testConsoleReportWithPrettyPrintFromPayload(string $payload, $ex */ public function payloadProvider(): Generator { + $infered = 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_ccccc: null|string, tid_bbbbb: null|string}'; + $declared = 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_aaaaaa: null|string, tid_bbbbb: null|string}'; + $paylaod = <<<'EOT' 'ERROR: InvalidReturnStatement - XXXX.php:66:16 - - The inferred type 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_ccccc: null|string, tid_bbbbb: null|string}' does not match the declared return type 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_aaaaaa: null|string, tid_bbbbb: null|string}' for YYYYY() (see https://psalm.dev/128) + The inferred type '$infered' does not match the declared return type '$declared' for YYYYY() (see https://psalm.dev/128) EOT; $expected = <<<"EOT" @@ -1459,14 +1469,13 @@ public function payloadProvider(): Generator | datetime: null|string, | datetime: null|string, | money: float|null, | money: float|null, | id_yyyy: null|string, | id_yyyy: null|string, - | tid_ccccc: null|string, | tid_aaaaaa: null|string, + | tid_aaaaaa: null|string, | tid_ccccc: null|string, | tid_bbbbb: null|string | tid_bbbbb: null|string | } | } | EOT; - - yield [$paylaod, $expected]; + yield [$paylaod, $infered, $declared, $expected]; } private function prepareConsoleOptionsForPrettyPrint(): ReportOptions From 7f181e2bbde80507fed1af3e23b9a36176caa2c5 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Tue, 17 May 2022 22:39:42 +0200 Subject: [PATCH 14/46] simplify the code --- src/Psalm/Report/ConsoleReport.php | 24 +------ .../Report/PrettyPrintArray/PrettyCompare.php | 6 +- .../PrettyPrintArray/PrettyDetectArray.php | 72 ------------------- .../Report/PrettyPrintArray/PrettyFormat.php | 3 + 4 files changed, 9 insertions(+), 96 deletions(-) delete mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index d1d217a6c30..16e3f566675 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -7,19 +7,15 @@ use Psalm\Internal\Analyzer\IssueData; use Psalm\Report; use Psalm\Report\PrettyPrintArray\PrettyCompare; -use Psalm\Report\PrettyPrintArray\PrettyDetectArray; use Psalm\Report\PrettyPrintArray\PrettyFormat; use Psalm\Report\PrettyPrintArray\PrettyGeneric; use Throwable; - use function basename; -use function count; use function get_cfg_var; use function ini_get; use function strlen; use function strtr; use function substr; - use const PHP_EOL; final class ConsoleReport extends Report @@ -98,23 +94,9 @@ private function prettyPrintArray(IssueData $issue_data): string return ''; } - $separator = '----'; - $declaredType = $issue_data->involvedTypes->getDeclaredType(); - $declaredType = PrettyGeneric::normalizeBracket($declaredType); - $declaredType = PrettyGeneric::normalizeTokens($declaredType); - $arrayPrettyPrinted0 = $prettyFormat->format($declaredType); - - $inferedType = $issue_data->involvedTypes->getInferedType(); - $inferedType = PrettyGeneric::normalizeBracket($inferedType); - $inferedType = PrettyGeneric::normalizeTokens($inferedType); - $arrayPrettyPrinted1 = $prettyFormat->format($inferedType); - - $listOfArrays = []; - $listOfArrays[] = $arrayPrettyPrinted0; - $listOfArrays[] = $separator; - $listOfArrays[] = $arrayPrettyPrinted1; - - $toIssue = PHP_EOL.$prettyPaired->compare($listOfArrays); + $arrayPrettyPrinted0 = $prettyFormat->format($issue_data->involvedTypes->getDeclaredType()); + $arrayPrettyPrinted1 = $prettyFormat->format($issue_data->involvedTypes->getInferedType()); + $toIssue = PHP_EOL.$prettyPaired->compare($arrayPrettyPrinted0,$arrayPrettyPrinted1); return PrettyGeneric::revertNormalizedTokens($toIssue); } catch (Throwable $throwable) { diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php index 570fdf01de9..323f10a1148 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php @@ -11,12 +11,12 @@ final class PrettyCompare { - public function compare(array $arrays): string + public function compare(string $infered, string $declared): string { $formatTable = '| %-50s | %-50s '; - $requested = explode(PHP_EOL, $arrays[0]); - $provided = explode(PHP_EOL, $arrays[2]); + $requested = explode(PHP_EOL, $infered); + $provided = explode(PHP_EOL, $declared); $maxOf = count($requested) > count($provided) ? count($requested) : count($provided); $indexOne = 0; diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php b/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php deleted file mode 100644 index 411e45756c9..00000000000 --- a/src/Psalm/Report/PrettyPrintArray/PrettyDetectArray.php +++ /dev/null @@ -1,72 +0,0 @@ -getFirstArrayPayload($workingPayload); - yield $arrayPayload['payload']; - - $arrayPayload = $this->getFirstArrayPayload($arrayPayload['nextPayload']); - yield $arrayPayload['payload']; - } - - private function getPositionOfEndArray(string $payload): ?int - { - $countChar = 0; - $prettyCursorBracket = new PrettyCursorBracket(); - - $positionArrayWord = strpos($payload, 'array'); - if ($positionArrayWord === false) { - return null; - } - - $arrayPayload = substr($payload, $positionArrayWord); - - foreach (str_split($arrayPayload) as $char) { - $countChar++; - - $prettyCursorBracket->accept($char); - if ($prettyCursorBracket->closed()) { - break; - } - } - - return $countChar; - } - - /** - * @return array { - * payload: string, - * start: int - * end: int, - * nextPayload: string - * } - */ - private function getFirstArrayPayload(string $payload): ?array - { - $posStart = strpos($payload, 'array'); - if ($posStart === false) { - return null; - } - $posEnd = $this->getPositionOfEndArray($payload); - - $payloadArray = substr($payload, $posStart, $posEnd); - $nextPayload = substr($payload, $posStart+$posEnd); - - return [ - 'payload' => $payloadArray, - 'start' => $posStart, - 'end' => $posEnd, - 'nextPayload' => $nextPayload - ]; - } -} diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php index a10d9fce71d..e6d14ad5c07 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php @@ -18,6 +18,9 @@ public function format(string $inputPayload): string $prettyCursorBracket = new PrettyCursorBracket(); $payload = $inputPayload; + $payload = PrettyGeneric::normalizeBracket($payload); + $payload = PrettyGeneric::normalizeTokens($payload); + foreach (str_split($payload) as $char) { $prettyCursorBracket->accept($char); From 3fe68d244dad79e6b502cf6b7e3c2c145c4e0eef Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 18 May 2022 21:23:40 +0200 Subject: [PATCH 15/46] cs-fix --- src/Psalm/Internal/Analyzer/IssueData.php | 1 + .../Internal/Analyzer/Statements/ReturnAnalyzer.php | 3 ++- src/Psalm/Issue/InvolvedTypes.php | 1 - src/Psalm/Report/ConsoleReport.php | 10 ++++++---- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/IssueData.php b/src/Psalm/Internal/Analyzer/IssueData.php index 306bfe4a439..720207268ae 100644 --- a/src/Psalm/Internal/Analyzer/IssueData.php +++ b/src/Psalm/Internal/Analyzer/IssueData.php @@ -3,6 +3,7 @@ namespace Psalm\Internal\Analyzer; use Psalm\Issue\InvolvedTypes; + use function str_pad; use const STR_PAD_LEFT; diff --git a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php index 09a3dfa94ce..b585d72509e 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php @@ -487,7 +487,8 @@ public static function analyze( new CodeLocation($source, $stmt->expr), new InvolvedTypes( $inferred_type->getId(), - $local_return_type->getId()) + $local_return_type->getId() + ) ), $statements_analyzer->getSuppressedIssues() ); diff --git a/src/Psalm/Issue/InvolvedTypes.php b/src/Psalm/Issue/InvolvedTypes.php index f6f6ec17e53..7802b5314c7 100644 --- a/src/Psalm/Issue/InvolvedTypes.php +++ b/src/Psalm/Issue/InvolvedTypes.php @@ -22,5 +22,4 @@ public function getDeclaredType(): string { return $this->declaredType; } - } diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index 16e3f566675..b7833dd3e02 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -10,12 +10,14 @@ use Psalm\Report\PrettyPrintArray\PrettyFormat; use Psalm\Report\PrettyPrintArray\PrettyGeneric; use Throwable; + use function basename; use function get_cfg_var; use function ini_get; use function strlen; use function strtr; use function substr; + use const PHP_EOL; final class ConsoleReport extends Report @@ -90,13 +92,13 @@ private function prettyPrintArray(IssueData $issue_data): string $prettyPaired = new PrettyCompare(); try { - if (!$issue_data->involvedTypes) { - return ''; - } + if (!$issue_data->involvedTypes) { + return ''; + } $arrayPrettyPrinted0 = $prettyFormat->format($issue_data->involvedTypes->getDeclaredType()); $arrayPrettyPrinted1 = $prettyFormat->format($issue_data->involvedTypes->getInferedType()); - $toIssue = PHP_EOL.$prettyPaired->compare($arrayPrettyPrinted0,$arrayPrettyPrinted1); + $toIssue = PHP_EOL.$prettyPaired->compare($arrayPrettyPrinted0, $arrayPrettyPrinted1); return PrettyGeneric::revertNormalizedTokens($toIssue); } catch (Throwable $throwable) { From c28eab16b2485e0183f1a7d0659a1970e2e5d4c2 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Wed, 18 May 2022 22:03:42 +0200 Subject: [PATCH 16/46] changes namespace of InvolvedTypes.php, fixes some test --- src/Psalm/Internal/Analyzer/IssueData.php | 3 +-- src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php | 3 +-- src/Psalm/{Issue => Internal}/InvolvedTypes.php | 2 +- src/Psalm/Issue/CodeIssue.php | 1 + tests/ReportOutputTest.php | 7 ++++++- 5 files changed, 10 insertions(+), 6 deletions(-) rename src/Psalm/{Issue => Internal}/InvolvedTypes.php (94%) diff --git a/src/Psalm/Internal/Analyzer/IssueData.php b/src/Psalm/Internal/Analyzer/IssueData.php index 720207268ae..36c00f15c42 100644 --- a/src/Psalm/Internal/Analyzer/IssueData.php +++ b/src/Psalm/Internal/Analyzer/IssueData.php @@ -2,8 +2,7 @@ namespace Psalm\Internal\Analyzer; -use Psalm\Issue\InvolvedTypes; - +use Psalm\Internal\InvolvedTypes; use function str_pad; use const STR_PAD_LEFT; diff --git a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php index b585d72509e..fce387b408d 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php @@ -28,8 +28,7 @@ use Psalm\Issue\FalsableReturnStatement; use Psalm\Issue\InvalidDocblock; use Psalm\Issue\InvalidReturnStatement; -use Psalm\Issue\InvolvedTypes; -use Psalm\Issue\LessSpecificReturnStatement; +use Psalm\Internal\InvolvedTypes;use Psalm\Issue\LessSpecificReturnStatement; use Psalm\Issue\MixedReturnStatement; use Psalm\Issue\MixedReturnTypeCoercion; use Psalm\Issue\NoValue; diff --git a/src/Psalm/Issue/InvolvedTypes.php b/src/Psalm/Internal/InvolvedTypes.php similarity index 94% rename from src/Psalm/Issue/InvolvedTypes.php rename to src/Psalm/Internal/InvolvedTypes.php index 7802b5314c7..3d576a7517f 100644 --- a/src/Psalm/Issue/InvolvedTypes.php +++ b/src/Psalm/Internal/InvolvedTypes.php @@ -1,6 +1,6 @@ 'https://psalm.dev/024', 'taint_trace' => null, 'other_references' => null, + 'involvedTypes' => null ], [ 'severity' => 'error', @@ -752,6 +753,7 @@ public function testJsonReport(): void 'link' => 'https://psalm.dev/138', 'taint_trace' => null, 'other_references' => null, + 'involvedTypes' => null ], [ 'severity' => 'error', @@ -774,6 +776,7 @@ public function testJsonReport(): void 'link' => 'https://psalm.dev/047', 'taint_trace' => null, 'other_references' => null, + 'involvedTypes' => null ], [ 'severity' => 'error', @@ -796,6 +799,7 @@ public function testJsonReport(): void 'link' => 'https://psalm.dev/020', 'taint_trace' => null, 'other_references' => null, + 'involvedTypes' => null ], [ 'severity' => 'info', @@ -818,6 +822,7 @@ public function testJsonReport(): void 'link' => 'https://psalm.dev/126', 'taint_trace' => null, 'other_references' => null, + 'involvedTypes' => null ], ]; From f41279b475a07c479fefa23794b62a8cd3505e72 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 19 May 2022 09:12:44 +0200 Subject: [PATCH 17/46] fixes typo --- src/Psalm/Internal/Analyzer/IssueData.php | 3 ++- src/Psalm/Internal/InvolvedTypes.php | 10 +++++----- src/Psalm/Report/ConsoleReport.php | 2 +- src/Psalm/Report/PrettyPrintArray/PrettyCompare.php | 4 ++-- tests/ReportOutputTest.php | 10 +++++----- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/IssueData.php b/src/Psalm/Internal/Analyzer/IssueData.php index 36c00f15c42..6ec185fbce2 100644 --- a/src/Psalm/Internal/Analyzer/IssueData.php +++ b/src/Psalm/Internal/Analyzer/IssueData.php @@ -129,9 +129,10 @@ class IssueData public $dupe_key; /** + * @var ?InvolvedTypes * @readonly */ - public ?InvolvedTypes $involvedTypes; + public $involvedTypes; /** * @param ?list $taint_trace diff --git a/src/Psalm/Internal/InvolvedTypes.php b/src/Psalm/Internal/InvolvedTypes.php index 3d576a7517f..9ab4ca48682 100644 --- a/src/Psalm/Internal/InvolvedTypes.php +++ b/src/Psalm/Internal/InvolvedTypes.php @@ -4,18 +4,18 @@ final class InvolvedTypes { - private string $inferedType; + private string $inferredType; private string $declaredType; - public function __construct(string $inferedType, string $declaredType) + public function __construct(string $inferredType, string $declaredType) { - $this->inferedType = $inferedType; + $this->inferredType = $inferredType; $this->declaredType = $declaredType; } - public function getInferedType(): string + public function getInferredType(): string { - return $this->inferedType; + return $this->inferredType; } public function getDeclaredType(): string diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index b7833dd3e02..aac3e2fe08a 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -97,7 +97,7 @@ private function prettyPrintArray(IssueData $issue_data): string } $arrayPrettyPrinted0 = $prettyFormat->format($issue_data->involvedTypes->getDeclaredType()); - $arrayPrettyPrinted1 = $prettyFormat->format($issue_data->involvedTypes->getInferedType()); + $arrayPrettyPrinted1 = $prettyFormat->format($issue_data->involvedTypes->getInferredType()); $toIssue = PHP_EOL.$prettyPaired->compare($arrayPrettyPrinted0, $arrayPrettyPrinted1); return PrettyGeneric::revertNormalizedTokens($toIssue); diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php index 323f10a1148..16811063a5e 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php @@ -11,11 +11,11 @@ final class PrettyCompare { - public function compare(string $infered, string $declared): string + public function compare(string $inferred, string $declared): string { $formatTable = '| %-50s | %-50s '; - $requested = explode(PHP_EOL, $infered); + $requested = explode(PHP_EOL, $inferred); $provided = explode(PHP_EOL, $declared); $maxOf = count($requested) > count($provided) ? count($requested) : count($provided); diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 57112d7c579..b35742a8c57 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1418,7 +1418,7 @@ function accept(array $input): void /** * @dataProvider payloadProvider() */ - public function testConsoleReportWithPrettyPrintFromPayload(string $payload, string $infered, string $declared, $expected_output): void + public function testConsoleReportWithPrettyPrintFromPayload(string $payload, string $inferred, string $declared, $expected_output): void { $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); $issues_data = [ @@ -1443,7 +1443,7 @@ public function testConsoleReportWithPrettyPrintFromPayload(string $payload, str null, null, null, - new InvolvedTypes($infered, $declared) + new InvolvedTypes($inferred, $declared) ), ]; @@ -1457,12 +1457,12 @@ public function testConsoleReportWithPrettyPrintFromPayload(string $payload, str */ public function payloadProvider(): Generator { - $infered = 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_ccccc: null|string, tid_bbbbb: null|string}'; + $inferred = 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_ccccc: null|string, tid_bbbbb: null|string}'; $declared = 'array{code_xxx: null|string, datetime: null|string, money: float|null, id_yyyy: null|string, tid_aaaaaa: null|string, tid_bbbbb: null|string}'; $paylaod = <<<'EOT' 'ERROR: InvalidReturnStatement - XXXX.php:66:16 - - The inferred type '$infered' does not match the declared return type '$declared' for YYYYY() (see https://psalm.dev/128) + The inferred type '$inferred' does not match the declared return type '$declared' for YYYYY() (see https://psalm.dev/128) EOT; $expected = <<<"EOT" @@ -1480,7 +1480,7 @@ public function payloadProvider(): Generator | EOT; - yield [$paylaod, $infered, $declared, $expected]; + yield [$paylaod, $inferred, $declared, $expected]; } private function prepareConsoleOptionsForPrettyPrint(): ReportOptions From e2a6c5061a2161b8d08586cfac39839c889b6b57 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 19 May 2022 09:28:16 +0200 Subject: [PATCH 18/46] cs-fix --- src/Psalm/Internal/Analyzer/IssueData.php | 1 + src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php | 3 ++- src/Psalm/Issue/CodeIssue.php | 2 +- src/Psalm/Report/PrettyPrintArray/PrettyCompare.php | 3 ++- tests/ReportOutputTest.php | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/IssueData.php b/src/Psalm/Internal/Analyzer/IssueData.php index 6ec185fbce2..c4b70acd9fe 100644 --- a/src/Psalm/Internal/Analyzer/IssueData.php +++ b/src/Psalm/Internal/Analyzer/IssueData.php @@ -3,6 +3,7 @@ namespace Psalm\Internal\Analyzer; use Psalm\Internal\InvolvedTypes; + use function str_pad; use const STR_PAD_LEFT; diff --git a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php index fce387b408d..a3ef0e13cfc 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php @@ -19,6 +19,7 @@ use Psalm\Internal\Codebase\TaintFlowGraph; use Psalm\Internal\Codebase\VariableUseGraph; use Psalm\Internal\DataFlow\DataFlowNode; +use Psalm\Internal\InvolvedTypes; use Psalm\Internal\MethodIdentifier; use Psalm\Internal\Type\Comparator\TypeComparisonResult; use Psalm\Internal\Type\Comparator\UnionTypeComparator; @@ -28,7 +29,7 @@ use Psalm\Issue\FalsableReturnStatement; use Psalm\Issue\InvalidDocblock; use Psalm\Issue\InvalidReturnStatement; -use Psalm\Internal\InvolvedTypes;use Psalm\Issue\LessSpecificReturnStatement; +use Psalm\Issue\LessSpecificReturnStatement; use Psalm\Issue\MixedReturnStatement; use Psalm\Issue\MixedReturnTypeCoercion; use Psalm\Issue\NoValue; diff --git a/src/Psalm/Issue/CodeIssue.php b/src/Psalm/Issue/CodeIssue.php index 8c0975fdf5e..69722f5cb69 100644 --- a/src/Psalm/Issue/CodeIssue.php +++ b/src/Psalm/Issue/CodeIssue.php @@ -4,8 +4,8 @@ use Psalm\CodeLocation; use Psalm\Internal\Analyzer\IssueData; - use Psalm\Internal\InvolvedTypes; + use function array_pop; use function explode; diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php index 16811063a5e..0545a88ab14 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCompare.php @@ -37,11 +37,12 @@ public function compare(string $inferred, string $declared): string return ''; } + $pairedFormattedResult = []; $pairedFormattedResult[] = '|'; $pairedFormattedResult[] = sprintf($formatTable, 'Expected', 'Provided'); $pairedFormattedResult[] = sprintf($formatTable, '---', '---'); - foreach ($paired as $k => $rows) { + foreach ($paired as $rows) { $pairedFormattedResult[] = sprintf($formatTable, ...$rows); } diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index b35742a8c57..d542fbe1a6d 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -8,10 +8,10 @@ use Psalm\Context; use Psalm\Internal\Analyzer\IssueData; use Psalm\Internal\Analyzer\ProjectAnalyzer; +use Psalm\Internal\InvolvedTypes; use Psalm\Internal\Provider\FakeFileProvider; use Psalm\Internal\Provider\Providers; use Psalm\Internal\RuntimeCaches; -use Psalm\Internal\InvolvedTypes; use Psalm\IssueBuffer; use Psalm\Report; use Psalm\Report\JsonReport; From 9ab3e4207bb76576200b933cfb15b0d5eeecd1d0 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 19 May 2022 09:58:10 +0200 Subject: [PATCH 19/46] try to fix issue with windows --- tests/ReportOutputTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index d542fbe1a6d..aac8817bb71 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1497,7 +1497,10 @@ private function assertOutputPrettyPrintEquals($expected_output, string $output) $lines = explode(PHP_EOL, $expected_output); foreach ($lines as $line) { - $this->assertStringContainsString($line, $output); + $this->assertStringContainsString( + $this->toUnixLineEndings($line), + $this->toUnixLineEndings($output) + ); } } } From 4949c77c21d7a8efb9aec10d267d126dbf5ca48a Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 19 May 2022 10:24:19 +0200 Subject: [PATCH 20/46] fix test ReportOutputTest.php --- tests/ReportOutputTest.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index aac8817bb71..0bfe4e48d29 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1336,7 +1336,7 @@ private function toUnixLineEndings(string $output): string /** * @dataProvider outputProvider() */ - public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_contents, $expected_output): void + public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_contents, string $expected_output): void { $this->addFile('somefile.php', $file_contents); $this->analyzeFile('somefile.php', new Context()); @@ -1418,7 +1418,7 @@ function accept(array $input): void /** * @dataProvider payloadProvider() */ - public function testConsoleReportWithPrettyPrintFromPayload(string $payload, string $inferred, string $declared, $expected_output): void + public function testConsoleReportWithPrettyPrintFromPayload(string $payload, string $inferred, string $declared, string $expected_output): void { $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); $issues_data = [ @@ -1492,14 +1492,16 @@ private function prepareConsoleOptionsForPrettyPrint(): ReportOptions return $console_report_options; } - private function assertOutputPrettyPrintEquals($expected_output, string $output): void + private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void { - $lines = explode(PHP_EOL, $expected_output); + $asUnixLinesOutput = explode(PHP_EOL, $this->toUnixLineEndings($expected_output)); + $asUnixOutput = $this->toUnixLineEndings($output); + + foreach ($asUnixLinesOutput as $line) { - foreach ($lines as $line) { $this->assertStringContainsString( - $this->toUnixLineEndings($line), - $this->toUnixLineEndings($output) + $line, + $asUnixOutput ); } } From 0a4ade023186ed3b56457fd5ab9dff452a20855e Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 19 May 2022 11:07:02 +0200 Subject: [PATCH 21/46] try to fix psalm issues --- src/Psalm/Internal/Analyzer/IssueData.php | 2 +- .../Internal/Analyzer/Statements/ReturnAnalyzer.php | 2 +- src/Psalm/{Internal => }/InvolvedTypes.php | 2 +- src/Psalm/Issue/CodeIssue.php | 7 +++++-- src/Psalm/Report/ConsoleReport.php | 9 +++++---- tests/ReportOutputTest.php | 3 +-- 6 files changed, 14 insertions(+), 11 deletions(-) rename src/Psalm/{Internal => }/InvolvedTypes.php (94%) diff --git a/src/Psalm/Internal/Analyzer/IssueData.php b/src/Psalm/Internal/Analyzer/IssueData.php index c4b70acd9fe..5c9c68a4952 100644 --- a/src/Psalm/Internal/Analyzer/IssueData.php +++ b/src/Psalm/Internal/Analyzer/IssueData.php @@ -2,7 +2,7 @@ namespace Psalm\Internal\Analyzer; -use Psalm\Internal\InvolvedTypes; +use Psalm\InvolvedTypes; use function str_pad; diff --git a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php index a3ef0e13cfc..18fdcf67243 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php @@ -19,13 +19,13 @@ use Psalm\Internal\Codebase\TaintFlowGraph; use Psalm\Internal\Codebase\VariableUseGraph; use Psalm\Internal\DataFlow\DataFlowNode; -use Psalm\Internal\InvolvedTypes; use Psalm\Internal\MethodIdentifier; use Psalm\Internal\Type\Comparator\TypeComparisonResult; use Psalm\Internal\Type\Comparator\UnionTypeComparator; use Psalm\Internal\Type\TemplateInferredTypeReplacer; use Psalm\Internal\Type\TemplateResult; use Psalm\Internal\Type\TypeExpander; +use Psalm\InvolvedTypes; use Psalm\Issue\FalsableReturnStatement; use Psalm\Issue\InvalidDocblock; use Psalm\Issue\InvalidReturnStatement; diff --git a/src/Psalm/Internal/InvolvedTypes.php b/src/Psalm/InvolvedTypes.php similarity index 94% rename from src/Psalm/Internal/InvolvedTypes.php rename to src/Psalm/InvolvedTypes.php index 9ab4ca48682..0f06617b38a 100644 --- a/src/Psalm/Internal/InvolvedTypes.php +++ b/src/Psalm/InvolvedTypes.php @@ -1,6 +1,6 @@ involvedTypes) { + $involvedTypes = $issue_data->involvedTypes; + if (!$involvedTypes) { return ''; } - $arrayPrettyPrinted0 = $prettyFormat->format($issue_data->involvedTypes->getDeclaredType()); - $arrayPrettyPrinted1 = $prettyFormat->format($issue_data->involvedTypes->getInferredType()); - $toIssue = PHP_EOL.$prettyPaired->compare($arrayPrettyPrinted0, $arrayPrettyPrinted1); + $arrayPrettyPrinted0 = $prettyFormat->format($involvedTypes->getDeclaredType()); + $arrayPrettyPrinted1 = $prettyFormat->format($involvedTypes->getInferredType()); + $toIssue = PHP_EOL.$prettyPaired->compare($arrayPrettyPrinted0, $arrayPrettyPrinted1); return PrettyGeneric::revertNormalizedTokens($toIssue); } catch (Throwable $throwable) { diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 0bfe4e48d29..584f80c96f9 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -8,10 +8,10 @@ use Psalm\Context; use Psalm\Internal\Analyzer\IssueData; use Psalm\Internal\Analyzer\ProjectAnalyzer; -use Psalm\Internal\InvolvedTypes; use Psalm\Internal\Provider\FakeFileProvider; use Psalm\Internal\Provider\Providers; use Psalm\Internal\RuntimeCaches; +use Psalm\InvolvedTypes; use Psalm\IssueBuffer; use Psalm\Report; use Psalm\Report\JsonReport; @@ -1498,7 +1498,6 @@ private function assertOutputPrettyPrintEquals(string $expected_output, string $ $asUnixOutput = $this->toUnixLineEndings($output); foreach ($asUnixLinesOutput as $line) { - $this->assertStringContainsString( $line, $asUnixOutput From b8843d6850ff2abef7849f658f1285a06cf70991 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 19 May 2022 11:53:01 +0200 Subject: [PATCH 22/46] supress psalm error for probable error --- tests/ReportOutputTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 584f80c96f9..3e6513e076e 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1348,7 +1348,9 @@ public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_conten } /** - * @return Generator> + * Because bug I think: https://psalm.dev/r/ccb7da7a53 + * @psalm-suppress InvalidReturnType + * @return Generator */ public function outputProvider(): Generator { From 48f77dfb8ef2084d5d36637c14ceb05a4b295e01 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 19 May 2022 12:58:12 +0200 Subject: [PATCH 23/46] suppress psalm error in test --- tests/ReportOutputTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 3e6513e076e..f970dcefcd1 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1350,7 +1350,7 @@ public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_conten /** * Because bug I think: https://psalm.dev/r/ccb7da7a53 * @psalm-suppress InvalidReturnType - * @return Generator + * @return Generator */ public function outputProvider(): Generator { @@ -1455,7 +1455,9 @@ public function testConsoleReportWithPrettyPrintFromPayload(string $payload, str } /** - * @return Generator> + * Because bug I think: https://psalm.dev/r/ccb7da7a53 + * @psalm-suppress InvalidReturnType + * @return Generator */ public function payloadProvider(): Generator { From 454753aa2375c5683c7849f1fc5d72bf326aac9b Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Mon, 23 May 2022 19:51:02 +0200 Subject: [PATCH 24/46] adds test InvolvedTypesTest.php --- tests/InvolvedTypesTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/InvolvedTypesTest.php diff --git a/tests/InvolvedTypesTest.php b/tests/InvolvedTypesTest.php new file mode 100644 index 00000000000..1e86d974330 --- /dev/null +++ b/tests/InvolvedTypesTest.php @@ -0,0 +1,17 @@ +assertEquals($inferredType, $involveType->getInferredType()); + $this->assertEquals($declaredType, $involveType->getDeclaredType()); + } +} From 029a06f7870bee27f782eb339dcc35dc8dd35ff6 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Mon, 23 May 2022 19:59:31 +0200 Subject: [PATCH 25/46] refactor PrettyFormat.php --- src/Psalm/Report/PrettyPrintArray/PrettyFormat.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php index e6d14ad5c07..2d7f6acdd15 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php @@ -35,21 +35,22 @@ public function format(string $inputPayload): string $charAfter = self::CHAR_SPACE; } + $numChars = $prettyCursorBracket->getNumberBrackets(); if (',' === $char) { $charAfter = PHP_EOL; } elseif (',' === $previousChar) { - $charBefore = $this->addIdentChar($prettyCursorBracket); + $charBefore = $this->addIdentChar($numChars); } if ('{' === $previousChar) { - $charBefore = $this->addIdentChar($prettyCursorBracket); + $charBefore = $this->addIdentChar($numChars); } elseif ('{' === $char) { $charBefore = self::CHAR_SPACE; $charAfter = PHP_EOL; } if ('}' === $char) { - $charBefore = PHP_EOL .$this->addIdentChar($prettyCursorBracket); + $charBefore = PHP_EOL .$this->addIdentChar($numChars); } $buffer .= $charBefore @@ -64,8 +65,8 @@ public function format(string $inputPayload): string return $buffer; } - private function addIdentChar(PrettyCursorBracket $prettyCursorBracket): string + private function addIdentChar(int $numChars): string { - return str_repeat(self::CHAR_SPACE, $prettyCursorBracket->getNumberBrackets()); + return str_repeat(self::CHAR_SPACE, $numChars); } } From b0ff81ade67075f7a4b48a67f9c7bb7b2016a1d9 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Mon, 23 May 2022 20:05:13 +0200 Subject: [PATCH 26/46] change name PrettyGeneric.php to PrettyHelper.php --- src/Psalm/Report/ConsoleReport.php | 4 ++-- src/Psalm/Report/PrettyPrintArray/PrettyFormat.php | 4 ++-- .../PrettyPrintArray/{PrettyGeneric.php => PrettyHelper.php} | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/Psalm/Report/PrettyPrintArray/{PrettyGeneric.php => PrettyHelper.php} (95%) diff --git a/src/Psalm/Report/ConsoleReport.php b/src/Psalm/Report/ConsoleReport.php index 8ffc140a4db..457feb1cf79 100644 --- a/src/Psalm/Report/ConsoleReport.php +++ b/src/Psalm/Report/ConsoleReport.php @@ -8,7 +8,7 @@ use Psalm\Report; use Psalm\Report\PrettyPrintArray\PrettyCompare; use Psalm\Report\PrettyPrintArray\PrettyFormat; -use Psalm\Report\PrettyPrintArray\PrettyGeneric; +use Psalm\Report\PrettyPrintArray\PrettyHelper; use Throwable; use function basename; @@ -101,7 +101,7 @@ private function prettyPrintArray(IssueData $issue_data): string $arrayPrettyPrinted1 = $prettyFormat->format($involvedTypes->getInferredType()); $toIssue = PHP_EOL.$prettyPaired->compare($arrayPrettyPrinted0, $arrayPrettyPrinted1); - return PrettyGeneric::revertNormalizedTokens($toIssue); + return PrettyHelper::revertNormalizedTokens($toIssue); } catch (Throwable $throwable) { //todo: log ? return 'Pretty Print Array failed for unexpected error. Error: ' . $throwable->getMessage(); diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php index 2d7f6acdd15..7485b492db0 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php @@ -18,8 +18,8 @@ public function format(string $inputPayload): string $prettyCursorBracket = new PrettyCursorBracket(); $payload = $inputPayload; - $payload = PrettyGeneric::normalizeBracket($payload); - $payload = PrettyGeneric::normalizeTokens($payload); + $payload = PrettyHelper::normalizeBracket($payload); + $payload = PrettyHelper::normalizeTokens($payload); foreach (str_split($payload) as $char) { $prettyCursorBracket->accept($char); diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php b/src/Psalm/Report/PrettyPrintArray/PrettyHelper.php similarity index 95% rename from src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php rename to src/Psalm/Report/PrettyPrintArray/PrettyHelper.php index 086c158a43d..58b4efef9cb 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyGeneric.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyHelper.php @@ -4,7 +4,7 @@ use function str_replace; -final class PrettyGeneric +final class PrettyHelper { public static function normalizeBracket(string $payload): string { From 1e45d5e3e885b76e331e4e1cdbfec2e5ee0cc799 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 28 May 2022 00:07:45 +0200 Subject: [PATCH 27/46] adds test for PrettyCompareTest.php --- .../PrettyPrintArray/PrettyHelperTest.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/Report/PrettyPrintArray/PrettyHelperTest.php diff --git a/tests/Report/PrettyPrintArray/PrettyHelperTest.php b/tests/Report/PrettyPrintArray/PrettyHelperTest.php new file mode 100644 index 00000000000..e3c18042ac0 --- /dev/null +++ b/tests/Report/PrettyPrintArray/PrettyHelperTest.php @@ -0,0 +1,33 @@ + aa bb cc'; + $actual = PrettyHelper::normalizeBracket($payload); + + $this->assertSame('{ } aa bb cc', $actual); + } + + public function testNormalizeTokens(): void + { + $payload = 'array-key'; + $actual = PrettyHelper::normalizeTokens($payload); + + $this->assertSame('psalm-key', $actual); + } + + public function testRevertNormalizedTokens(): void + { + $payload = 'psalm-key'; + $actual = PrettyHelper::revertNormalizedTokens($payload); + + $this->assertSame('array-key', $actual); + } +} From 8008f8f1c5b488d57f37aa8e7ac3c8a8fb922bf0 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 28 May 2022 00:07:58 +0200 Subject: [PATCH 28/46] adds test for PrettyFormatTest.php --- .../PrettyPrintArray/PrettyFormatTest.php | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 tests/Report/PrettyPrintArray/PrettyFormatTest.php diff --git a/tests/Report/PrettyPrintArray/PrettyFormatTest.php b/tests/Report/PrettyPrintArray/PrettyFormatTest.php new file mode 100644 index 00000000000..1b25eab901a --- /dev/null +++ b/tests/Report/PrettyPrintArray/PrettyFormatTest.php @@ -0,0 +1,121 @@ +format($payload); + + $this->assertSame($expected, $actual); + } + + /** + * Because bug I think: https://psalm.dev/r/ccb7da7a53 + * @psalm-suppress InvalidReturnType + * @return Generator + */ + public function providerValidPayload(): Generator + { + yield [ + 'field:', + 'field: ' + ]; + + yield [ + 'field:value', + 'field: value' + ]; + + $expected = <<<"EOT" + field: value, + field2: value2 + EOT; + + yield [ + 'field:value,field2:value2', + $expected + ]; + + $expected = <<<"EOT" + field: value, + field2: value2, + arr1: array { + foo: bar + } + EOT; + + yield [ + 'field:value,field2:value2, arr1: array{foo:bar} ', + $expected + ]; + + $expected = <<<"EOT" + field: value, + field2: value2, + arr1: array { + arr2: array { + foo: bar + } + } + EOT; + + yield [ + 'field:value,field2:value2, arr1: array{arr2: array{foo:bar}} ', + $expected + ]; + + $expected = <<<"EOT" + field: value, + field2: value2, + arr1: array { + arr2: array { + arr3: array { + foo: bar + } + } + } + EOT; + + yield [ + 'field:value,field2:value2, arr1: array{ arr2: array{ arr3: array{ foo:bar } } }', + $expected + ]; + + yield [ + 'field:value,field2:value2,arr1:array{arr2:array{arr3:array{foo:bar}}}', + $expected + ]; + + yield [ + 'field:value,field2:value2,arr1:array>>', + $expected + ]; + + $expected = <<<"EOT" + field: value, + field2: value2, + arr1: array { + arr2: array { + arr3: array { + psalm-key: bar + } + } + } + EOT; + + yield [ + 'field:value,field2:value2, arr1: array{ arr2: array{ arr3: array{ array-key:bar } } }', + $expected + ]; + } +} From 74db30e6340b3ecf0ce0395a04a40ce47f5d03c0 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 28 May 2022 00:08:20 +0200 Subject: [PATCH 29/46] adds test for PrettyCursorBracketTest.php --- .../PrettyPrintArray/PrettyCursorBracket.php | 6 ++- .../PrettyCursorBracketTest.php | 51 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/Report/PrettyPrintArray/PrettyCursorBracketTest.php diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php b/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php index ce1c4684b4c..36c5ccfe33d 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyCursorBracket.php @@ -26,6 +26,11 @@ public function accept(string $char): void } if (self::BRACKET_CLOSE === $char) { + if ($this->getNumberBrackets() === 0) { + $this->nBrackets = 1; + return; + } + $this->nBrackets--; } } @@ -33,7 +38,6 @@ public function accept(string $char): void public function closed(): bool { if ($this->openedBracket === true && self::BRACKET_CLOSE === $this->char) { - $this->nBrackets--; if ($this->nBrackets <= 0) { return true; } diff --git a/tests/Report/PrettyPrintArray/PrettyCursorBracketTest.php b/tests/Report/PrettyPrintArray/PrettyCursorBracketTest.php new file mode 100644 index 00000000000..dd792320f82 --- /dev/null +++ b/tests/Report/PrettyPrintArray/PrettyCursorBracketTest.php @@ -0,0 +1,51 @@ +accept($char); + } + + $this->assertSame($closed, $sut->closed()); + $this->assertSame($numeroBrackets, $sut->getNumberBrackets()); + } + + /** + * @return Generator + */ + public function providerValidCases(): Generator + { + yield ['',false,0]; + + yield ['{',false,1]; + + yield ['}',false,1]; + + yield ['{}',true,0]; + + yield ['{} {}',true,0]; + + yield ['{{ }',false,1]; + + yield ['{{{ }',false,2]; + + yield ['{{{ }}',false,1]; + + yield ['{{{ }}}',true,0]; + } +} From 9f46f65f40e5ec2dd3734b5b8281b4f9e134d3f1 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 28 May 2022 00:08:39 +0200 Subject: [PATCH 30/46] adds test for PrettyCompareTest.php --- .../PrettyPrintArray/PrettyCompareTest.php | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/Report/PrettyPrintArray/PrettyCompareTest.php diff --git a/tests/Report/PrettyPrintArray/PrettyCompareTest.php b/tests/Report/PrettyPrintArray/PrettyCompareTest.php new file mode 100644 index 00000000000..060c2b3c5fe --- /dev/null +++ b/tests/Report/PrettyPrintArray/PrettyCompareTest.php @@ -0,0 +1,85 @@ +compare($inferred, $declared); + + $this->assertOutputPrettyPrintEquals($expected, $actual); + } + + private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void + { + $linesOutput = explode(PHP_EOL, ($expected_output)); + + foreach ($linesOutput as $line) { + $this->assertStringContainsString( + $line, + $output + ); + } + } + + + /** + * @return Generator + */ + public function providerValidPayload(): Generator + { + $inferred = <<<"EOT" + field: value, + field2: value2, + arr1: array { + arr2: array { + arr3: array { + foo: bar + } + } + } + EOT; + + $declared = <<<"EOT" + field: value, + field2: value2, + arr1: array { + arr2: array { + arr3: array { + foo: bar + } + } + } + EOT; + + $expected = <<<"EOT" + | Expected | Provided + | --- | --- + | field: value, | field: value, + | field2: value2, | field2: value2, + | arr1: array { | arr1: array { + | arr2: array { | arr2: array { + | arr3: array { | arr3: array { + | foo: bar | foo: bar + | } | } + | } | } + | } | } + | | + EOT; + + yield [$inferred, $declared, $expected]; + } +} From ecd78ab68a082ea3e24c8f5d449a33dc822df14a Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 28 May 2022 14:42:15 +0200 Subject: [PATCH 31/46] try to fix windows issues --- tests/ReportOutputTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index f970dcefcd1..38a61ee2886 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1503,7 +1503,7 @@ private function assertOutputPrettyPrintEquals(string $expected_output, string $ foreach ($asUnixLinesOutput as $line) { $this->assertStringContainsString( - $line, + $this->toUnixLineEndings($line), $asUnixOutput ); } From 647293658d8614bdd404508f61d7ff307a92e616 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 28 May 2022 15:06:29 +0200 Subject: [PATCH 32/46] try to fix windows issues attempt 1 --- tests/ReportOutputTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 38a61ee2886..aa4db4f6a46 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1498,13 +1498,13 @@ private function prepareConsoleOptionsForPrettyPrint(): ReportOptions private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void { - $asUnixLinesOutput = explode(PHP_EOL, $this->toUnixLineEndings($expected_output)); - $asUnixOutput = $this->toUnixLineEndings($output); + $asExpectedOutput = explode(PHP_EOL, $expected_output); + $asActualOutput = $output; - foreach ($asUnixLinesOutput as $line) { + foreach ($asExpectedOutput as $line) { $this->assertStringContainsString( - $this->toUnixLineEndings($line), - $asUnixOutput + str_replace('\n', '', $line), + $asActualOutput ); } } From 0160796f4ecdf20d64e8d49029bdbd5deb6a024f Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 28 May 2022 15:14:42 +0200 Subject: [PATCH 33/46] try to fix windows issues attempt 1 + csfix --- tests/ReportOutputTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index aa4db4f6a46..f8ac84afda7 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -25,6 +25,7 @@ use function ob_end_clean; use function ob_start; use function preg_replace; +use function str_replace; use function unlink; use const JSON_THROW_ON_ERROR; From 62b57b6566799dcadfcc33b59ac2fb862a56d563 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Sat, 28 May 2022 15:26:52 +0200 Subject: [PATCH 34/46] try to fix windows issues attempt 2 --- tests/ReportOutputTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index f8ac84afda7..46a20ce0e02 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1504,8 +1504,8 @@ private function assertOutputPrettyPrintEquals(string $expected_output, string $ foreach ($asExpectedOutput as $line) { $this->assertStringContainsString( - str_replace('\n', '', $line), - $asActualOutput + str_replace(PHP_EOL, '', $line), + str_replace(PHP_EOL, '', $asActualOutput), ); } } From 5b41392257c11d10d426de34d1304486c754fdfa Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Mon, 30 May 2022 08:20:58 +0200 Subject: [PATCH 35/46] try to fix windows issues attempt 3 --- tests/ReportOutputTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 46a20ce0e02..ad777c485eb 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1499,13 +1499,14 @@ private function prepareConsoleOptionsForPrettyPrint(): ReportOptions private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void { + $token = ['\r\n','\r','\n']; $asExpectedOutput = explode(PHP_EOL, $expected_output); $asActualOutput = $output; foreach ($asExpectedOutput as $line) { $this->assertStringContainsString( - str_replace(PHP_EOL, '', $line), - str_replace(PHP_EOL, '', $asActualOutput), + str_replace($token, '', $line), + str_replace($token, '', $asActualOutput), ); } } From 76ede51f8457d8592eb44be3518340f1130ecdac Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 2 Jun 2022 22:19:03 +0200 Subject: [PATCH 36/46] try to fix windows issues attempt 4 (double quote) --- tests/ReportOutputTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index ad777c485eb..0b1b700d470 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1499,14 +1499,14 @@ private function prepareConsoleOptionsForPrettyPrint(): ReportOptions private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void { - $token = ['\r\n','\r','\n']; + $tokens = ["\r\n","\r","\n"]; $asExpectedOutput = explode(PHP_EOL, $expected_output); $asActualOutput = $output; foreach ($asExpectedOutput as $line) { $this->assertStringContainsString( - str_replace($token, '', $line), - str_replace($token, '', $asActualOutput), + str_replace($tokens, '', $line), + str_replace($tokens, '', $asActualOutput), ); } } From fdd3f32d3fc5bd2af0a7e5a26f09e2429e5ce79f Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 2 Jun 2022 22:32:40 +0200 Subject: [PATCH 37/46] try to fix windows issues attempt 5 (mark test as skipped) --- .../PrettyPrintArray/PrettyCompareTest.php | 2 + .../PrettyPrintArray/PrettyFormatTest.php | 2 + tests/ReportOutputTest.php | 61 ++++++++++--------- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/tests/Report/PrettyPrintArray/PrettyCompareTest.php b/tests/Report/PrettyPrintArray/PrettyCompareTest.php index 060c2b3c5fe..c0bc1cfc11a 100644 --- a/tests/Report/PrettyPrintArray/PrettyCompareTest.php +++ b/tests/Report/PrettyPrintArray/PrettyCompareTest.php @@ -17,6 +17,8 @@ class PrettyCompareTest extends TestCase */ public function testCompare(string $inferred, string $declared, string $expected): void { + $this->markTestSkipped('Needs to fix'); + $sut = new PrettyCompare(); $actual = $sut->compare($inferred, $declared); diff --git a/tests/Report/PrettyPrintArray/PrettyFormatTest.php b/tests/Report/PrettyPrintArray/PrettyFormatTest.php index 1b25eab901a..668895d7347 100644 --- a/tests/Report/PrettyPrintArray/PrettyFormatTest.php +++ b/tests/Report/PrettyPrintArray/PrettyFormatTest.php @@ -13,6 +13,8 @@ class PrettyFormatTest extends TestCase */ public function testFormat(string $payload, string $expected): void { + $this->markTestSkipped('Needs to fix'); + $sut = new PrettyFormat(); $actual = $sut->format($payload); diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 0b1b700d470..f7d58e4ef3c 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1339,6 +1339,7 @@ private function toUnixLineEndings(string $output): string */ public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_contents, string $expected_output): void { + $this->markTestSkipped('Needs to fix'); $this->addFile('somefile.php', $file_contents); $this->analyzeFile('somefile.php', new Context()); @@ -1386,36 +1387,36 @@ function accept(array $input): void yield [$file_contents, $expected_output]; - $file_contents = <<<'EOT' - - */ - function request(): array - { - return [ "aa" => 111]; - } - - function accept(array $input): void - { - $v = $input["foo"]; - } - - accept(request()); - ; - EOT; - - $exp = <<<"EOT" - | Expected | Provided - | --- | --- - | array { | array { - | array-key, | aa: 111 - | string | } - | } | - | | - EOT; - - yield [$file_contents, $exp]; +// $file_contents = <<<'EOT' +// +// */ +// function request(): array +// { +// return [ "aa" => 111]; +// } +// +// function accept(array $input): void +// { +// $v = $input["foo"]; +// } +// +// accept(request()); +// ; +// EOT; +// +// $exp = <<<"EOT" +// | Expected | Provided +// | --- | --- +// | array { | array { +// | array-key, | aa: 111 +// | string | } +// | } | +// | | +// EOT; +// +// yield [$file_contents, $exp]; } /** From e151de1ca22e1fff1ebb842923850824c49e7508 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 2 Jun 2022 22:43:25 +0200 Subject: [PATCH 38/46] try to fix windows issues attempt 6 (normalized to \n) --- tests/ReportOutputTest.php | 64 +++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index f7d58e4ef3c..4c046976292 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1387,36 +1387,36 @@ function accept(array $input): void yield [$file_contents, $expected_output]; -// $file_contents = <<<'EOT' -// -// */ -// function request(): array -// { -// return [ "aa" => 111]; -// } -// -// function accept(array $input): void -// { -// $v = $input["foo"]; -// } -// -// accept(request()); -// ; -// EOT; -// -// $exp = <<<"EOT" -// | Expected | Provided -// | --- | --- -// | array { | array { -// | array-key, | aa: 111 -// | string | } -// | } | -// | | -// EOT; -// -// yield [$file_contents, $exp]; + $file_contents = <<<'EOT' + + */ + function request(): array + { + return [ "aa" => 111]; + } + + function accept(array $input): void + { + $v = $input["foo"]; + } + + accept(request()); + ; + EOT; + + $exp = <<<"EOT" + | Expected | Provided + | --- | --- + | array { | array { + | array-key, | aa: 111 + | string | } + | } | + | | + EOT; + + yield [$file_contents, $exp]; } /** @@ -1506,8 +1506,8 @@ private function assertOutputPrettyPrintEquals(string $expected_output, string $ foreach ($asExpectedOutput as $line) { $this->assertStringContainsString( - str_replace($tokens, '', $line), - str_replace($tokens, '', $asActualOutput), + str_replace($tokens, '\n', $line), + str_replace($tokens, '\n', $asActualOutput), ); } } From f42aee2a97787521061b22c164a7dae403b98467 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 2 Jun 2022 23:03:59 +0200 Subject: [PATCH 39/46] try to fix windows issues attempt 6-a (enable some test \n) --- tests/ReportOutputTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 4c046976292..09c259dec29 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1339,7 +1339,6 @@ private function toUnixLineEndings(string $output): string */ public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_contents, string $expected_output): void { - $this->markTestSkipped('Needs to fix'); $this->addFile('somefile.php', $file_contents); $this->analyzeFile('somefile.php', new Context()); From 3a25e062081d00d11ff597b69152ff401d606d0a Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 2 Jun 2022 23:11:01 +0200 Subject: [PATCH 40/46] try to fix windows issues attempt 6-b (add compare test \n) --- tests/Report/PrettyPrintArray/PrettyCompareTest.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/Report/PrettyPrintArray/PrettyCompareTest.php b/tests/Report/PrettyPrintArray/PrettyCompareTest.php index c0bc1cfc11a..4eb1d3572b5 100644 --- a/tests/Report/PrettyPrintArray/PrettyCompareTest.php +++ b/tests/Report/PrettyPrintArray/PrettyCompareTest.php @@ -7,6 +7,7 @@ use Psalm\Tests\TestCase; use function explode; +use function str_replace; use const PHP_EOL; @@ -17,8 +18,6 @@ class PrettyCompareTest extends TestCase */ public function testCompare(string $inferred, string $declared, string $expected): void { - $this->markTestSkipped('Needs to fix'); - $sut = new PrettyCompare(); $actual = $sut->compare($inferred, $declared); @@ -27,12 +26,14 @@ public function testCompare(string $inferred, string $declared, string $expected private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void { - $linesOutput = explode(PHP_EOL, ($expected_output)); + $tokens = ["\r\n","\r","\n"]; + $asExpectedOutput = explode(PHP_EOL, $expected_output); + $asActualOutput = $output; - foreach ($linesOutput as $line) { + foreach ($asExpectedOutput as $line) { $this->assertStringContainsString( - $line, - $output + str_replace($tokens, '\n', $line), + str_replace($tokens, '\n', $asActualOutput), ); } } From ba18b913d0f860a06bc70dd1ae775131425aaff1 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 2 Jun 2022 23:17:21 +0200 Subject: [PATCH 41/46] try to fix windows issues attempt 6-c (add format test \n) --- tests/Report/PrettyPrintArray/PrettyFormatTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Report/PrettyPrintArray/PrettyFormatTest.php b/tests/Report/PrettyPrintArray/PrettyFormatTest.php index 668895d7347..1b25eab901a 100644 --- a/tests/Report/PrettyPrintArray/PrettyFormatTest.php +++ b/tests/Report/PrettyPrintArray/PrettyFormatTest.php @@ -13,8 +13,6 @@ class PrettyFormatTest extends TestCase */ public function testFormat(string $payload, string $expected): void { - $this->markTestSkipped('Needs to fix'); - $sut = new PrettyFormat(); $actual = $sut->format($payload); From 935806fc942d23d2797405cb5973b634e6c543e1 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Thu, 2 Jun 2022 23:26:26 +0200 Subject: [PATCH 42/46] optimize common code with trait --- tests/HelperTest/HelperAssert.php | 25 +++++++++++++++++++ .../PrettyPrintArray/PrettyCompareTest.php | 22 +++------------- tests/ReportOutputTest.php | 20 +++------------ 3 files changed, 31 insertions(+), 36 deletions(-) create mode 100644 tests/HelperTest/HelperAssert.php diff --git a/tests/HelperTest/HelperAssert.php b/tests/HelperTest/HelperAssert.php new file mode 100644 index 00000000000..769cc4719fd --- /dev/null +++ b/tests/HelperTest/HelperAssert.php @@ -0,0 +1,25 @@ +assertOutputPrettyPrintEquals($expected, $actual); } - private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void - { - $tokens = ["\r\n","\r","\n"]; - $asExpectedOutput = explode(PHP_EOL, $expected_output); - $asActualOutput = $output; - - foreach ($asExpectedOutput as $line) { - $this->assertStringContainsString( - str_replace($tokens, '\n', $line), - str_replace($tokens, '\n', $asActualOutput), - ); - } - } - /** * @return Generator diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 09c259dec29..b8e7f8ffcad 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -16,23 +16,23 @@ use Psalm\Report; use Psalm\Report\JsonReport; use Psalm\Report\ReportOptions; +use Psalm\Tests\HelperTest\HelperAssert; use Psalm\Tests\Internal\Provider\FakeParserCacheProvider; use UnexpectedValueException; -use function explode; use function file_get_contents; use function json_decode; use function ob_end_clean; use function ob_start; use function preg_replace; -use function str_replace; use function unlink; use const JSON_THROW_ON_ERROR; -use const PHP_EOL; class ReportOutputTest extends TestCase { + use HelperAssert; + public function setUp(): void { // `TestCase::setUp()` creates its own ProjectAnalyzer and Config instance, but we don't want to do that in this @@ -1496,18 +1496,4 @@ private function prepareConsoleOptionsForPrettyPrint(): ReportOptions $console_report_options->pretty_print_array = true; return $console_report_options; } - - private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void - { - $tokens = ["\r\n","\r","\n"]; - $asExpectedOutput = explode(PHP_EOL, $expected_output); - $asActualOutput = $output; - - foreach ($asExpectedOutput as $line) { - $this->assertStringContainsString( - str_replace($tokens, '\n', $line), - str_replace($tokens, '\n', $asActualOutput), - ); - } - } } From 155c6d0e57f6e01da1125db53803cc6ba7d42b74 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Fri, 3 Jun 2022 08:25:47 +0200 Subject: [PATCH 43/46] Revert "optimize common code with trait" This reverts commit 935806fc942d23d2797405cb5973b634e6c543e1. --- tests/HelperTest/HelperAssert.php | 25 ------------------- .../PrettyPrintArray/PrettyCompareTest.php | 22 +++++++++++++--- tests/ReportOutputTest.php | 20 ++++++++++++--- 3 files changed, 36 insertions(+), 31 deletions(-) delete mode 100644 tests/HelperTest/HelperAssert.php diff --git a/tests/HelperTest/HelperAssert.php b/tests/HelperTest/HelperAssert.php deleted file mode 100644 index 769cc4719fd..00000000000 --- a/tests/HelperTest/HelperAssert.php +++ /dev/null @@ -1,25 +0,0 @@ -assertOutputPrettyPrintEquals($expected, $actual); } + private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void + { + $tokens = ["\r\n","\r","\n"]; + $asExpectedOutput = explode(PHP_EOL, $expected_output); + $asActualOutput = $output; + + foreach ($asExpectedOutput as $line) { + $this->assertStringContainsString( + str_replace($tokens, '\n', $line), + str_replace($tokens, '\n', $asActualOutput), + ); + } + } + /** * @return Generator diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index b8e7f8ffcad..09c259dec29 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -16,23 +16,23 @@ use Psalm\Report; use Psalm\Report\JsonReport; use Psalm\Report\ReportOptions; -use Psalm\Tests\HelperTest\HelperAssert; use Psalm\Tests\Internal\Provider\FakeParserCacheProvider; use UnexpectedValueException; +use function explode; use function file_get_contents; use function json_decode; use function ob_end_clean; use function ob_start; use function preg_replace; +use function str_replace; use function unlink; use const JSON_THROW_ON_ERROR; +use const PHP_EOL; class ReportOutputTest extends TestCase { - use HelperAssert; - public function setUp(): void { // `TestCase::setUp()` creates its own ProjectAnalyzer and Config instance, but we don't want to do that in this @@ -1496,4 +1496,18 @@ private function prepareConsoleOptionsForPrettyPrint(): ReportOptions $console_report_options->pretty_print_array = true; return $console_report_options; } + + private function assertOutputPrettyPrintEquals(string $expected_output, string $output): void + { + $tokens = ["\r\n","\r","\n"]; + $asExpectedOutput = explode(PHP_EOL, $expected_output); + $asActualOutput = $output; + + foreach ($asExpectedOutput as $line) { + $this->assertStringContainsString( + str_replace($tokens, '\n', $line), + str_replace($tokens, '\n', $asActualOutput), + ); + } + } } From e322eef98977fe32377f173c8ce71cd02bb07599 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Fri, 10 Jun 2022 23:51:30 +0200 Subject: [PATCH 44/46] new testcase and micro fix --- tests/ReportOutputTest.php | 78 ++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/tests/ReportOutputTest.php b/tests/ReportOutputTest.php index 09c259dec29..1dca91d579a 100644 --- a/tests/ReportOutputTest.php +++ b/tests/ReportOutputTest.php @@ -1337,15 +1337,15 @@ private function toUnixLineEndings(string $output): string /** * @dataProvider outputProvider() */ - public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_contents, string $expected_output): void + public function testConsoleReportWithPrettyPrintFromAnalyzer(string $file_contents, string $expectedOutput): void { $this->addFile('somefile.php', $file_contents); $this->analyzeFile('somefile.php', new Context()); $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); - $output = IssueBuffer::getOutput(IssueBuffer::getIssuesData(), $console_report_options); + $actualOutput = IssueBuffer::getOutput(IssueBuffer::getIssuesData(), $console_report_options); - $this->assertOutputPrettyPrintEquals($expected_output, $output); + $this->assertOutputPrettyPrintEquals($expectedOutput, $actualOutput); } /** @@ -1378,9 +1378,8 @@ function accept(array $input): void | Expected | Provided | --- | --- | array { | array { - | array-key, | aa: 'bar' - | int | } - | } | + | int | aa: 'bar' + | } | } | | EOT; @@ -1409,9 +1408,8 @@ function accept(array $input): void | Expected | Provided | --- | --- | array { | array { - | array-key, | aa: 111 - | string | } - | } | + | string | aa: 111 + | } | } | | EOT; @@ -1421,7 +1419,7 @@ function accept(array $input): void /** * @dataProvider payloadProvider() */ - public function testConsoleReportWithPrettyPrintFromPayload(string $payload, string $inferred, string $declared, string $expected_output): void + public function testConsoleReportWithPrettyPrintFromPayload(string $payload, string $inferred, string $declared, string $expectedOutput): void { $console_report_options = $this->prepareConsoleOptionsForPrettyPrint(); $issues_data = [ @@ -1451,8 +1449,8 @@ public function testConsoleReportWithPrettyPrintFromPayload(string $payload, str ]; $consoleReport = new Report\ConsoleReport($issues_data, [], $console_report_options); - $output = $consoleReport->create(); - $this->assertOutputPrettyPrintEquals($expected_output, $output); + $actualOutput = $consoleReport->create(); + $this->assertOutputPrettyPrintEquals($expectedOutput, $actualOutput); } /** @@ -1486,6 +1484,62 @@ public function payloadProvider(): Generator EOT; yield [$paylaod, $inferred, $declared, $expected]; + + $inferred = "array{array{_id: '6259381a37d1f57503ca646f', activeFrom: '2022-04-16T00:00:00.000+02:00', actualCity: 'Aachen', address: 'elefantenstrasse 12', annualSalaryFrom: 55000, annualSalaryTo: 70000, candidateContactWay: 'Email', cityCategory: 'Aachen', company: 'bkip ebus solutions GmbH', companyId: '623b3be0c421b2d41d3778db', companySize: '<50', companyType: 'Startup', expLevel: 'Senior', expiresOn: null, hasVisaSponsorship: 'No', isFullRemote: false, jobType: 'Full-Time', jobUrl: 'bippokippo-solutions-Architekten-mwd-fr-Elektromobilitt', language: 'English', latitude: float(50.76881525), logoImg: 'bkip-ebus-solutions-gmbh-logo.jpg', longitude: float(6.08364339), name: 'Software-Architekten (m/w/d) für Elektromobilität', offerStockOrBonus: false, postalCode: '52064', techCategory: 'Architect', technologies: array{'Angular', 'CI/CD', 'DevOps', 'Docker', 'ElasticSearch', 'Git', 'JBoss', 'Java', 'Jenkins', 'Quarkus'}}}"; + $declared = "array}>"; + + $paylaod = <<<'EOT' + ERROR: InvalidReturnStatement - 40:12 - The inferred type 'array{array{_id: '6259381a37d1f57503ca646f', activeFrom: '2022-04-16T00:00:00.000+02:00', actualCity: 'Aachen', address: 'elefantenstrasse 12', annualSalaryFrom: 55000, annualSalaryTo: 70000, candidateContactWay: 'Email', cityCategory: 'Aachen', company: 'bkip ebus solutions GmbH', companyId: '623b3be0c421b2d41d3778db', companySize: '<50', companyType: 'Startup', expLevel: 'Senior', expiresOn: null, hasVisaSponsorship: 'No', isFullRemote: false, jobType: 'Full-Time', jobUrl: 'bippokippo-solutions-Architekten-mwd-fr-Elektromobilitt', language: 'English', latitude: float(50.76881525), logoImg: 'bkip-ebus-solutions-gmbh-logo.jpg', longitude: float(6.08364339), name: 'Software-Architekten (m/w/d) für Elektromobilität', offerStockOrBonus: false, postalCode: '52064', techCategory: 'Architect', technologies: array{'Angular', 'CI/CD', 'DevOps', 'Docker', 'ElasticSearch', 'Git', 'JBoss', 'Java', 'Jenkins', 'Quarkus'}}}' does not match the declared return type 'array}>' for Test::getApiJobs + EOT; + + $expected = <<<"EOT" + | + | Expected | Provided + | --- | --- + | array { | array { + | array { | array { + | _id: string, | _id: '6259381a37d1f57503ca646f', + | activeFrom: string, | activeFrom: '2022-04-16T00: 00: 00.000+02: 00', + | actualCity: string, | actualCity: 'Aachen', + | address: string, | address: 'elefantenstrasse12', + | annualSalaryFrom: int, | annualSalaryFrom: 55000, + | annualSalaryTo: int, | annualSalaryTo: 70000, + | candidateContactWay: string, | candidateContactWay: 'Email', + | cityCategory: string, | cityCategory: 'Aachen', + | company: string, | company: 'bkipebussolutionsGmbH', + | companyId: string, | companyId: '623b3be0c421b2d41d3778db', + | companySize: string, | companySize: ' { + | companyType: string, | 50', + | country: 'ch'|'de', | companyType: 'Startup', + | expLevel: string, | expLevel: 'Senior', + | expiresOn: null|string, | expiresOn: null, + | hasVisaSponsorship: string, | hasVisaSponsorship: 'No', + | isFullRemote: bool, | isFullRemote: false, + | jobType: string, | jobType: 'Full-Time', + | jobUrl: string, | jobUrl: 'bippokippo-solutions-Architekten-mwd-fr-Elektromobilitt', + | language: string, | language: 'English', + | latitude: float, | latitude: float(50.76881525), + | logoImg: string, | logoImg: 'bkip-ebus-solutions-gmbh-logo.jpg', + | longitude: float, | longitude: float(6.08364339), + | name: string, | name: 'Software-Architekten(m/w/d)fürElektromobilität', + | offerStockOrBonus: bool, | offerStockOrBonus: false, + | postalCode: string, | postalCode: '52064', + | techCategory: string, | techCategory: 'Architect', + | technologies: array { | technologies: array { + | int, | 'Angular', + | string | 'CI/CD', + | } | 'DevOps', + | } | 'Docker', + | } | 'ElasticSearch', + | | 'Git', + | | 'JBoss', + | | 'Java', + | | 'Jenkins', + | | 'Quarkus' + | | } + EOT; + + yield [$paylaod, $inferred, $declared, $expected]; } private function prepareConsoleOptionsForPrettyPrint(): ReportOptions From 1483b931a2c11cf59168c10a5d847e62189a3065 Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Fri, 10 Jun 2022 23:51:53 +0200 Subject: [PATCH 45/46] improve code and test of prettyFormat --- .../Report/PrettyPrintArray/PrettyFormat.php | 107 ++++++++++++------ .../PrettyPrintArray/PrettyFormatTest.php | 14 +++ 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php index 7485b492db0..020aec1fe23 100644 --- a/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php +++ b/src/Psalm/Report/PrettyPrintArray/PrettyFormat.php @@ -2,62 +2,60 @@ namespace Psalm\Report\PrettyPrintArray; +use function count; use function str_repeat; -use function str_split; use const PHP_EOL; final class PrettyFormat { - private const CHAR_SPACE = ' '; - public function format(string $inputPayload): string { - $buffer = ''; - $previousChar = ''; + $buffer = $previousToken = ''; $prettyCursorBracket = new PrettyCursorBracket(); - $payload = $inputPayload; + $prettyMatchTokens = new PrettyMatchTokens(); - $payload = PrettyHelper::normalizeBracket($payload); + $payload = PrettyHelper::normalizeBracket($inputPayload); $payload = PrettyHelper::normalizeTokens($payload); - foreach (str_split($payload) as $char) { - $prettyCursorBracket->accept($char); + $prettyMatchTokens->tokenize($payload); + $tokens = $prettyMatchTokens->getMatchedTokens(); - if (self::CHAR_SPACE === $char) { - continue; - } + for ($i=0; $iaccept($token); - if (':' === $char) { - $charAfter = self::CHAR_SPACE; + if (PrettyMatchTokens::T_SPACE === $token) { + continue; } - $numChars = $prettyCursorBracket->getNumberBrackets(); - if (',' === $char) { - $charAfter = PHP_EOL; - } elseif (',' === $previousChar) { - $charBefore = $this->addIdentChar($numChars); + if ($token === PrettyMatchTokens::T_PSALM_KEY && + $nextToken === PrettyMatchTokens::T_COMMA) { + $i++; + continue; } - if ('{' === $previousChar) { - $charBefore = $this->addIdentChar($numChars); - } elseif ('{' === $char) { - $charBefore = self::CHAR_SPACE; - $charAfter = PHP_EOL; - } + $tokenAfter = $tokenBefore = ''; + $numBrackets = $prettyCursorBracket->getNumberBrackets(); - if ('}' === $char) { - $charBefore = PHP_EOL .$this->addIdentChar($numChars); - } + [$tokenAfter, $tokenBefore] = $this->processByCurrentToken( + $token, + $tokenBefore, + $tokenAfter, + $numBrackets + ); - $buffer .= $charBefore - . $char - . $charAfter; + $tokenBefore = $this->processByPreviousToken( + $previousToken, + $numBrackets, + $tokenBefore + ); - $previousChar = $char; + $buffer .= $tokenBefore . $token . $tokenAfter; + + $previousToken = $token; if ($prettyCursorBracket->closed()) { break; } @@ -65,8 +63,45 @@ public function format(string $inputPayload): string return $buffer; } - private function addIdentChar(int $numChars): string + private function indentOf(int $numBrackets): string + { + return str_repeat(PrettyMatchTokens::T_SPACE, $numBrackets); + } + + private function processByPreviousToken(string $previousToken, int $numBrackets, string $tokenBefore): string + { + if ($previousToken === PrettyMatchTokens::T_COMMA) { + return $this->indentOf($numBrackets); + } + + if ($previousToken === PrettyMatchTokens::T_CURLY_BRACKET_OPEN) { + return $this->indentOf($numBrackets); + } + + return $tokenBefore; + } + + /** + * @return array{string,string} + */ + private function processByCurrentToken(string $token, string $tokenBefore, string $tokenAfter, int $numBrackets): array { - return str_repeat(self::CHAR_SPACE, $numChars); + if ($token === PrettyMatchTokens::T_COLON) { + return [PrettyMatchTokens::T_SPACE,$tokenAfter]; + } + + if ($token === PrettyMatchTokens::T_COMMA) { + return [PHP_EOL,$tokenAfter]; + } + + if ($token === PrettyMatchTokens::T_CURLY_BRACKET_OPEN) { + return [PHP_EOL,PrettyMatchTokens::T_SPACE]; + } + + if ($token === PrettyMatchTokens::T_CURLY_BRACKET_CLOSE) { + return [$tokenAfter,PHP_EOL . $this->indentOf($numBrackets)]; + } + + return [$tokenAfter, $tokenBefore]; } } diff --git a/tests/Report/PrettyPrintArray/PrettyFormatTest.php b/tests/Report/PrettyPrintArray/PrettyFormatTest.php index 1b25eab901a..a48a9557493 100644 --- a/tests/Report/PrettyPrintArray/PrettyFormatTest.php +++ b/tests/Report/PrettyPrintArray/PrettyFormatTest.php @@ -26,6 +26,20 @@ public function testFormat(string $payload, string $expected): void */ public function providerValidPayload(): Generator { + $expected = <<<"EOT" + array { + array { + _id: string, + activeFrom: string + } + } + EOT; + + yield [ + 'array', + $expected + ]; + yield [ 'field:', 'field: ' From 8bac4c6e625fe2249e3a473c419fa5e868596d8f Mon Sep 17 00:00:00 2001 From: BruceGitHub Date: Fri, 10 Jun 2022 23:53:10 +0200 Subject: [PATCH 46/46] improvement code, and test of prettyMatchToken --- .../PrettyPrintArray/PrettyMatchTokens.php | 108 ++++++++++++++++++ .../PrettyMatchTokensTest.php | 60 ++++++++++ 2 files changed, 168 insertions(+) create mode 100644 src/Psalm/Report/PrettyPrintArray/PrettyMatchTokens.php create mode 100644 tests/Report/PrettyPrintArray/PrettyMatchTokensTest.php diff --git a/src/Psalm/Report/PrettyPrintArray/PrettyMatchTokens.php b/src/Psalm/Report/PrettyPrintArray/PrettyMatchTokens.php new file mode 100644 index 00000000000..c916308a9ee --- /dev/null +++ b/src/Psalm/Report/PrettyPrintArray/PrettyMatchTokens.php @@ -0,0 +1,108 @@ +tokens = $tokens; + $this->machedTokens = []; + } + + public function tokenize(string $payload): void + { + $getNextToken = function (string $payload, int $start): array { + $restPayload = substr($payload, $start); +// print_r(PHP_EOL.PHP_EOL."REST [ $restPayload ] start: $start"); + + $offset = 0; + $streamToken = ''; + + foreach (str_split($restPayload) as $char) { +// print_r(PHP_EOL."DEBUG-CHAR: [ $char ] [ offset: $offset ] "); + + if (in_array($streamToken, $this->tokens, true)) { +// print_r(PHP_EOL."DEBUG-DOUBLE: [ $streamToken ] [ offset: $offset ] "); + + return [$offset,$streamToken]; + } + + if (in_array($char, $this->tokens, true)) { +// print_r(PHP_EOL."DEBUG-SINGLE: [ $char ] [ offset: $offset ] "); + + if ($streamToken !== '') { + return [$offset,$streamToken]; + } + + return [$offset,$char]; + } + + $streamToken .= $char; + $offset++; + } + return [$offset,$streamToken]; + }; + + + /** @psalm-suppress UnusedVariable */ + $firstIsAToken = fn (int $newOffset, int $offset): int => $newOffset === 0 ? ++$offset : $offset; + + $offset = 0; + while ($offset < strlen($payload)) { + [$newOffset,$token] = $getNextToken($payload, $offset); + + $offset += $newOffset; + $offset = $firstIsAToken($newOffset, $offset); + $this->machedTokens[] = $token; + + if ($timeout++ >= 10000) { + die(PHP_EOL."timeout: $timeout reach!"); + } + } + } + + /** + * @return string[] + */ + public function getMatchedTokens(): array + { + return $this->machedTokens; + } +} diff --git a/tests/Report/PrettyPrintArray/PrettyMatchTokensTest.php b/tests/Report/PrettyPrintArray/PrettyMatchTokensTest.php new file mode 100644 index 00000000000..194343e3729 --- /dev/null +++ b/tests/Report/PrettyPrintArray/PrettyMatchTokensTest.php @@ -0,0 +1,60 @@ +tokenize($payload); + $actual = $prettyMatchTokens->getMatchedTokens(); + + $this->assertSame($expected, $actual); + } + + /** + * @return Generator + */ + public function payload(): Generator + { + yield [ + 'psalm-ke', + ['psalm-ke'] + ]; + + yield [ + 'array{psalm-key, array{_id: string, activeFrom: string}}', + ['array', '{', 'psalm-key', ',', ' ', 'array', '{','_id',':',' ','string',',',' ','activeFrom',':',' ','string','}','}'] + ]; + + yield [ + 'psalm-keypsalm-key', + ['psalm-key','psalm-key',] + ]; + + yield [ + '{{', + ['{','{',] + ]; + + yield [ + ' ,psalm-key{}:', + [' ', ',', 'psalm-key', '{','}', ':'] + ]; + + yield [ + 'psalm-key', + ['psalm-key',] + ]; + } +}