Skip to content

Commit

Permalink
feat: remove more instaceof checks (#1571)
Browse files Browse the repository at this point in the history
  • Loading branch information
canvural committed Mar 4, 2023
1 parent 9a3c2d0 commit 206d6f8
Show file tree
Hide file tree
Showing 52 changed files with 544 additions and 376 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"illuminate/pipeline": "^9.47.0 || ^10.0.0",
"illuminate/support": "^9.47.0 || ^10.0.0",
"phpmyadmin/sql-parser": "^5.6.0",
"phpstan/phpstan": "^1.9.8"
"phpstan/phpstan": "~1.10.3"
},
"require-dev": {
"nikic/php-parser": "^4.15.2",
Expand Down
5 changes: 5 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ parameters:
count: 1
path: src/ReturnTypes/CollectionGenericStaticMethodDynamicMethodReturnTypeExtension.php

-
message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericObjectType is error\\-prone and deprecated\\.$#"
count: 2
path: src/Rules/ModelRuleHelper.php

63 changes: 23 additions & 40 deletions src/Methods/BuilderHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace NunoMaduro\Larastan\Methods;

use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Support\Str;
use NunoMaduro\Larastan\Reflection\AnnotationScopeMethodParameterReflection;
Expand All @@ -22,7 +21,6 @@
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\VerbosityLevel;

class BuilderHelper
Expand Down Expand Up @@ -71,35 +69,33 @@ public function dynamicWhere(
return null;
}

if ($returnObject instanceof GenericObjectType && $this->checkProperties) {
$returnClassReflection = $returnObject->getClassReflection();
if (count($returnObject->getObjectClassReflections()) > 0 && $this->checkProperties) {
$returnClassReflection = $returnObject->getObjectClassReflections()[0];

if ($returnClassReflection !== null) {
$modelType = $returnClassReflection->getActiveTemplateTypeMap()->getType('TModelClass');
$modelType = $returnClassReflection->getActiveTemplateTypeMap()->getType('TModelClass');

if ($modelType === null) {
$modelType = $returnClassReflection->getActiveTemplateTypeMap()->getType('TRelatedModel');
}
if ($modelType === null) {
$modelType = $returnClassReflection->getActiveTemplateTypeMap()->getType('TRelatedModel');
}

if ($modelType !== null) {
$finder = substr($methodName, 5);
if ($modelType !== null) {
$finder = substr($methodName, 5);

$segments = preg_split(
'/(And|Or)(?=[A-Z])/', $finder, -1, PREG_SPLIT_DELIM_CAPTURE
);
$segments = preg_split(
'/(And|Or)(?=[A-Z])/', $finder, -1, PREG_SPLIT_DELIM_CAPTURE
);

if ($segments !== false) {
$trinaryLogic = TrinaryLogic::createYes();
if ($segments !== false) {
$trinaryLogic = TrinaryLogic::createYes();

foreach ($segments as $segment) {
if ($segment !== 'And' && $segment !== 'Or') {
$trinaryLogic = $trinaryLogic->and($modelType->hasProperty(Str::snake($segment)));
}
foreach ($segments as $segment) {
if ($segment !== 'And' && $segment !== 'Or') {
$trinaryLogic = $trinaryLogic->and($modelType->hasProperty(Str::snake($segment)));
}
}

if (! $trinaryLogic->yes()) {
return null;
}
if (! $trinaryLogic->yes()) {
return null;
}
}
}
Expand Down Expand Up @@ -212,25 +208,12 @@ public function determineBuilderName(string $modelClassName): string
return EloquentBuilder::class;
}

if ($returnType instanceof TypeWithClassName) {
return $returnType->getClassName();
$classNames = $returnType->getObjectClassNames();

if (count($classNames) === 1) {
return $classNames[0];
}

return $returnType->describe(VerbosityLevel::value());
}

public function determineCollectionClassName(string $modelClassName): string
{
try {
$newCollectionMethod = $this->reflectionProvider->getClass($modelClassName)->getNativeMethod('newCollection');
$returnType = ParametersAcceptorSelector::selectSingle($newCollectionMethod->getVariants())->getReturnType();
if ($returnType instanceof TypeWithClassName) {
return $returnType->getClassName();
}

return $returnType->describe(VerbosityLevel::value());
} catch (MissingMethodFromReflectionException|ShouldNotHappenException $e) {
return Collection::class;
}
}
}
13 changes: 3 additions & 10 deletions src/Methods/EloquentBuilderForwardsCallsExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateMixedType;
use PHPStan\Type\Generic\TemplateObjectType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;

final class EloquentBuilderForwardsCallsExtension implements MethodsClassReflectionExtension
{
Expand Down Expand Up @@ -76,7 +74,6 @@ private function findMethod(ClassReflection $classReflection, string $methodName
return null;
}

/** @var Type|TemplateMixedType|null $modelType */
$modelType = $classReflection->getActiveTemplateTypeMap()->getType('TModelClass');

// Generic type is not specified
Expand All @@ -88,23 +85,19 @@ private function findMethod(ClassReflection $classReflection, string $methodName
$modelType = $modelType->getBound();
}

if ($modelType instanceof TypeWithClassName) {
$modelReflection = $modelType->getClassReflection();
if ($modelType->getObjectClassReflections() !== []) {
$modelReflection = $modelType->getObjectClassReflections()[0];
} else {
$modelReflection = $this->reflectionProvider->getClass(Model::class);
}

if ($modelReflection === null) {
return null;
}

$ref = $this->builderHelper->searchOnEloquentBuilder($classReflection, $methodName, $modelReflection);

if ($ref === null) {
// Special case for `SoftDeletes` trait
if (
in_array($methodName, ['withTrashed', 'onlyTrashed', 'withoutTrashed', 'restore'], true) &&
in_array(SoftDeletes::class, array_keys($modelReflection->getTraits(true)))
array_key_exists(SoftDeletes::class, $modelReflection->getTraits(true))
) {
$ref = $this->reflectionProvider->getClass(SoftDeletes::class)->getMethod($methodName, new OutOfClassScope());

Expand Down
12 changes: 2 additions & 10 deletions src/Methods/HigherOrderTapProxyExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\MethodsClassReflectionExtension;
use PHPStan\Type\ObjectType;
use PHPStan\Type\TypeWithClassName;

final class HigherOrderTapProxyExtension implements MethodsClassReflectionExtension
{
Expand All @@ -24,11 +22,7 @@ public function hasMethod(ClassReflection $classReflection, string $methodName):

$templateType = $templateTypeMap->getType('TClass');

if (! $templateType instanceof TypeWithClassName) {
return false;
}

if ($templateType->getClassReflection() === null) {
if ($templateType === null || $templateType->getObjectClassReflections() === []) {
return false;
}

Expand All @@ -39,11 +33,9 @@ public function getMethod(
ClassReflection $classReflection,
string $methodName
): MethodReflection {
/** @var ObjectType $templateType */
$templateType = $classReflection->getActiveTemplateTypeMap()->getType('TClass');

/** @var ClassReflection $reflection */
$reflection = $templateType->getClassReflection();
$reflection = $templateType->getObjectClassReflections()[0]; // @phpstan-ignore-line

return $reflection->getMethod($methodName, new OutOfClassScope());
}
Expand Down
11 changes: 2 additions & 9 deletions src/Methods/RelationForwardsCallsExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateMixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;

final class RelationForwardsCallsExtension implements MethodsClassReflectionExtension
{
Expand Down Expand Up @@ -77,23 +75,18 @@ private function findMethod(ClassReflection $classReflection, string $methodName
return null;
}

/** @var Type|TemplateMixedType|null $relatedModel */
$relatedModel = $classReflection->getActiveTemplateTypeMap()->getType('TRelatedModel');

if ($relatedModel === null) {
return null;
}

if ($relatedModel instanceof TypeWithClassName) {
$modelReflection = $relatedModel->getClassReflection();
if ($relatedModel->getObjectClassReflections() !== []) {
$modelReflection = $relatedModel->getObjectClassReflections()[0];
} else {
$modelReflection = $this->reflectionProvider->getClass(Model::class);
}

if ($modelReflection === null) {
return null;
}

$builderName = $this->builderHelper->determineBuilderName($modelReflection->getName());

$builderReflection = $this->reflectionProvider->getClass($builderName)->withTypes([$relatedModel]);
Expand Down
11 changes: 9 additions & 2 deletions src/Properties/HigherOrderCollectionProxyPropertyExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace NunoMaduro\Larastan\Properties;

use Illuminate\Database\Eloquent\Collection;
use NunoMaduro\Larastan\Support\HigherOrderCollectionProxyHelper;
use PHPStan\Analyser\OutOfClassScope;
use PHPStan\Reflection\ClassReflection;
Expand Down Expand Up @@ -31,12 +32,18 @@ public function getProperty(
/** @var Type\ObjectType $modelType */
$modelType = $activeTemplateTypeMap->getType('TValue');

/** @var Type\ObjectType $collectionType */
/** @var Type\Type $collectionType */
$collectionType = $activeTemplateTypeMap->getType('TCollection');

$propertyType = $modelType->getProperty($propertyName, new OutOfClassScope())->getReadableType();

$returnType = HigherOrderCollectionProxyHelper::determineReturnType($methodType->getValue(), $modelType, $propertyType, $collectionType->getClassName());
if ($collectionType->getObjectClassNames() !== []) {
$collectionClassName = $collectionType->getObjectClassNames()[0];
} else {
$collectionClassName = Collection::class;
}

$returnType = HigherOrderCollectionProxyHelper::determineReturnType($methodType->getValue(), $modelType, $propertyType, $collectionClassName);

return new class($classReflection, $returnType) implements PropertyReflection
{
Expand Down
6 changes: 3 additions & 3 deletions src/Properties/ModelAccessorExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use PHPStan\Reflection\PropertiesClassReflectionExtension;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\MixedType;

/**
* @internal
Expand All @@ -36,11 +36,11 @@ public function hasProperty(ClassReflection $classReflection, string $propertyNa

$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();

if (! $returnType instanceof GenericObjectType) {
if ($returnType->getObjectClassReflections() === [] || ! $returnType->getObjectClassReflections()[0]->isGeneric()) {
return false;
}

if (! (new ObjectType(Attribute::class))->isSuperTypeOf($returnType)->yes()) {
if (! (new GenericObjectType(Attribute::class, [new MixedType(), new MixedType()]))->isSuperTypeOf($returnType)->yes()) {
return false;
}

Expand Down
9 changes: 4 additions & 5 deletions src/Properties/ModelCastHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeWithClassName;

class ModelCastHelper
{
Expand Down Expand Up @@ -69,8 +68,8 @@ public function getReadableType(string $cast, Type $originalType): Type
$methodReflection = $classReflection->getNativeMethod('castUsing');
$castUsingReturn = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();

if ($castUsingReturn instanceof ObjectType && $castReflection = $castUsingReturn->getClassReflection()) {
$classReflection = $castReflection;
if ($castUsingReturn->getObjectClassReflections() !== []) {
$classReflection = $castUsingReturn->getObjectClassReflections()[0];
}
}

Expand Down Expand Up @@ -126,8 +125,8 @@ public function getWriteableType(string $cast, Type $originalType): Type
$methodReflection = $classReflection->getNativeMethod('castUsing');
$castUsingReturn = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();

if ($castUsingReturn instanceof TypeWithClassName && $castReflection = $castUsingReturn->getClassReflection()) {
$classReflection = $castReflection;
if ($castUsingReturn->getObjectClassReflections() !== []) {
$classReflection = $castUsingReturn->getObjectClassReflections()[0];
}
}

Expand Down
Loading

0 comments on commit 206d6f8

Please sign in to comment.