Merge branch '4.4'
* 4.4: Add return-types with help from DebugClassLoader in the CI do not mock removed getPublicDir() method [Bridge/Doctrine] fix review [ErrorHandler] make DebugClassLoader able to add return type declarations
This commit is contained in:
commit
23fac65a3c
35
.github/patch-types.php
vendored
Normal file
35
.github/patch-types.php
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (false === getenv('SYMFONY_PATCH_TYPE_DECLARATIONS')) {
|
||||||
|
putenv('SYMFONY_PATCH_TYPE_DECLARATIONS=force=1&php71-compat=0');
|
||||||
|
}
|
||||||
|
|
||||||
|
require __DIR__.'/../.phpunit/phpunit-8.3-0/vendor/autoload.php';
|
||||||
|
|
||||||
|
$loader = require __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
|
Symfony\Component\ErrorHandler\DebugClassLoader::enable();
|
||||||
|
|
||||||
|
foreach ($loader->getClassMap() as $class => $file) {
|
||||||
|
switch (true) {
|
||||||
|
case false !== strpos(realpath($file), '/vendor/'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Bridge/PhpUnit/'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Article.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/Config/Tests/Fixtures/BadParent.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Compiler/OptionalServiceClass.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ParentNotExists.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/BadClasses/MissingParent.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/ErrorHandler/Tests/Fixtures/'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ObjectOuter.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/NotLoadableClass.php'):
|
||||||
|
case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/Php74.php') && \PHP_VERSION_ID < 70400:
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
class_exists($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
Symfony\Component\ErrorHandler\DebugClassLoader::disable();
|
20
.travis.yml
20
.travis.yml
@ -26,6 +26,7 @@ env:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- php: 7.2
|
- php: 7.2
|
||||||
|
env: php_extra="7.4snapshot"
|
||||||
- php: 7.3
|
- php: 7.3
|
||||||
env: deps=high
|
env: deps=high
|
||||||
- php: 7.4snapshot
|
- php: 7.4snapshot
|
||||||
@ -78,10 +79,8 @@ before_install:
|
|||||||
export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n')
|
export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n')
|
||||||
find ~/.phpenv -name xdebug.ini -delete
|
find ~/.phpenv -name xdebug.ini -delete
|
||||||
|
|
||||||
if [[ $TRAVIS_PHP_VERSION = 7.4* && $deps ]]; then
|
if [[ $TRAVIS_PHP_VERSION = 7.4* ]]; then
|
||||||
export PHPUNIT_X="$PHPUNIT_X,issue-32995"
|
export PHPUNIT_X="$PHPUNIT_X,issue-32995"
|
||||||
elif [[ $TRAVIS_PHP_VERSION = 7.4* ]]; then
|
|
||||||
export PHPUNIT_X="$PHPUNIT --group issue-32995"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nanoseconds () {
|
nanoseconds () {
|
||||||
@ -149,7 +148,7 @@ before_install:
|
|||||||
- |
|
- |
|
||||||
# php.ini configuration
|
# php.ini configuration
|
||||||
for PHP in $TRAVIS_PHP_VERSION $php_extra; do
|
for PHP in $TRAVIS_PHP_VERSION $php_extra; do
|
||||||
phpenv global $PHP 2>/dev/null || (cd / && wget https://s3.amazonaws.com/travis-php-archives/binaries/ubuntu/14.04/x86_64/php-$PHP.tar.bz2 -O - | tar -xj)
|
phpenv global $PHP 2>/dev/null || (cd / && wget https://storage.googleapis.com/travis-ci-language-archives/php/binaries/ubuntu/16.04/x86_64/php-$PHP.tar.bz2 -O - | tar -xj)
|
||||||
INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini
|
INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini
|
||||||
echo date.timezone = Europe/Paris >> $INI
|
echo date.timezone = Europe/Paris >> $INI
|
||||||
echo memory_limit = -1 >> $INI
|
echo memory_limit = -1 >> $INI
|
||||||
@ -261,7 +260,7 @@ install:
|
|||||||
run_tests () {
|
run_tests () {
|
||||||
set -e
|
set -e
|
||||||
export PHP=$1
|
export PHP=$1
|
||||||
if [[ $PHP != $TRAVIS_PHP_VERSION && $TRAVIS_PULL_REQUEST != false ]]; then
|
if [[ $PHP != 7.4* && $PHP != $TRAVIS_PHP_VERSION && $TRAVIS_PULL_REQUEST != false ]]; then
|
||||||
echo -e "\\n\\e[1;34mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"
|
echo -e "\\n\\e[1;34mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@ -278,6 +277,17 @@ install:
|
|||||||
echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && ([ -e composer.lock ] && ${COMPOSER_UP/update/install} || $COMPOSER_UP --prefer-lowest --prefer-stable) && $PHPUNIT_X'"
|
echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && ([ -e composer.lock ] && ${COMPOSER_UP/update/install} || $COMPOSER_UP --prefer-lowest --prefer-stable) && $PHPUNIT_X'"
|
||||||
echo "$COMPONENTS" | xargs -n1 -I{} tar --append -f ~/php-ext/composer-lowest.lock.tar {}/composer.lock
|
echo "$COMPONENTS" | xargs -n1 -I{} tar --append -f ~/php-ext/composer-lowest.lock.tar {}/composer.lock
|
||||||
else
|
else
|
||||||
|
if [[ $PHP = 7.4* ]]; then
|
||||||
|
# add return types before running the test suite
|
||||||
|
rm vendor/symfony/contracts -Rf
|
||||||
|
ln -sd $(realpath src/Symfony/Contracts) vendor/symfony/contracts
|
||||||
|
sed -i 's/"\*\*\/Tests\/"//' composer.json
|
||||||
|
composer install --optimize-autoloader
|
||||||
|
php .github/patch-types.php
|
||||||
|
php .github/patch-types.php # ensure the script is idempotent
|
||||||
|
export PHPUNIT_X="$PHPUNIT_X,issue-32995,legacy"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "$COMPONENTS" | parallel --gnu "tfold {} $PHPUNIT_X {}"
|
echo "$COMPONENTS" | parallel --gnu "tfold {} $PHPUNIT_X {}"
|
||||||
tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty
|
tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty
|
||||||
if [[ $PHP = ${MIN_PHP%.*} ]]; then
|
if [[ $PHP = ${MIN_PHP%.*} ]]; then
|
||||||
|
@ -84,6 +84,6 @@ class ORMQueryBuilderLoader implements EntityLoaderInterface
|
|||||||
return $qb->andWhere($where)
|
return $qb->andWhere($where)
|
||||||
->getQuery()
|
->getQuery()
|
||||||
->setParameter($parameter, $values, $parameterType)
|
->setParameter($parameter, $values, $parameterType)
|
||||||
->getResult() ?: [];
|
->getResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,10 @@ class ORMQueryBuilderLoaderTest extends TestCase
|
|||||||
->setMethods(['setParameter', 'getResult', 'getSql', '_doExecute'])
|
->setMethods(['setParameter', 'getResult', 'getSql', '_doExecute'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
|
$query
|
||||||
|
->method('getResult')
|
||||||
|
->willReturn([]);
|
||||||
|
|
||||||
$query->expects($this->once())
|
$query->expects($this->once())
|
||||||
->method('setParameter')
|
->method('setParameter')
|
||||||
->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [1, 2], $expectedType)
|
->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [1, 2], $expectedType)
|
||||||
@ -66,6 +70,10 @@ class ORMQueryBuilderLoaderTest extends TestCase
|
|||||||
->setMethods(['setParameter', 'getResult', 'getSql', '_doExecute'])
|
->setMethods(['setParameter', 'getResult', 'getSql', '_doExecute'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
|
$query
|
||||||
|
->method('getResult')
|
||||||
|
->willReturn([]);
|
||||||
|
|
||||||
$query->expects($this->once())
|
$query->expects($this->once())
|
||||||
->method('setParameter')
|
->method('setParameter')
|
||||||
->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [1, 2, 3, '9223372036854775808'], Connection::PARAM_INT_ARRAY)
|
->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [1, 2, 3, '9223372036854775808'], Connection::PARAM_INT_ARRAY)
|
||||||
@ -98,6 +106,10 @@ class ORMQueryBuilderLoaderTest extends TestCase
|
|||||||
->setMethods(['setParameter', 'getResult', 'getSql', '_doExecute'])
|
->setMethods(['setParameter', 'getResult', 'getSql', '_doExecute'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
|
$query
|
||||||
|
->method('getResult')
|
||||||
|
->willReturn([]);
|
||||||
|
|
||||||
$query->expects($this->once())
|
$query->expects($this->once())
|
||||||
->method('setParameter')
|
->method('setParameter')
|
||||||
->with('ORMQueryBuilderLoader_getEntitiesByIds_id', ['71c5fd46-3f16-4abb-bad7-90ac1e654a2d', 'b98e8e11-2897-44df-ad24-d2627eb7f499'], Connection::PARAM_STR_ARRAY)
|
->with('ORMQueryBuilderLoader_getEntitiesByIds_id', ['71c5fd46-3f16-4abb-bad7-90ac1e654a2d', 'b98e8e11-2897-44df-ad24-d2627eb7f499'], Connection::PARAM_STR_ARRAY)
|
||||||
@ -133,6 +145,10 @@ class ORMQueryBuilderLoaderTest extends TestCase
|
|||||||
->setMethods(['setParameter', 'getResult', 'getSql', '_doExecute'])
|
->setMethods(['setParameter', 'getResult', 'getSql', '_doExecute'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
|
$query
|
||||||
|
->method('getResult')
|
||||||
|
->willReturn([]);
|
||||||
|
|
||||||
$query->expects($this->once())
|
$query->expects($this->once())
|
||||||
->method('setParameter')
|
->method('setParameter')
|
||||||
->with('ORMQueryBuilderLoader_getEntitiesByIds_id_value', [1, 2, 3], Connection::PARAM_INT_ARRAY)
|
->with('ORMQueryBuilderLoader_getEntitiesByIds_id_value', [1, 2, 3], Connection::PARAM_INT_ARRAY)
|
||||||
|
@ -42,7 +42,7 @@ class DebugClassLoader
|
|||||||
'bool' => 'bool',
|
'bool' => 'bool',
|
||||||
'callable' => 'callable',
|
'callable' => 'callable',
|
||||||
'float' => 'float',
|
'float' => 'float',
|
||||||
'int' => 'integer',
|
'int' => 'int',
|
||||||
'iterable' => 'iterable',
|
'iterable' => 'iterable',
|
||||||
'object' => 'object',
|
'object' => 'object',
|
||||||
'string' => 'string',
|
'string' => 'string',
|
||||||
@ -64,10 +64,79 @@ class DebugClassLoader
|
|||||||
'parent' => true,
|
'parent' => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private const MAGIC_METHODS = [
|
||||||
|
'__set' => 'void',
|
||||||
|
'__isset' => 'bool',
|
||||||
|
'__unset' => 'void',
|
||||||
|
'__sleep' => 'array',
|
||||||
|
'__wakeup' => 'void',
|
||||||
|
'__toString' => 'string',
|
||||||
|
'__clone' => 'void',
|
||||||
|
'__debugInfo' => 'array',
|
||||||
|
'__serialize' => 'array',
|
||||||
|
'__unserialize' => 'void',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const INTERNAL_TYPES = [
|
||||||
|
'ArrayAccess' => [
|
||||||
|
'offsetExists' => 'bool',
|
||||||
|
'offsetSet' => 'void',
|
||||||
|
'offsetUnset' => 'void',
|
||||||
|
],
|
||||||
|
'Countable' => [
|
||||||
|
'count' => 'int',
|
||||||
|
],
|
||||||
|
'Iterator' => [
|
||||||
|
'next' => 'void',
|
||||||
|
'valid' => 'bool',
|
||||||
|
'rewind' => 'void',
|
||||||
|
],
|
||||||
|
'IteratorAggregate' => [
|
||||||
|
'getIterator' => '\Traversable',
|
||||||
|
],
|
||||||
|
'OuterIterator' => [
|
||||||
|
'getInnerIterator' => '\Iterator',
|
||||||
|
],
|
||||||
|
'RecursiveIterator' => [
|
||||||
|
'hasChildren' => 'bool',
|
||||||
|
],
|
||||||
|
'SeekableIterator' => [
|
||||||
|
'seek' => 'void',
|
||||||
|
],
|
||||||
|
'Serializable' => [
|
||||||
|
'serialize' => 'string',
|
||||||
|
'unserialize' => 'void',
|
||||||
|
],
|
||||||
|
'SessionHandlerInterface' => [
|
||||||
|
'open' => 'bool',
|
||||||
|
'close' => 'bool',
|
||||||
|
'read' => 'string',
|
||||||
|
'write' => 'bool',
|
||||||
|
'destroy' => 'bool',
|
||||||
|
'gc' => 'bool',
|
||||||
|
],
|
||||||
|
'SessionIdInterface' => [
|
||||||
|
'create_sid' => 'string',
|
||||||
|
],
|
||||||
|
'SessionUpdateTimestampHandlerInterface' => [
|
||||||
|
'validateId' => 'bool',
|
||||||
|
'updateTimestamp' => 'bool',
|
||||||
|
],
|
||||||
|
'Throwable' => [
|
||||||
|
'getMessage' => 'string',
|
||||||
|
'getCode' => 'int',
|
||||||
|
'getFile' => 'string',
|
||||||
|
'getLine' => 'int',
|
||||||
|
'getTrace' => 'array',
|
||||||
|
'getPrevious' => '?\Throwable',
|
||||||
|
'getTraceAsString' => 'string',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
private $classLoader;
|
private $classLoader;
|
||||||
private $isFinder;
|
private $isFinder;
|
||||||
private $loaded = [];
|
private $loaded = [];
|
||||||
private $compatPatch;
|
private $patchTypes;
|
||||||
private static $caseCheck;
|
private static $caseCheck;
|
||||||
private static $checkedClasses = [];
|
private static $checkedClasses = [];
|
||||||
private static $final = [];
|
private static $final = [];
|
||||||
@ -80,12 +149,13 @@ class DebugClassLoader
|
|||||||
private static $method = [];
|
private static $method = [];
|
||||||
private static $returnTypes = [];
|
private static $returnTypes = [];
|
||||||
private static $methodTraits = [];
|
private static $methodTraits = [];
|
||||||
|
private static $fileOffsets = [];
|
||||||
|
|
||||||
public function __construct(callable $classLoader)
|
public function __construct(callable $classLoader)
|
||||||
{
|
{
|
||||||
$this->classLoader = $classLoader;
|
$this->classLoader = $classLoader;
|
||||||
$this->isFinder = \is_array($classLoader) && method_exists($classLoader[0], 'findFile');
|
$this->isFinder = \is_array($classLoader) && method_exists($classLoader[0], 'findFile');
|
||||||
$this->compatPatch = getenv('SYMFONY_PATCH_TYPE_DECLARATIONS_COMPAT') ?: null;
|
parse_str(getenv('SYMFONY_PATCH_TYPE_DECLARATIONS') ?: '', $this->patchTypes);
|
||||||
|
|
||||||
if (!isset(self::$caseCheck)) {
|
if (!isset(self::$caseCheck)) {
|
||||||
$file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), \DIRECTORY_SEPARATOR);
|
$file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), \DIRECTORY_SEPARATOR);
|
||||||
@ -160,13 +230,22 @@ class DebugClassLoader
|
|||||||
spl_autoload_unregister($function);
|
spl_autoload_unregister($function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$loader = null;
|
||||||
|
|
||||||
foreach ($functions as $function) {
|
foreach ($functions as $function) {
|
||||||
if (\is_array($function) && $function[0] instanceof self) {
|
if (\is_array($function) && $function[0] instanceof self) {
|
||||||
|
$loader = $function[0];
|
||||||
$function = $function[0]->getClassLoader();
|
$function = $function[0]->getClassLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_autoload_register($function);
|
spl_autoload_register($function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $loader) {
|
||||||
|
foreach (array_merge(get_declared_interfaces(), get_declared_traits(), get_declared_classes()) as $class) {
|
||||||
|
$loader->checkClass($class);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findFile(string $class): ?string
|
public function findFile(string $class): ?string
|
||||||
@ -256,6 +335,9 @@ class DebugClassLoader
|
|||||||
|
|
||||||
public function checkAnnotations(\ReflectionClass $refl, string $class): array
|
public function checkAnnotations(\ReflectionClass $refl, string $class): array
|
||||||
{
|
{
|
||||||
|
if ('Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV7' === $class || 'Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV6' === $class) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
$deprecations = [];
|
$deprecations = [];
|
||||||
|
|
||||||
// Don't trigger deprecations for classes in the same vendor
|
// Don't trigger deprecations for classes in the same vendor
|
||||||
@ -348,7 +430,7 @@ class DebugClassLoader
|
|||||||
if (trait_exists($class)) {
|
if (trait_exists($class)) {
|
||||||
$file = $refl->getFileName();
|
$file = $refl->getFileName();
|
||||||
|
|
||||||
foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) {
|
foreach ($refl->getMethods() as $method) {
|
||||||
if ($method->getFileName() === $file) {
|
if ($method->getFileName() === $file) {
|
||||||
self::$methodTraits[$file][$method->getStartLine()] = $class;
|
self::$methodTraits[$file][$method->getStartLine()] = $class;
|
||||||
}
|
}
|
||||||
@ -368,9 +450,17 @@ class DebugClassLoader
|
|||||||
self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use];
|
self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== (self::INTERNAL_TYPES[$use] ?? null)) {
|
||||||
|
foreach (self::INTERNAL_TYPES[$use] as $method => $returnType) {
|
||||||
|
if ('void' !== $returnType) {
|
||||||
|
self::$returnTypes[$class] += [$method => [$returnType, $returnType, $class, '']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) {
|
foreach ($refl->getMethods() as $method) {
|
||||||
if ($method->class !== $class) {
|
if ($method->class !== $class) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -413,32 +503,69 @@ class DebugClassLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset(self::$returnTypes[$class][$method->name]) && !$method->hasReturnType() && !($doc && preg_match('/\n\s+\* @return +(\S+)/', $doc))) {
|
$forcePatchTypes = $this->patchTypes['force'] ?? null;
|
||||||
list($normalizedType, $returnType, $declaringClass, $declaringFile) = self::$returnTypes[$class][$method->name];
|
|
||||||
|
|
||||||
if (null !== $this->compatPatch && 0 === strpos($class, $this->compatPatch)) {
|
if ($canAddReturnType = null !== $forcePatchTypes && false === strpos($method->getFileName(), \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR)) {
|
||||||
self::fixReturnStatements($method, $normalizedType);
|
if ('void' !== (self::MAGIC_METHODS[$method->name] ?? 'void')) {
|
||||||
|
$this->patchTypes['force'] = $forcePatchTypes ?: 'docblock';
|
||||||
|
}
|
||||||
|
|
||||||
|
$canAddReturnType = ($this->patchTypes['force'] ?? false)
|
||||||
|
|| false !== strpos($refl->getFileName(), \DIRECTORY_SEPARATOR.'Tests'.\DIRECTORY_SEPARATOR)
|
||||||
|
|| $refl->isFinal()
|
||||||
|
|| $method->isFinal()
|
||||||
|
|| $method->isPrivate()
|
||||||
|
|| ('' === (self::$internal[$class] ?? null) && !$refl->isAbstract())
|
||||||
|
|| '' === (self::$final[$class] ?? null)
|
||||||
|
|| preg_match('/@(final|internal)$/m', $doc)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== ($returnType = self::$returnTypes[$class][$method->name] ?? self::MAGIC_METHODS[$method->name] ?? null) && !$method->hasReturnType() && !($doc && preg_match('/\n\s+\* @return +(\S+)/', $doc))) {
|
||||||
|
if ('void' === $returnType) {
|
||||||
|
$canAddReturnType = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($normalizedType, $returnType, $declaringClass, $declaringFile) = \is_string($returnType) ? [$returnType, $returnType, '', ''] : $returnType;
|
||||||
|
|
||||||
|
if ($canAddReturnType && 'docblock' !== ($this->patchTypes['force'] ?? false)) {
|
||||||
|
$this->patchMethod($method, $returnType, $declaringFile, $normalizedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp($ns, $declaringClass, $len)) {
|
if (strncmp($ns, $declaringClass, $len)) {
|
||||||
if (null !== $this->compatPatch && 0 === strpos($class, $this->compatPatch)) {
|
if ($canAddReturnType && 'docblock' === ($this->patchTypes['force'] ?? false) && false === strpos($method->getFileName(), \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR)) {
|
||||||
self::patchMethod($method, $returnType, $declaringFile);
|
$this->patchMethod($method, $returnType, $declaringFile, $normalizedType);
|
||||||
}
|
} elseif ('' !== $declaringClass) {
|
||||||
|
|
||||||
$deprecations[] = sprintf('Method "%s::%s()" will return "%s" as of its next major version. Doing the same in child class "%s" will be required when upgrading.', $declaringClass, $method->name, $normalizedType, $class);
|
$deprecations[] = sprintf('Method "%s::%s()" will return "%s" as of its next major version. Doing the same in child class "%s" will be required when upgrading.', $declaringClass, $method->name, $normalizedType, $class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$doc) {
|
if (!$doc) {
|
||||||
|
$this->patchTypes['force'] = $forcePatchTypes;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$method->hasReturnType() && false !== strpos($doc, '@return') && preg_match('/\n\s+\* @return +(\S+)/', $doc, $matches)) {
|
$matches = [];
|
||||||
|
|
||||||
|
if (!$method->hasReturnType() && ((false !== strpos($doc, '@return') && preg_match('/\n\s+\* @return +(\S+)/', $doc, $matches)) || 'void' !== (self::MAGIC_METHODS[$method->name] ?? 'void'))) {
|
||||||
|
$matches = $matches ?: [1 => self::MAGIC_METHODS[$method->name]];
|
||||||
$this->setReturnType($matches[1], $method, $parent);
|
$this->setReturnType($matches[1], $method, $parent);
|
||||||
|
|
||||||
if (null !== $this->compatPatch && 0 === strpos($class, $this->compatPatch)) {
|
if (isset(self::$returnTypes[$class][$method->name][0]) && $canAddReturnType) {
|
||||||
self::fixReturnStatements($method, self::$returnTypes[$class][$method->name][0] ?? '?');
|
$this->fixReturnStatements($method, self::$returnTypes[$class][$method->name][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($method->isPrivate()) {
|
||||||
|
unset(self::$returnTypes[$class][$method->name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->patchTypes['force'] = $forcePatchTypes;
|
||||||
|
|
||||||
|
if ($method->isPrivate()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$finalOrInternal = false;
|
$finalOrInternal = false;
|
||||||
@ -609,9 +736,13 @@ class DebugClassLoader
|
|||||||
$typesMap[$this->normalizeType($t, $method->class, $parent)] = $t;
|
$typesMap[$this->normalizeType($t, $method->class, $parent)] = $t;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($typesMap['array']) && (isset($typesMap['Traversable']) || isset($typesMap['\Traversable']))) {
|
if (isset($typesMap['array'])) {
|
||||||
|
if (isset($typesMap['Traversable']) || isset($typesMap['\Traversable'])) {
|
||||||
$typesMap['iterable'] = 'array' !== $typesMap['array'] ? $typesMap['array'] : 'iterable';
|
$typesMap['iterable'] = 'array' !== $typesMap['array'] ? $typesMap['array'] : 'iterable';
|
||||||
unset($typesMap['array'], $typesMap['Traversable'], $typesMap['\Traversable']);
|
unset($typesMap['array'], $typesMap['Traversable'], $typesMap['\Traversable']);
|
||||||
|
} elseif ('array' !== $typesMap['array'] && isset(self::$returnTypes[$method->class][$method->name])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($typesMap['array']) && isset($typesMap['iterable'])) {
|
if (isset($typesMap['array']) && isset($typesMap['iterable'])) {
|
||||||
@ -630,7 +761,7 @@ class DebugClassLoader
|
|||||||
} elseif ('null' === $normalizedType) {
|
} elseif ('null' === $normalizedType) {
|
||||||
$normalizedType = $t;
|
$normalizedType = $t;
|
||||||
$returnType = $t;
|
$returnType = $t;
|
||||||
} elseif ($n !== $normalizedType) {
|
} elseif ($n !== $normalizedType || !preg_match('/^\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+$/', $n)) {
|
||||||
// ignore multi-types return declarations
|
// ignore multi-types return declarations
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -680,7 +811,7 @@ class DebugClassLoader
|
|||||||
/**
|
/**
|
||||||
* Utility method to add @return annotations to the Symfony code-base where it triggers a self-deprecations.
|
* Utility method to add @return annotations to the Symfony code-base where it triggers a self-deprecations.
|
||||||
*/
|
*/
|
||||||
private static function patchMethod(\ReflectionMethod $method, string $returnType, string $declaringFile)
|
private function patchMethod(\ReflectionMethod $method, string $returnType, string $declaringFile, string $normalizedType)
|
||||||
{
|
{
|
||||||
static $patchedMethods = [];
|
static $patchedMethods = [];
|
||||||
static $useStatements = [];
|
static $useStatements = [];
|
||||||
@ -690,8 +821,10 @@ class DebugClassLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
$patchedMethods[$file][$startLine] = true;
|
$patchedMethods[$file][$startLine] = true;
|
||||||
$patchedMethods[$file][0] = $patchedMethods[$file][0] ?? 0;
|
$fileOffset = self::$fileOffsets[$file] ?? 0;
|
||||||
$startLine += $patchedMethods[$file][0] - 2;
|
$startLine += $fileOffset - 2;
|
||||||
|
$nullable = '?' === $normalizedType[0] ? '?' : '';
|
||||||
|
$normalizedType = ltrim($normalizedType, '?');
|
||||||
$returnType = explode('|', $returnType);
|
$returnType = explode('|', $returnType);
|
||||||
$code = file($file);
|
$code = file($file);
|
||||||
|
|
||||||
@ -737,17 +870,22 @@ class DebugClassLoader
|
|||||||
if (!isset($useMap[$alias])) {
|
if (!isset($useMap[$alias])) {
|
||||||
$useStatements[$file][2][$alias] = $type;
|
$useStatements[$file][2][$alias] = $type;
|
||||||
$code[$useOffset] = "use $type;\n".$code[$useOffset];
|
$code[$useOffset] = "use $type;\n".$code[$useOffset];
|
||||||
++$patchedMethods[$file][0];
|
++$fileOffset;
|
||||||
} elseif ($useMap[$alias] !== $type) {
|
} elseif ($useMap[$alias] !== $type) {
|
||||||
$alias .= 'FIXME';
|
$alias .= 'FIXME';
|
||||||
$useStatements[$file][2][$alias] = $type;
|
$useStatements[$file][2][$alias] = $type;
|
||||||
$code[$useOffset] = "use $type as $alias;\n".$code[$useOffset];
|
$code[$useOffset] = "use $type as $alias;\n".$code[$useOffset];
|
||||||
++$patchedMethods[$file][0];
|
++$fileOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
$returnType[$i] = null !== $format ? sprintf($format, $alias) : $alias;
|
$returnType[$i] = null !== $format ? sprintf($format, $alias) : $alias;
|
||||||
|
|
||||||
|
if (!isset(self::SPECIAL_RETURN_TYPES[$normalizedType]) && !isset(self::SPECIAL_RETURN_TYPES[$returnType[$i]])) {
|
||||||
|
$normalizedType = $returnType[$i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('docblock' === ($this->patchTypes['force'] ?? null) || ('object' === $normalizedType && ($this->patchTypes['php71-compat'] ?? false))) {
|
||||||
$returnType = implode('|', $returnType);
|
$returnType = implode('|', $returnType);
|
||||||
|
|
||||||
if ($method->getDocComment()) {
|
if ($method->getDocComment()) {
|
||||||
@ -761,8 +899,13 @@ class DebugClassLoader
|
|||||||
EOTXT;
|
EOTXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
$patchedMethods[$file][0] += substr_count($code[$startLine], "\n") - 1;
|
$fileOffset += substr_count($code[$startLine], "\n") - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$fileOffsets[$file] = $fileOffset;
|
||||||
file_put_contents($file, $code);
|
file_put_contents($file, $code);
|
||||||
|
|
||||||
|
$this->fixReturnStatements($method, $nullable.$normalizedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getUseStatements(string $file): array
|
private static function getUseStatements(string $file): array
|
||||||
@ -808,15 +951,25 @@ EOTXT;
|
|||||||
return [$namespace, $useOffset, $useMap];
|
return [$namespace, $useOffset, $useMap];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function fixReturnStatements(\ReflectionMethod $method, string $returnType)
|
private function fixReturnStatements(\ReflectionMethod $method, string $returnType)
|
||||||
{
|
{
|
||||||
|
if (($this->patchTypes['php71-compat'] ?? false) && 'object' === ltrim($returnType, '?') && 'docblock' !== ($this->patchTypes['force'] ?? null)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!file_exists($file = $method->getFileName())) {
|
if (!file_exists($file = $method->getFileName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fixedCode = $code = file($file);
|
$fixedCode = $code = file($file);
|
||||||
$end = $method->getEndLine();
|
$i = (self::$fileOffsets[$file] ?? 0) + $method->getStartLine();
|
||||||
for ($i = $method->getStartLine(); $i < $end; ++$i) {
|
|
||||||
|
if ('?' !== $returnType && 'docblock' !== ($this->patchTypes['force'] ?? null)) {
|
||||||
|
$fixedCode[$i - 1] = preg_replace('/\)(;?\n)/', "): $returnType\\1", $code[$i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$end = $method->isGenerator() ? $i : $method->getEndLine();
|
||||||
|
for (; $i < $end; ++$i) {
|
||||||
if ('void' === $returnType) {
|
if ('void' === $returnType) {
|
||||||
$fixedCode[$i] = str_replace(' return null;', ' return;', $code[$i]);
|
$fixedCode[$i] = str_replace(' return null;', ' return;', $code[$i]);
|
||||||
} elseif ('mixed' === $returnType || '?' === $returnType[0]) {
|
} elseif ('mixed' === $returnType || '?' === $returnType[0]) {
|
||||||
|
@ -100,7 +100,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function gc($maxlifetime)
|
public function gc($maxlifetime)
|
||||||
{
|
{
|
||||||
|
@ -21,7 +21,6 @@ use Symfony\Component\HttpFoundation\Response;
|
|||||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||||
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
|
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
|
||||||
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
|
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
|
||||||
use Symfony\Component\HttpKernel\HttpKernel;
|
|
||||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
use Symfony\Component\HttpKernel\Kernel;
|
use Symfony\Component\HttpKernel\Kernel;
|
||||||
use Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest;
|
use Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest;
|
||||||
@ -595,7 +594,7 @@ EOF;
|
|||||||
{
|
{
|
||||||
$bundle = $this
|
$bundle = $this
|
||||||
->getMockBuilder('Symfony\Component\HttpKernel\Bundle\BundleInterface')
|
->getMockBuilder('Symfony\Component\HttpKernel\Bundle\BundleInterface')
|
||||||
->setMethods(['getPath', 'getParent', 'getName'])
|
->setMethods(['getPath', 'getName'])
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -617,12 +616,6 @@ EOF;
|
|||||||
->willReturn($dir)
|
->willReturn($dir)
|
||||||
;
|
;
|
||||||
|
|
||||||
$bundle
|
|
||||||
->expects($this->any())
|
|
||||||
->method('getParent')
|
|
||||||
->willReturn($parent)
|
|
||||||
;
|
|
||||||
|
|
||||||
return $bundle;
|
return $bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user