Skip to content
Permalink
Browse files

Fix #2438 - improve handling of get_class calls

  • Loading branch information
muglug committed Dec 7, 2019
1 parent d7fdd9b commit 3c521023887f1b879ca0a3629a58e04f0d2790a1
@@ -619,36 +619,49 @@ public static function analyze(
}
}

if ($stmt->name instanceof PhpParser\Node\Name &&
($stmt->name->parts === ['get_class'] || $stmt->name->parts === ['gettype']) &&
$stmt->args
if ($stmt->name instanceof PhpParser\Node\Name
&& ($stmt->name->parts === ['get_class'] || $stmt->name->parts === ['gettype'])
) {
$var = $stmt->args[0]->value;
if ($stmt->args) {
$var = $stmt->args[0]->value;

if ($var instanceof PhpParser\Node\Expr\Variable
&& is_string($var->name)
) {
$var_id = '$' . $var->name;
if ($var instanceof PhpParser\Node\Expr\Variable
&& is_string($var->name)
) {
$var_id = '$' . $var->name;

if (isset($context->vars_in_scope[$var_id])) {
$atomic_type = $stmt->name->parts === ['get_class']
? new Type\Atomic\GetClassT($var_id, $context->vars_in_scope[$var_id])
: new Type\Atomic\GetTypeT($var_id);
if (isset($context->vars_in_scope[$var_id])) {
$atomic_type = $stmt->name->parts === ['get_class']
? new Type\Atomic\GetClassT($var_id, $context->vars_in_scope[$var_id])
: new Type\Atomic\GetTypeT($var_id);

$statements_analyzer->node_data->setType($stmt, new Type\Union([$atomic_type]));
}
} elseif ($var_type = $statements_analyzer->node_data->getType($var)) {
$class_string_types = [];
$statements_analyzer->node_data->setType($stmt, new Type\Union([$atomic_type]));
}
} elseif ($var_type = $statements_analyzer->node_data->getType($var)) {
$class_string_types = [];

foreach ($var_type->getTypes() as $class_type) {
if ($class_type instanceof Type\Atomic\TNamedObject) {
$class_string_types[] = new Type\Atomic\TClassString($class_type->value, clone $class_type);
foreach ($var_type->getTypes() as $class_type) {
if ($class_type instanceof Type\Atomic\TNamedObject) {
$class_string_types[] = new Type\Atomic\TClassString($class_type->value, clone $class_type);
}
}
}

if ($class_string_types) {
$statements_analyzer->node_data->setType($stmt, new Type\Union($class_string_types));
if ($class_string_types) {
$statements_analyzer->node_data->setType($stmt, new Type\Union($class_string_types));
}
}
} elseif ($stmt->name->parts === ['get_class']
&& ($get_class_name = $statements_analyzer->getFQCLN())
) {
$statements_analyzer->node_data->setType(
$stmt,
new Type\Union([
new Type\Atomic\TClassString(
$get_class_name,
new Type\Atomic\TNamedObject($get_class_name)
)
])
);
}
}

@@ -155,11 +155,27 @@ public static function analyze(

if ($lhs_type_part instanceof Type\Atomic\TLiteralClassString
|| $lhs_type_part instanceof Type\Atomic\TClassString
|| $lhs_type_part instanceof Type\Atomic\GetClassT
) {
if (!$statements_analyzer->node_data->getType($stmt)) {
$class_name = $lhs_type_part instanceof Type\Atomic\TClassString
? $lhs_type_part->as
: $lhs_type_part->value;
if ($lhs_type_part instanceof Type\Atomic\TClassString) {
$class_name = $lhs_type_part->as;
} elseif ($lhs_type_part instanceof Type\Atomic\GetClassT) {
$class_name = 'object';

if ($lhs_type_part->as_type
&& $lhs_type_part->as_type->hasObjectType()
&& $lhs_type_part->as_type->isSingle()
) {
foreach ($lhs_type_part->as_type->getTypes() as $typeof_type_atomic) {
if ($typeof_type_atomic instanceof Type\Atomic\TNamedObject) {
$class_name = $typeof_type_atomic->value;
}
}
}
} else {
$class_name = $lhs_type_part->value;
}

if ($lhs_type_part instanceof Type\Atomic\TClassString) {
$can_extend = true;
@@ -232,6 +232,21 @@ public static function analyze(
}

$intersection_types = $lhs_type_part->as_type->extra_types;
} elseif ($lhs_type_part instanceof Type\Atomic\GetClassT
&& !$lhs_type_part->as_type->hasObject()
) {
$fq_class_name = 'object';

if ($lhs_type_part->as_type
&& $lhs_type_part->as_type->hasObjectType()
&& $lhs_type_part->as_type->isSingle()
) {
foreach ($lhs_type_part->as_type->getTypes() as $typeof_type_atomic) {
if ($typeof_type_atomic instanceof Type\Atomic\TNamedObject) {
$fq_class_name = $typeof_type_atomic->value;
}
}
}
} elseif ($lhs_type_part instanceof Type\Atomic\TLiteralClassString) {
$fq_class_name = $lhs_type_part->value;

@@ -618,6 +618,48 @@ class A {}
new \RuntimeException();
}',
],
'createNewObjectFromGetClass' => [
'<?php
class Example {
static function staticMethod(): string {
return "";
}
public function instanceMethod(): string {
$className = get_class();
return $className::staticMethod();
}
}
/**
* @param class-string<Example> $className
*/
function example(string $className, Example $object): string {
$objectClassName = get_class($object);
takesExampleClassString($className);
takesExampleClassString($objectClassName);
if (rand(0, 1)) {
return (new $className)->instanceMethod();
}
if (rand(0, 1)) {
return (new $objectClassName)->instanceMethod();
}
if (rand(0, 1)) {
return $className::staticMethod();
}
return $objectClassName::staticMethod();
}
/** @param class-string<Example> $className */
function takesExampleClassString(string $className): void {}'
],
];
}

0 comments on commit 3c52102

Please sign in to comment.
You can’t perform that action at this time.