Skip to content

Commit 64f4efc

Browse files
committed
Pre-lowercase callmaps
1 parent 972f75b commit 64f4efc

19 files changed

+21407
-21278
lines changed

bin/Dockerfile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
ARG VERSION
2+
FROM php:${VERSION}
3+
4+
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
5+
6+
RUN chmod +x /usr/local/bin/install-php-extensions && \
7+
install-php-extensions pcntl uv-beta ffi pgsql intl gmp mbstring pdo_mysql xml dom iconv zip igbinary gd && \
8+
rm /usr/local/bin/install-php-extensions
9+
10+
ADD php.ini /usr/local/etc/php/php.ini

bin/gen_base_callmap.php

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
$callmap = [];
6+
7+
require __DIR__ . '/gen_callmap_utils.php';
8+
9+
foreach (get_defined_functions()['internal'] as $name) {
10+
$func = new ReflectionFunction($name);
11+
12+
$args = paramsToEntries($func);
13+
14+
$callmap[$name] = $args;
15+
}
16+
17+
foreach (get_declared_classes() as $class) {
18+
foreach ((new ReflectionClass($class))->getMethods() as $method) {
19+
$args = paramsToEntries($method);
20+
21+
$callmap[$class.'::'.$method->getName()] = $args;
22+
}
23+
}
24+
25+
var_dump($callmap);

bin/gen_base_callmap.sh

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
VERSIONS="7.0 7.1 7.2 7.3 7.4 8.0 8.1 8.2 8.3 8.4"
4+
5+
cd bin
6+
7+
for f in $VERSIONS; do
8+
docker build --build-arg VERSION=$f . -t psalm_test_$f &
9+
done
10+
11+
wait
12+
13+
for f in $VERSIONS; do
14+
15+
done

bin/gen_callmap.php

+5-158
Original file line numberDiff line numberDiff line change
@@ -6,171 +6,18 @@
66

77
require 'vendor/autoload.php';
88

9+
require __DIR__ . '/gen_callmap_utils.php';
10+
911
use DG\BypassFinals;
1012
use Psalm\Internal\Analyzer\ProjectAnalyzer;
11-
use Psalm\Internal\Codebase\Reflection;
1213
use Psalm\Internal\Provider\FileProvider;
1314
use Psalm\Internal\Provider\Providers;
14-
use Psalm\Internal\Type\Comparator\UnionTypeComparator;
1515
use Psalm\Tests\TestConfig;
16-
use Psalm\Type;
17-
use Psalm\Type\Atomic\TNull;
18-
19-
/**
20-
* Returns the correct reflection type for function or method name.
21-
*/
22-
function getReflectionFunction(string $functionName): ?ReflectionFunctionAbstract
23-
{
24-
try {
25-
if (strpos($functionName, '::') !== false) {
26-
if (PHP_VERSION_ID < 8_03_00) {
27-
return new ReflectionMethod($functionName);
28-
}
29-
30-
return ReflectionMethod::createFromMethodName($functionName);
31-
}
32-
33-
/** @var callable-string $functionName */
34-
return new ReflectionFunction($functionName);
35-
} catch (ReflectionException $e) {
36-
return null;
37-
}
38-
}
39-
40-
/**
41-
* @param array<string, string> $entryParameters
42-
*/
43-
function assertEntryParameters(ReflectionFunctionAbstract $function, array &$entryParameters): void
44-
{
45-
assertEntryReturnType($function, $entryParameters[0]);
46-
/**
47-
* Parse the parameter names from the map.
48-
*
49-
* @var array<string, array{byRef: bool, refMode: 'rw'|'w'|'r', variadic: bool, optional: bool, type: string}>
50-
*/
51-
$normalizedEntries = [];
52-
53-
foreach ($entryParameters as $key => &$entry) {
54-
if ($key === 0) {
55-
continue;
56-
}
57-
$normalizedKey = $key;
58-
/**
59-
* @var array{byRef: bool, refMode: 'rw'|'w'|'r', variadic: bool, optional: bool, type: string} $normalizedEntry
60-
*/
61-
$normalizedEntry = [
62-
'variadic' => false,
63-
'byRef' => false,
64-
'optional' => false,
65-
'type' => &$entry,
66-
];
67-
if (strncmp($normalizedKey, '&', 1) === 0) {
68-
$normalizedEntry['byRef'] = true;
69-
$normalizedKey = substr($normalizedKey, 1);
70-
}
71-
72-
if (strncmp($normalizedKey, '...', 3) === 0) {
73-
$normalizedEntry['variadic'] = true;
74-
$normalizedKey = substr($normalizedKey, 3);
75-
}
76-
77-
// Read the reference mode
78-
if ($normalizedEntry['byRef']) {
79-
$parts = explode('_', $normalizedKey, 2);
80-
if (count($parts) === 2) {
81-
if (!($parts[0] === 'rw' || $parts[0] === 'w' || $parts[0] === 'r')) {
82-
throw new InvalidArgumentException('Invalid refMode: '.$parts[0]);
83-
}
84-
$normalizedEntry['refMode'] = $parts[0];
85-
$normalizedKey = $parts[1];
86-
} else {
87-
$normalizedEntry['refMode'] = 'rw';
88-
}
89-
}
90-
91-
// Strip prefixes.
92-
if (substr($normalizedKey, -1, 1) === "=") {
93-
$normalizedEntry['optional'] = true;
94-
$normalizedKey = substr($normalizedKey, 0, -1);
95-
}
96-
97-
$normalizedEntry['name'] = $normalizedKey;
98-
$normalizedEntries[$normalizedKey] = $normalizedEntry;
99-
}
100-
101-
foreach ($function->getParameters() as $parameter) {
102-
if (isset($normalizedEntries[$parameter->getName()])) {
103-
assertParameter($normalizedEntries[$parameter->getName()], $parameter);
104-
}
105-
}
106-
}
107-
108-
/**
109-
* @param array{byRef: bool, name?: string, refMode: 'rw'|'w'|'r', variadic: bool, optional: bool, type: string} $normalizedEntry
110-
*/
111-
function assertParameter(array &$normalizedEntry, ReflectionParameter $param): void
112-
{
113-
$name = $param->getName();
114-
115-
$expectedType = $param->getType();
116-
117-
if (isset($expectedType) && !empty($normalizedEntry['type'])) {
118-
$func = $param->getDeclaringFunction()->getName();
119-
assertTypeValidity($expectedType, $normalizedEntry['type'], "Param $func '{$name}'");
120-
}
121-
}
122-
123-
function assertEntryReturnType(ReflectionFunctionAbstract $function, string &$entryReturnType): void
124-
{
125-
if (version_compare(PHP_VERSION, '8.1.0', '>=')) {
126-
$expectedType = $function->hasTentativeReturnType() ? $function->getTentativeReturnType() : $function->getReturnType();
127-
} else {
128-
$expectedType = $function->getReturnType();
129-
}
130-
131-
if ($expectedType !== null) {
132-
assertTypeValidity($expectedType, $entryReturnType, 'Return');
133-
}
134-
}
135-
136-
/**
137-
* Since string equality is too strict, we do some extra checking here
138-
*/
139-
function assertTypeValidity(ReflectionType $reflected, string &$specified, string $msgPrefix): void
140-
{
141-
$expectedType = Reflection::getPsalmTypeFromReflectionType($reflected);
142-
$callMapType = Type::parseString($specified === '' ? 'mixed' : $specified);
143-
144-
$codebase = ProjectAnalyzer::getInstance()->getCodebase();
145-
try {
146-
if (!UnionTypeComparator::isContainedBy($codebase, $callMapType, $expectedType, false, false, null, false, false) && !str_contains($specified, 'static')) {
147-
$specified = $expectedType->getId(true);
148-
$callMapType = $expectedType;
149-
}
150-
} catch (Throwable) {
151-
}
152-
153-
if ($expectedType->hasMixed()) {
154-
return;
155-
}
156-
$callMapType = $callMapType->getBuilder();
157-
if ($expectedType->isNullable() !== $callMapType->isNullable()) {
158-
if ($expectedType->isNullable()) {
159-
$callMapType->addType(new TNull());
160-
} else {
161-
$callMapType->removeType('null');
162-
}
163-
}
164-
$specified = $callMapType->getId(true);
165-
// //$this->assertSame($expectedType->hasBool(), $callMapType->hasBool(), "{$msgPrefix} type '{$specified}' missing bool from reflected type '{$reflected}'");
166-
// $this->assertSame($expectedType->hasArray(), $callMapType->hasArray(), "{$msgPrefix} type '{$specified}' missing array from reflected type '{$reflected}'");
167-
// $this->assertSame($expectedType->hasInt(), $callMapType->hasInt(), "{$msgPrefix} type '{$specified}' missing int from reflected type '{$reflected}'");
168-
// $this->assertSame($expectedType->hasFloat(), $callMapType->hasFloat(), "{$msgPrefix} type '{$specified}' missing float from reflected type '{$reflected}'");
169-
}
17016

17117
BypassFinals::enable();
17218

173-
function writeCallMap(string $file, array $callMap) {
19+
function writeCallMap(string $file, array $callMap): void
20+
{
17421
file_put_contents($file, '<?php // phpcs:ignoreFile
17522
17623
return '.var_export($callMap, true).';');
@@ -203,4 +50,4 @@ function writeCallMap(string $file, array $callMap) {
20350
}
20451
}
20552

206-
writeCallMap($diffFile, $diff);
53+
writeCallMap($diffFile, $diff);

0 commit comments

Comments
 (0)