Merge pull request #465 from isfedorov/master
New architecture of test suite
This commit is contained in:
commit
b643efdde0
|
@ -11,9 +11,6 @@ rest-client.private.env.json
|
||||||
.idea/workspace.xml
|
.idea/workspace.xml
|
||||||
.idea/shelf
|
.idea/shelf
|
||||||
|
|
||||||
#Test temporary file
|
|
||||||
tests/stub.json
|
|
||||||
|
|
||||||
#Composer
|
#Composer
|
||||||
vendor
|
vendor
|
||||||
composer.lock
|
composer.lock
|
|
@ -2,7 +2,7 @@
|
||||||
<module type="WEB_MODULE" version="4">
|
<module type="WEB_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="StubTests\" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
|
||||||
|
|
|
@ -13,7 +13,6 @@ php:
|
||||||
install:
|
install:
|
||||||
- composer install
|
- composer install
|
||||||
script:
|
script:
|
||||||
- docker-compose -f tests/docker-compose.yml pull
|
- docker-compose -f docker-compose.yml pull
|
||||||
- docker-compose -f tests/docker-compose.yml build
|
- docker-compose -f docker-compose.yml build
|
||||||
- docker-compose -f tests/docker-compose.yml run php > ./tests/stub.json
|
- docker-compose -f docker-compose.yml run php
|
||||||
- phpunit tests/TestStubs.php
|
|
||||||
|
|
|
@ -26,8 +26,7 @@ The set of extensions enabled by default in PhpStorm can change anytime without
|
||||||
|
|
||||||
### How to run tests
|
### How to run tests
|
||||||
1. Execute `composer install`
|
1. Execute `composer install`
|
||||||
2. Execute `docker-compose -f tests/docker-compose.yml run php > tests/stub.json`
|
2. Execute `docker-compose -f docker-compose.yml run php`
|
||||||
3. Run the test `phpunit tests/TestStubs.php`
|
|
||||||
|
|
||||||
### License
|
### License
|
||||||
[Apache 2]
|
[Apache 2]
|
||||||
|
|
|
@ -966,7 +966,8 @@ class SplTempFileObject extends SplFileObject {
|
||||||
* The SplDoublyLinkedList class provides the main functionalities of a doubly linked list.
|
* The SplDoublyLinkedList class provides the main functionalities of a doubly linked list.
|
||||||
* @link https://php.net/manual/en/class.spldoublylinkedlist.php
|
* @link https://php.net/manual/en/class.spldoublylinkedlist.php
|
||||||
*/
|
*/
|
||||||
class SplDoublyLinkedList implements Iterator, Countable, ArrayAccess {
|
class SplDoublyLinkedList implements Iterator, Countable, ArrayAccess, Serializable
|
||||||
|
{
|
||||||
const IT_MODE_LIFO = 2;
|
const IT_MODE_LIFO = 2;
|
||||||
const IT_MODE_FIFO = 0;
|
const IT_MODE_FIFO = 0;
|
||||||
const IT_MODE_DELETE = 1;
|
const IT_MODE_DELETE = 1;
|
||||||
|
|
|
@ -1,21 +1,26 @@
|
||||||
{
|
{
|
||||||
"name": "jetbrains/phpstorm-stubs",
|
"name": "jetbrains/phpstorm-stubs",
|
||||||
"description": "PHP runtime & extensions header files for PhpStorm",
|
"description": "PHP runtime & extensions header files for PhpStorm",
|
||||||
"homepage": "https://www.jetbrains.com/phpstorm",
|
"homepage": "https://www.jetbrains.com/phpstorm",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"JetBrains",
|
"JetBrains",
|
||||||
"PHPStorm",
|
"PHPStorm",
|
||||||
"stubs",
|
"stubs",
|
||||||
"autocomplete",
|
"autocomplete",
|
||||||
"type",
|
"type",
|
||||||
"inference",
|
"inference",
|
||||||
"code",
|
"code",
|
||||||
"inspection"
|
"inspection"
|
||||||
],
|
],
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"nikic/php-parser": "v4.0.1",
|
"nikic/php-parser": "v4.0.1",
|
||||||
"phpdocumentor/reflection-docblock": "^4.3",
|
"phpdocumentor/reflection-docblock": "^4.3",
|
||||||
"phpunit/phpunit": "7.1.4"
|
"phpunit/phpunit": "7.1.4"
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"StubTests\\": "tests/"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,4 +4,4 @@ services:
|
||||||
image: php:7.2
|
image: php:7.2
|
||||||
volumes:
|
volumes:
|
||||||
- .:/opt/project
|
- .:/opt/project
|
||||||
command: php /opt/project/PHPReflectionParser.php
|
command: /opt/project/vendor/bin/phpunit /opt/project/tests/TestStubs.php
|
|
@ -158,7 +158,8 @@ interface SessionUpdateTimestampHandlerInterface {
|
||||||
* @link https://php.net/manual/en/class.reflectionzendextension.php
|
* @link https://php.net/manual/en/class.reflectionzendextension.php
|
||||||
* @since 5.4.0
|
* @since 5.4.0
|
||||||
*/
|
*/
|
||||||
class SessionHandler implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {
|
class SessionHandler implements SessionHandlerInterface, SessionIdInterface
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the session
|
* Close the session
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
abstract class BasePHPClass extends PHPElementWithPHPDoc
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var PHPMethod[]
|
||||||
|
*/
|
||||||
|
public $methods = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var PHPConst[]
|
||||||
|
*/
|
||||||
|
public $constants = [];
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use PhpParser\Node\Stmt\Namespace_;
|
||||||
|
use PhpParser\NodeAbstract;
|
||||||
|
|
||||||
|
abstract class BasePHPElement
|
||||||
|
{
|
||||||
|
public $name;
|
||||||
|
public $parseError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $object
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
abstract public function readObjectFromReflection($object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $node
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
abstract public function readObjectFromStubNode($node);
|
||||||
|
|
||||||
|
protected function getConstantFQN(NodeAbstract $node, string $nodeName): string
|
||||||
|
{
|
||||||
|
$namespace = '';
|
||||||
|
if ($node->getAttribute('parent') instanceof Namespace_ && !empty($node->getAttribute('parent')->name)) {
|
||||||
|
$namespace = '\\' . implode('\\', $node->getAttribute('parent')->name->parts) . '\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $namespace . $nodeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFQN($node): string
|
||||||
|
{
|
||||||
|
$fqn = '';
|
||||||
|
if ($node->namespacedName === null) {
|
||||||
|
$fqn = $node->name->parts[0];
|
||||||
|
} else {
|
||||||
|
/**@var string $part*/
|
||||||
|
foreach ($node->namespacedName->parts as $part) {
|
||||||
|
$fqn .= "$part\\";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtrim($fqn, "\\");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use PhpParser\Node\Stmt\Class_;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionClassConstant;
|
||||||
|
use ReflectionException;
|
||||||
|
use ReflectionMethod;
|
||||||
|
|
||||||
|
class PHPClass extends BasePHPClass
|
||||||
|
{
|
||||||
|
public $parentClass;
|
||||||
|
public $interfaces = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ReflectionClass $clazz
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromReflection($clazz): self
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$reflectionClass = new ReflectionClass($clazz);
|
||||||
|
$this->name = $reflectionClass->getName();
|
||||||
|
$parentClass = $reflectionClass->getParentClass();
|
||||||
|
if ($parentClass !== false) {
|
||||||
|
$this->parentClass = $reflectionClass->getParentClass()->getName();
|
||||||
|
}
|
||||||
|
$this->interfaces = $reflectionClass->getInterfaceNames();
|
||||||
|
|
||||||
|
/**@var ReflectionMethod $method */
|
||||||
|
foreach ($reflectionClass->getMethods() as $method) {
|
||||||
|
if ($method->getDeclaringClass()->getName() !== $this->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->methods[$method->name] = (new PHPMethod())->readObjectFromReflection($method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@var ReflectionClassConstant $constant */
|
||||||
|
foreach ($reflectionClass->getReflectionConstants() as $constant) {
|
||||||
|
if ($constant->getDeclaringClass()->getName() !== $this->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->constants[$constant->name] = (new PHPConst())->readObjectFromReflection($constant);
|
||||||
|
}
|
||||||
|
} catch (ReflectionException $ex) {
|
||||||
|
$this->parseError = $ex;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Class_ $node
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromStubNode($node): self
|
||||||
|
{
|
||||||
|
$this->name = $this->getFQN($node);
|
||||||
|
$this->collectLinks($node);
|
||||||
|
if (!empty($node->extends)) {
|
||||||
|
$this->parentClass = '';
|
||||||
|
foreach ($node->extends->parts as $part) {
|
||||||
|
$this->parentClass .= "\\$part";
|
||||||
|
}
|
||||||
|
$this->parentClass = ltrim($this->parentClass, "\\");
|
||||||
|
}
|
||||||
|
if (!empty($node->implements)) {
|
||||||
|
foreach ($node->implements as $interfaceObject) {
|
||||||
|
$interfaceFQN = '';
|
||||||
|
foreach ($interfaceObject->parts as $interface) {
|
||||||
|
$interfaceFQN .= "\\$interface";
|
||||||
|
}
|
||||||
|
$this->interfaces[] = ltrim($interfaceFQN, "\\");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use PhpParser\Node\Const_;
|
||||||
|
use PhpParser\Node\Stmt\ClassConst;
|
||||||
|
use ReflectionClassConstant;
|
||||||
|
|
||||||
|
class PHPConst extends PHPElementWithPHPDoc
|
||||||
|
{
|
||||||
|
public $parentName;
|
||||||
|
public $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ReflectionClassConstant $constant
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromReflection($constant)
|
||||||
|
{
|
||||||
|
$this->name = $constant->name;
|
||||||
|
$this->value = $constant->getValue();
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Const_ $node
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromStubNode($node)
|
||||||
|
{
|
||||||
|
$this->name = $this->getConstantFQN($node, $node->name->name);
|
||||||
|
$this->value = $this->getConstValue($node);
|
||||||
|
$this->collectLinks($node);
|
||||||
|
if ($node->getAttribute('parent') instanceof ClassConst) {
|
||||||
|
$this->parentName = $this->getFQN($node->getAttribute('parent')->getAttribute('parent'));
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConstValue($node)
|
||||||
|
{
|
||||||
|
if (in_array('value', $node->value->getSubNodeNames(), true)) {
|
||||||
|
return $node->value->value;
|
||||||
|
}
|
||||||
|
if (in_array('expr', $node->value->getSubNodeNames(), true)) {
|
||||||
|
return $node->value->expr->value;
|
||||||
|
}
|
||||||
|
if (in_array('name', $node->value->getSubNodeNames(), true)) {
|
||||||
|
return $node->value->name->parts[0];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use PhpParser\Node\Expr\FuncCall;
|
||||||
|
|
||||||
|
class PHPDefineConstant extends PHPConst
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param array $constant
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromReflection($constant)
|
||||||
|
{
|
||||||
|
$this->name = utf8_encode($constant[0]);
|
||||||
|
$this->value = is_resource($constant[1]) ? 'PHPSTORM_RESOURCE' : utf8_encode($constant[1]);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param FuncCall $node
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromStubNode($node)
|
||||||
|
{
|
||||||
|
$constName = $this->getConstantFQN($node, $node->args[0]->value->value);
|
||||||
|
if (in_array($constName, ['null', 'true', 'false'])) {
|
||||||
|
$constName = strtoupper($constName);
|
||||||
|
}
|
||||||
|
$this->name = $constName;
|
||||||
|
$this->value = $this->getConstValue($node->args[1]);
|
||||||
|
$this->collectLinks($node);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use phpDocumentor\Reflection\DocBlock\Tag;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use StubTests\Parsers\DocFactoryProvider;
|
||||||
|
|
||||||
|
abstract class PHPElementWithPHPDoc extends BasePHPElement
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Tag[]
|
||||||
|
*/
|
||||||
|
public $links = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Tag[]
|
||||||
|
*/
|
||||||
|
public $see = [];
|
||||||
|
|
||||||
|
protected function collectLinks(Node $node): void
|
||||||
|
{
|
||||||
|
if ($node->getDocComment() !== null) {
|
||||||
|
try {
|
||||||
|
$phpDoc = DocFactoryProvider::getDocFactory()->create($node->getDocComment()->getText());
|
||||||
|
$this->links = $phpDoc->getTagsByName('link');
|
||||||
|
$this->see = $phpDoc->getTagsByName('see');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->parseError = $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
|
||||||
|
use phpDocumentor\Reflection\Type;
|
||||||
|
use PhpParser\Node\FunctionLike;
|
||||||
|
use PhpParser\Node\Stmt\Function_;
|
||||||
|
use ReflectionException;
|
||||||
|
use ReflectionFunction;
|
||||||
|
use ReflectionParameter;
|
||||||
|
use StubTests\Parsers\DocFactoryProvider;
|
||||||
|
|
||||||
|
class PHPFunction extends PHPElementWithPHPDoc
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var boolean $is_deprecated
|
||||||
|
*/
|
||||||
|
public $is_deprecated;
|
||||||
|
/**
|
||||||
|
* @var PHPParameter[]
|
||||||
|
*/
|
||||||
|
public $parameters = [];
|
||||||
|
/**
|
||||||
|
* @var Type $returnTag
|
||||||
|
*/
|
||||||
|
public $returnTag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ReflectionFunction $function
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromReflection($function)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$reflectionFunction = new ReflectionFunction($function);
|
||||||
|
$this->name = $reflectionFunction->name;
|
||||||
|
$this->is_deprecated = $reflectionFunction->isDeprecated();
|
||||||
|
/**@var ReflectionParameter $parameter */
|
||||||
|
foreach ($reflectionFunction->getParameters() as $parameter) {
|
||||||
|
$this->parameters[] = (new PHPParameter())->readObjectFromReflection($parameter);
|
||||||
|
}
|
||||||
|
} catch (ReflectionException $ex) {
|
||||||
|
$this->parseError = $ex;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Function_ $node
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromStubNode($node)
|
||||||
|
{
|
||||||
|
$functionName = $this->getFQN($node);
|
||||||
|
$this->name = $functionName;
|
||||||
|
|
||||||
|
foreach ($node->getParams() as $parameter) {
|
||||||
|
$this->parameters[] = (new PHPParameter())->readObjectFromStubNode($parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->collectLinks($node);
|
||||||
|
$this->checkDeprecationTag($node);
|
||||||
|
$this->checkReturnTag($node);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkDeprecationTag(FunctionLike $node): void
|
||||||
|
{
|
||||||
|
if ($node->getDocComment() !== null) {
|
||||||
|
try {
|
||||||
|
$phpDoc = DocFactoryProvider::getDocFactory()->create($node->getDocComment()->getText());
|
||||||
|
if (empty($phpDoc->getTagsByName('deprecated'))) {
|
||||||
|
$this->is_deprecated = false;
|
||||||
|
} else {
|
||||||
|
$this->is_deprecated = true;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->parseError = $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkReturnTag(FunctionLike $node): void
|
||||||
|
{
|
||||||
|
if ($node->getDocComment() !== null) {
|
||||||
|
try {
|
||||||
|
$phpDoc = DocFactoryProvider::getDocFactory()->create($node->getDocComment()->getText());
|
||||||
|
$parsedReturnTag = $phpDoc->getTagsByName('return');
|
||||||
|
if (!empty($parsedReturnTag) && $parsedReturnTag[0] instanceof Return_) {
|
||||||
|
$this->returnTag = $parsedReturnTag[0]->getType() . '';
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->parseError = $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use PhpParser\Node\Stmt\Interface_;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionClassConstant;
|
||||||
|
use ReflectionException;
|
||||||
|
use ReflectionMethod;
|
||||||
|
|
||||||
|
class PHPInterface extends BasePHPClass
|
||||||
|
{
|
||||||
|
public $parentInterfaces = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ReflectionClass $interface
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromReflection($interface): self
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$reflectionInterface = new ReflectionClass($interface);
|
||||||
|
$this->name = $reflectionInterface->getName();
|
||||||
|
/**@var ReflectionMethod $method */
|
||||||
|
foreach ($reflectionInterface->getMethods() as $method) {
|
||||||
|
if ($method->getDeclaringClass()->getName() !== $this->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->methods[$method->name] = (new PHPMethod())->readObjectFromReflection($method);
|
||||||
|
}
|
||||||
|
$this->parentInterfaces = $reflectionInterface->getInterfaceNames();
|
||||||
|
/**@var ReflectionClassConstant $constant */
|
||||||
|
foreach ($reflectionInterface->getReflectionConstants() as $constant) {
|
||||||
|
if ($constant->getDeclaringClass()->getName() !== $this->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->constants[$constant->name] = (new PHPConst())->readObjectFromReflection($constant);
|
||||||
|
}
|
||||||
|
} catch (ReflectionException $ex) {
|
||||||
|
$this->parseError = $ex;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Interface_ $node
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromStubNode($node): self
|
||||||
|
{
|
||||||
|
$this->name = $this->getFQN($node);
|
||||||
|
$this->collectLinks($node);
|
||||||
|
if (!empty($node->extends)) {
|
||||||
|
foreach ($node->extends[0]->parts as $part) {
|
||||||
|
$this->parentInterfaces[] = $part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use PhpParser\Node\Stmt\ClassMethod;
|
||||||
|
use ReflectionParameter;
|
||||||
|
|
||||||
|
class PHPMethod extends PHPFunction
|
||||||
|
{
|
||||||
|
public $access;
|
||||||
|
public $is_static;
|
||||||
|
public $is_final;
|
||||||
|
public $parentName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \ReflectionMethod $method
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromReflection($method)
|
||||||
|
{
|
||||||
|
$this->name = $method->name;
|
||||||
|
$this->is_static = $method->isStatic();
|
||||||
|
$this->is_final = $method->isFinal();
|
||||||
|
/**@var ReflectionParameter $parameter */
|
||||||
|
foreach ($method->getParameters() as $parameter) {
|
||||||
|
$this->parameters[] = (new PHPParameter())->readObjectFromReflection($parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($method->isProtected()) {
|
||||||
|
$access = 'protected';
|
||||||
|
} elseif ($method->isPrivate()) {
|
||||||
|
$access = 'private';
|
||||||
|
} else {
|
||||||
|
$access = 'public';
|
||||||
|
}
|
||||||
|
$this->access = $access;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ClassMethod $node
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromStubNode($node)
|
||||||
|
{
|
||||||
|
$this->parentName = $this->getFQN($node->getAttribute('parent'));
|
||||||
|
$this->name = $node->name->name;
|
||||||
|
|
||||||
|
$this->collectLinks($node);
|
||||||
|
$this->checkDeprecationTag($node);
|
||||||
|
$this->checkReturnTag($node);
|
||||||
|
|
||||||
|
if (strncmp($this->name, 'PS_UNRESERVE_PREFIX_', 20) === 0) {
|
||||||
|
$this->name = substr($this->name, strlen('PS_UNRESERVE_PREFIX_'));
|
||||||
|
}
|
||||||
|
foreach ($node->getParams() as $parameter) {
|
||||||
|
$this->parameters[] = (new PHPParameter())->readObjectFromStubNode($parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->is_final = $node->isFinal();
|
||||||
|
$this->is_static = $node->isStatic();
|
||||||
|
if ($node->isPrivate()) {
|
||||||
|
$this->access = 'private';
|
||||||
|
} elseif ($node->isProtected()) {
|
||||||
|
$this->access = 'protected';
|
||||||
|
} else {
|
||||||
|
$this->access = 'public';
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Model;
|
||||||
|
|
||||||
|
use PhpParser\Node\Param;
|
||||||
|
use ReflectionParameter;
|
||||||
|
|
||||||
|
class PHPParameter extends BasePHPElement
|
||||||
|
{
|
||||||
|
public $type = '';
|
||||||
|
public $is_vararg;
|
||||||
|
public $is_passed_by_ref;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ReflectionParameter $parameter
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromReflection($parameter): self
|
||||||
|
{
|
||||||
|
$this->name = $parameter->name;
|
||||||
|
if (!empty($parameter->getType())) {
|
||||||
|
$this->type = $parameter->getType()->getName();
|
||||||
|
}
|
||||||
|
$this->is_vararg = $parameter->isVariadic();
|
||||||
|
$this->is_passed_by_ref = $parameter->isPassedByReference();
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Param $node
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function readObjectFromStubNode($node): self
|
||||||
|
{
|
||||||
|
$this->name = $node->var->name;
|
||||||
|
if ($node->type !== null) {
|
||||||
|
if (empty($node->type->name)) {
|
||||||
|
if (!empty($node->type->parts)) {
|
||||||
|
$this->type = $node->type->parts[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->type = $node->type->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->is_vararg = $node->variadic;
|
||||||
|
$this->is_passed_by_ref = $node->byRef;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,171 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
$constants = [];
|
|
||||||
foreach (get_defined_constants() as $name => $value) {
|
|
||||||
$constants[] = (new PHPConst())->serialize($name, $value);
|
|
||||||
}
|
|
||||||
$data['constants'] = $constants;
|
|
||||||
|
|
||||||
$functions = [];
|
|
||||||
foreach (get_defined_functions()['internal'] as $name) {
|
|
||||||
$functions[] = (new PHPFunction())->serialize(new ReflectionFunction($name));
|
|
||||||
}
|
|
||||||
$data['functions'] = $functions;
|
|
||||||
|
|
||||||
$classes = [];
|
|
||||||
foreach (get_declared_classes() as $class) {
|
|
||||||
$classes[] = (new PHPClass())->serialize(new ReflectionClass($class));
|
|
||||||
}
|
|
||||||
$data['classes'] = $classes;
|
|
||||||
|
|
||||||
$interfaces = [];
|
|
||||||
foreach (get_declared_interfaces() as $interface) {
|
|
||||||
$interfaces[] = (new PHPInterface())->serialize(new ReflectionClass($interface));
|
|
||||||
}
|
|
||||||
$data['interfaces'] = $interfaces;
|
|
||||||
|
|
||||||
$json = json_encode($data, JSON_NUMERIC_CHECK);
|
|
||||||
echo $json;
|
|
||||||
|
|
||||||
|
|
||||||
class PHPClass
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $methods = [];
|
|
||||||
public $constants = [];
|
|
||||||
public $parentClass;
|
|
||||||
public $interfaces = [];
|
|
||||||
|
|
||||||
public function serialize(ReflectionClass $reflectionClass): array
|
|
||||||
{
|
|
||||||
$this->name = $reflectionClass->getName();
|
|
||||||
$parentClass = $reflectionClass->getParentClass();
|
|
||||||
if (false !== $parentClass) {
|
|
||||||
$this->parentClass = $reflectionClass->getParentClass()->getName();
|
|
||||||
}
|
|
||||||
$this->interfaces = $reflectionClass->getInterfaceNames();
|
|
||||||
foreach ($reflectionClass->getMethods() as $method) {
|
|
||||||
if ($method->getDeclaringClass()->getName() !== $this->name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->methods[$method->name] = (new PHPMethod())->serialize($method);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($reflectionClass->getReflectionConstants() as $constant) {
|
|
||||||
if ($constant->getDeclaringClass()->getName() !== $this->name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->constants[$constant->name] = (new PHPConst())->serialize($constant->name, $constant->getValue());
|
|
||||||
}
|
|
||||||
return (array)$this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class PHPConst
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $value;
|
|
||||||
|
|
||||||
public function serialize($name, $value): array
|
|
||||||
{
|
|
||||||
$this->name = utf8_encode($name);
|
|
||||||
$this->value = is_resource($value) ? 'PHPSTORM_RESOURCE' : utf8_encode($value);
|
|
||||||
return (array)$this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PHPFunction
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $is_deprecated;
|
|
||||||
public $parameters = [];
|
|
||||||
|
|
||||||
public function serialize(ReflectionFunction $reflectionFunction): array
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->name = $reflectionFunction->name;
|
|
||||||
$this->is_deprecated = $reflectionFunction->isDeprecated();
|
|
||||||
foreach ($reflectionFunction->getParameters() as $parameter) {
|
|
||||||
$this->parameters[] = (new PHPParameter())->serialize($parameter);
|
|
||||||
}
|
|
||||||
return (array)$this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class PHPMethod
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $is_static;
|
|
||||||
public $access;
|
|
||||||
public $is_final;
|
|
||||||
public $parameters = [];
|
|
||||||
|
|
||||||
public function serialize(ReflectionMethod $method): array
|
|
||||||
{
|
|
||||||
$this->name = $method->name;
|
|
||||||
$this->is_static = $method->isStatic();
|
|
||||||
$this->is_final = $method->isFinal();
|
|
||||||
foreach ($method->getParameters() as $parameter) {
|
|
||||||
$this->parameters[] = (new PHPParameter())->serialize($parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($method->isProtected()) {
|
|
||||||
$access = 'protected';
|
|
||||||
} else if ($method->isPrivate()) {
|
|
||||||
$access = 'private';
|
|
||||||
} else {
|
|
||||||
$access = 'public';
|
|
||||||
}
|
|
||||||
$this->access = $access;
|
|
||||||
return (array)$this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class PHPParameter
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $type = '';
|
|
||||||
public $is_vararg;
|
|
||||||
public $is_passed_by_ref;
|
|
||||||
|
|
||||||
public function serialize(ReflectionParameter $parameter): array
|
|
||||||
{
|
|
||||||
$this->name = $parameter->name;
|
|
||||||
if (!empty($parameter->getType())) {
|
|
||||||
$this->type = $parameter->getType()->getName();
|
|
||||||
}
|
|
||||||
$this->is_vararg = $parameter->isVariadic();
|
|
||||||
$this->is_passed_by_ref = $parameter->isPassedByReference();
|
|
||||||
return (array)$this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PHPInterface
|
|
||||||
{
|
|
||||||
public $name;
|
|
||||||
public $methods = [];
|
|
||||||
public $constants = [];
|
|
||||||
public $parentInterfaces = [];
|
|
||||||
|
|
||||||
public function serialize(ReflectionClass $reflectionClass): array
|
|
||||||
{
|
|
||||||
$this->name = $reflectionClass->getName();
|
|
||||||
foreach ($reflectionClass->getMethods() as $method) {
|
|
||||||
if ($method->getDeclaringClass()->getName() !== $this->name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->methods[$method->name] = (new PHPMethod())->serialize($method);
|
|
||||||
}
|
|
||||||
$this->parentInterfaces = $reflectionClass->getInterfaceNames();
|
|
||||||
foreach ($reflectionClass->getReflectionConstants() as $constant) {
|
|
||||||
if ($constant->getDeclaringClass()->getName() !== $this->name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->constants[$constant->name] = (new PHPConst())->serialize($constant->name, $constant->getValue());
|
|
||||||
}
|
|
||||||
return (array)$this;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Parsers;
|
||||||
|
|
||||||
|
use phpDocumentor\Reflection\DocBlockFactory;
|
||||||
|
|
||||||
|
class DocFactoryProvider
|
||||||
|
{
|
||||||
|
private static $docFactory;
|
||||||
|
|
||||||
|
public static function getDocFactory(): DocBlockFactory
|
||||||
|
{
|
||||||
|
if (self::$docFactory === null) {
|
||||||
|
self::$docFactory = DocBlockFactory::createInstance();
|
||||||
|
}
|
||||||
|
return self::$docFactory;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Parsers;
|
||||||
|
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionFunction;
|
||||||
|
use StubTests\Model\PHPClass;
|
||||||
|
use StubTests\Model\PHPConst;
|
||||||
|
use StubTests\Model\PHPDefineConstant;
|
||||||
|
use StubTests\Model\PHPFunction;
|
||||||
|
use StubTests\Model\PHPInterface;
|
||||||
|
|
||||||
|
class PHPReflectionParser
|
||||||
|
{
|
||||||
|
|
||||||
|
public static function getStubs(): array
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$const_groups = get_defined_constants(true);
|
||||||
|
unset($const_groups['user']);
|
||||||
|
$const_groups = Utils::flattenArray($const_groups, true);
|
||||||
|
$data[PHPConst::class] = [];
|
||||||
|
foreach ($const_groups as $name => $value) {
|
||||||
|
$data[PHPConst::class][] = (new PHPDefineConstant())->readObjectFromReflection([$name, $value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[PHPFunction::class] = [];
|
||||||
|
/**@var ReflectionFunction $function */
|
||||||
|
foreach (get_defined_functions()['internal'] as $function) {
|
||||||
|
$data[PHPFunction::class][] = (new PHPFunction())->readObjectFromReflection($function);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[PHPClass::class] = [];
|
||||||
|
$cl = get_declared_classes();
|
||||||
|
foreach ($cl as $clazz) {
|
||||||
|
$reflectionClass = new ReflectionClass($clazz);
|
||||||
|
if ($reflectionClass->isInternal()) {
|
||||||
|
$data[PHPClass::class][] = (new PHPClass())->readObjectFromReflection($clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[PHPInterface::class] = [];
|
||||||
|
/**@var ReflectionClass $interface */
|
||||||
|
foreach (get_declared_interfaces() as $interface) {
|
||||||
|
$reflectionInterface = new ReflectionClass($interface);
|
||||||
|
if ($reflectionInterface->isInternal()) {
|
||||||
|
$data[PHPInterface::class][] = (new PHPInterface())->readObjectFromReflection($interface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace StubTests\Parsers;
|
||||||
|
|
||||||
|
use FilesystemIterator;
|
||||||
|
use PhpParser\NodeTraverser;
|
||||||
|
use PhpParser\NodeVisitor\NameResolver;
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
use SplFileInfo;
|
||||||
|
use StubTests\Model\PHPClass;
|
||||||
|
use StubTests\Model\PHPInterface;
|
||||||
|
use StubTests\Parsers\Visitors\ASTVisitor;
|
||||||
|
use StubTests\Parsers\Visitors\ParentConnector;
|
||||||
|
|
||||||
|
class StubParser
|
||||||
|
{
|
||||||
|
public static function getPhpStormStubs(): array
|
||||||
|
{
|
||||||
|
/** @noinspection PhpUnhandledExceptionInspection */
|
||||||
|
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||||
|
$nameResolver = new NameResolver;
|
||||||
|
|
||||||
|
$stubs = [];
|
||||||
|
$visitor = new ASTVisitor($stubs);
|
||||||
|
|
||||||
|
$stubsIterator =
|
||||||
|
new RecursiveIteratorIterator(
|
||||||
|
new RecursiveDirectoryIterator(__DIR__ . '/../../', FilesystemIterator::SKIP_DOTS)
|
||||||
|
);
|
||||||
|
/** @var SplFileInfo $file */
|
||||||
|
foreach ($stubsIterator as $file) {
|
||||||
|
if (strpos($file->getRealPath(), 'vendor') || strpos($file->getRealPath(), '.git') ||
|
||||||
|
strpos($file->getRealPath(), 'tests') || strpos($file->getRealPath(), '.idea')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$code = file_get_contents($file->getRealPath());
|
||||||
|
$traverser = new NodeTraverser();
|
||||||
|
$traverser->addVisitor(new ParentConnector());
|
||||||
|
$traverser->addVisitor($nameResolver);
|
||||||
|
$traverser->addVisitor($visitor);
|
||||||
|
$traverser->traverse($parser->parse($code, new StubsParserErrorHandler()));
|
||||||
|
}
|
||||||
|
/**@var PHPInterface $interface */
|
||||||
|
foreach ($stubs[PHPInterface::class] as $interface) {
|
||||||
|
$stubs[PHPInterface::class][$interface->name]->parentInterfaces = $visitor->combineParentInterfaces($interface);
|
||||||
|
}
|
||||||
|
/**@var PHPClass $class */
|
||||||
|
foreach ($stubs[PHPClass::class] as $class) {
|
||||||
|
$stubs[PHPClass::class][$class->name]->interfaces = Utils::flattenArray($visitor->combineImplementedInterfaces($class), false);
|
||||||
|
}
|
||||||
|
return $stubs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Parsers;
|
||||||
|
|
||||||
|
use PhpParser\Error;
|
||||||
|
use PhpParser\ErrorHandler;
|
||||||
|
|
||||||
|
class StubsParserErrorHandler implements ErrorHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an error generated during lexing, parsing or some other operation.
|
||||||
|
*
|
||||||
|
* @param Error $error The error that needs to be handled
|
||||||
|
*/
|
||||||
|
public function handleError(Error $error): void
|
||||||
|
{
|
||||||
|
$error->setRawMessage($error->getRawMessage() . "\n" . $error->getFile());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace StubTests\Parsers;
|
||||||
|
|
||||||
|
use RecursiveArrayIterator;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
|
||||||
|
class Utils
|
||||||
|
{
|
||||||
|
public static function flattenArray(array $arr, bool $group)
|
||||||
|
{
|
||||||
|
return iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)), $group);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Parsers\Visitors;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Const_;
|
||||||
|
use PhpParser\Node\Expr\FuncCall;
|
||||||
|
use PhpParser\Node\Stmt\Class_;
|
||||||
|
use PhpParser\Node\Stmt\ClassMethod;
|
||||||
|
use PhpParser\Node\Stmt\Function_;
|
||||||
|
use PhpParser\Node\Stmt\Interface_;
|
||||||
|
use PhpParser\NodeVisitorAbstract;
|
||||||
|
use StubTests\Model\PHPClass;
|
||||||
|
use StubTests\Model\PHPConst;
|
||||||
|
use StubTests\Model\PHPDefineConstant;
|
||||||
|
use StubTests\Model\PHPFunction;
|
||||||
|
use StubTests\Model\PHPInterface;
|
||||||
|
use StubTests\Model\PHPMethod;
|
||||||
|
use StubTests\Parsers\Utils;
|
||||||
|
use function key_exists;
|
||||||
|
|
||||||
|
class ASTVisitor extends NodeVisitorAbstract
|
||||||
|
{
|
||||||
|
public $stubs;
|
||||||
|
|
||||||
|
public function __construct(array &$stubs)
|
||||||
|
{
|
||||||
|
$this->stubs = &$stubs;
|
||||||
|
$this->stubs[PHPFunction::class] = [];
|
||||||
|
$this->stubs[PHPConst::class] = [];
|
||||||
|
$this->stubs[PHPClass::class] = [];
|
||||||
|
$this->stubs[PHPInterface::class] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enterNode(Node $node)
|
||||||
|
{
|
||||||
|
if ($node instanceof Function_) {
|
||||||
|
$function = (new PHPFunction())->readObjectFromStubNode($node);
|
||||||
|
$this->stubs[PHPFunction::class][$function->name] = $function;
|
||||||
|
} elseif ($node instanceof Const_) {
|
||||||
|
$constant = (new PHPConst())->readObjectFromStubNode($node);
|
||||||
|
if ($constant->parentName === null) {
|
||||||
|
$this->stubs[PHPConst::class][$constant->name] = $constant;
|
||||||
|
} elseif (array_key_exists($constant->parentName, $this->stubs[PHPClass::class])) {
|
||||||
|
$this->stubs[PHPClass::class][$constant->parentName]->constants[$constant->name] = $constant;
|
||||||
|
} else {
|
||||||
|
$this->stubs[PHPInterface::class][$constant->parentName]->constants[$constant->name] = $constant;
|
||||||
|
}
|
||||||
|
} elseif ($node instanceof FuncCall) {
|
||||||
|
if ($node->name->parts[0] === 'define') {
|
||||||
|
$constant = (new PHPDefineConstant())->readObjectFromStubNode($node);
|
||||||
|
$this->stubs[PHPConst::class][$constant->name] = $constant;
|
||||||
|
}
|
||||||
|
} elseif ($node instanceof ClassMethod) {
|
||||||
|
$method = (new PHPMethod())->readObjectFromStubNode($node);
|
||||||
|
if (array_key_exists($method->parentName, $this->stubs[PHPClass::class])) {
|
||||||
|
$this->stubs[PHPClass::class][$method->parentName]->methods[$method->name] = $method;
|
||||||
|
} else {
|
||||||
|
$this->stubs[PHPInterface::class][$method->parentName]->methods[$method->name] = $method;
|
||||||
|
}
|
||||||
|
} elseif ($node instanceof Interface_) {
|
||||||
|
$interface = (new PHPInterface())->readObjectFromStubNode($node);
|
||||||
|
$this->stubs[PHPInterface::class][$interface->name] = $interface;
|
||||||
|
} elseif ($node instanceof Class_) {
|
||||||
|
$class = (new PHPClass())->readObjectFromStubNode($node);
|
||||||
|
$this->stubs[PHPClass::class][$class->name] = $class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function combineParentInterfaces($interface): array
|
||||||
|
{
|
||||||
|
$parents = [];
|
||||||
|
if (empty($interface->parentInterfaces)) {
|
||||||
|
return $parents;
|
||||||
|
}
|
||||||
|
/**@var PHPInterface $parentInterface */
|
||||||
|
foreach ($interface->parentInterfaces as $parentInterface) {
|
||||||
|
$parents[] = $parentInterface;
|
||||||
|
if (key_exists($parentInterface, $this->stubs[PHPInterface::class])) {
|
||||||
|
/**@var PHPInterface $parentInterface */
|
||||||
|
foreach ($this->combineParentInterfaces($this->stubs[PHPInterface::class][$parentInterface]) as $value) {
|
||||||
|
$parents[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $parents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function combineImplementedInterfaces($class): array
|
||||||
|
{
|
||||||
|
$interfaces = [];
|
||||||
|
/**@var PHPInterface $interface */
|
||||||
|
foreach ($class->interfaces as $interface) {
|
||||||
|
$interfaces[] = $interface;
|
||||||
|
if (key_exists($interface, $this->stubs[PHPInterface::class])) {
|
||||||
|
$interfaces[] = $this->stubs[PHPInterface::class][$interface]->parentInterfaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($class->parentClass === null) {
|
||||||
|
return $interfaces;
|
||||||
|
}
|
||||||
|
if (key_exists($class->parentClass, $this->stubs[PHPClass::class])
|
||||||
|
&& $this->stubs[PHPClass::class][$class->parentClass] !== null
|
||||||
|
) {
|
||||||
|
$inherited = $this->combineImplementedInterfaces($this->stubs[PHPClass::class][$class->parentClass]);
|
||||||
|
$interfaces[] = Utils::flattenArray($inherited, false);
|
||||||
|
}
|
||||||
|
return $interfaces;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\Parsers\Visitors;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\NodeVisitorAbstract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The visitor is required to provide "parent" attribute to nodes
|
||||||
|
*/
|
||||||
|
class ParentConnector extends NodeVisitorAbstract
|
||||||
|
{
|
||||||
|
private $stack;
|
||||||
|
|
||||||
|
public function beforeTraverse(array $nodes)
|
||||||
|
{
|
||||||
|
$this->stack = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enterNode(Node $node)
|
||||||
|
{
|
||||||
|
if (!empty($this->stack)) {
|
||||||
|
$node->setAttribute('parent', $this->stack[count($this->stack) - 1]);
|
||||||
|
}
|
||||||
|
$this->stack[] = $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function leaveNode(Node $node)
|
||||||
|
{
|
||||||
|
array_pop($this->stack);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,350 +0,0 @@
|
||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
require __DIR__ . '/../vendor/autoload.php';
|
|
||||||
|
|
||||||
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
|
|
||||||
use phpDocumentor\Reflection\DocBlockFactory;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\{Const_,
|
|
||||||
Expr\FuncCall,
|
|
||||||
FunctionLike,
|
|
||||||
Stmt\Class_,
|
|
||||||
Stmt\ClassMethod,
|
|
||||||
Stmt\Function_,
|
|
||||||
Stmt\Interface_,
|
|
||||||
Stmt\Namespace_};
|
|
||||||
use PhpParser\NodeAbstract;
|
|
||||||
use PhpParser\NodeTraverser;
|
|
||||||
use PhpParser\NodeVisitorAbstract;
|
|
||||||
use PhpParser\ParserFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The visitor is required to provide "parent" attribute to nodes
|
|
||||||
*/
|
|
||||||
class ParentConnector extends NodeVisitorAbstract
|
|
||||||
{
|
|
||||||
private $stack;
|
|
||||||
|
|
||||||
public function beforeTraverse(array $nodes)
|
|
||||||
{
|
|
||||||
$this->stack = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function enterNode(Node $node)
|
|
||||||
{
|
|
||||||
if (!empty($this->stack)) {
|
|
||||||
$node->setAttribute('parent', $this->stack[count($this->stack) - 1]);
|
|
||||||
}
|
|
||||||
$this->stack[] = $node;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function leaveNode(Node $node)
|
|
||||||
{
|
|
||||||
array_pop($this->stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ASTVisitor extends NodeVisitorAbstract
|
|
||||||
{
|
|
||||||
private $docFactory;
|
|
||||||
private $stubs;
|
|
||||||
|
|
||||||
public function __construct(DocBlockFactory $docFactory, stdClass $stubs)
|
|
||||||
{
|
|
||||||
$this->docFactory = $docFactory;
|
|
||||||
$this->stubs = $stubs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function enterNode(Node $node)
|
|
||||||
{
|
|
||||||
if ($node instanceof Function_) {
|
|
||||||
$this->visitFunction($node);
|
|
||||||
} elseif ($node instanceof Const_) {
|
|
||||||
$this->visitConstant($node);
|
|
||||||
} elseif ($node instanceof FuncCall) {
|
|
||||||
$this->visitDefine($node);
|
|
||||||
} elseif ($node instanceof ClassMethod) {
|
|
||||||
$this->visitMethod($node);
|
|
||||||
} elseif ($node instanceof Interface_) {
|
|
||||||
$this->visitInterface($node);
|
|
||||||
} elseif ($node instanceof Class_) {
|
|
||||||
$this->visitClass($node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function visitFunction(Function_ $node): void
|
|
||||||
{
|
|
||||||
$function = new stdClass();
|
|
||||||
$functionName = $this->getFQN($node, $node->name->name);
|
|
||||||
$function->name = $functionName;
|
|
||||||
|
|
||||||
$function->parameters = $this->parseParams($node);
|
|
||||||
|
|
||||||
$function->parseError = null;
|
|
||||||
$this->collectLinks($node, $function);
|
|
||||||
if ($node->getDocComment() !== null) {
|
|
||||||
try {
|
|
||||||
$phpDoc = $this->docFactory->create($node->getDocComment()->getText());
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$function->parseError = $e->getMessage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (empty($phpDoc->getTagsByName('deprecated'))) {
|
|
||||||
$function->is_deprecated = false;
|
|
||||||
} else {
|
|
||||||
$function->is_deprecated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->stubs->functions[$functionName] = $function;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function visitConstant(Const_ $node): void
|
|
||||||
{
|
|
||||||
$const = new stdClass();
|
|
||||||
$constName = $this->getFQN($node, $node->name->name);
|
|
||||||
$const->name = $constName;
|
|
||||||
$const->value = $this->getConstValue($node);
|
|
||||||
$const->parseError = null;
|
|
||||||
$this->collectLinks($node, $const);
|
|
||||||
if ($node->getAttribute('parent') instanceof Node\Stmt\ClassConst) {
|
|
||||||
$parentName = $this->getFQN($node->getAttribute('parent')->getAttribute('parent'),
|
|
||||||
$node->getAttribute('parent')->getAttribute('parent')->name->name);
|
|
||||||
if (array_key_exists($parentName, $this->stubs->classes)) {
|
|
||||||
$this->stubs->classes[$parentName]->constants[$constName] = $const;
|
|
||||||
} else {
|
|
||||||
$this->stubs->interfaces[$parentName]->constants[$constName] = $const;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->stubs->constants[$constName] = $const;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function visitDefine(FuncCall $node): void
|
|
||||||
{
|
|
||||||
if ($node->name->parts[0] === 'define') {
|
|
||||||
$constName = $this->getFQN($node, $node->args[0]->value->value);
|
|
||||||
$const = new stdClass();
|
|
||||||
if (in_array($constName, ['null', 'true', 'false'])) {
|
|
||||||
$constName = strtoupper($constName);
|
|
||||||
}
|
|
||||||
$const->name = $constName;
|
|
||||||
$const->value = $this->getConstValue($node->args[1]);
|
|
||||||
$const->parseError = null;
|
|
||||||
$this->collectLinks($node, $const);
|
|
||||||
$this->stubs->constants[$constName] = $const;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function collectLinks(NodeAbstract $node, stdClass $stub){
|
|
||||||
$stub->links = [];
|
|
||||||
$stub->see = [];
|
|
||||||
if ($node->getDocComment() !== null) {
|
|
||||||
try {
|
|
||||||
$phpDoc = $this->docFactory->create($node->getDocComment()->getText());
|
|
||||||
$stub->links = $phpDoc->getTagsByName('link');
|
|
||||||
$stub->see = $phpDoc->getTagsByName('see');
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$stub->parseError = $e->getMessage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getConstValue($node)
|
|
||||||
{
|
|
||||||
if (in_array('value', $node->value->getSubNodeNames(), true)) {
|
|
||||||
return $node->value->value;
|
|
||||||
}
|
|
||||||
if (in_array('expr', $node->value->getSubNodeNames(), true)) {
|
|
||||||
return $node->value->expr->value;
|
|
||||||
}
|
|
||||||
if (in_array('name', $node->value->getSubNodeNames(), true)) {
|
|
||||||
return $node->value->name->parts[0];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function visitMethod(ClassMethod $node): void
|
|
||||||
{
|
|
||||||
$parentName = $this->getFQN($node->getAttribute('parent'), $node->getAttribute('parent')->name->name);
|
|
||||||
$method = new stdClass();
|
|
||||||
$method->name = $node->name->name;
|
|
||||||
|
|
||||||
//this will test PHPDocs
|
|
||||||
$method->parseError = null;
|
|
||||||
$method->returnTag = null;
|
|
||||||
$this->collectLinks($node, $method);
|
|
||||||
if ($node->getDocComment() !== null) {
|
|
||||||
try {
|
|
||||||
$phpDoc = $this->docFactory->create($node->getDocComment()->getText());
|
|
||||||
$parsedReturnTag = $phpDoc->getTagsByName('return');
|
|
||||||
if(!empty($parsedReturnTag) && $parsedReturnTag[0] instanceof Return_){
|
|
||||||
$method->returnTag = $parsedReturnTag[0]->getType() . "";
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$method->parseError = $e->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strncmp($method->name, 'PS_UNRESERVE_PREFIX_', 20) === 0) {
|
|
||||||
$method->name = substr($method->name, strlen('PS_UNRESERVE_PREFIX_'));
|
|
||||||
}
|
|
||||||
$method->parameters = $this->parseParams($node);
|
|
||||||
$method->is_final = $node->isFinal();
|
|
||||||
$method->is_static = $node->isStatic();
|
|
||||||
if ($node->isPrivate()) {
|
|
||||||
$method->access = 'private';
|
|
||||||
} elseif ($node->isProtected()) {
|
|
||||||
$method->access = 'protected';
|
|
||||||
} else {
|
|
||||||
$method->access = 'public';
|
|
||||||
}
|
|
||||||
if (array_key_exists($parentName, $this->stubs->classes)) {
|
|
||||||
$this->stubs->classes[$parentName]->methods[$method->name] = $method;
|
|
||||||
} else {
|
|
||||||
$this->stubs->interfaces[$parentName]->methods[$method->name] = $method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function visitClass(Class_ $node): void
|
|
||||||
{
|
|
||||||
$class = new stdClass();
|
|
||||||
$className = $this->getFQN($node, $node->name->name);
|
|
||||||
//this will test PHPDocs
|
|
||||||
$class->parseError = null;
|
|
||||||
$this->collectLinks($node, $class);
|
|
||||||
if ($node->getDocComment() !== null) {
|
|
||||||
try {
|
|
||||||
$this->docFactory->create($node->getDocComment()->getText());
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$class->parseError = $e->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$class->name = $className;
|
|
||||||
if (empty($node->extends)) {
|
|
||||||
$class->parentClass = null;
|
|
||||||
} else {
|
|
||||||
$class->parentClass = $this->getFQN($node, $node->extends->parts[0]);
|
|
||||||
}
|
|
||||||
$class->interfaces = $node->implements;
|
|
||||||
$this->stubs->classes[$className] = $class;
|
|
||||||
$this->stubs->classes[$className]->constants = [];
|
|
||||||
$this->stubs->classes[$className]->methods = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function visitInterface(Interface_ $node): void
|
|
||||||
{
|
|
||||||
$interface = new stdClass();
|
|
||||||
$interfaceName = $this->getFQN($node, $node->name->name);
|
|
||||||
//this will test PHPDocs
|
|
||||||
$interface->parseError = null;
|
|
||||||
$this->collectLinks($node, $interface);
|
|
||||||
if ($node->getDocComment() !== null) {
|
|
||||||
try {
|
|
||||||
$this->docFactory->create($node->getDocComment()->getText());
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$interface->parseError = $e->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$interface->name = $interfaceName;
|
|
||||||
$interface->parentInterfaces = [];
|
|
||||||
if (!empty($node->extends)) {
|
|
||||||
foreach ($node->extends[0]->parts as $part) {
|
|
||||||
array_push($interface->parentInterfaces, $this->getFQN($node, $part));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->stubs->interfaces[$interfaceName] = $interface;
|
|
||||||
$this->stubs->interfaces[$interfaceName]->constants = [];
|
|
||||||
$this->stubs->interfaces[$interfaceName]->methods = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function combineParentInterfaces($interface): array
|
|
||||||
{
|
|
||||||
$parents = [];
|
|
||||||
if (empty($interface->parentInterfaces)) {
|
|
||||||
return $parents;
|
|
||||||
} else {
|
|
||||||
foreach ($interface->parentInterfaces as $parentInterface) {
|
|
||||||
array_push($parents, $parentInterface);
|
|
||||||
foreach ($this->combineParentInterfaces($this->stubs->interfaces[$parentInterface]) as $value) {
|
|
||||||
array_push($parents, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $parents;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function parseParams(FunctionLike $node): array
|
|
||||||
{
|
|
||||||
$params = $node->getParams();
|
|
||||||
$parsedParams = [];
|
|
||||||
/** @var Node\Param $param */
|
|
||||||
foreach ($params as $param) {
|
|
||||||
$parsedParam = new stdClass();
|
|
||||||
$parsedParam->name = $param->var->name;
|
|
||||||
if ($param->type !== null) {
|
|
||||||
if (empty($param->type->name)) {
|
|
||||||
if (!empty($param->type->parts)) {
|
|
||||||
$parsedParam->type = $param->type->parts[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$parsedParam->type = $param->type->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$parsedParam->type = '';
|
|
||||||
}
|
|
||||||
$parsedParam->is_vararg = $param->variadic;
|
|
||||||
$parsedParam->is_passed_by_ref = $param->byRef;
|
|
||||||
$parsedParams[] = $parsedParam;
|
|
||||||
}
|
|
||||||
return $parsedParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getFQN(NodeAbstract $node, string $nodeName): string
|
|
||||||
{
|
|
||||||
$namespace = '';
|
|
||||||
if ($node->getAttribute('parent') instanceof Namespace_ && !empty($node->getAttribute('parent')->name)) {
|
|
||||||
$namespace = '\\' . implode('\\', $node->getAttribute('parent')->name->parts) . '\\';
|
|
||||||
}
|
|
||||||
return $namespace . $nodeName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPhpStormStubs(): stdClass
|
|
||||||
{
|
|
||||||
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
|
||||||
$docFactory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
|
|
||||||
$stubs = new stdClass();
|
|
||||||
$visitor = new ASTVisitor($docFactory, $stubs);
|
|
||||||
|
|
||||||
$stubsIterator =
|
|
||||||
new RecursiveIteratorIterator(
|
|
||||||
new RecursiveDirectoryIterator(__DIR__ . '/../', FilesystemIterator::SKIP_DOTS)
|
|
||||||
);
|
|
||||||
/** @var SplFileInfo $file */
|
|
||||||
foreach ($stubsIterator as $file) {
|
|
||||||
if (strpos($file->getRealPath(), 'vendor') || strpos($file->getRealPath(), '.git') || substr(dirname($file->getRealPath(), 1), -5) === 'tests') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$code = file_get_contents($file->getRealPath());
|
|
||||||
|
|
||||||
try {
|
|
||||||
$ast = $parser->parse($code);
|
|
||||||
} catch (\PhpParser\Error $error){
|
|
||||||
$error->setRawMessage($error->getRawMessage() . "\n" . $file->getRealPath());
|
|
||||||
throw $error;
|
|
||||||
}
|
|
||||||
$traverser = new NodeTraverser();
|
|
||||||
|
|
||||||
$traverser->addVisitor(new ParentConnector());
|
|
||||||
$traverser->addVisitor($visitor);
|
|
||||||
$traverser->traverse($ast);
|
|
||||||
}
|
|
||||||
foreach ($stubs->interfaces as $interface) {
|
|
||||||
$interface->parentInterfaces = $visitor->combineParentInterfaces($interface);
|
|
||||||
}
|
|
||||||
return $stubs;
|
|
||||||
}
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\TestData;
|
||||||
|
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class MutedProblems
|
||||||
|
{
|
||||||
|
/** @var stdClass */
|
||||||
|
private $mutedProblems;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$json = file_get_contents(__DIR__ . '/mutedProblems.json');
|
||||||
|
$this->mutedProblems = json_decode($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMutedProblemsForConstant(string $constantName): array
|
||||||
|
{
|
||||||
|
/**@var stdClass $constant */
|
||||||
|
foreach ($this->mutedProblems->constants as $constant) {
|
||||||
|
if ($constant->name === $constantName) {
|
||||||
|
return $constant->problems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMutedProblemsForFunction(string $functionName): array
|
||||||
|
{
|
||||||
|
/**@var stdClass $function */
|
||||||
|
foreach ($this->mutedProblems->functions as $function) {
|
||||||
|
if ($function->name === $functionName) {
|
||||||
|
return $function->problems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMutedProblemsForClass(string $className): array
|
||||||
|
{
|
||||||
|
/**@var stdClass $class */
|
||||||
|
foreach ($this->mutedProblems->classes as $class) {
|
||||||
|
if ($class->name === $className && !empty($class->problems)) {
|
||||||
|
return $class->problems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMutedProblemsForMethod(string $className, $methodName): array
|
||||||
|
{
|
||||||
|
/**@var stdClass $class */
|
||||||
|
foreach ($this->mutedProblems->classes as $class) {
|
||||||
|
if ($class->name === $className && !empty($class->methods)) {
|
||||||
|
/**@var stdClass $method */
|
||||||
|
foreach ($class->methods as $method) {
|
||||||
|
if ($method->name === $methodName) {
|
||||||
|
return $method->problems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMutedProblemsForClassConstants($className, $constantName): array
|
||||||
|
{
|
||||||
|
/**@var stdClass $class */
|
||||||
|
foreach ($this->mutedProblems->classes as $class) {
|
||||||
|
if ($class->name === $className && !empty($class->constants)) {
|
||||||
|
/**@var stdClass $constant */
|
||||||
|
foreach ($class->constants as $constant) {
|
||||||
|
if ($constant->name === $constantName) {
|
||||||
|
return $constant->problems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMutedProblemsForInterface($interfaceName): array
|
||||||
|
{
|
||||||
|
/**@var stdClass $interface */
|
||||||
|
foreach ($this->mutedProblems->interfaces as $interface) {
|
||||||
|
if ($interface->name === $interfaceName && !empty($interface->problems)) {
|
||||||
|
return $interface->problems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\TestData\Providers;
|
||||||
|
|
||||||
|
use StubTests\Model\PHPClass;
|
||||||
|
use StubTests\Model\PHPConst;
|
||||||
|
use StubTests\Model\PHPFunction;
|
||||||
|
use StubTests\Model\PHPInterface;
|
||||||
|
use StubTests\Parsers\PHPReflectionParser;
|
||||||
|
|
||||||
|
class ReflectionTestDataProviders
|
||||||
|
{
|
||||||
|
|
||||||
|
public static function constantProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPConst $constant */
|
||||||
|
foreach (ReflectionStubsSingleton::getReflectionStubs()[PHPConst::class] as $constant) {
|
||||||
|
yield "constant {$constant->name}" => [$constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function functionProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPFunction $function */
|
||||||
|
foreach (ReflectionStubsSingleton::getReflectionStubs()[PHPFunction::class] as $function) {
|
||||||
|
yield "function {$function->name}" => [$function];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function classProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPClass $class */
|
||||||
|
foreach (ReflectionStubsSingleton::getReflectionStubs()[PHPClass::class] as $class) {
|
||||||
|
//exclude classes from PHPReflectionParser
|
||||||
|
if (strncmp($class->name, 'PHP', 3) !== 0) {
|
||||||
|
yield "class {$class->name}" => [$class];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function interfaceProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPInterface $interface */
|
||||||
|
foreach (ReflectionStubsSingleton::getReflectionStubs()[PHPInterface::class] as $interface) {
|
||||||
|
yield "interface {$interface->name}" => [$interface];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReflectionStubsSingleton
|
||||||
|
{
|
||||||
|
private static $reflectionStubs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getReflectionStubs(): array
|
||||||
|
{
|
||||||
|
if (self::$reflectionStubs === null) {
|
||||||
|
self::$reflectionStubs = PHPReflectionParser::getStubs();
|
||||||
|
}
|
||||||
|
return self::$reflectionStubs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StubTests\TestData\Providers;
|
||||||
|
|
||||||
|
use StubTests\Model\PHPClass;
|
||||||
|
use StubTests\Model\PHPConst;
|
||||||
|
use StubTests\Model\PHPFunction;
|
||||||
|
use StubTests\Model\PHPInterface;
|
||||||
|
use StubTests\Model\PHPMethod;
|
||||||
|
use StubTests\Parsers\StubParser;
|
||||||
|
|
||||||
|
class StubsTestDataProviders
|
||||||
|
{
|
||||||
|
|
||||||
|
public static function stubClassConstantProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPClass $class */
|
||||||
|
foreach (PhpStormStubsSingleton::getPhpStormStubs()[PHPClass::class] as $class) {
|
||||||
|
foreach ($class->constants as $constant) {
|
||||||
|
yield "constant {$class->name}::{$constant->name}" => [$class->name, $constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@var PHPInterface $interface */
|
||||||
|
foreach (PhpStormStubsSingleton::getPhpStormStubs()[PHPInterface::class] as $interfaceName => $interface) {
|
||||||
|
foreach ($interface->constants as $constantName => $constant) {
|
||||||
|
yield "constant {$interfaceName}::{$constantName}" => [$interfaceName, $constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stubConstantProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPConst $constant */
|
||||||
|
foreach (PhpStormStubsSingleton::getPhpStormStubs()[PHPConst::class] as $constantName => $constant) {
|
||||||
|
yield "constant {$constantName}" => [$constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stubFunctionProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPFunction $function */
|
||||||
|
foreach (PhpStormStubsSingleton::getPhpStormStubs()[PHPFunction::class] as $functionName => $function) {
|
||||||
|
yield "function {$functionName}" => [$function];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stubClassProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPClass $class */
|
||||||
|
foreach (PhpStormStubsSingleton::getPhpStormStubs()[PHPClass::class] as $class) {
|
||||||
|
yield "class {$class->name}" => [$class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@var PHPInterface $interface */
|
||||||
|
foreach (PhpStormStubsSingleton::getPhpStormStubs()[PHPInterface::class] as $interface) {
|
||||||
|
yield "interface {$interface->name}" => [$interface];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stubMethodProvider()
|
||||||
|
{
|
||||||
|
/**@var PHPClass $class */
|
||||||
|
foreach (PhpStormStubsSingleton::getPhpStormStubs()[PHPClass::class] as $className => $class) {
|
||||||
|
/**@var PHPMethod $method */
|
||||||
|
foreach ($class->methods as $methodName => $method) {
|
||||||
|
yield "method {$className}::{$methodName}" => [$methodName, $method];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@var PHPInterface $interface */
|
||||||
|
foreach (PhpStormStubsSingleton::getPhpStormStubs()[PHPInterface::class] as $interfaceName => $interface) {
|
||||||
|
/**@var PHPMethod $method */
|
||||||
|
foreach ($interface->methods as $methodName => $method) {
|
||||||
|
yield "interface {$interfaceName}::{$methodName}" => [$methodName, $method];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PhpStormStubsSingleton
|
||||||
|
{
|
||||||
|
private static $phpstormStubs;
|
||||||
|
|
||||||
|
public static function getPhpStormStubs(): array
|
||||||
|
{
|
||||||
|
if (self::$phpstormStubs === null) {
|
||||||
|
self::$phpstormStubs = StubParser::getPhpStormStubs();
|
||||||
|
}
|
||||||
|
return self::$phpstormStubs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,533 @@
|
||||||
{
|
{
|
||||||
"constants": [
|
"constants": [
|
||||||
|
{
|
||||||
|
"name": "E_ALL",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DEBUG_BACKTRACE_PROVIDE_OBJECT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DEBUG_BACKTRACE_IGNORE_ARGS",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TRUE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FALSE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZEND_THREAD_SAFE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZEND_DEBUG_BUILD",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "NULL",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_MAJOR_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_MINOR_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_RELEASE_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_EXTRA_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_VERSION_ID",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DEFAULT_INCLUDE_PATH",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PEAR_INSTALL_DIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PEAR_EXTENSION_DIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_PREFIX",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_BINDIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_MANDIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_LIBDIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_DATADIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_SYSCONFDIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_LOCALSTATEDIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_EXTENSION_DIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_CONFIG_FILE_PATH",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_CONFIG_FILE_SCAN_DIR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_INT_MIN",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_BINARY",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_OUTPUT_HANDLER_CONT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PHP_OUTPUT_HANDLER_END",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STDIN",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STDOUT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STDERR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DATE_COOKIE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LIBXML_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LIBXML_DOTTED_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LIBXML_LOADED_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LIBXML_BIGLINES",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OPENSSL_VERSION_TEXT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OPENSSL_VERSION_NUMBER",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OPENSSL_DEFAULT_STREAM_CIPHERS",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PCRE_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_ENCODING_RAW",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_VERNUM",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_ERRNO",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_STREAM_ERROR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_DATA_ERROR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_BUF_ERROR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_VERSION_ERROR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZLIB_MEM_ERROR",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLINFO_LASTONE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLM_CALL_MULTI_PERFORM",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLAUTH_ANY",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLAUTH_ANYSAFE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLOPT_MAX_RECV_SPEED_LARGE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLOPT_MAX_SEND_SPEED_LARGE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLSSH_AUTH_ANY",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLSSH_AUTH_DEFAULT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLOPT_CERTINFO",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLOPT_PROTOCOLS",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLOPT_REDIR_PROTOCOLS",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLPROTO_ALL",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CURLOPT_SAFE_UPLOAD",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FILEINFO_EXTENSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FILTER_SANITIZE_FULL_SPECIAL_CHARS",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FTP_AUTORESUME",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ICONV_VERSION",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "POSIX_RLIMIT_AS",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "POSIX_RLIMIT_MEMLOCK",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "POSIX_RLIMIT_NOFILE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "POSIX_RLIMIT_NPROC",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "POSIX_RLIMIT_INFINITY",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STREAM_CRYPTO_METHOD_SSLv2_CLIENT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STREAM_CRYPTO_METHOD_SSLv3_CLIENT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STREAM_CRYPTO_METHOD_SSLv23_CLIENT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STREAM_CRYPTO_METHOD_TLS_CLIENT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STREAM_CRYPTO_METHOD_SSLv2_SERVER",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STREAM_CRYPTO_METHOD_SSLv3_SERVER",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STREAM_CRYPTO_METHOD_SSLv23_SERVER",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "STREAM_CRYPTO_METHOD_TLS_SERVER",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FNM_NOESCAPE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FNM_PATHNAME",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "IMAGETYPE_COUNT",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DNS_ALL",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SODIUM_CRYPTO_BOX_SEALBYTES",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE",
|
||||||
|
"problems": [
|
||||||
|
"wrong value"
|
||||||
|
]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"functions": [
|
"functions": [
|
||||||
{
|
{
|
|
@ -1,391 +1,316 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace StubTests;
|
||||||
|
|
||||||
|
use phpDocumentor\Reflection\DocBlock\Tag;
|
||||||
use phpDocumentor\Reflection\DocBlock\Tags\Link;
|
use phpDocumentor\Reflection\DocBlock\Tags\Link;
|
||||||
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Url;
|
use phpDocumentor\Reflection\DocBlock\Tags\Reference\Url;
|
||||||
use phpDocumentor\Reflection\DocBlock\Tags\See;
|
use phpDocumentor\Reflection\DocBlock\Tags\See;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use StubTests\Model\BasePHPClass;
|
||||||
include __DIR__ . '/StubParser.php';
|
use StubTests\Model\PHPClass;
|
||||||
include __DIR__ . '/../vendor/autoload.php';
|
use StubTests\Model\PHPConst;
|
||||||
|
use StubTests\Model\PHPFunction;
|
||||||
class ReflectionStubsSingleton
|
use StubTests\Model\PHPInterface;
|
||||||
{
|
use StubTests\Model\PHPMethod;
|
||||||
private static $reflectionStubs;
|
use StubTests\TestData\MutedProblems;
|
||||||
|
use StubTests\TestData\providers\PhpStormStubsSingleton;
|
||||||
public static function getReflectionStubs(): stdClass
|
|
||||||
{
|
|
||||||
if (self::$reflectionStubs === null) {
|
|
||||||
$json = file_get_contents(__DIR__ . '/stub.json');
|
|
||||||
self::$reflectionStubs = json_decode($json);
|
|
||||||
}
|
|
||||||
return self::$reflectionStubs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhpStormStubsSingleton
|
|
||||||
{
|
|
||||||
private static $phpstormStubs;
|
|
||||||
|
|
||||||
public static function getPhpStormStubs(): stdClass
|
|
||||||
{
|
|
||||||
if (self::$phpstormStubs === null) {
|
|
||||||
self::$phpstormStubs = getPhpStormStubs();
|
|
||||||
}
|
|
||||||
return self::$phpstormStubs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MutedProblems
|
|
||||||
{
|
|
||||||
/** @var stdClass */
|
|
||||||
private $mutedProblems;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$json = file_get_contents(__DIR__ . '/mutedProblems.json');
|
|
||||||
$this->mutedProblems = json_decode($json);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMutedProblemsForConstant(string $constantName): array
|
|
||||||
{
|
|
||||||
foreach ($this->mutedProblems->constants as $constant) {
|
|
||||||
if ($constant->name === $constantName) {
|
|
||||||
return $constant->problems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMutedProblemsForFunction(string $functionName): array
|
|
||||||
{
|
|
||||||
foreach ($this->mutedProblems->functions as $function) {
|
|
||||||
if ($function->name === $functionName) {
|
|
||||||
return $function->problems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMutedProblemsForClass(string $className): array
|
|
||||||
{
|
|
||||||
foreach ($this->mutedProblems->classes as $class) {
|
|
||||||
if ($class->name === $className && !empty($class->problems)) {
|
|
||||||
return $class->problems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMutedProblemsForMethod(string $className, $methodName): array
|
|
||||||
{
|
|
||||||
foreach ($this->mutedProblems->classes as $class) {
|
|
||||||
if ($class->name === $className && !empty($class->methods)) {
|
|
||||||
foreach ($class->methods as $method) {
|
|
||||||
if ($method->name === $methodName) {
|
|
||||||
return $method->problems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMutedProblemsForClassConstants($className, $constantName)
|
|
||||||
{
|
|
||||||
foreach ($this->mutedProblems->classes as $class) {
|
|
||||||
if ($class->name === $className && !empty($class->constants)) {
|
|
||||||
foreach ($class->constants as $constant) {
|
|
||||||
if ($constant->name === $constantName) {
|
|
||||||
return $constant->problems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMutedProblemsForInterface($interfaceName)
|
|
||||||
{
|
|
||||||
foreach ($this->mutedProblems->interfaces as $interface) {
|
|
||||||
if ($interface->name === $interfaceName && !empty($interface->problems)) {
|
|
||||||
return $interface->problems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestStubs extends TestCase
|
class TestStubs extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @var MutedProblems */
|
/** @var MutedProblems */
|
||||||
private static $mutedProblems;
|
private static $mutedProblems;
|
||||||
|
|
||||||
public static function setUpBeforeClass()/* The :void return type declaration that should be here would cause a BC issue */
|
public static function setUpBeforeClass()
|
||||||
{
|
{
|
||||||
|
parent::setUpBeforeClass();
|
||||||
self::$mutedProblems = new MutedProblems();
|
self::$mutedProblems = new MutedProblems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function constantProvider()
|
|
||||||
{
|
|
||||||
foreach (ReflectionStubsSingleton::getReflectionStubs()->constants as $constant) {
|
|
||||||
yield "constant {$constant->name}" => [$constant];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider constantProvider
|
* @dataProvider \StubTests\TestData\Providers\ReflectionTestDataProviders::constantProvider
|
||||||
|
* @param PHPConst $constant
|
||||||
*/
|
*/
|
||||||
public function testConstants(stdClass $constant)
|
public function testConstants(PHPConst $constant): void
|
||||||
{
|
{
|
||||||
$constantName = $constant->name;
|
$constantName = $constant->name;
|
||||||
$constantValue = $constant->value;
|
$constantValue = $constant->value;
|
||||||
$stubConstants = PhpStormStubsSingleton::getPhpStormStubs()->constants;
|
$stubConstants = PhpStormStubsSingleton::getPhpStormStubs()[PHPConst::class];
|
||||||
if (in_array('missing constant', self::$mutedProblems->getMutedProblemsForConstant($constantName), true)) {
|
if (in_array('missing constant', self::$mutedProblems->getMutedProblemsForConstant($constantName), true)) {
|
||||||
$this->markTestSkipped('constant is excluded');
|
static::markTestSkipped('constant is excluded');
|
||||||
}
|
|
||||||
$this->assertArrayHasKey($constantName, $stubConstants, "Missing constant: const $constantName = $constantValue\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function functionProvider()
|
|
||||||
{
|
|
||||||
foreach (ReflectionStubsSingleton::getReflectionStubs()->functions as $function) {
|
|
||||||
yield "function {$function->name}" => [$function];
|
|
||||||
}
|
}
|
||||||
|
static::assertArrayHasKey(
|
||||||
|
$constantName,
|
||||||
|
$stubConstants,
|
||||||
|
"Missing constant: const $constantName = $constantValue\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider functionProvider
|
* @dataProvider \StubTests\TestData\Providers\ReflectionTestDataProviders::constantProvider
|
||||||
|
* @param PHPConst $constant
|
||||||
*/
|
*/
|
||||||
public function testFunctions(stdClass $function)
|
public function testConstantsValues(PHPConst $constant): void
|
||||||
|
{
|
||||||
|
$constantName = $constant->name;
|
||||||
|
$constantValue = $constant->value;
|
||||||
|
/**@var PHPConst[] $stubConstants */
|
||||||
|
$stubConstants = PhpStormStubsSingleton::getPhpStormStubs()[PHPConst::class];
|
||||||
|
if (in_array('wrong value', self::$mutedProblems->getMutedProblemsForConstant($constantName), true)) {
|
||||||
|
static::markTestSkipped('constant is excluded');
|
||||||
|
}
|
||||||
|
|
||||||
|
static::assertEquals(
|
||||||
|
$constantValue,
|
||||||
|
$stubConstants[$constantName]->value,
|
||||||
|
"Constant value mismatch: const $constantName \n
|
||||||
|
Expected value: $constantValue but was {$stubConstants[$constantName]->value}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider \StubTests\TestData\Providers\ReflectionTestDataProviders::functionProvider
|
||||||
|
* @param PHPFunction $function
|
||||||
|
*/
|
||||||
|
public function testFunctions(PHPFunction $function): void
|
||||||
{
|
{
|
||||||
$functionName = $function->name;
|
$functionName = $function->name;
|
||||||
$stubFunctions = PhpStormStubsSingleton::getPhpStormStubs()->functions;
|
$stubFunctions = PhpStormStubsSingleton::getPhpStormStubs()[PHPFunction::class];
|
||||||
$params = $this->getParameterRepresentation($function);
|
$params = $this->getParameterRepresentation($function);
|
||||||
if (in_array('missing function', self::$mutedProblems->getMutedProblemsForFunction($functionName), true)) {
|
if (in_array('missing function', self::$mutedProblems->getMutedProblemsForFunction($functionName), true)) {
|
||||||
$this->markTestSkipped('function is excluded');
|
static::markTestSkipped('function is excluded');
|
||||||
}
|
}
|
||||||
$this->assertArrayHasKey($functionName, $stubFunctions, "Missing function: function $functionName($params){}");
|
static::assertArrayHasKey($functionName, $stubFunctions, "Missing function: function $functionName($params){}");
|
||||||
|
/**@var PHPFunction $phpstormFunction */
|
||||||
$phpstormFunction = $stubFunctions[$functionName];
|
$phpstormFunction = $stubFunctions[$functionName];
|
||||||
if (!in_array('deprecated function', self::$mutedProblems->getMutedProblemsForFunction($functionName), true)) {
|
if (!in_array('deprecated function', self::$mutedProblems->getMutedProblemsForFunction($functionName), true)) {
|
||||||
$this->assertFalse($function->is_deprecated && $phpstormFunction->is_deprecated !== true, "Function $functionName is not deprecated in stubs");
|
static::assertFalse(
|
||||||
|
$function->is_deprecated && $phpstormFunction->is_deprecated !== true,
|
||||||
|
"Function $functionName is not deprecated in stubs"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!in_array('parameter mismatch', self::$mutedProblems->getMutedProblemsForFunction($functionName), true)) {
|
if (!in_array('parameter mismatch', self::$mutedProblems->getMutedProblemsForFunction($functionName), true)) {
|
||||||
$this->assertSameSize($function->parameters, $phpstormFunction->parameters,
|
static::assertSameSize(
|
||||||
"Parameter number mismatch for function $functionName. Expected: " . $this->getParameterRepresentation($function));
|
$function->parameters,
|
||||||
}
|
$phpstormFunction->parameters,
|
||||||
|
"Parameter number mismatch for function $functionName.
|
||||||
}
|
Expected: " . $this->getParameterRepresentation($function)
|
||||||
|
);
|
||||||
|
|
||||||
public function classProvider()
|
|
||||||
{
|
|
||||||
foreach (ReflectionStubsSingleton::getReflectionStubs()->classes as $class) {
|
|
||||||
//exclude classes from PHPReflectionParser
|
|
||||||
if (0 !== strncmp($class->name, 'PHP', 3)) {
|
|
||||||
yield "class {$class->name}" => [$class];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider classProvider
|
* @dataProvider \StubTests\TestData\Providers\ReflectionTestDataProviders::classProvider
|
||||||
|
* @param PHPClass $class
|
||||||
*/
|
*/
|
||||||
public function testClasses(stdClass $class)
|
public function testClasses(PHPClass $class): void
|
||||||
{
|
{
|
||||||
$className = $class->name;
|
$className = $class->name;
|
||||||
$stubClasses = PhpStormStubsSingleton::getPhpStormStubs()->classes;
|
$stubClasses = PhpStormStubsSingleton::getPhpStormStubs()[PHPClass::class];
|
||||||
if (in_array('missing class', self::$mutedProblems->getMutedProblemsForClass($className), true)) {
|
if (in_array('missing class', self::$mutedProblems->getMutedProblemsForClass($className), true)) {
|
||||||
$this->markTestSkipped('class is skipped');
|
static::markTestSkipped('class is skipped');
|
||||||
}
|
}
|
||||||
$this->assertArrayHasKey($className, $stubClasses, "Missing class $className: class $className {}");
|
static::assertArrayHasKey($className, $stubClasses, "Missing class $className: class $className {}");
|
||||||
|
/**@var PHPClass $stubClass */
|
||||||
$stubClass = $stubClasses[$className];
|
$stubClass = $stubClasses[$className];
|
||||||
if (!in_array('wrong parent', self::$mutedProblems->getMutedProblemsForClass($className), true)) {
|
if (!in_array('wrong parent', self::$mutedProblems->getMutedProblemsForClass($className), true)) {
|
||||||
$this->assertEquals($class->parentClass, $stubClass->parentClass, "Class $className should extend {$class->parentClass}");
|
static::assertEquals(
|
||||||
|
$class->parentClass,
|
||||||
|
$stubClass->parentClass,
|
||||||
|
"Class $className should extend {$class->parentClass}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
foreach ($class->constants as $constant) {
|
foreach ($class->constants as $constant) {
|
||||||
if (!in_array('missing constant', self::$mutedProblems->getMutedProblemsForClassConstants($className, $constant->name), true)) {
|
if (!in_array('missing constant', self::$mutedProblems->getMutedProblemsForClassConstants($className, $constant->name), true)) {
|
||||||
$this->assertArrayHasKey($constant->name, $stubClass->constants, "Missing constant $className::{$constant->name}");
|
static::assertArrayHasKey(
|
||||||
|
$constant->name,
|
||||||
|
$stubClass->constants,
|
||||||
|
"Missing constant $className::{$constant->name}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($class->methods as $method) {
|
foreach ($class->methods as $method) {
|
||||||
$params = $this->getParameterRepresentation($method);
|
$params = $this->getParameterRepresentation($method);
|
||||||
$methodName = $method->name;
|
$methodName = $method->name;
|
||||||
if (!in_array('missing method', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
if (!in_array('missing method', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
||||||
$this->assertArrayHasKey($methodName, $stubClass->methods, "Missing method $className::$methodName($params){}");
|
static::assertArrayHasKey(
|
||||||
|
$methodName,
|
||||||
|
$stubClass->methods,
|
||||||
|
"Missing method $className::$methodName($params){}"
|
||||||
|
);
|
||||||
$stubMethod = $stubClass->methods[$methodName];
|
$stubMethod = $stubClass->methods[$methodName];
|
||||||
if (!in_array('not final', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
if (!in_array('not final', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
||||||
$this->assertEquals($method->is_final, $stubMethod->is_final, "Method $className::$methodName final modifier is incorrect");
|
static::assertEquals(
|
||||||
|
$method->is_final,
|
||||||
|
$stubMethod->is_final,
|
||||||
|
"Method $className::$methodName final modifier is incorrect"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!in_array('not static', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
if (!in_array('not static', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
||||||
$this->assertEquals($method->is_static, $stubMethod->is_static, "Method $className::$methodName static modifier is incorrect");
|
static::assertEquals(
|
||||||
|
$method->is_static,
|
||||||
|
$stubMethod->is_static,
|
||||||
|
"Method $className::$methodName static modifier is incorrect"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!in_array('access modifiers', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
if (!in_array('access modifiers', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
||||||
$this->assertEquals($method->access, $stubMethod->access, "Method $className::$methodName access modifier is incorrect");
|
static::assertEquals(
|
||||||
|
$method->access,
|
||||||
|
$stubMethod->access,
|
||||||
|
"Method $className::$methodName access modifier is incorrect"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!in_array('parameter mismatch', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
if (!in_array('parameter mismatch', self::$mutedProblems->getMutedProblemsForMethod($className, $methodName), true)) {
|
||||||
$this->assertSameSize($method->parameters, $stubMethod->parameters, "Parameter number mismatch for method $className::$methodName. Expected: " . $this->getParameterRepresentation($method));
|
static::assertSameSize(
|
||||||
|
$method->parameters,
|
||||||
|
$stubMethod->parameters,
|
||||||
|
"Parameter number mismatch for method $className::$methodName.
|
||||||
|
Expected: " . $this->getParameterRepresentation($method)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach ($class->interfaces as $interface) {
|
||||||
}
|
if (!in_array('wrong interface', self::$mutedProblems->getMutedProblemsForClass($className), true)) {
|
||||||
|
static::assertContains(
|
||||||
public function interfaceProvider()
|
$interface,
|
||||||
{
|
$stubClass->interfaces,
|
||||||
foreach (ReflectionStubsSingleton::getReflectionStubs()->interfaces as $interface) {
|
"Class $className doesn't implement interface $interface"
|
||||||
yield "interface {$interface->name}" => [$interface];
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider interfaceProvider
|
* @dataProvider \StubTests\TestData\Providers\ReflectionTestDataProviders::interfaceProvider
|
||||||
|
* @param PHPInterface $interface
|
||||||
*/
|
*/
|
||||||
public function testInterfaces(stdClass $interface)
|
public function testInterfaces(PHPInterface $interface): void
|
||||||
{
|
{
|
||||||
$interfaceName = $interface->name;
|
$interfaceName = $interface->name;
|
||||||
$stubInterfaces = PhpStormStubsSingleton::getPhpStormStubs()->interfaces;
|
/**@var PHPInterface[] $stubInterfaces */
|
||||||
|
$stubInterfaces = PhpStormStubsSingleton::getPhpStormStubs()[PHPInterface::class];
|
||||||
if (in_array('missing interface', self::$mutedProblems->getMutedProblemsForInterface($interfaceName), true)) {
|
if (in_array('missing interface', self::$mutedProblems->getMutedProblemsForInterface($interfaceName), true)) {
|
||||||
$this->markTestSkipped('interface is skipped');
|
static::markTestSkipped('interface is skipped');
|
||||||
}
|
}
|
||||||
$this->assertArrayHasKey($interfaceName, $stubInterfaces, "Missing interface $interfaceName: interface $interfaceName {}");
|
static::assertArrayHasKey(
|
||||||
|
$interfaceName,
|
||||||
|
$stubInterfaces,
|
||||||
|
"Missing interface $interfaceName: interface $interfaceName {}"
|
||||||
|
);
|
||||||
$stubInterface = $stubInterfaces[$interfaceName];
|
$stubInterface = $stubInterfaces[$interfaceName];
|
||||||
if (!in_array('wrong parent', self::$mutedProblems->getMutedProblemsForInterface($interfaceName), true)) {
|
if (!in_array('wrong parent', self::$mutedProblems->getMutedProblemsForInterface($interfaceName), true)) {
|
||||||
$this->assertEquals($stubInterface->parentInterfaces, $interface->parentInterfaces);
|
static::assertEquals($stubInterface->parentInterfaces, $interface->parentInterfaces);
|
||||||
}
|
}
|
||||||
foreach ($interface->constants as $constant) {
|
foreach ($interface->constants as $constant) {
|
||||||
if (!in_array('missing constant', self::$mutedProblems->getMutedProblemsForClassConstants($interfaceName, $constant->name), true)) {
|
if (!in_array('missing constant', self::$mutedProblems->getMutedProblemsForClassConstants($interfaceName, $constant->name), true)) {
|
||||||
$this->assertArrayHasKey($constant->name, $stubInterface->constants, "Missing constant $interfaceName::{$constant->name}");
|
static::assertArrayHasKey(
|
||||||
|
$constant->name,
|
||||||
|
$stubInterface->constants,
|
||||||
|
"Missing constant $interfaceName::{$constant->name}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($interface->methods as $method) {
|
foreach ($interface->methods as $method) {
|
||||||
$params = $this->getParameterRepresentation($method);
|
$params = $this->getParameterRepresentation($method);
|
||||||
$methodName = $method->name;
|
$methodName = $method->name;
|
||||||
if (!in_array('missing method', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
if (!in_array('missing method', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
||||||
$this->assertArrayHasKey($methodName, $stubInterface->methods, "Missing method $interfaceName::$methodName($params){}");
|
static::assertArrayHasKey(
|
||||||
|
$methodName,
|
||||||
|
$stubInterface->methods,
|
||||||
|
"Missing method $interfaceName::$methodName($params){}"
|
||||||
|
);
|
||||||
$stubMethod = $stubInterface->methods[$methodName];
|
$stubMethod = $stubInterface->methods[$methodName];
|
||||||
if (!in_array('not final', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
if (!in_array('not final', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
||||||
$this->assertEquals($method->is_final, $stubMethod->is_final, "Method $interfaceName::$methodName final modifier is incorrect");
|
static::assertEquals(
|
||||||
|
$method->is_final,
|
||||||
|
$stubMethod->is_final,
|
||||||
|
"Method $interfaceName::$methodName final modifier is incorrect"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!in_array('not static', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
if (!in_array('not static', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
||||||
$this->assertEquals($method->is_static, $stubMethod->is_static, "Method $interfaceName::$methodName static modifier is incorrect");
|
static::assertEquals(
|
||||||
|
$method->is_static,
|
||||||
|
$stubMethod->is_static,
|
||||||
|
"Method $interfaceName::$methodName static modifier is incorrect"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!in_array('access modifiers', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
if (!in_array('access modifiers', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
||||||
$this->assertEquals($method->access, $stubMethod->access, "Method $interfaceName::$methodName access modifier is incorrect");
|
static::assertEquals(
|
||||||
|
$method->access,
|
||||||
|
$stubMethod->access,
|
||||||
|
"Method $interfaceName::$methodName access modifier is incorrect"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!in_array('parameter mismatch', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
if (!in_array('parameter mismatch', self::$mutedProblems->getMutedProblemsForMethod($interfaceName, $methodName), true)) {
|
||||||
$this->assertSameSize($method->parameters, $stubMethod->parameters, "Parameter number mismatch for method $interfaceName::$methodName. Expected: " . $this->getParameterRepresentation($method));
|
static::assertSameSize(
|
||||||
|
$method->parameters,
|
||||||
|
$stubMethod->parameters,
|
||||||
|
"Parameter number mismatch for method $interfaceName::$methodName.
|
||||||
|
Expected: " . $this->getParameterRepresentation($method)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function stubClassConstantProvider(){
|
|
||||||
foreach (PhpStormStubsSingleton::getPhpStormStubs()->classes as $className => $class) {
|
|
||||||
foreach ($class->constants as $constantName => $constant) {
|
|
||||||
yield "Constant {$className}::{$constantName}" => [$className, $constant];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (PhpStormStubsSingleton::getPhpStormStubs()->interfaces as $interfaceName => $interface) {
|
|
||||||
foreach ($interface->constants as $constantName => $constant) {
|
|
||||||
yield "Constant {$interfaceName}::{$constantName}" => [$interfaceName, $constant];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider stubClassConstantProvider
|
* @dataProvider \StubTests\TestData\Providers\StubsTestDataProviders::stubClassConstantProvider
|
||||||
|
* @param string $className
|
||||||
|
* @param PHPConst $constant
|
||||||
*/
|
*/
|
||||||
public function testClassConstantsPHPDocs(string $className, stdClass $constant)
|
public function testClassConstantsPHPDocs(string $className, PHPConst $constant): void
|
||||||
{
|
{
|
||||||
$this->assertNull($constant->parseError, $constant->parseError ?: "");
|
static::assertNull($constant->parseError, $constant->parseError ?: '');
|
||||||
$this->checkLinks($constant, "constant $className::$constant->name");
|
$this->checkLinks($constant, "constant $className::$constant->name");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stubConstantProvider()
|
|
||||||
{
|
|
||||||
foreach (PhpStormStubsSingleton::getPhpStormStubs()->constants as $constantName => $constant) {
|
|
||||||
yield "constant {$constantName}" => [$constant];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider stubConstantProvider
|
* @dataProvider \StubTests\TestData\Providers\StubsTestDataProviders::stubConstantProvider
|
||||||
|
* @param PHPConst $constant
|
||||||
*/
|
*/
|
||||||
public function testConstantsPHPDocs(stdClass $constant)
|
public function testConstantsPHPDocs(PHPConst $constant): void
|
||||||
{
|
{
|
||||||
$this->assertNull($constant->parseError, $constant->parseError ?: "");
|
static::assertNull($constant->parseError, $constant->parseError ?: '');
|
||||||
$this->checkLinks($constant, "function $constant->name");
|
$this->checkLinks($constant, "function $constant->name");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stubFunctionProvider()
|
|
||||||
{
|
|
||||||
foreach (PhpStormStubsSingleton::getPhpStormStubs()->functions as $functionName => $function) {
|
|
||||||
yield "function {$functionName}" => [$function];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider stubFunctionProvider
|
* @dataProvider \StubTests\TestData\Providers\StubsTestDataProviders::stubFunctionProvider
|
||||||
|
* @param PHPFunction $function
|
||||||
*/
|
*/
|
||||||
public function testFunctionPHPDocs(stdClass $function)
|
public function testFunctionPHPDocs(PHPFunction $function): void
|
||||||
{
|
{
|
||||||
$this->assertNull($function->parseError, $function->parseError ?: "");
|
static::assertNull($function->parseError, $function->parseError ?: '');
|
||||||
$this->checkLinks($function, "function $function->name");
|
$this->checkLinks($function, "function $function->name");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stubClassProvider()
|
|
||||||
{
|
|
||||||
foreach (PhpStormStubsSingleton::getPhpStormStubs()->classes as $className => $class) {
|
|
||||||
yield "class {$className}" => [$class];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (PhpStormStubsSingleton::getPhpStormStubs()->interfaces as $interfaceName => $interface) {
|
|
||||||
yield "interface {$interfaceName}" => [$interface];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider stubClassProvider
|
* @dataProvider \StubTests\TestData\Providers\StubsTestDataProviders::stubClassProvider
|
||||||
|
* @param BasePHPClass $class
|
||||||
*/
|
*/
|
||||||
public function testClassesPHPDocs(stdClass $class)
|
public function testClassesPHPDocs(BasePHPClass $class): void
|
||||||
{
|
{
|
||||||
$this->assertNull($class->parseError, $class->parseError ?: "");
|
static::assertNull($class->parseError, $class->parseError ?: '');
|
||||||
$this->checkLinks($class, "class $class->name");
|
$this->checkLinks($class, "class $class->name");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stubMethodProvider()
|
|
||||||
{
|
|
||||||
foreach (PhpStormStubsSingleton::getPhpStormStubs()->classes as $className => $class) {
|
|
||||||
foreach ($class->methods as $methodName => $method) {
|
|
||||||
yield "Method {$className}::{$methodName}" => [$methodName, $method];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (PhpStormStubsSingleton::getPhpStormStubs()->interfaces as $interfaceName => $interface) {
|
|
||||||
foreach ($interface->methods as $methodName => $method) {
|
|
||||||
yield "Method {$interfaceName}::{$methodName}" => [$methodName, $method];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider stubMethodProvider
|
* @dataProvider \StubTests\TestData\Providers\StubsTestDataProviders::stubMethodProvider
|
||||||
|
* @param string $methodName
|
||||||
|
* @param PHPMethod $method
|
||||||
*/
|
*/
|
||||||
public function testMethodsPHPDocs(string $methodName, stdClass $method)
|
public function testMethodsPHPDocs(string $methodName, PHPMethod $method): void
|
||||||
{
|
{
|
||||||
if ($methodName === "__construct") {
|
if ($methodName === '__construct') {
|
||||||
$this->assertNull($method->returnTag, "@return tag for __construct should be omitted");
|
static::assertNull($method->returnTag, '@return tag for __construct should be omitted');
|
||||||
}
|
}
|
||||||
$this->assertNull($method->parseError, $method->parseError ?: "");
|
static::assertNull($method->parseError, $method->parseError ?: '');
|
||||||
$this->checkLinks($method, "method $methodName");
|
$this->checkLinks($method, "method $methodName");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getParameterRepresentation(stdClass $function): string
|
private function getParameterRepresentation(PHPFunction $function): string
|
||||||
{
|
{
|
||||||
$result = '';
|
$result = '';
|
||||||
foreach ($function->parameters as $parameter) {
|
foreach ($function->parameters as $parameter) {
|
||||||
|
@ -401,22 +326,27 @@ class TestStubs extends TestCase
|
||||||
$result .= '$' . $parameter->name . ', ';
|
$result .= '$' . $parameter->name . ', ';
|
||||||
}
|
}
|
||||||
$result = rtrim($result, ', ');
|
$result = rtrim($result, ', ');
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkLinks($element, $elementName): void
|
private function checkLinks($element, $elementName): void
|
||||||
{
|
{
|
||||||
|
/**@var Tag $link */
|
||||||
foreach ($element->links as $link) {
|
foreach ($element->links as $link) {
|
||||||
if ($link instanceof Link) {
|
if ($link instanceof Link) {
|
||||||
$this->assertStringStartsWith('https', $link->getLink(), "In $elementName @link doesn't start with https");
|
static::assertStringStartsWith(
|
||||||
|
'https',
|
||||||
|
$link->getLink(),
|
||||||
|
"In $elementName @link doesn't start with https"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**@var Tag $see */
|
||||||
foreach ($element->see as $see) {
|
foreach ($element->see as $see) {
|
||||||
if ($see instanceof See && $see->getReference() instanceof Url) {
|
if ($see instanceof See && $see->getReference() instanceof Url && strncmp($see, 'http', 4) === 0) {
|
||||||
if (strpos($see, 'http') === 0) {
|
static::assertStringStartsWith('https', $see, "In $elementName @see doesn't start with https");
|
||||||
$this->assertStringStartsWith('https', $see, "In $elementName @see doesn't start with https");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue