diff --git a/.github/workflows/composer.yml b/.github/workflows/composer.yml index 0e83b596..eb73a30c 100644 --- a/.github/workflows/composer.yml +++ b/.github/workflows/composer.yml @@ -13,10 +13,10 @@ jobs: fail-fast: false matrix: php: [ '8.0', '8.1', '8.2' ] - outdated-args: [ '--ignore=phpunit/phpunit --ignore=phpstan/phpstan-nette' ] + outdated-args: [ '--ignore=phpunit/phpunit' ] include: - php: '7.4' - outdated-args: '--ignore=nette/finder --ignore=phpunit/phpunit --ignore=phpstan/phpstan-nette' + outdated-args: '--ignore=nette/finder --ignore=phpunit/phpunit' name: Composer outdated - PHP ${{ matrix.php }} diff --git a/composer.json b/composer.json index b88afbe5..ce40b9ba 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "require": { "php": ">=7.4 <8.3", "ext-json": "*", - "phpstan/phpstan": "^1.10.6", + "phpstan/phpstan": "^1.10.21", "phpstan/phpstan-nette": "^1.2.6", "latte/latte": "^2.11.6 | ^3.0.4", "nette/utils": "^3.2|^4.0", diff --git a/phpstan.neon b/phpstan.neon index ecb586be..47420d46 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,6 +1,7 @@ includes: - vendor/phpstan/phpstan-strict-rules/rules.neon - vendor/spaze/phpstan-disallowed-calls/extension.neon + - vendor/phpstan/phpstan/conf/bleedingEdge.neon parameters: checkUninitializedProperties: true @@ -45,7 +46,9 @@ parameters: ignoreErrors: - - message: '#^Calling PHPStan\\DependencyInjection\\DerivativeContainerFactory\:\:create\(\) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version\.$#' + messages: + - '#^Calling PHPStan\\DependencyInjection\\DerivativeContainerFactory\:\:create\(\) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version\.$#' + - '#^Accessing PHPStan\\Analyser\\FileAnalyser::class is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' path: src/Analyser/FileAnalyserFactory.php - message: '#^Calling PHPStan\\File\\FileExcluder::isExcludedFromAnalysing\(\) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version\.$#' @@ -58,7 +61,10 @@ parameters: - '#^Creating new PHPStan\\Collectors\\Registry is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' path: src/Rule/LatteTemplatesRule.php - - message: '#^Calling PHPStan\\File\\SimpleRelativePathHelper\:\:getRelativePath\(\) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version\.$#' + messages: + - '#^Calling PHPStan\\File\\SimpleRelativePathHelper\:\:getRelativePath\(\) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version\.$#' + - '#^Accessing PHPStan\\Command\\AnalyseCommand::DEFAULT_LEVEL is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + - '#^Accessing PHPStan\\Command\\AnalyseCommand::OPTION_LEVEL is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' path: src/Error/TableErrorFormatter.php - @@ -132,3 +138,38 @@ parameters: message: '#^Method Latte\\CompileException\:\:setSource\(\) invoked with 3 parameters, 1-2 required\.$#' path: src/Compiler/Compiler/Latte2Compiler.php reportUnmatched: false + + # is covered by backward compatibility promise + - + messages: + - '#^Although PHPStan\\Node\\InClassNode is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#' + - '#^Although PHPStan\\Node\\ClassMethod is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#' + + - + messages: + -'#^Although PHPStan\\Rules\\MetadataRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#' + -'#^Although PHPStan\\Rules\\FileRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#' + -'#^Although PHPStan\\Rules\\LineRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#' + -'#^Although PHPStan\\Rules\\TipRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#' + -'#^Although PHPStan\\Rules\\IdentifierRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#' + -'#^Although PHPStan\\Rules\\NonIgnorableRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#' + path: src/Error/ErrorBuilder.php + + # to be done later, no idea how to fix it now + - + message: '#^Method Efabrica\\PHPStanLatte\\Collector\\Collector\\AbstractCollector::collectItems\(\) should return array\\|null but returns array\\>\.$#' + path: src/Collector/Collector/AbstractCollector.php + - + messages: + - '#^Doing instanceof PHPStan\\Type\\ObjectType is error-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + - '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error-prone and deprecated\.$#' + path: src/LatteContext/Collector/ComponentCollector.php + - + message: '#^Parameter \#1 \$object of function get_class expects object, mixed given\.$#' + paths: + - src/Compiler/NodeVisitor/ChangeFiltersNodeVisitor.php + - src/Compiler/NodeVisitor/ChangeFunctionsNodeVisitor.php + - + # present only in nette/utils 4 + message: '#^PHPDoc tag @var with type SplFileInfo is not subtype of native type Nette\\Utils\\FileInfo\.$#' + reportUnmatched: false diff --git a/src/Analyser/LatteContextData.php b/src/Analyser/LatteContextData.php index 7d049f0f..7233f354 100644 --- a/src/Analyser/LatteContextData.php +++ b/src/Analyser/LatteContextData.php @@ -11,19 +11,13 @@ class LatteContextData { - /** - * @var array - */ + /** @var array */ private array $errors; - /** - * @var array - */ + /** @var array */ private array $collectedData = []; - /** - * @var array - */ + /** @var array */ private array $collectedDataByType = []; /** diff --git a/src/Collector/Finder/ResolvedNodeFinder.php b/src/Collector/Finder/ResolvedNodeFinder.php index 49e8c7df..2e8bdf92 100644 --- a/src/Collector/Finder/ResolvedNodeFinder.php +++ b/src/Collector/Finder/ResolvedNodeFinder.php @@ -15,14 +15,10 @@ */ final class ResolvedNodeFinder { - /** - * @var array - */ + /** @var array */ private array $collectedResolvedNodes = []; - /** - * @var array - */ + /** @var array */ private array $analysedFiles = []; /** diff --git a/src/Compiler/NodeVisitor/AddExtractParamsToTopNodeVisitor.php b/src/Compiler/NodeVisitor/AddExtractParamsToTopNodeVisitor.php index 7cadfc3d..5727ef89 100644 --- a/src/Compiler/NodeVisitor/AddExtractParamsToTopNodeVisitor.php +++ b/src/Compiler/NodeVisitor/AddExtractParamsToTopNodeVisitor.php @@ -33,11 +33,7 @@ public function enterNode(Node $node): ?Node } $type = $this->getType($class); - if (!$type instanceof ObjectType) { - return null; - } - - if (!$type->isInstanceOf('\Latte\Runtime\Template')->yes()) { + if ($type === null || !(new ObjectType('\Latte\Runtime\Template'))->isSuperTypeOf($type)->yes()) { return null; } diff --git a/src/Compiler/NodeVisitor/AddFormClassesNodeVisitor.php b/src/Compiler/NodeVisitor/AddFormClassesNodeVisitor.php index b531b782..188fe9c1 100644 --- a/src/Compiler/NodeVisitor/AddFormClassesNodeVisitor.php +++ b/src/Compiler/NodeVisitor/AddFormClassesNodeVisitor.php @@ -193,7 +193,7 @@ public function enterNode(Node $node): ?Node } $formControlType = $formControl->getType(); - if ($formControlType instanceof ObjectType && ($formControlType->isInstanceOf('Nette\Forms\Controls\CheckboxList')->yes() || $formControlType->isInstanceOf('Nette\Forms\Controls\RadioList')->yes())) { + if ((new ObjectType('Nette\Forms\Controls\CheckboxList'))->isSuperTypeOf($formControlType)->yes() || (new ObjectType('Nette\Forms\Controls\RadioList'))->isSuperTypeOf($formControlType)->yes()) { $this->possibleAlwaysTrueLabels[] = $this->findParentStmt($node); } } elseif ($node->dim instanceof Variable) { diff --git a/src/Compiler/NodeVisitor/ChangeFiltersNodeVisitor.php b/src/Compiler/NodeVisitor/ChangeFiltersNodeVisitor.php index b0d152d0..db5ab781 100644 --- a/src/Compiler/NodeVisitor/ChangeFiltersNodeVisitor.php +++ b/src/Compiler/NodeVisitor/ChangeFiltersNodeVisitor.php @@ -136,11 +136,7 @@ private function addFilterVariables(ClassMethod $node): void } $type = $this->getType($class); - if (!$type instanceof ObjectType) { - return; - } - - if (!$type->isInstanceOf('\Latte\Runtime\Template')->yes()) { + if ($type === null || !(new ObjectType('\Latte\Runtime\Template'))->isSuperTypeOf($type)->yes()) { return; } diff --git a/src/Compiler/NodeVisitor/NotNullableSnippetDriverNodeVisitor.php b/src/Compiler/NodeVisitor/NotNullableSnippetDriverNodeVisitor.php index c912041a..e6f7220b 100644 --- a/src/Compiler/NodeVisitor/NotNullableSnippetDriverNodeVisitor.php +++ b/src/Compiler/NodeVisitor/NotNullableSnippetDriverNodeVisitor.php @@ -23,7 +23,7 @@ public function enterNode(Node $node): ?Node } $callerType = $this->getType($node->var); - if ($callerType instanceof ObjectType && $callerType->isInstanceOf('Nette\Bridges\ApplicationLatte\SnippetDriver')->yes()) { + if ($callerType !== null && (new ObjectType('Nette\Bridges\ApplicationLatte\SnippetDriver'))->isSuperTypeOf($callerType)->yes()) { $methodCall = new MethodCall($node->var, $node->name, $node->args); $methodCall->setAttributes($node->getAttributes()); return $methodCall; diff --git a/src/LatteContext/CollectedData/CollectedMethodCall.php b/src/LatteContext/CollectedData/CollectedMethodCall.php index 8e4beb78..46fb60cf 100644 --- a/src/LatteContext/CollectedData/CollectedMethodCall.php +++ b/src/LatteContext/CollectedData/CollectedMethodCall.php @@ -15,9 +15,7 @@ final class CollectedMethodCall extends CollectedLatteContextObject public const TERMINATING_CALL = 'terminating'; public const OUTPUT_CALL = 'output'; - /** - * @var ?class-string - */ + /** @var ?class-string */ private ?string $callerClassName; private string $callerMethodName; @@ -33,9 +31,7 @@ final class CollectedMethodCall extends CollectedLatteContextObject /** @var array */ private array $params; - /** - * @var ?class-string - */ + /** @var ?class-string */ private ?string $currentClassName; /** diff --git a/src/LatteContext/Collector/ComponentCollector.php b/src/LatteContext/Collector/ComponentCollector.php index 9c629ff1..a54db4a2 100644 --- a/src/LatteContext/Collector/ComponentCollector.php +++ b/src/LatteContext/Collector/ComponentCollector.php @@ -177,12 +177,12 @@ private function buildComponents(Node $node, Scope $scope, ClassReflection $clas $names = $this->valueResolver->resolveStrings($componentNameArg, $scope) ?? []; $componentType = null; - if ($componentArgType instanceof ObjectType && $componentArgType->isInstanceOf('Nette\ComponentModel\IComponent')->yes()) { + if ((new ObjectType('Nette\ComponentModel\IComponent'))->isSuperTypeOf($componentArgType)->yes()) { $componentType = $componentArgType; } elseif ($componentArgType instanceof UnionType) { $componentTypes = []; foreach ($componentArgType->getTypes() as $type) { - if ($type instanceof ObjectType && $type->isInstanceOf('Nette\ComponentModel\IComponent')->yes()) { + if ((new ObjectType('Nette\ComponentModel\IComponent'))->isSuperTypeOf($type)->yes()) { $componentTypes[] = $type; } } diff --git a/src/LatteContext/Collector/FormCollector.php b/src/LatteContext/Collector/FormCollector.php index 05f728dc..a27c13f0 100644 --- a/src/LatteContext/Collector/FormCollector.php +++ b/src/LatteContext/Collector/FormCollector.php @@ -69,11 +69,7 @@ private function findCreateComponent(ClassMethod $node, ClassReflection $classRe } $returnType = $parametersAcceptor->getReturnType(); - if (!$returnType instanceof ObjectType) { - return null; - } - - if (!$returnType->isInstanceOf('Nette\Forms\Form')->yes()) { + if (!(new ObjectType('Nette\Forms\Form'))->isSuperTypeOf($returnType)->yes()) { return null; } diff --git a/src/LatteContext/Collector/FormControlCollector.php b/src/LatteContext/Collector/FormControlCollector.php index 2ff580f8..8d7846a7 100644 --- a/src/LatteContext/Collector/FormControlCollector.php +++ b/src/LatteContext/Collector/FormControlCollector.php @@ -14,7 +14,6 @@ use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ReflectionProvider; -use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ObjectType; /** @@ -63,12 +62,7 @@ public function collectData(Node $node, Scope $scope): ?array } $formType = $scope->getType($node->var); - - if (!$formType instanceof ObjectType) { - return null; - } - - if (!$formType->isInstanceOf('Nette\Forms\Container')->yes()) { + if (!(new ObjectType('Nette\Forms\Container'))->isSuperTypeOf($formType)->yes()) { return null; } @@ -91,8 +85,12 @@ public function collectData(Node $node, Scope $scope): ?array $controlNameArg = $node->getArgs()[1] ?? null; $controlNameDefault = null; } else { + $objectClassNames = $formType->getObjectClassNames(); + if ($objectClassNames === []) { + return null; + } // other form methods - $formClassReflection = $this->reflectionProvider->getClass($formType->getClassName()); + $formClassReflection = $this->reflectionProvider->getClass($objectClassNames[0]); if (!$formClassReflection->hasMethod($formMethodName)) { return null; } @@ -109,8 +107,9 @@ public function collectData(Node $node, Scope $scope): ?array $formControlParameters = $formControlParametersAcceptor->getParameters(); $controlNameDefaultType = isset($formControlParameters[0]) ? $formControlParameters[0]->getDefaultValue() : null; - if ($controlNameDefaultType instanceof ConstantStringType) { - $controlNameDefault = trim($controlNameDefaultType->getValue(), '"\''); + $constantStringTypes = $controlNameDefaultType !== null ? $controlNameDefaultType->getConstantStrings() : []; + if ($constantStringTypes !== []) { + $controlNameDefault = trim($constantStringTypes[0]->getValue(), '"\''); } else { $controlNameDefault = null; } diff --git a/src/LatteContext/Collector/VariableCollector/AssignToArrayOfTemplateVariablesCollector.php b/src/LatteContext/Collector/VariableCollector/AssignToArrayOfTemplateVariablesCollector.php index a45307f1..a2bf292f 100644 --- a/src/LatteContext/Collector/VariableCollector/AssignToArrayOfTemplateVariablesCollector.php +++ b/src/LatteContext/Collector/VariableCollector/AssignToArrayOfTemplateVariablesCollector.php @@ -16,7 +16,6 @@ use PhpParser\Node\Expr\List_; use PhpParser\Node\Expr\PropertyFetch; use PHPStan\Analyser\Scope; -use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\MixedType; /** @@ -56,8 +55,8 @@ public function collect(Node $node, Scope $scope): ?array $types = []; $expressionTypes = $scope->getType($node->expr); - if ($expressionTypes instanceof ConstantArrayType) { - $types = $expressionTypes->getValueTypes(); + foreach ($expressionTypes->getConstantArrays() as $constantArrayType) { + $types = array_merge($types, $constantArrayType->getValueTypes()); } $variables = []; diff --git a/src/LatteContext/Finder/ComponentFinder.php b/src/LatteContext/Finder/ComponentFinder.php index e774a9ae..35820429 100644 --- a/src/LatteContext/Finder/ComponentFinder.php +++ b/src/LatteContext/Finder/ComponentFinder.php @@ -14,14 +14,10 @@ final class ComponentFinder { - /** - * @var array> - */ + /** @var array> */ private array $assignedComponents = []; - /** - * @var array> - */ + /** @var array> */ private array $declaredComponents = []; private ReflectionProvider $reflectionProvider; diff --git a/src/LatteContext/Finder/FilterFinder.php b/src/LatteContext/Finder/FilterFinder.php index 6fd47474..4d2fe743 100644 --- a/src/LatteContext/Finder/FilterFinder.php +++ b/src/LatteContext/Finder/FilterFinder.php @@ -12,9 +12,7 @@ final class FilterFinder { - /** - * @var array> - */ + /** @var array> */ private array $collectedFilters = []; private ReflectionProvider $reflectionProvider; diff --git a/src/LatteContext/Finder/FormControlFinder.php b/src/LatteContext/Finder/FormControlFinder.php index b5a40974..82f4e4fc 100644 --- a/src/LatteContext/Finder/FormControlFinder.php +++ b/src/LatteContext/Finder/FormControlFinder.php @@ -12,9 +12,7 @@ final class FormControlFinder { - /** - * @var array> - */ + /** @var array> */ private array $assignedFormControls = []; private ReflectionProvider $reflectionProvider; diff --git a/src/LatteContext/Finder/FormFinder.php b/src/LatteContext/Finder/FormFinder.php index 1533a941..4952447d 100644 --- a/src/LatteContext/Finder/FormFinder.php +++ b/src/LatteContext/Finder/FormFinder.php @@ -12,9 +12,7 @@ final class FormFinder { - /** - * @var array> - */ + /** @var array> */ private array $collectedForms = []; private ReflectionProvider $reflectionProvider; diff --git a/src/LatteContext/Finder/MethodCallFinder.php b/src/LatteContext/Finder/MethodCallFinder.php index d863ed85..75824803 100644 --- a/src/LatteContext/Finder/MethodCallFinder.php +++ b/src/LatteContext/Finder/MethodCallFinder.php @@ -15,19 +15,13 @@ final class MethodCallFinder private LattePhpDocResolver $lattePhpDocResolver; - /** - * @var array> - */ + /** @var array> */ private array $collectedMethodCalled = []; - /** - * @var array>> - */ + /** @var array> */ private array $hasTerminatingCalls = []; - /** - * @var array>> - */ + /** @var array> */ private array $hasOutputCalls = []; public function __construct(LatteContextData $latteContext, ReflectionProvider $reflectionProvider, LattePhpDocResolver $lattePhpDocResolver) diff --git a/src/LatteContext/Finder/MethodFinder.php b/src/LatteContext/Finder/MethodFinder.php index 00058b32..4dae3cdd 100644 --- a/src/LatteContext/Finder/MethodFinder.php +++ b/src/LatteContext/Finder/MethodFinder.php @@ -9,9 +9,7 @@ final class MethodFinder { - /** - * @var array>> - */ + /** @var array> */ private array $collectedMethods = []; private MethodCallFinder $methodCallFinder; diff --git a/src/LatteContext/Finder/TemplatePathFinder.php b/src/LatteContext/Finder/TemplatePathFinder.php index 73641912..0fb4ff79 100644 --- a/src/LatteContext/Finder/TemplatePathFinder.php +++ b/src/LatteContext/Finder/TemplatePathFinder.php @@ -11,9 +11,7 @@ final class TemplatePathFinder { - /** - * @var array>> - */ + /** @var array>> */ private array $collectedTemplatePaths = []; private ReflectionProvider $reflectionProvider; diff --git a/src/LatteContext/Finder/TemplateRenderFinder.php b/src/LatteContext/Finder/TemplateRenderFinder.php index be6f9fdf..41759634 100644 --- a/src/LatteContext/Finder/TemplateRenderFinder.php +++ b/src/LatteContext/Finder/TemplateRenderFinder.php @@ -10,9 +10,7 @@ final class TemplateRenderFinder { - /** - * @var array> - */ + /** @var array> */ private array $collectedTemplateRenders = []; private MethodCallFinder $methodCallFinder; diff --git a/src/LatteContext/LatteContextHelper.php b/src/LatteContext/LatteContextHelper.php index 7094a502..a400d539 100644 --- a/src/LatteContext/LatteContextHelper.php +++ b/src/LatteContext/LatteContextHelper.php @@ -11,8 +11,6 @@ use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\Variable as VariableExpr; use PHPStan\Analyser\Scope; -use PHPStan\Type\Constant\ConstantArrayType; -use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ObjectType; use PHPStan\Type\ThisType; use PHPStan\Type\Type; @@ -23,22 +21,20 @@ final class LatteContextHelper /** * @return Variable[] */ - public static function variablesFromType(?Type $type): array + public static function variablesFromType(Type $type): array { - if ($type instanceof ObjectType) { - $type = $type->toArray(); - } + $type = $type->toArray(); $variables = []; - if ($type instanceof ConstantArrayType) { - $keyTypes = $type->getKeyTypes(); - $valueTypes = $type->getValueTypes(); + foreach ($type->getConstantArrays() as $constantArrayType) { + $keyTypes = $constantArrayType->getKeyTypes(); + $valueTypes = $constantArrayType->getValueTypes(); foreach ($keyTypes as $k => $arrayKeyType) { - if (!$arrayKeyType instanceof ConstantStringType) { // only string keys - continue; + $constantStringTypes = $arrayKeyType->getConstantStrings(); + foreach ($constantStringTypes as $constantStringType) { + $variableName = $constantStringType->getValue(); + $variables[$variableName] = new Variable($variableName, $valueTypes[$k]); } - $variableName = $arrayKeyType->getValue(); - $variables[$variableName] = new Variable($variableName, $valueTypes[$k]); } } return $variables; @@ -94,17 +90,17 @@ public static function isClass(Node $node, Scope $scope, $classes): bool foreach ($classes as $class) { $allowedType = new ObjectType($class); - if ($type instanceof ObjectType) { - if ($allowedType->isSuperTypeOf($type)->yes()) { - return true; - } - } elseif ($type instanceof UnionType) { + if ($type instanceof UnionType) { foreach ($type->getTypes() as $unionType) { if ($allowedType->isSuperTypeOf($unionType)->yes()) { return true; } } } + + if ($allowedType->isSuperTypeOf($type)->yes()) { + return true; + } } return false; diff --git a/src/Resolver/CallResolver/CalledClassResolver.php b/src/Resolver/CallResolver/CalledClassResolver.php index 3683ceb9..f4187b3c 100644 --- a/src/Resolver/CallResolver/CalledClassResolver.php +++ b/src/Resolver/CallResolver/CalledClassResolver.php @@ -10,7 +10,6 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; use PHPStan\Analyser\Scope; -use PHPStan\Type\ObjectType; final class CalledClassResolver { @@ -56,7 +55,8 @@ public function resolve(Node $node, Scope $scope): ?string return null; } $callerType = $scope->getType($node->var); - return $callerType instanceof ObjectType ? $callerType->getClassName() : null; + $callerClassNames = $callerType->getObjectClassNames(); + return $callerClassNames[0] ?? null; } } } diff --git a/src/Resolver/TypeResolver/TemplateTypeResolver.php b/src/Resolver/TypeResolver/TemplateTypeResolver.php index f89a6113..8b3f9b68 100644 --- a/src/Resolver/TypeResolver/TemplateTypeResolver.php +++ b/src/Resolver/TypeResolver/TemplateTypeResolver.php @@ -17,16 +17,14 @@ final class TemplateTypeResolver { public function resolve(Type $type): bool { - if ($type instanceof ObjectType) { - return $type->isInstanceOf('Nette\Application\UI\Template')->yes() || $type->isInstanceOf('Nette\Application\UI\ITemplate')->yes(); - } elseif ($type instanceof UnionType) { + if ($type instanceof UnionType) { foreach ($type->getTypes() as $unionType) { if ($this->resolve($unionType)) { return true; } } } - return false; + return (new ObjectType('Nette\Application\UI\Template'))->isSuperTypeOf($type)->yes() || (new ObjectType('Nette\Application\UI\ITemplate'))->isSuperTypeOf($type)->yes(); } public function resolveByNodeAndScope(Node $node, Scope $scope): bool diff --git a/src/Resolver/ValueResolver/PathResolver.php b/src/Resolver/ValueResolver/PathResolver.php index e73e1a1a..014895a9 100644 --- a/src/Resolver/ValueResolver/PathResolver.php +++ b/src/Resolver/ValueResolver/PathResolver.php @@ -17,7 +17,6 @@ use PHPStan\Analyser\Scope; use PHPStan\ShouldNotHappenException; use PHPStan\Type\Constant\ConstantStringType; -use PHPStan\Type\TypeWithClassName; use SplFileInfo; final class PathResolver @@ -76,10 +75,11 @@ private function evaluate(Expr $expr, Scope $scope): string throw new ConstExprEvaluationException(); } $calledOnType = $scope->getType($expr->var); - if (!$calledOnType instanceof TypeWithClassName) { + $objectClassNames = $calledOnType->getObjectClassNames(); + if ($objectClassNames === []) { throw new ConstExprEvaluationException(); } - $className = $calledOnType->getClassName(); + $className = $objectClassNames[0]; $methodName = (string)$expr->name; return $this->methodCallPlaceholder($className, $methodName); } elseif ($expr instanceof StaticCall) { diff --git a/src/Resolver/ValueResolver/ValueResolver.php b/src/Resolver/ValueResolver/ValueResolver.php index 98d28808..61716b9b 100644 --- a/src/Resolver/ValueResolver/ValueResolver.php +++ b/src/Resolver/ValueResolver/ValueResolver.php @@ -16,7 +16,6 @@ use PhpParser\Node\Scalar\MagicConst\Dir; use PhpParser\Node\Scalar\MagicConst\File; use PHPStan\Analyser\Scope; -use PHPStan\Type\ConstantScalarType; use PHPStan\Type\IntegerRangeType; use PHPStan\Type\UnionType; @@ -33,8 +32,9 @@ public function resolve(Expr $expr, Scope $scope, $fallbackEvaluator = null) $type = $scope->getType($expr); - if ($type instanceof ConstantScalarType) { - return $type->getValue(); + $constantScalarValues = $type->getConstantScalarValues(); + if ($constantScalarValues !== []) { + return $constantScalarValues[0]; } if ($expr instanceof Dir) { @@ -111,10 +111,11 @@ public function resolve(Expr $expr, Scope $scope, $fallbackEvaluator = null) if ($type instanceof UnionType) { $options = []; foreach ($type->getTypes() as $subType) { - if (!$subType instanceof ConstantScalarType) { + $constantScalarValues = $subType->getConstantScalarValues(); + if ($constantScalarValues === []) { return null; } - $options[] = $subType->getValue(); + $options[] = $constantScalarValues[0]; } return $options; }