Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1169

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176
10BC0 Format-preserving pretty-printing for Mutants by maks-rafalko · Pull Request #2448 · infection/infection · GitHub
Nothing Special   »   [go: up one dir, main page]

Skip to content

Conversation

maks-rafalko
Copy link
Member
@maks-rafalko maks-rafalko commented Oct 14, 2025

Format-preserving pretty printing is hard :| After a week of evenings of debugging, here we go.

https://github.com/nikic/PHP-Parser/blob/master/doc/component/Pretty_printing.markdown#formatting-preserving-pretty-printing

Why is this needed?

Instead of 1000 words, examples:

Before:

@@ @@
     }
     public function logVerbosityDeprecationNotice(string $valueToUse): void
     {
-        $this->logger->notice('Numeric versions of log-verbosity have been deprecated, please use, ' . $valueToUse . ' to keep the same result', ['block' => true]);
+        $this->logger->notice('Numeric versions of log-verbosity have been deprecated, please use, ' . $valueToUse . ' to keep the same result', []);
     }
     public function logUnknownVerbosityOption(string $default): void
     {

After:

@@ @@
     {
         $this->logger->notice(
             'Numeric versions of log-verbosity have been deprecated, please use, ' . $valueToUse . ' to keep the same result',
-            ['block' => true],
+            [],
         );
     }

As you can see, previously Infection modified the source code formatting, then created a Mutant, and then compared modified original code with mutant.

Now, original code is compared with a mutant as is - we ONLY change the mutated node. No more reformatting.

This gives us much more readable and clear diffs. Long multiline arrays are no longer changed to lengthy one-liners.


During implementation, I found several bugs in php-parser:

These are not blockers, but interesting to see the answers from Nikita. I have a feeling that either these are bugs or we don't use nodes replacements correctly (probably we should do them in-place) - let's see.


  • check how HTML report works after these changes

@maks-rafalko maks-rafalko added the DX Developer Experience label Oct 14, 2025
@maks-rafalko maks-rafalko force-pushed the feature/format-preserving-pretty-print-2 branch from 9814cc8 to 40b228a Compare October 14, 2025 20:12
# Conflicts:
#	tests/phpunit/Mutation/MutationTest.php
Copy link
Member
@theofidry theofidry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So how do we test the result for a specific mutator? When replacing - with + there is no change of character/position so I guess it's an easy scenario, but if there is bigger transformations then how does it plays out an 10BC0 d how can we see that?

@maks-rafalko
Copy link
Member Author

So how do we test the result for a specific mutator? When replacing - with + there is no change of character/position so I guess it's an easy scenario, but if there is bigger transformations then how does it plays out and how can we see that?

that's why I've created #2450 - to be able to test exactly that formatting that happens for Mutants. Currently, different prinetrs are used so it's impossible.

But I will do it in separate PR what will target this one, as it's quite big

@maks-rafalko
Copy link
Member Author

So how do we test the result for a specific mutator? When replacing - with + there is no change of character/position so I guess it's an easy scenario, but if there is bigger transformations then how does it plays out and how can we see that?

I've spent much more time on it and updated the tests to use format-preserving pretty printer.

Many of the tests have been updated (as they obviously failed), unfortunately it's impossible to move it to a separate PR, so please take a look.

I've found already ~4 potential bugs in php-parser (mentioned them in the PR description), but none of them are blockers, yet annoying. You will find workarounds for them in the diff.

@maks-rafalko maks-rafalko marked this pull request as ready for review October 19, 2025 09:07
private readonly MutatedNode $mutatedNode,
private readonly int $mutationByMutatorIndex,
private readonly array $tests,
private readonly array $originalFileTokens,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since those are readonly maybe they could be public?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided not to do it, because it won't be consistent. We can translate private readonly properties to public as a separate PR using Rector I guess on the project level

*
* @return Token[]
*/
public function getTokens(): array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of this API. It fits in the current usage but it lacks any cohesiveness. Can't we change FileParser to return a tuple instead?

Suggested change
public function getTokens(): array
/**
* @throws UnparsableFile
*
* @return array{Stmt[], Token[]}
*/
public function parse(SplFileInfo $fileInfo): array
{
try {
$statements = $this->parser->parse($fileInfo->getContents()) ?? [];
$tokens = $this->parser->getTokens();
return [$statements, $tokens];
} catch (Throwable $throwable) {
$filePath = $fileInfo->getRealPath() === false
? $fileInfo->getPathname()
: $fileInfo->getRealPath()
;
throw UnparsableFile::fromInvalidFile($filePath, $throwable);
}
}

I appreciate it has a greater impact though

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided not to do it because ->parse($file) and ->getTokens() this is exactly the API that php-parser exposes. Yes, it's arguable, but we only have a wrapper.

Such change will affect many files and IMO if we really want it (I have doubts) it shouldn't be done here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already questionable in PHP-Parser and the advantage of having a wrapper is to be able to correct such API issues.

Such change will affect many files

Does it? From what I saw it only affects 3 files which you are already touching. That said this could be done in a separate PR.

In the end I don't think it's a fundamental change so I won't insist more than that, but it would be nicer to not introduce loose APIs.

@maks-rafalko maks-rafalko merged commit ef962f6 into master Oct 21, 2025
55 of 57 checks passed
@maks-rafalko maks-rafalko deleted the feature/format-preserving-pretty-print-2 branch October 21, 2025 16:39
maks-rafalko added a commit that referenced this pull request Oct 21, 2025
This is an extracted PR to fix review comment
#2448 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DX Developer Experience

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

0