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
base: 1.11.x
Are you sure you want to change the base?
Changes from all commits
8079876
2561a62
9b1b043
3b5cf54
337342c
1de8bff
4a68879
26d20dc
f41fd91
c90e17c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionFunction; | ||
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter; | ||
use PHPStan\BetterReflection\Reflection\ReflectionConstant; | ||
use PHPStan\ShouldNotHappenException; | ||
use function array_slice; | ||
use function count; | ||
use function explode; | ||
|
@@ -18,6 +19,9 @@ | |
class InitializerExprContext implements NamespaceAnswerer | ||
{ | ||
|
||
/** | ||
* @param non-empty-string|null $namespace | ||
*/ | ||
private function __construct( | ||
private ?string $file, | ||
private ?string $namespace, | ||
|
@@ -43,11 +47,18 @@ public static function fromScope(Scope $scope): self | |
); | ||
} | ||
|
||
/** | ||
* @return non-empty-string|null | ||
*/ | ||
private static function parseNamespace(string $name): ?string | ||
{ | ||
$parts = explode('\\', $name); | ||
if (count($parts) > 1) { | ||
return implode('\\', array_slice($parts, 0, -1)); | ||
$ns = implode('\\', array_slice($parts, 0, -1)); | ||
if ($ns === '') { | ||
throw new ShouldNotHappenException('Namespace cannot be empty.'); | ||
} | ||
return $ns; | ||
} | ||
|
||
return null; | ||
|
@@ -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.'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be tackled by a better typehint in BetterReflection. |
||
} | ||
|
||
return new self( | ||
$constant->getFileName(), | ||
$constant->getNamespaceName(), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,9 @@ | |
interface NamespaceAnswerer | ||
{ | ||
|
||
/** | ||
* @return non-empty-string|null | ||
*/ | ||
public function getNamespace(): ?string; | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
use PHPStan\Rules\ClassNameNodePair; | ||
use PHPStan\Rules\IdentifierRuleError; | ||
use PHPStan\Rules\RuleErrorBuilder; | ||
use PHPStan\ShouldNotHappenException; | ||
use PHPStan\Type\ArrayType; | ||
use PHPStan\Type\BooleanType; | ||
use PHPStan\Type\Constant\ConstantArrayType; | ||
|
@@ -66,6 +67,10 @@ public function check( | |
{ | ||
$messages = []; | ||
foreach ($templateTags as $templateTag) { | ||
if ($templateTag->getName() === '') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be tackled in TemplateTag by typehinting |
||
throw new ShouldNotHappenException('Template tag name cannot be empty.'); | ||
} | ||
|
||
$templateTagName = $scope->resolveName(new Node\Name($templateTag->getName())); | ||
if ($this->reflectionProvider->hasClass($templateTagName)) { | ||
$messages[] = RuleErrorBuilder::message(sprintf( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,8 +33,8 @@ | |
use function array_map; | ||
use function count; | ||
use function is_string; | ||
use function ltrim; | ||
use function strtolower; | ||
use function substr; | ||
|
||
class ArrayFilterFunctionReturnTypeReturnTypeExtension implements DynamicFunctionReturnTypeExtension | ||
{ | ||
|
@@ -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 === '') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can definitely write some userland code that will execute this condition |
||
throw new ShouldNotHappenException(); | ||
} | ||
|
||
return new Name\FullyQualified($fqcn); | ||
} | ||
|
||
if ($funcName === '') { | ||
throw new ShouldNotHappenException(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can definitely write some userland code that will execute this condition |
||
} | ||
|
||
return new Name($funcName); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,18 +8,27 @@ | |
use PhpParser\Node\Identifier; | ||
use PhpParser\Node\Name; | ||
use PhpParser\Node\Name\FullyQualified; | ||
use PHPStan\ShouldNotHappenException; | ||
use function count; | ||
use function explode; | ||
use function ltrim; | ||
|
||
class ConstantHelper | ||
{ | ||
|
||
/** | ||
* @param non-empty-string $constantName | ||
*/ | ||
public function createExprFromConstantName(string $constantName): Expr | ||
{ | ||
$classConstParts = explode('::', $constantName); | ||
if (count($classConstParts) >= 2) { | ||
$classConstName = new FullyQualified(ltrim($classConstParts[0], '\\')); | ||
$fqcn = ltrim($classConstParts[0], '\\'); | ||
if ($fqcn === '') { | ||
throw new ShouldNotHappenException(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if you can |
||
} | ||
|
||
$classConstName = new FullyQualified($fqcn); | ||
if ($classConstName->isSpecialClassName()) { | ||
$classConstName = new Name($classConstName->toString()); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace PhpParser\Node; | ||
|
||
use PhpParser\NodeAbstract; | ||
|
||
class Name extends NodeAbstract | ||
{ | ||
/** | ||
* Constructs a name node. | ||
* | ||
* @param non-empty-string|non-empty-array<string>|self $name Name as string, part array or Name instance (copy ctor) | ||
* @param array<mixed> $attributes Additional attributes | ||
*/ | ||
public function __construct($name, array $attributes = []) { | ||
} | ||
|
||
/** @return non-empty-string */ | ||
public function toString() : string { | ||
} | ||
|
||
/** @return non-empty-string */ | ||
public function toCodeString() : string { | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
namespace Bug10867; | ||
|
||
function doFoo():void { | ||
$sysERR = ''; | ||
?> | ||
|
||
<p><?php echo constant($sysERR); ?></p> | ||
<?php | ||
} |
There was a problem hiding this comment.
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.There was a problem hiding this comment.
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
.