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

[TypeDeclaration] Handle fallback from param same type object on ReturnTypeFromReturnNewRector #5039

Merged
merged 11 commits into from
Sep 18, 2023
5 changes: 1 addition & 4 deletions bin/rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,8 @@ public function loadIfExistsAndNotLoadedYet(string $filePath): void
return;
}

/** @var string $realPath always string after file_exists() check */
$realPath = realpath($filePath);
if (! is_string($realPath)) {
return;
}

$this->alreadyLoadedAutoloadFiles[] = $realPath;

require_once $filePath;
Expand Down
1 change: 1 addition & 0 deletions packages/Caching/Detector/ChangedFilesDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public function setFirstResolvedConfigFileInfo(string $filePath): void

private function resolvePath(string $filePath): string
{
/** @var string|false $realPath */
$realPath = realpath($filePath);

if ($realPath === false) {
Expand Down
6 changes: 4 additions & 2 deletions packages/Config/RectorConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,12 @@ private function isRuleNoLongerExists(mixed $skipRule): bool
is_string($skipRule)
// not regex path
&& ! str_contains($skipRule, '*')
// not realpath
&& realpath($skipRule) === false
// a Rector end
&& str_ends_with($skipRule, 'Rector')
// not directory
&& ! is_dir($skipRule)
// not file
&& ! is_file($skipRule)
// class not exists
&& ! class_exists($skipRule);
}
Expand Down
1 change: 1 addition & 0 deletions packages/Skipper/FileSystem/FnMatchPathNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function normalizeForFnmatch(string $path): string
}

if (\str_contains($path, '..')) {
/** @var string|false $path */
$path = realpath($path);
if ($path === false) {
return '';
Expand Down
2 changes: 2 additions & 0 deletions packages/Skipper/RealpathMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ final class RealpathMatcher
{
public function match(string $matchingPath, string $filePath): bool
{
/** @var string|false $realPathMatchingPath */
$realPathMatchingPath = realpath($matchingPath);
if (! is_string($realPathMatchingPath)) {
return false;
}

/** @var string|false $realpathFilePath */
$realpathFilePath = realpath($filePath);
if (! is_string($realpathFilePath)) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture;

use Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Source\SomeResponse;

final class FallbackFromParam
{
public function action(SomeResponse $someResponse)
{
if (rand(0, 1)) {
return new SomeResponse();
}

return $someResponse;
}
}

?>
-----
<?php

declare(strict_types=1);

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture;

use Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Source\SomeResponse;

final class FallbackFromParam
{
public function action(SomeResponse $someResponse): \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Source\SomeResponse
{
if (rand(0, 1)) {
return new SomeResponse();
}

return $someResponse;
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture;

final class FallbackFromParamSelf
{
public function action(self $obj)
{
if (rand(0, 1)) {
return new FallbackFromParamSelf();
}

return $obj;
}
}

?>
-----
<?php

declare(strict_types=1);

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture;

final class FallbackFromParamSelf
{
public function action(self $obj): \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture\FallbackFromParamSelf
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need another test for a static and/or parent typed param?

Copy link
Member Author

Choose a reason for hiding this comment

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

static already error on the first place :)

Copy link
Member Author

Choose a reason for hiding this comment

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

multiple return already skipped at

$returnType = $this->returnTypeInferer->inferFunctionLike($node);
if ($returnType instanceof UnionType) {

{
if (rand(0, 1)) {
return new FallbackFromParamSelf();
}

return $obj;
}
}

?>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Rector\TypeDeclaration\Rector\ClassMethod;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\New_;
Expand Down Expand Up @@ -200,7 +201,17 @@ private function resolveReturnNewType(array $returns): ?array
{
$newTypes = [];
foreach ($returns as $return) {
if (! $return->expr instanceof Expr) {
return null;
}

if (! $return->expr instanceof New_) {
$returnType = $this->nodeTypeResolver->getNativeType($return->expr);
if ($returnType instanceof ObjectType) {
$newTypes[] = $returnType;
continue;
}

return null;
}

Expand Down
1 change: 1 addition & 0 deletions src/Autoloading/BootstrapFilesIncluder.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public function includeBootstrapFiles(): void

private function requireRectorStubs(): void
{
/** @var false|string $stubsRectorDirectory */
$stubsRectorDirectory = realpath(__DIR__ . '/../../stubs-rector');
if ($stubsRectorDirectory === false) {
return;
Expand Down
4 changes: 3 additions & 1 deletion utils/Command/MissingInSetCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ static function (string $rectorClass): bool {
$hasError = true;
$this->symfonyStyle->title('We could not find there rules in configs');

$setRealpath = (string) realpath($setFile);
/** @var string|false $setRealpath */
$setRealpath = realpath($setFile);
$setRealpath = (string) $setRealpath;
$relativeFilePath = Strings::after($setRealpath, getcwd() . '/');
Comment on lines +144 to 147
Copy link
Member

@TomasVotruba TomasVotruba Sep 18, 2023

Choose a reason for hiding this comment

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

This will be always string, as we use existing set paths:

            $setRealpath = realpath($setFile);
            $relativeFilePath = Strings::after($setRealpath, getcwd() . '/');

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Thanks 👏

Copy link
Contributor

Choose a reason for hiding this comment

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

the php process might still not be able to read this file (e.g. because of filesystem persmissions) and return false?

Copy link
Member Author

Choose a reason for hiding this comment

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

@staabm that's what I thought, but since tools/ directory is not shipped to rector/rector, I guess it safe for user, the concern is probably when directory/set removed in the future and not detected.

The better solution is probably use:

Assert::string($setRealpath);

so it will be detected early when path removed/renamed.


$this->symfonyStyle->writeln(' * ' . $relativeFilePath);
Expand Down