Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Experiment] Rework child classes detection on DynamicSourceLocatorProvider #5735

Merged
merged 28 commits into from
Apr 25, 2024

Conversation

samsonasik
Copy link
Member

@samsonasik samsonasik commented Mar 17, 2024

@samsonasik samsonasik marked this pull request as draft March 17, 2024 23:45
@samsonasik
Copy link
Member Author

Ok, here investigation:

1 Tried back to Rector 0.19.15 before the FinalizeClassesWithoutChildrenRector is deprecated, tested with:

git clone git@github.com:samsonasik/ci4-album.git rector-0.x

got output:

➜  ci4-album git:(rector-0.x) ✗ vendor/bin/rector --dry-run
 49/49 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
2 files with changes
====================

1) src/Domain/Exception/DuplicatedRecordException.php:12

    ---------- begin diff ----------
@@ @@

 use DomainException;

-class DuplicatedRecordException extends DomainException
+final class DuplicatedRecordException extends DomainException

which shouldnot as the class has child. I will check if there is possible way to "init" the classes to be resolved by phpstan Reflection.

@samsonasik
Copy link
Member Author

@TomasVotruba @staabm It somehow can be resolved by patch:

-            if (!$classReflection->isSubclassOf($desiredClassReflection->getName())) {
+            if ($desiredClassReflection->getName() !== $classReflection->getName() && !$classReflection->isSubclassOf($desiredClassReflection->getName())) {
                continue;
            }

it seems isSubclassOf() definition make same class name as true on the removed FamilyRelationsAnalyzer::getChildrenOfClassReflection() on rector 0.19.5

if (! $classReflection->isSubclassOf($desiredClassReflection->getName())) {

I will try apply the child detection back.

@staabm
Copy link
Contributor

staabm commented Apr 22, 2024

I cannot follow, but you are right that isSubclassOf requires a actual subclass and does not include equality.

you can use is if you need the equality check to also return true.

@samsonasik
Copy link
Member Author

samsonasik commented Apr 22, 2024

It seems the classes only get the paths that scanned:

        $classReflections = $this->privatesAccessor->getPrivateProperty($this->reflectionProvider, 'classes');
        var_dump(count($classReflections));

Running on actual path only got 6 classes:

➜  ci4-album git:(rector-0.x) vendor/bin/rector process src/Domain/Exception/RecordNotFoundException.php  --dry-run --clear-cache
 0/1 [░░░░░░░░░░░░░░░░░░░░░░░░░░░░]   0%int(6)
string(46) "Album\Domain\Exception\RecordNotFoundException"
string(15) "DomainException"
string(14) "LogicException"
string(9) "Exception"
string(9) "Throwable"
string(10) "Stringable"

which should not, I will continue investigating if there is a way to init somewhere.

@staabm
Copy link
Contributor

staabm commented Apr 22, 2024

ClassReflection only works on paths in the analyzed path or scan* configurations, thats expected and correct from PHPStan point of view (and composer autoloading I guess).

@samsonasik
Copy link
Member Author

@staabm thank you, I remember that on old phpstan, the code is working fine without the tweak, and on some point of phpstan release, it no longer working, I will continue investigating as it is interesting, I expect it should work with at least run on no path provided:

vendor/bin/rector

which means all classes loaded.

@samsonasik
Copy link
Member Author

@TomasVotruba @staabm I finally got it working prototype 🎉 , tested on Rector 0.19.5 before the FinalizeClassesWithoutChildrenRector deprecated that test sub classes.

the getClass() need to be called to trigger collect classes property of MemoizingReflectionProvider 9a2fdbd

Before

➜  ci4-album git:(rector-0.x) ✗ vendor/bin/rector process --dry-run --clear-cache
 49/49 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
2 files with changes
====================

1) src/Domain/Exception/DuplicatedRecordException.php:12

    ---------- begin diff ----------
@@ @@

 use DomainException;

-class DuplicatedRecordException extends DomainException
+final class DuplicatedRecordException extends DomainException

After

➜  ci4-album git:(rector-0.x) ✗ vendor/bin/rector process --dry-run --clear-cache
 49/49 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

                                                                                                                        
 [OK] Rector is done!                                                                                                   

I will check segmentation fault on package tests

@samsonasik samsonasik marked this pull request as ready for review April 23, 2024 20:04
@samsonasik
Copy link
Member Author

samsonasik commented Apr 23, 2024

@nuryagdym @TomasVotruba @staabm it finally working again 🎉 🎉 🎉 , here the story:


Long time ago, the children classes detection mostly always working, and mostly just require composer dump-autoload, until on some point release of phpstan, it no longer working, even autoload the classes early,

Turns out, the PHPStan has NewOptimizedDirectorySourceLocator which seems a brand new source locator, which somehow, make the PHPStan ReflectionProvider require to touch it to trigger classes to make it collected.

I tested in my own module: samsonasik/ci4-album#16 and it seems manually apply the code, and it finally working fine.

This PR added back the feature, and the handle in ClassMethodReturnTypeOverrideGuard which detect if child classes override the return type, it will not be allowed, see fixture https://github.com/rectorphp/rector-src/pull/5735/files#diff-d52d2b21cf8f834596c1ab5e7bee4fae94181a109dec119b506d538f8017f8d6

and e2e test for the proof for bin/rector command usage f5f5973

Limitation:

  • Directly pass to single file will only get classes on single file, which expected.
➜  ci4-album git:(rector-0.x) ✗ vendor/bin/rector process src/Domain/Exception/DuplicatedRecordException.php --dry-run --clear-cache
 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
1 file with changes
===================

1) src/Domain/Exception/DuplicatedRecordException.php:12

    ---------- begin diff ----------
@@ @@

 use DomainException;

-class DuplicatedRecordException extends DomainException
+final class DuplicatedRecordException extends DomainException

so the run needs to apply on the parent and child classes contains, eg, both parent and child classes files:

➜  ci4-album git:(rector-0.x) ✗ vendor/bin/rector process src/Domain/Exception/DuplicatedRecordException.php src/Domain/Track/TrackDuplicatedRectorException.php  --dry-run --clear-cache
 2/2 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

                                                                                                                        
 [OK] Rector is done!                                                                                                   
                                                                                                                        

or the directory containst both:

➜  ci4-album git:(rector-0.x) ✗ vendor/bin/rector process src/ --dry-run --clear-cache 
 36/36 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

                                                                                                                        
 [OK] Rector is done!                                                                                                                                                                                                                    

or just without arg:

➜  ci4-album git:(rector-0.x) ✗ vendor/bin/rector
 36/36 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

                                                                                                                        
 [OK] Rector is done!     

If this PR merged, we can un-deprecate FinalizeClassesWithoutChildrenRector and make it works out off the box, in separate PR.

@TomasVotruba TomasVotruba merged commit 9bcded0 into main Apr 25, 2024
43 checks passed
@TomasVotruba TomasVotruba deleted the rework-child-detection branch April 25, 2024 08:20
@TomasVotruba
Copy link
Member

Thank you 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants