Skip to content

Commit

Permalink
Generate functionMetadata.php from PhpStorm stubs' #[Pure] attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Oct 24, 2020
1 parent da9d32f commit 2817690
Show file tree
Hide file tree
Showing 4 changed files with 1,006 additions and 38 deletions.
101 changes: 101 additions & 0 deletions bin/functionMetadata_original.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php declare(strict_types = 1);

return [
'abs' => ['hasSideEffects' => false],
'acos' => ['hasSideEffects' => false],
'acosh' => ['hasSideEffects' => false],
'addcslashes' => ['hasSideEffects' => false],
'addslashes' => ['hasSideEffects' => false],
'array_change_key_case' => ['hasSideEffects' => false],
'array_chunk' => ['hasSideEffects' => false],
'array_column' => ['hasSideEffects' => false],
'array_combine' => ['hasSideEffects' => false],
'array_count_values' => ['hasSideEffects' => false],
'array_diff' => ['hasSideEffects' => false],
'array_diff_assoc' => ['hasSideEffects' => false],
'array_diff_key' => ['hasSideEffects' => false],
'array_diff_uassoc' => ['hasSideEffects' => false],
'array_diff_ukey' => ['hasSideEffects' => false],
'array_fill' => ['hasSideEffects' => false],
'array_fill_keys' => ['hasSideEffects' => false],
'array_flip' => ['hasSideEffects' => false],
'array_intersect' => ['hasSideEffects' => false],
'array_intersect_assoc' => ['hasSideEffects' => false],
'array_intersect_key' => ['hasSideEffects' => false],
'array_intersect_uassoc' => ['hasSideEffects' => false],
'array_intersect_ukey' => ['hasSideEffects' => false],
'array_key_first' => ['hasSideEffects' => false],
'array_key_last' => ['hasSideEffects' => false],
'array_key_exists' => ['hasSideEffects' => false],
'array_keys' => ['hasSideEffects' => false],
'array_merge' => ['hasSideEffects' => false],
'array_merge_recursive' => ['hasSideEffects' => false],
'array_pad' => ['hasSideEffects' => false],
'array_product' => ['hasSideEffects' => false],
'array_rand' => ['hasSideEffects' => false],
'array_replace' => ['hasSideEffects' => false],
'array_replace_recursive' => ['hasSideEffects' => false],
'array_reverse' => ['hasSideEffects' => false],
'array_slice' => ['hasSideEffects' => false],
'array_sum' => ['hasSideEffects' => false],
'array_udiff' => ['hasSideEffects' => false],
'array_udiff_assoc' => ['hasSideEffects' => false],
'array_udiff_uassoc' => ['hasSideEffects' => false],
'array_uintersect' => ['hasSideEffects' => false],
'array_uintersect_assoc' => ['hasSideEffects' => false],
'array_uintersect_uassoc' => ['hasSideEffects' => false],
'array_unique' => ['hasSideEffects' => false],
'array_values' => ['hasSideEffects' => false],
'asin' => ['hasSideEffects' => false],
'asinh' => ['hasSideEffects' => false],
'atan' => ['hasSideEffects' => false],
'atan2' => ['hasSideEffects' => false],
'atanh' => ['hasSideEffects' => false],
'base64_decode' => ['hasSideEffects' => false],
'base64_encode' => ['hasSideEffects' => false],
'base_convert' => ['hasSideEffects' => false],
'basename' => ['hasSideEffects' => false],
'bcadd' => ['hasSideEffects' => false],
'bccomp' => ['hasSideEffects' => false],
'bcdiv' => ['hasSideEffects' => false],
'bcmod' => ['hasSideEffects' => false],
'bcmul' => ['hasSideEffects' => false],
// continue functionMap.php, line 424
'count' => ['hasSideEffects' => false],
'sprintf' => ['hasSideEffects' => false],

// methods
'DateTime::createFromFormat' => ['hasSideEffects' => false],
'DateTime::createFromImmutable' => ['hasSideEffects' => false],
'DateTime::getLastErrors' => ['hasSideEffects' => false],
'DateTime::add' => ['hasSideEffects' => true],
'DateTime::modify' => ['hasSideEffects' => true],
'DateTime::setDate' => ['hasSideEffects' => true],
'DateTime::setISODate' => ['hasSideEffects' => true],
'DateTime::setTime' => ['hasSideEffects' => true],
'DateTime::setTimestamp' => ['hasSideEffects' => true],
'DateTime::setTimezone' => ['hasSideEffects' => true],
'DateTime::sub' => ['hasSideEffects' => true],
'DateTime::diff' => ['hasSideEffects' => false],
'DateTime::format' => ['hasSideEffects' => false],
'DateTime::getOffset' => ['hasSideEffects' => false],
'DateTime::getTimestamp' => ['hasSideEffects' => false],
'DateTime::getTimezone' => ['hasSideEffects' => false],

'DateTimeImmutable::createFromFormat' => ['hasSideEffects' => false],
'DateTimeImmutable::createFromMutable' => ['hasSideEffects' => false],
'DateTimeImmutable::getLastErrors' => ['hasSideEffects' => false],
'DateTimeImmutable::add' => ['hasSideEffects' => false],
'DateTimeImmutable::modify' => ['hasSideEffects' => false],
'DateTimeImmutable::setDate' => ['hasSideEffects' => false],
'DateTimeImmutable::setISODate' => ['hasSideEffects' => false],
'DateTimeImmutable::setTime' => ['hasSideEffects' => false],
'DateTimeImmutable::setTimestamp' => ['hasSideEffects' => false],
'DateTimeImmutable::setTimezone' => ['hasSideEffects' => false],
'DateTimeImmutable::sub' => ['hasSideEffects' => false],
'DateTimeImmutable::diff' => ['hasSideEffects' => false],
'DateTimeImmutable::format' => ['hasSideEffects' => false],
'DateTimeImmutable::getOffset' => ['hasSideEffects' => false],
'DateTimeImmutable::getTimestamp' => ['hasSideEffects' => false],
'DateTimeImmutable::getTimezone' => ['hasSideEffects' => false],
];
82 changes: 82 additions & 0 deletions bin/generate-function-metadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env php
<?php declare(strict_types=1);

use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\ParserFactory;

(function () {
require_once __DIR__ . '/../vendor/autoload.php';

$parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7);
$finder = new Symfony\Component\Finder\Finder();
$finder->in(__DIR__ . '/../vendor/jetbrains/phpstorm-stubs')->files()->name('*.php');

$visitor = new class() extends \PhpParser\NodeVisitorAbstract {

/** @var string[] */
public $functions = [];

public function enterNode(Node $node)
{
if (!$node instanceof Node\Stmt\Function_) {
return;
}

foreach ($node->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
if ($attr->name->toString() === \JetBrains\PhpStorm\Pure::class) {
$this->functions[] = $node->namespacedName->toLowerString();
break;
}
}
}

return null;
}
};

foreach ($finder as $stubFile) {
$path = $stubFile->getPathname();
$traverser = new NodeTraverser();
$traverser->addVisitor(new NameResolver());
$traverser->addVisitor($visitor);

$traverser->traverse(
$parser->parse(\PHPStan\File\FileReader::read($path))
);
}

$metadata = require __DIR__ . '/functionMetadata_original.php';
foreach ($visitor->functions as $functionName) {
if (array_key_exists($functionName, $metadata)) {
if ($metadata[$functionName]['hasSideEffects']) {
throw new \PHPStan\ShouldNotHappenException($functionName);
}
}
$metadata[$functionName] = ['hasSideEffects' => false];
}

ksort($metadata);

$template = <<<'php'
<?php declare(strict_types = 1);
return [
%s
];
php;
$content = '';
foreach ($metadata as $name => $meta) {
$content .= sprintf(
"\t%s => [%s => %s],\n",
var_export($name, true),
var_export('hasSideEffects', true),
var_export($meta['hasSideEffects'], true),
);
}

\PHPStan\File\FileWriter::write(__DIR__ . '/../resources/functionMetadata.php', sprintf($template, $content));

})();
Loading

0 comments on commit 2817690

Please sign in to comment.