Skip to content

Commit

Permalink
[PHP 8.0] Skip union types docs to code with soft vendor lock (#781)
Browse files Browse the repository at this point in the history
* add test case to skip contracts

* [PHP 8.0] Skip union types docs to code with soft vendor lock
  • Loading branch information
TomasVotruba committed Aug 27, 2021
1 parent d8b3be9 commit 130b634
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 25 deletions.
Expand Up @@ -21,6 +21,25 @@ public function __construct(
) {
}

/**
* Includes non-vendor classes
*/
public function isSoftLocked(ClassMethod $classMethod): bool
{
if ($this->isVendorLocked($classMethod)) {
return true;
}

$classReflection = $this->resolveClassReflection($classMethod);
if (! $classReflection instanceof ClassReflection) {
return false;
}

/** @var string $methodName */
$methodName = $this->nodeNameResolver->getName($classMethod);
return $this->hasClassMethodLockMatchingFileName($classReflection, $methodName, '');
}

public function isVendorLocked(ClassMethod $classMethod): bool
{
if ($classMethod->isMagic()) {
Expand All @@ -34,7 +53,6 @@ public function isVendorLocked(ClassMethod $classMethod): bool

/** @var string $methodName */
$methodName = $this->nodeNameResolver->getName($classMethod);

if ($this->hasTraitMethodVendorLock($classReflection, $methodName)) {
return true;
}
Expand All @@ -44,30 +62,10 @@ public function isVendorLocked(ClassMethod $classMethod): bool
return true;
}

/** @var string $methodName */
$methodName = $this->nodeNameResolver->getName($classMethod);
foreach ($classReflection->getAncestors() as $ancestorClassReflection) {
// skip self
if ($ancestorClassReflection === $classReflection) {
continue;
}

// parent type
if (! $ancestorClassReflection->hasNativeMethod($methodName)) {
continue;
}

// is file in vendor?
$fileName = $ancestorClassReflection->getFileName();
// probably internal class
if ($fileName === false) {
continue;
}

$normalizedFileName = $this->pathNormalizer->normalizePath($fileName, '/');
return str_contains($normalizedFileName, '/vendor/');
}

return false;
return $this->hasClassMethodLockMatchingFileName($classReflection, $methodName, '/vendor/');
}

private function hasTraitMethodVendorLock(ClassReflection $classReflection, string $methodName): bool
Expand Down Expand Up @@ -111,4 +109,41 @@ private function hasParentInterfaceMethod(ClassReflection $classReflection, stri

return false;
}

private function hasClassMethodLockMatchingFileName(
ClassReflection $classReflection,
string $methodName,
string $filePathPartName
): bool {
foreach ($classReflection->getAncestors() as $ancestorClassReflection) {
// skip self
if ($ancestorClassReflection === $classReflection) {
continue;
}

// parent type
if (! $ancestorClassReflection->hasNativeMethod($methodName)) {
continue;
}

// is file in vendor?
$fileName = $ancestorClassReflection->getFileName();
// probably internal class
if ($fileName === false) {
continue;
}

// not conditions? its a match
if ($filePathPartName === '') {
return true;
}

$normalizedFileName = $this->pathNormalizer->normalizePath($fileName, '/');
if (str_contains($normalizedFileName, $filePathPartName)) {
return true;
}
}

return false;
}
}
@@ -0,0 +1,15 @@
<?php

namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;

use Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Source\SomeContract;

final class SkipParentContract implements SomeContract
{
/**
* @param int|string $param
*/
public function run($param)
{
}
}
@@ -0,0 +1,15 @@
<?php

namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;

use Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Source\SomeContractClass;

final class SkipParentContractClass extends SomeContractClass
{
/**
* @param int|string $param
*/
public function run($param)
{
}
}
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Source;

interface SomeContract
{
public function run($param);
}
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Source;

abstract class SomeContractClass
{
public function run($param)
{
}
}
20 changes: 18 additions & 2 deletions rules/Php80/Rector/FunctionLike/UnionTypesRector.php
Expand Up @@ -33,6 +33,8 @@
*/
final class UnionTypesRector extends AbstractRector implements MinPhpVersionInterface
{
private bool $hasChanged = false;

public function __construct(
private ReturnTagRemover $returnTagRemover,
private ParamTagRemover $paramTagRemover,
Expand Down Expand Up @@ -87,6 +89,8 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?Node
{
$this->hasChanged = false;

$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);

$this->refactorParamTypes($node, $phpDocInfo);
Expand All @@ -95,7 +99,15 @@ public function refactor(Node $node): ?Node
$this->paramTagRemover->removeParamTagsIfUseless($phpDocInfo, $node);
$this->returnTagRemover->removeReturnTagIfUseless($phpDocInfo, $node);

return $node;
if ($phpDocInfo->hasChanged()) {
$this->hasChanged = true;
}

if ($this->hasChanged) {
return $node;
}

return null;
}

public function provideMinPhpVersion(): int
Expand All @@ -107,7 +119,8 @@ private function refactorParamTypes(
ClassMethod | Function_ | Closure | ArrowFunction $functionLike,
PhpDocInfo $phpDocInfo
): void {
if ($functionLike instanceof ClassMethod && $this->classMethodParamVendorLockResolver->isVendorLocked(
// skip parent class lock too, just to be safe in case of different parent docs
if ($functionLike instanceof ClassMethod && $this->classMethodParamVendorLockResolver->isSoftLocked(
$functionLike
)) {
return;
Expand Down Expand Up @@ -145,6 +158,7 @@ private function refactorParamTypes(
}

$param->type = $phpParserUnionType;
$this->hasChanged = true;
}
}

Expand All @@ -155,6 +169,7 @@ private function changeObjectWithoutClassType(Param $param, UnionType $unionType
}

$param->type = new Name('object');
$this->hasChanged = true;
}

private function refactorReturnType(
Expand Down Expand Up @@ -186,6 +201,7 @@ private function refactorReturnType(
}

$functionLike->returnType = $phpParserUnionType;
$this->hasChanged = true;
}

private function filterOutDuplicatedArrayTypes(UnionType $unionType): UnionType | Type
Expand Down
Expand Up @@ -34,6 +34,8 @@
*/
final class ParamTypeDeclarationRector extends AbstractRector implements MinPhpVersionInterface
{
private bool $hasChanged = false;

public function __construct(
private VendorLockResolver $vendorLockResolver,
private ParamTypeInferer $paramTypeInferer,
Expand Down Expand Up @@ -121,6 +123,8 @@ public function change(int $number)
*/
public function refactor(Node $node): ?Node
{
$this->hasChanged = false;

if ($node->params === []) {
return null;
}
Expand All @@ -129,6 +133,10 @@ public function refactor(Node $node): ?Node
$this->refactorParam($param, $node);
}

if ($this->hasChanged) {
return $node;
}

return null;
}

Expand Down Expand Up @@ -170,6 +178,8 @@ private function refactorParam(Param $param, ClassMethod | Function_ $functionLi

$functionLikePhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($functionLike);
$this->paramTagRemover->removeParamTagsIfUseless($functionLikePhpDocInfo, $functionLike);

$this->hasChanged = true;
}

private function shouldSkipParam(Param $param, ClassMethod | Function_ $functionLike): bool
Expand Down

0 comments on commit 130b634

Please sign in to comment.