[Php70] add a rector to pass only variables as arguments by reference#2546
[Php70] add a rector to pass only variables as arguments by reference#2546TomasVotruba merged 1 commit intorectorphp:masterfrom Lctrs:argument_by_reference
Conversation
|
Hi, is this ready for review or do you plan more work first? |
|
I'm planning to handle a few more cases and simplify code a little bit, but main structure/flow is here. |
TomasVotruba
left a comment
There was a problem hiding this comment.
Great job with covergin with test 👍
I've left few mostly readability comments.
Have you use bin/rector create command?
|
Yes I have used the create command. |
|
@TomasVotruba Ready for review. Build failure is unrelated I guess. |
|
@TomasVotruba Finally still WIP. Tried it on a real project. Got errors. |
|
No troubles. Just ping me when you need me |
|
CI should pass completely now. Just fixed the master |
|
@TomasVotruba Any idea what |
|
That happens when you get node, but return an array of nodes. |
|
How/Where can this happen ? I don't return an array in my rector. |
|
There can be like dozens of cases where this can happen. I'd have to see the test case. |
|
@TomasVotruba It was caused by a return statement. When I add something like Otherwise, it's finally ready for review. It worked well in one of my project. I tried to be as extensive as possible on test. |
|
Only the PHAR compilation fails ATM. Will take a look at it. |
|
@TomasVotruba All good 🎉 |
TomasVotruba
left a comment
There was a problem hiding this comment.
Thank you for a great job!
I've added few notes. Mostly about decopuling Reflection from Rector
| } | ||
| } | ||
|
|
||
| private function processArgument(Expr $expr, Scope $scope): VariableAssignPair |
There was a problem hiding this comment.
This looks like VariableAssignPairFactory.
process/refactor method should change nodes in some way
| private function createCountedValueName(?string $valueName, Scope $scope): string | ||
| { | ||
| $countedValueName = $valueName ?? self::DEFAULT_VARIABLE_NAME; | ||
|
|
||
| // make sure variable name is unique | ||
| if (! $scope->hasVariableType($countedValueName)->yes()) { | ||
| return $countedValueName; | ||
| } | ||
|
|
||
| // we need to add number suffix until the variable is unique | ||
| $i = 2; | ||
| $countedValueNamePart = $countedValueName; | ||
| while ($scope->hasVariableType($countedValueName)->yes()) { | ||
| $countedValueName = $countedValueNamePart . $i; | ||
| ++$i; | ||
| } | ||
|
|
||
| return $countedValueName; | ||
| } | ||
| } |
There was a problem hiding this comment.
This would be great if abstracted in AbstractRector, as this logic is used in multiple places now
There was a problem hiding this comment.
@TomasVotruba How would you handle things like suffix ? (ForRepeatedCountToOwnVariableRector uses a suffix)
There was a problem hiding this comment.
What do you mean? Suffix of what?
I'd just move this to protected method to abstract class, so it can be re-used in multiple Rector rules.
|
|
||
| ?> | ||
| ----- | ||
| <?php | ||
|
|
||
| namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture; | ||
|
|
||
| function propertyFetch() | ||
| { | ||
| reset((new \stdClass())->dummy); | ||
| } | ||
|
|
||
| ?> |
There was a problem hiding this comment.
This can be removed, as nothing changes
| public function refactor(Node $node): ?Node | ||
| { | ||
| $scope = $node->getAttribute(AttributeKey::SCOPE); | ||
| if (! $scope instanceof MutatingScope) { |
There was a problem hiding this comment.
Scope is good enough as interface
There was a problem hiding this comment.
Scope doesn't contains the method assignExpression sadly. See (upcoming) explanation below.
There was a problem hiding this comment.
Ah, I see. I'm affraid that this will go in mess like "which one to use when", since instanceof Scope is used everywhere now.
There was a problem hiding this comment.
Will see if I can do something with the ScopeFactory instead.
There was a problem hiding this comment.
But a simple rule could be if you need to mutate scope, go with MutatingScope, otherwise use Scope.
There was a problem hiding this comment.
It might, but classes with more public method than interfaces they implement always create crappy code. It's PHPStan design flaw we cannot cover here I'm affraid.
Let's keep it your way for now, not that important.
There was a problem hiding this comment.
Furthermore, MutatingScope seems to be the only available implementation of Scope.
| $this->addNodeBeforeNode($replacements->assign(), $current instanceof Return_ ? $current : $node); | ||
| $node->args[$key]->value = $replacements->variable(); | ||
|
|
||
| $scope = $scope->assignExpression($replacements->variable(), $scope->getType($replacements->variable())); |
There was a problem hiding this comment.
I never used this before. What is it for? When should we use it?
There was a problem hiding this comment.
It returns a new Scope from the previous Scope + the assigned expression (for example, if you pass a variable to it, the new scope will be aware of this variable).
I did this so that Scope is aware of newly created variables, so that createCountedValueName() returns a truly unique variable name.
There was a problem hiding this comment.
I see, thanks!
Maybe it would be more consistent to add type here:
/** @var MutatingScope $scope */
$scope = $scope->assignExpression($replacements->variable(), $scope->getType($replacements->variable()));There was a problem hiding this comment.
assignExpression() always returns a MutatingScope. No need to add a phpDoc IMHO.
There was a problem hiding this comment.
I meant it to have instanceof Scope above and here make the annotation for variable on the right:
/** @var MutatingScope $scope */
$whatever = **$scope**->assignExpression(...);|
@TomasVotruba New version with most of your comments adressed. Only things missing is extracting |
|
@TomasVotruba Should be good. |
|
@TomasVotruba FYI, I have a working version locally that uses the core reflection API (well, and also |
|
All rigth. Maybe look at PHPStan static reflection there is since 0.12.4 Ping me when ready for review |
|
Should I understand that you prefer to use the Reflection API from PHPStan ? |
|
Some of these commits: https://github.com/phpstan/phpstan-src/search?q=static+reflection&type=Commits |
|
Yeah but if we use a reflection provider from PHPStan, we'll get objects implementing the reflection API from PHPStan, not from the core. Or maybe I'm missing something ? |
|
It's just for inspiration, I don't personally use it |
|
@TomasVotruba WDYT ? Yeah I know that |
That would disable I think we should first finish the rule, then add more dependencies. This PR is already mixing many various problems. One step at a time. |
|
Okay, I reverted my last commit for now, I think I covered all your remarks. Maybe I'm missing something ? |
|
I'm looking at it |
|
All looks good! It's like reading a well written story. Thanks for this aweseome feature. I think you're the most skilled first contritbutor Rector ever had 🙇♂️ |
rectorphp/rector-src@dd4064e cleanup php-version bound tests, now under one version no need to separate (#2546)
Still WIP.
Creating it to gather first reviews.