Skip to content

Commit

Permalink
create a return type provider for mb_internal_encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
orklah committed Jan 19, 2022
1 parent 5a6dccd commit ac858e3
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php
Expand Up @@ -30,6 +30,7 @@
use Psalm\Internal\Provider\ReturnTypeProvider\HexdecReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\InArrayReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\IteratorToArrayReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\MbInternalEncodingReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\MinMaxReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\MktimeReturnTypeProvider;
use Psalm\Internal\Provider\ReturnTypeProvider\ParseUrlReturnTypeProvider;
Expand Down Expand Up @@ -97,6 +98,7 @@ public function __construct()
$this->registerClass(RandReturnTypeProvider::class);
$this->registerClass(InArrayReturnTypeProvider::class);
$this->registerClass(RoundReturnTypeProvider::class);
$this->registerClass(MbInternalEncodingReturnTypeProvider::class);
}

/**
Expand Down
@@ -0,0 +1,116 @@
<?php

declare(strict_types=1);

namespace Psalm\Internal\Provider\ReturnTypeProvider;

use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent;
use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface;
use Psalm\Type;
use Psalm\Type\Atomic\TBool;
use Psalm\Type\Atomic\TFalse;
use Psalm\Type\Atomic\TNever;
use Psalm\Type\Atomic\TNull;
use Psalm\Type\Atomic\TString;
use Psalm\Type\Atomic\TTrue;
use Psalm\Type\Union;

use function assert;
use function count;

/**
* @internal
*/
class MbInternalEncodingReturnTypeProvider implements FunctionReturnTypeProviderInterface
{
/**
* @return array<lowercase-string>
*/
public static function getFunctionIds(): array
{
return ['mb_internal_encoding'];
}

public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Union
{
$call_args = $event->getCallArgs();
if (count($call_args) === 0) {
return Type::getString();
}

$statements_source = $event->getStatementsSource();
$nodeTypeProvider = $statements_source->getNodeTypeProvider();
$codebase = $statements_source->getCodebase();

$first_arg_type = $nodeTypeProvider->getType($call_args[0]->value);
if ($first_arg_type === null) {
if ($codebase->analysis_php_version_id >= 8_00_00) {
return new Union([new TString(), new TTrue()]);
} else {
return new Union([new TString(), new TBool()]);
}
}

$has_stringable = false;
$has_tostring = false;
$has_string = false;
$has_null = false;
$has_unknown = false;

foreach ($first_arg_type->getAtomicTypes() as $atomic_type) {
if ($atomic_type instanceof Type\Atomic\TNamedObject
&& $codebase->classlikes->classImplements($atomic_type->value, 'Stringable')
) {
$has_stringable = true;
continue;
}

if ($atomic_type instanceof Type\Atomic\TObjectWithProperties
&& isset($atomic_type->methods['__toString'])
) {
$has_tostring = true;
continue;
}

if ($atomic_type instanceof TString) {
$has_string = true;
continue;
}

if ($atomic_type instanceof TNull) {
$has_null = true;
continue;
}

$has_unknown = true;
}

$list_return_atomics = [];
if ($has_string || $has_stringable || $has_tostring) {
if ($codebase->analysis_php_version_id >= 8_00_00) {
$list_return_atomics[] = new TTrue();
} else {
$list_return_atomics[] = new TBool();
}
}

if ($has_null) {
if ($codebase->analysis_php_version_id >= 8_00_00) {
$list_return_atomics[] = new TString();
} else {
$list_return_atomics[] = new TFalse();
}
}

if ($has_unknown) {
if ($codebase->analysis_php_version_id >= 8_00_00) {
$list_return_atomics[] = new TNever();
} else {
$list_return_atomics[] = new TNull();
}
}

assert($list_return_atomics !== []);
return new Union($list_return_atomics);
}
}

0 comments on commit ac858e3

Please sign in to comment.