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

Fix fatal error on constant('') #3013

Open
wants to merge 10 commits into
base: 1.11.x
Choose a base branch
from
Open

Conversation

staabm
Copy link
Contributor

@staabm staabm commented Apr 12, 2024

closes phpstan/phpstan#10867

there are only 2 other callers for this very same method in the codebase, and there we already early exit on '':

e.g.

if (
!$constantName instanceof ConstantStringType
|| $constantName->getValue() === ''
) {
return new SpecifiedTypes([], []);
}
return $this->typeSpecifier->create(
$this->constantHelper->createExprFromConstantName($constantName->getValue()),
new MixedType(),
$context,

@staabm staabm marked this pull request as ready for review April 12, 2024 19:21
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

Copy link
Member

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

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

I'd like to have a stub for Name constructor and all Name subclasses constructors that enforces non-empty-string.

fix

fix

fix

fix

fix

Update Type.php

Revert "Update Type.php"

This reverts commit a239561a19109a244f370a59532891959438f0eb.

fix tests

fix

fix

Update phpstan-baseline.neon
@staabm
Copy link
Contributor Author

staabm commented Apr 12, 2024

using non-empty-string names everywhere would spread across the whole codebase. I fixed the places which worked without ugly catches and baselined the remaining ones

@staabm
Copy link
Contributor Author

staabm commented Apr 12, 2024

tested locally with regarding __construct() in all known Name classes

➜  phpstan-src git:(bug10867) ✗ cat test4.php 
<?php

$n = new \PhpParser\Node\Name('');

$r = new \PhpParser\Node\Name\Relative('');

$fq = new \PhpParser\Node\Name\FullyQualified('');
➜  phpstan-src git:(bug10867) ✗ php bin/phpstan analyze test4.php --debug
Note: Using configuration file /Users/staabm/workspace/phpstan-src/phpstan.neon.dist.
/Users/staabm/workspace/phpstan-src/test4.php
 ------ ------------------------------------------------------------------------------------------------------------------------------------------------------------ 
  Line   test4.php                                                                                                                                                   
 ------ ------------------------------------------------------------------------------------------------------------------------------------------------------------ 
  3      Parameter #1 $name of class PhpParser\Node\Name constructor expects non-empty-array<string>|PhpParser\Node\Name|non-empty-string, '' given.                 
         💡 Type #1 from the union: '' is empty.                                                                                                                     
  5      Parameter #1 $name of class PhpParser\Node\Name\Relative constructor expects non-empty-array<string>|PhpParser\Node\Name|non-empty-string, '' given.        
         💡 Type #1 from the union: '' is empty.                                                                                                                     
  7      Parameter #1 $name of class PhpParser\Node\Name\FullyQualified constructor expects non-empty-array<string>|PhpParser\Node\Name|non-empty-string, '' given.  
         💡 Type #1 from the union: '' is empty.                                                                                                                     
 ------ ------------------------------------------------------------------------------------------------------------------------------------------------------------ 


                                                                                                                        
 [ERROR] Found 3 errors                                                                                                 
                                                                                                                        

also created a upstream PR for PHPParser: nikic/PHP-Parser#993

@ondrejmirtes
Copy link
Member

using non-empty-string names everywhere would spread across the whole codebase.

Yes, that's the idea. I'm not looking for a quick fix but a correct fix. Please do not baseline anything. Baseline is not supposed to grow.

@staabm
Copy link
Contributor Author

staabm commented Apr 13, 2024

looks like this will be a breaking change and can only be merged for 2.0?
should the crash fix be separated?

Copy link
Member

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

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

Please be more careful - in some places where we gain type safety thanks to the new PHPDocs, you instantly throw it away by throwing ShouldNotHappenException.

@@ -175,6 +175,7 @@ parameters:
- ../stubs/ext-ds.stub
- ../stubs/ImagickPixel.stub
- ../stubs/PDOStatement.stub
- ../stubs/PhpParserName.stub
Copy link
Member

Choose a reason for hiding this comment

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

Please register this stub only in build/phpstan.neon. It's only for internal PHPStan purposes.

Copy link
Member

Choose a reason for hiding this comment

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

And move the stub elsewhere, probably to build/stubs.

@@ -245,7 +245,16 @@ private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type
private static function createFunctionName(string $funcName): Name
{
if ($funcName[0] === '\\') {
return new Name\FullyQualified(substr($funcName, 1));
$fqcn = ltrim($funcName, '\\');
if ($fqcn === '') {
Copy link
Member

Choose a reason for hiding this comment

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

You can definitely write some userland code that will execute this condition

}

if ($funcName === '') {
throw new ShouldNotHappenException();
Copy link
Member

Choose a reason for hiding this comment

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

You can definitely write some userland code that will execute this condition

$classConstName = new FullyQualified(ltrim($classConstParts[0], '\\'));
$fqcn = ltrim($classConstParts[0], '\\');
if ($fqcn === '') {
throw new ShouldNotHappenException();
Copy link
Member

Choose a reason for hiding this comment

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

What if you can constant('::aa')? That will execute this condition

@@ -66,6 +67,10 @@ public function check(
{
$messages = [];
foreach ($templateTags as $templateTag) {
if ($templateTag->getName() === '') {
Copy link
Member

Choose a reason for hiding this comment

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

This should be tackled in TemplateTag by typehinting non-empty-string.

@@ -127,6 +138,10 @@ public static function fromStubParameter(

public static function fromGlobalConstant(ReflectionConstant $constant): self
{
if ($constant->getNamespaceName() === '') {
throw new ShouldNotHappenException('Namespace cannot be empty.');
Copy link
Member

Choose a reason for hiding this comment

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

This could be tackled by a better typehint in BetterReflection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants