mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-31 16:30:51 +00:00
[PHP 7.4] Skip dependency on native ReflectionProperty->getType() (#1409)
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
parent
26cc1817b2
commit
079b20c894
|
@ -9,6 +9,7 @@ use Rector\ChangesReporting\Annotation\RectorsChangelogResolver;
|
|||
use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface;
|
||||
use Rector\Core\ValueObject\Configuration;
|
||||
use Rector\Core\ValueObject\ProcessResult;
|
||||
use Rector\Parallel\ValueObject\Bridge;
|
||||
|
||||
final class JsonOutputFormatter implements OutputFormatterInterface
|
||||
{
|
||||
|
@ -29,7 +30,7 @@ final class JsonOutputFormatter implements OutputFormatterInterface
|
|||
|
||||
public function report(ProcessResult $processResult, Configuration $configuration): void
|
||||
{
|
||||
$errorsArray = [
|
||||
$errorsJson = [
|
||||
'meta' => [
|
||||
'config' => $configuration->getMainConfigFilePath(),
|
||||
],
|
||||
|
@ -47,7 +48,7 @@ final class JsonOutputFormatter implements OutputFormatterInterface
|
|||
|
||||
$appliedRectorsWithChangelog = $this->rectorsChangelogResolver->resolve($fileDiff->getRectorClasses());
|
||||
|
||||
$errorsArray['file_diffs'][] = [
|
||||
$errorsJson[Bridge::FILE_DIFFS][] = [
|
||||
'file' => $relativeFilePath,
|
||||
'diff' => $fileDiff->getDiff(),
|
||||
'applied_rectors' => $fileDiff->getRectorClasses(),
|
||||
|
@ -55,18 +56,18 @@ final class JsonOutputFormatter implements OutputFormatterInterface
|
|||
];
|
||||
|
||||
// for Rector CI
|
||||
$errorsArray['changed_files'][] = $relativeFilePath;
|
||||
$errorsJson['changed_files'][] = $relativeFilePath;
|
||||
}
|
||||
|
||||
$errors = $processResult->getErrors();
|
||||
$errorsArray['totals']['errors'] = count($errors);
|
||||
$errorsJson['totals']['errors'] = count($errors);
|
||||
|
||||
$errorsData = $this->createErrorsData($errors);
|
||||
if ($errorsData !== []) {
|
||||
$errorsArray['errors'] = $errorsData;
|
||||
$errorsJson['errors'] = $errorsData;
|
||||
}
|
||||
|
||||
$json = Json::encode($errorsArray, Json::PRETTY);
|
||||
$json = Json::encode($errorsJson, Json::PRETTY);
|
||||
echo $json . PHP_EOL;
|
||||
}
|
||||
|
||||
|
@ -79,20 +80,20 @@ final class JsonOutputFormatter implements OutputFormatterInterface
|
|||
$errorsData = [];
|
||||
|
||||
foreach ($errors as $error) {
|
||||
$errorData = [
|
||||
$errorDataJson = [
|
||||
'message' => $error->getMessage(),
|
||||
'file' => $error->getRelativeFilePath(),
|
||||
];
|
||||
|
||||
if ($error->getRectorClass()) {
|
||||
$errorData['caused_by'] = $error->getRectorClass();
|
||||
$errorDataJson['caused_by'] = $error->getRectorClass();
|
||||
}
|
||||
|
||||
if ($error->getLine() !== null) {
|
||||
$errorData['line'] = $error->getLine();
|
||||
$errorDataJson['line'] = $error->getLine();
|
||||
}
|
||||
|
||||
$errorsData[] = $errorData;
|
||||
$errorsData[] = $errorDataJson;
|
||||
}
|
||||
|
||||
return $errorsData;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp74\Rector\MethodCall\DowngradeReflectionGetTypeRector\Fixture;
|
||||
|
||||
use ReflectionNamedType;
|
||||
|
||||
final class SkipInstanceOf
|
||||
{
|
||||
public function run(\ReflectionProperty $reflectionProperty)
|
||||
{
|
||||
if ($reflectionProperty->getType() instanceof ReflectionNamedType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
|
|||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
|
||||
$services->set(MethodCallToMethodCallRector::class)
|
||||
->configure([new MethodCallToMethodCall(FirstDependency::class, 'go', SecondDependency::class, 'away')]);
|
||||
};
|
||||
|
|
|
@ -5,9 +5,11 @@ declare(strict_types=1);
|
|||
namespace Rector\DowngradePhp74\Rector\MethodCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Instanceof_;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
|
@ -73,6 +75,11 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parent instanceof Instanceof_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->nodeFactory->createNull();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,9 +95,9 @@ final class TypeProvidingExprFromClassResolver
|
|||
Scope $scope,
|
||||
ObjectType $objectType
|
||||
): ?PropertyFetch {
|
||||
$reflectionClass = $classReflection->getNativeReflection();
|
||||
$nativeReflectionClass = $classReflection->getNativeReflection();
|
||||
|
||||
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
|
||||
foreach ($nativeReflectionClass->getProperties() as $reflectionProperty) {
|
||||
/** @var PhpPropertyReflection $phpPropertyReflection */
|
||||
$phpPropertyReflection = $classReflection->getProperty($reflectionProperty->getName(), $scope);
|
||||
|
||||
|
|
|
@ -78,11 +78,7 @@ class SomeClass
|
|||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
[
|
||||
self::METHOD_CALLS_TO_METHOD_CALLS => [
|
||||
new MethodCallToMethodCall('FirstDependency', 'go', 'SecondDependency', 'away'),
|
||||
],
|
||||
]
|
||||
[new MethodCallToMethodCall('FirstDependency', 'go', 'SecondDependency', 'away')]
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
@ -172,7 +168,7 @@ CODE_SAMPLE
|
|||
return $newPropertyName;
|
||||
}
|
||||
|
||||
// re-use existing proeprty name
|
||||
// re-use existing property name
|
||||
return $this->getName($classContextProperty);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,14 +7,14 @@ namespace Rector\Core\NodeAnalyzer;
|
|||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\Php\PhpPropertyReflection;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use Rector\Core\PhpParser\AstResolver;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\Php80\NodeAnalyzer\PromotedPropertyResolver;
|
||||
use Rector\PostRector\ValueObject\PropertyMetadata;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* Can be local property, parent property etc.
|
||||
|
@ -25,7 +25,7 @@ final class PropertyPresenceChecker
|
|||
private readonly PromotedPropertyResolver $promotedPropertyResolver,
|
||||
private readonly NodeNameResolver $nodeNameResolver,
|
||||
private readonly ReflectionProvider $reflectionProvider,
|
||||
private readonly AstResolver $astResolver
|
||||
private readonly AstResolver $astResolver,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,11 @@ final class PropertyPresenceChecker
|
|||
|
||||
public function getClassContextProperty(Class_ $class, PropertyMetadata $propertyMetadata): Property | Param | null
|
||||
{
|
||||
$className = (string) $this->nodeNameResolver->getName($class);
|
||||
$className = $this->nodeNameResolver->getName($class);
|
||||
if ($className === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->reflectionProvider->hasClass($className)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -50,12 +54,13 @@ final class PropertyPresenceChecker
|
|||
return $property;
|
||||
}
|
||||
|
||||
$property = $this->matchPropertyByParentPublicOrProtectedProperties($className, $propertyMetadata);
|
||||
$property = $this->matchPropertyByParentNonPrivateProperties($className, $propertyMetadata);
|
||||
if ($property instanceof Property || $property instanceof Param) {
|
||||
return $property;
|
||||
}
|
||||
|
||||
$promotedPropertyParams = $this->promotedPropertyResolver->resolveFromClass($class);
|
||||
|
||||
foreach ($promotedPropertyParams as $promotedPropertyParam) {
|
||||
if ($this->nodeNameResolver->isName($promotedPropertyParam, $propertyMetadata->getName())) {
|
||||
return $promotedPropertyParam;
|
||||
|
@ -66,9 +71,9 @@ final class PropertyPresenceChecker
|
|||
}
|
||||
|
||||
/**
|
||||
* @return ReflectionProperty[]
|
||||
* @return PhpPropertyReflection[]
|
||||
*/
|
||||
private function getParentClassPublicAndProtectedPropertyReflections(string $className): array
|
||||
private function getParentClassNonPrivatePropertyReflections(string $className): array
|
||||
{
|
||||
if (! $this->reflectionProvider->hasClass($className)) {
|
||||
return [];
|
||||
|
@ -77,14 +82,13 @@ final class PropertyPresenceChecker
|
|||
$classReflection = $this->reflectionProvider->getClass($className);
|
||||
|
||||
$propertyReflections = [];
|
||||
|
||||
foreach ($classReflection->getParents() as $parentClassReflection) {
|
||||
$nativeReflectionClass = $parentClassReflection->getNativeReflection();
|
||||
$propertyNames = $this->resolveNonPrivatePropertyNames($parentClassReflection);
|
||||
|
||||
$currentPropertyReflections = $nativeReflectionClass->getProperties(
|
||||
ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED
|
||||
);
|
||||
|
||||
$propertyReflections = [...$propertyReflections, ...$currentPropertyReflections];
|
||||
foreach ($propertyNames as $propertyName) {
|
||||
$propertyReflections[] = $parentClassReflection->getNativeProperty($propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
return $propertyReflections;
|
||||
|
@ -92,57 +96,68 @@ final class PropertyPresenceChecker
|
|||
|
||||
private function matchPropertyByType(
|
||||
PropertyMetadata $propertyMetadata,
|
||||
ReflectionProperty $reflectionProperty
|
||||
PhpPropertyReflection $phpPropertyReflection
|
||||
): Property | Param | null {
|
||||
if ($propertyMetadata->getType() === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $reflectionProperty->getType() instanceof ReflectionNamedType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $propertyMetadata->getType() instanceof TypeWithClassName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$propertyObjectType = $propertyMetadata->getType();
|
||||
$propertyObjectTypeClassName = $propertyObjectType->getClassName();
|
||||
|
||||
if ($propertyObjectTypeClassName !== (string) $reflectionProperty->getType()) {
|
||||
if (! $phpPropertyReflection->getWritableType() instanceof TypeWithClassName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$propertyObjectType = $propertyMetadata->getType();
|
||||
$propertyObjectTypeClassName = $propertyObjectType->getClassName();
|
||||
|
||||
if ($propertyObjectTypeClassName !== (string) $reflectionProperty->getType()) {
|
||||
if (! $propertyObjectType->equals($phpPropertyReflection->getWritableType())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->astResolver->resolvePropertyFromPropertyReflection($reflectionProperty);
|
||||
return $this->astResolver->resolvePropertyFromPropertyReflection($phpPropertyReflection);
|
||||
}
|
||||
|
||||
private function matchPropertyByParentPublicOrProtectedProperties(
|
||||
private function matchPropertyByParentNonPrivateProperties(
|
||||
string $className,
|
||||
PropertyMetadata $propertyMetadata
|
||||
PropertyMetadata $propertyMetadata,
|
||||
): Property | Param | null {
|
||||
$availablePropertyReflections = $this->getParentClassPublicAndProtectedPropertyReflections($className);
|
||||
$availablePropertyReflections = $this->getParentClassNonPrivatePropertyReflections($className);
|
||||
|
||||
foreach ($availablePropertyReflections as $availablePropertyReflection) {
|
||||
// 1. match type by priority
|
||||
$property = $this->matchPropertyByType($propertyMetadata, $availablePropertyReflection);
|
||||
|
||||
if ($property instanceof Property || $property instanceof Param) {
|
||||
return $property;
|
||||
}
|
||||
|
||||
$nativePropertyReflection = $availablePropertyReflection->getNativeReflection();
|
||||
|
||||
// 2. match by name
|
||||
if ($availablePropertyReflection->getName() === $propertyMetadata->getName()) {
|
||||
if ($nativePropertyReflection->getName() === $propertyMetadata->getName()) {
|
||||
return $this->astResolver->resolvePropertyFromPropertyReflection($availablePropertyReflection);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveNonPrivatePropertyNames(ClassReflection $classReflection): array
|
||||
{
|
||||
$propertyNames = [];
|
||||
|
||||
$reflectionClass = $classReflection->getNativeReflection();
|
||||
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
|
||||
if ($reflectionProperty->isPrivate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$propertyNames[] = $reflectionProperty->getName();
|
||||
}
|
||||
|
||||
return $propertyNames;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ use PHPStan\Analyser\Scope;
|
|||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\FunctionReflection;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Reflection\Php\PhpPropertyReflection;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
|
@ -31,7 +32,6 @@ use Rector\Core\ValueObject\MethodName;
|
|||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use ReflectionProperty;
|
||||
use Symplify\Astral\PhpParser\SmartPhpParser;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
use Symplify\SmartFileSystem\SmartFileSystem;
|
||||
|
@ -257,12 +257,12 @@ final class AstResolver
|
|||
}
|
||||
|
||||
public function resolvePropertyFromPropertyReflection(
|
||||
ReflectionProperty $reflectionProperty
|
||||
PhpPropertyReflection $phpPropertyReflection
|
||||
): Property | Param | null {
|
||||
$reflectionClass = $reflectionProperty->getDeclaringClass();
|
||||
$classReflection = $phpPropertyReflection->getDeclaringClass();
|
||||
|
||||
$fileName = $reflectionClass->getFileName();
|
||||
if ($fileName === false) {
|
||||
$fileName = $classReflection->getFileName();
|
||||
if ($fileName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -271,7 +271,8 @@ final class AstResolver
|
|||
return null;
|
||||
}
|
||||
|
||||
$desiredPropertyName = $reflectionProperty->name;
|
||||
$nativeReflectionProperty = $phpPropertyReflection->getNativeReflection();
|
||||
$desiredPropertyName = $nativeReflectionProperty->getName();
|
||||
|
||||
/** @var Property[] $properties */
|
||||
$properties = $this->betterNodeFinder->findInstanceOf($nodes, Property::class);
|
||||
|
|
Loading…
Reference in New Issue
Block a user