Skip to content

Commit

Permalink
Part of Broker extracted into NativeFunctionReflectionProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Dec 19, 2019
1 parent 00d8c88 commit b6183bb
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 95 deletions.
3 changes: 3 additions & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,9 @@ services:
arguments:
classes: %universalObjectCratesClasses%

-
class: PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider

-
class: PHPStan\Reflection\SignatureMap\SignatureMapParser

Expand Down
107 changes: 17 additions & 90 deletions src/Broker/Broker.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,12 @@
use PHPStan\Reflection\BrokerAwareExtension;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\FunctionReflectionFactory;
use PHPStan\Reflection\FunctionVariant;
use PHPStan\Reflection\Native\NativeFunctionReflection;
use PHPStan\Reflection\Native\NativeParameterReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Reflection\SignatureMap\ParameterSignature;
use PHPStan\Reflection\SignatureMap\SignatureMapProvider;
use PHPStan\TrinaryLogic;
use PHPStan\Type\BooleanType;
use PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider;
use PHPStan\Type\FileTypeMapper;
use PHPStan\Type\FloatType;
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\IntegerType;
use PHPStan\Type\NullType;
use PHPStan\Type\OperatorTypeSpecifyingExtension;
use PHPStan\Type\StringAlwaysAcceptingObjectWithToStringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\UnionType;
use ReflectionClass;

class Broker implements ReflectionProvider
Expand Down Expand Up @@ -62,8 +50,8 @@ class Broker implements ReflectionProvider
/** @var \PHPStan\Type\FileTypeMapper */
private $fileTypeMapper;

/** @var \PHPStan\Reflection\SignatureMap\SignatureMapProvider */
private $signatureMapProvider;
/** @var \PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider */
private $nativeFunctionReflectionProvider;

/** @var \PhpParser\PrettyPrinter\Standard */
private $printer;
Expand Down Expand Up @@ -95,9 +83,6 @@ class Broker implements ReflectionProvider
/** @var bool[] */
private $hasClassCache;

/** @var NativeFunctionReflection[] */
private static $functionMap = [];

/** @var \PHPStan\Reflection\ClassReflection[] */
private static $anonymousClasses = [];

Expand All @@ -112,7 +97,7 @@ class Broker implements ReflectionProvider
* @param \PHPStan\Type\OperatorTypeSpecifyingExtension[] $operatorTypeSpecifyingExtensions
* @param \PHPStan\Reflection\FunctionReflectionFactory $functionReflectionFactory
* @param \PHPStan\Type\FileTypeMapper $fileTypeMapper
* @param \PHPStan\Reflection\SignatureMap\SignatureMapProvider $signatureMapProvider
* @param \PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider $nativeFunctionReflectionProvider
* @param \PhpParser\PrettyPrinter\Standard $printer
* @param AnonymousClassNameHelper $anonymousClassNameHelper
* @param Parser $parser
Expand All @@ -128,7 +113,7 @@ public function __construct(
array $operatorTypeSpecifyingExtensions,
FunctionReflectionFactory $functionReflectionFactory,
FileTypeMapper $fileTypeMapper,
SignatureMapProvider $signatureMapProvider,
NativeFunctionReflectionProvider $nativeFunctionReflectionProvider,
\PhpParser\PrettyPrinter\Standard $printer,
AnonymousClassNameHelper $anonymousClassNameHelper,
Parser $parser,
Expand Down Expand Up @@ -156,7 +141,7 @@ public function __construct(

$this->functionReflectionFactory = $functionReflectionFactory;
$this->fileTypeMapper = $fileTypeMapper;
$this->signatureMapProvider = $signatureMapProvider;
$this->nativeFunctionReflectionProvider = $nativeFunctionReflectionProvider;
$this->printer = $printer;
$this->anonymousClassNameHelper = $anonymousClassNameHelper;
$this->parser = $parser;
Expand Down Expand Up @@ -413,76 +398,18 @@ public function getFunction(\PhpParser\Node\Name $nameNode, ?Scope $scope): \PHP
}

$lowerCasedFunctionName = strtolower($functionName);
if (!isset($this->functionReflections[$lowerCasedFunctionName])) {
if (isset(self::$functionMap[$lowerCasedFunctionName])) {
return $this->functionReflections[$lowerCasedFunctionName] = self::$functionMap[$lowerCasedFunctionName];
}
if (isset($this->functionReflections[$lowerCasedFunctionName])) {
return $this->functionReflections[$lowerCasedFunctionName];
}

if ($this->signatureMapProvider->hasFunctionSignature($lowerCasedFunctionName)) {
$variantName = $lowerCasedFunctionName;
$variants = [];
$i = 0;
while ($this->signatureMapProvider->hasFunctionSignature($variantName)) {
$functionSignature = $this->signatureMapProvider->getFunctionSignature($variantName, null);
$returnType = $functionSignature->getReturnType();
if ($lowerCasedFunctionName === 'pow') {
$returnType = TypeUtils::toBenevolentUnion($returnType);
}
$variants[] = new FunctionVariant(
TemplateTypeMap::createEmpty(),
null,
array_map(static function (ParameterSignature $parameterSignature) use ($lowerCasedFunctionName): NativeParameterReflection {
$type = $parameterSignature->getType();
if (
$parameterSignature->getName() === 'args'
&& (
$lowerCasedFunctionName === 'printf'
|| $lowerCasedFunctionName === 'sprintf'
)
) {
$type = new UnionType([
new StringAlwaysAcceptingObjectWithToStringType(),
new IntegerType(),
new FloatType(),
new NullType(),
new BooleanType(),
]);
}
return new NativeParameterReflection(
$parameterSignature->getName(),
$parameterSignature->isOptional(),
$type,
$parameterSignature->passedByReference(),
$parameterSignature->isVariadic(),
null
);
}, $functionSignature->getParameters()),
$functionSignature->isVariadic(),
$returnType
);

$i++;
$variantName = sprintf($lowerCasedFunctionName . '\'' . $i);
}

if ($this->signatureMapProvider->hasFunctionMetadata($lowerCasedFunctionName)) {
$hasSideEffects = TrinaryLogic::createFromBoolean($this->signatureMapProvider->getFunctionMetadata($lowerCasedFunctionName)['hasSideEffects']);
} else {
$hasSideEffects = TrinaryLogic::createMaybe();
}
$functionReflection = new NativeFunctionReflection(
$lowerCasedFunctionName,
$variants,
null,
$hasSideEffects
);
self::$functionMap[$lowerCasedFunctionName] = $functionReflection;
$this->functionReflections[$lowerCasedFunctionName] = $functionReflection;
} else {
$this->functionReflections[$lowerCasedFunctionName] = $this->getCustomFunction($nameNode, $scope);
}
$nativeFunctionReflection = $this->nativeFunctionReflectionProvider->findFunctionReflection($lowerCasedFunctionName);
if ($nativeFunctionReflection !== null) {
$this->functionReflections[$lowerCasedFunctionName] = $nativeFunctionReflection;
return $nativeFunctionReflection;
}

$this->functionReflections[$lowerCasedFunctionName] = $this->getCustomFunction($nameNode, $scope);

return $this->functionReflections[$lowerCasedFunctionName];
}

Expand All @@ -498,7 +425,7 @@ public function hasCustomFunction(\PhpParser\Node\Name $nameNode, ?Scope $scope)
return false;
}

return !$this->signatureMapProvider->hasFunctionSignature($functionName);
return $this->nativeFunctionReflectionProvider->findFunctionReflection($functionName) === null;
}

public function getCustomFunction(\PhpParser\Node\Name $nameNode, ?Scope $scope): \PHPStan\Reflection\Php\PhpFunctionReflection
Expand Down Expand Up @@ -571,7 +498,7 @@ public function resolveFunctionName(\PhpParser\Node\Name $nameNode, ?Scope $scop
return true;
}

return $this->signatureMapProvider->hasFunctionSignature($name);
return $this->nativeFunctionReflectionProvider->findFunctionReflection($name) !== null;
}, $scope);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Broker/BrokerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use PHPStan\Parser\Parser;
use PHPStan\PhpDoc\StubPhpDocProvider;
use PHPStan\Reflection\FunctionReflectionFactory;
use PHPStan\Reflection\SignatureMap\SignatureMapProvider;
use PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider;
use PHPStan\Type\FileTypeMapper;

class BrokerFactory
Expand Down Expand Up @@ -42,7 +42,7 @@ public function create(): Broker
$this->container->getServicesByTag(self::OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG),
$this->container->getByType(FunctionReflectionFactory::class),
$this->container->getByType(FileTypeMapper::class),
$this->container->getByType(SignatureMapProvider::class),
$this->container->getByType(NativeFunctionReflectionProvider::class),
$this->container->getByType(\PhpParser\PrettyPrinter\Standard::class),
$this->container->getByType(AnonymousClassNameHelper::class),
$this->container->getByType(Parser::class),
Expand Down
105 changes: 105 additions & 0 deletions src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\SignatureMap;

use PHPStan\Reflection\FunctionVariant;
use PHPStan\Reflection\Native\NativeFunctionReflection;
use PHPStan\Reflection\Native\NativeParameterReflection;
use PHPStan\TrinaryLogic;
use PHPStan\Type\BooleanType;
use PHPStan\Type\FloatType;
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\IntegerType;
use PHPStan\Type\NullType;
use PHPStan\Type\StringAlwaysAcceptingObjectWithToStringType;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\UnionType;

class NativeFunctionReflectionProvider
{

/** @var NativeFunctionReflection[] */
private static $functionMap = [];

/** @var \PHPStan\Reflection\SignatureMap\SignatureMapProvider */
private $signatureMapProvider;

public function __construct(SignatureMapProvider $signatureMapProvider)
{
$this->signatureMapProvider = $signatureMapProvider;
}

public function findFunctionReflection(string $functionName): ?NativeFunctionReflection
{
$lowerCasedFunctionName = strtolower($functionName);
if (isset(self::$functionMap[$lowerCasedFunctionName])) {
return self::$functionMap[$lowerCasedFunctionName];
}

if (!$this->signatureMapProvider->hasFunctionSignature($lowerCasedFunctionName)) {
return null;
}

$variantName = $lowerCasedFunctionName;
$variants = [];
$i = 0;
while ($this->signatureMapProvider->hasFunctionSignature($variantName)) {
$functionSignature = $this->signatureMapProvider->getFunctionSignature($variantName, null);
$returnType = $functionSignature->getReturnType();
if ($lowerCasedFunctionName === 'pow') {
$returnType = TypeUtils::toBenevolentUnion($returnType);
}
$variants[] = new FunctionVariant(
TemplateTypeMap::createEmpty(),
null,
array_map(static function (ParameterSignature $parameterSignature) use ($lowerCasedFunctionName): NativeParameterReflection {
$type = $parameterSignature->getType();
if (
$parameterSignature->getName() === 'args'
&& (
$lowerCasedFunctionName === 'printf'
|| $lowerCasedFunctionName === 'sprintf'
)
) {
$type = new UnionType([
new StringAlwaysAcceptingObjectWithToStringType(),
new IntegerType(),
new FloatType(),
new NullType(),
new BooleanType(),
]);
}
return new NativeParameterReflection(
$parameterSignature->getName(),
$parameterSignature->isOptional(),
$type,
$parameterSignature->passedByReference(),
$parameterSignature->isVariadic(),
null
);
}, $functionSignature->getParameters()),
$functionSignature->isVariadic(),
$returnType
);

$i++;
$variantName = sprintf($lowerCasedFunctionName . '\'' . $i);
}

if ($this->signatureMapProvider->hasFunctionMetadata($lowerCasedFunctionName)) {
$hasSideEffects = TrinaryLogic::createFromBoolean($this->signatureMapProvider->getFunctionMetadata($lowerCasedFunctionName)['hasSideEffects']);
} else {
$hasSideEffects = TrinaryLogic::createMaybe();
}
$functionReflection = new NativeFunctionReflection(
$lowerCasedFunctionName,
$variants,
null,
$hasSideEffects
);
self::$functionMap[$lowerCasedFunctionName] = $functionReflection;

return $functionReflection;
}

}
3 changes: 2 additions & 1 deletion src/Testing/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use PHPStan\Reflection\Php\PhpMethodReflectionFactory;
use PHPStan\Reflection\Php\UniversalObjectCratesClassReflectionExtension;
use PHPStan\Reflection\PhpDefect\PhpDefectClassReflectionExtension;
use PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider;
use PHPStan\Reflection\SignatureMap\SignatureMapProvider;
use PHPStan\Rules\Properties\PropertyReflectionFinder;
use PHPStan\Type\FileTypeMapper;
Expand Down Expand Up @@ -256,7 +257,7 @@ public function create(
$this->getOperatorTypeSpecifyingExtensions(),
$functionReflectionFactory,
new FileTypeMapper($this->getParser(), $phpDocStringResolver, $phpDocNodeResolver, $cache, $anonymousClassNameHelper),
$signatureMapProvider,
self::getContainer()->getByType(NativeFunctionReflectionProvider::class),
self::getContainer()->getByType(Standard::class),
$anonymousClassNameHelper,
self::getContainer()->getByType(Parser::class),
Expand Down
4 changes: 2 additions & 2 deletions tests/PHPStan/Broker/BrokerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use PHPStan\PhpDoc\PhpDocStringResolver;
use PHPStan\PhpDoc\StubPhpDocProvider;
use PHPStan\Reflection\FunctionReflectionFactory;
use PHPStan\Reflection\SignatureMap\SignatureMapProvider;
use PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider;
use PHPStan\Type\FileTypeMapper;

class BrokerTest extends \PHPStan\Testing\TestCase
Expand Down Expand Up @@ -41,7 +41,7 @@ protected function setUp(): void
[],
$this->createMock(FunctionReflectionFactory::class),
new FileTypeMapper($this->getParser(), $phpDocStringResolver, $phpDocNodeResolver, $this->createMock(Cache::class), $anonymousClassNameHelper),
self::getContainer()->getByType(SignatureMapProvider::class),
self::getContainer()->getByType(NativeFunctionReflectionProvider::class),
self::getContainer()->getByType(\PhpParser\PrettyPrinter\Standard::class),
$anonymousClassNameHelper,
self::getContainer()->getByType(Parser::class),
Expand Down

0 comments on commit b6183bb

Please sign in to comment.