Skip to content

Commit

Permalink
[config] include bootstrap files of extensions, to let rector know ab…
Browse files Browse the repository at this point in the history
…out types as well (#3380)

* [config] include bootstrap files of extensions, to let rector know about types as well

* tidy

* make fixtures unique to easier find
  • Loading branch information
TomasVotruba committed Feb 14, 2023
1 parent dffddb2 commit 48228ed
Show file tree
Hide file tree
Showing 15 changed files with 220 additions and 142 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"composer/xdebug-handler": "^3.0.3",
"doctrine/inflector": "^2.0.6",
"fidry/cpu-core-counter": "^0.5.1",
"nette/neon": "^3.4",
"nette/utils": "^3.2.9",
"nikic/php-parser": "^4.15.3",
"ondram/ci-detector": "^4.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\NodeTypeResolver\DependencyInjection;

use Rector\NodeTypeResolver\DependencyInjection\PHPStanExtensionsConfigResolver;
use Rector\Testing\PHPUnit\AbstractTestCase;

final class PHPStanExtensionsConfigResolverTest extends AbstractTestCase
{
private PHPStanExtensionsConfigResolver $phpStanExtensionsConfigResolver;

protected function setUp(): void
{
$this->boot();

$this->phpStanExtensionsConfigResolver = $this->getService(PHPStanExtensionsConfigResolver::class);
}

public function test(): void
{
// these configs are required by this package, so must be in there

$phpunitExtensionFilePath = realpath(__DIR__ . '/../../../vendor/phpstan/phpstan-phpunit/extension.neon');

$assertExtensionFilePath = realpath(
__DIR__ . '/../../../vendor/phpstan/phpstan-webmozart-assert/extension.neon'
);

$extensionConfigFiles = $this->phpStanExtensionsConfigResolver->resolve();

$this->assertContains($phpunitExtensionFilePath, $extensionConfigFiles);
$this->assertContains($assertExtensionFilePath, $extensionConfigFiles);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\DependencyInjection;

use PHPStan\ExtensionInstaller\GeneratedConfig;
use Rector\Core\Exception\ShouldNotHappenException;
use ReflectionClass;

/**
* @see \Rector\Tests\NodeTypeResolver\DependencyInjection\PHPStanExtensionsConfigResolverTest
*/
final class PHPStanExtensionsConfigResolver
{
/**
* @var string[]
*/
private array $cachedExtensionConfigFiles = [];

/**
* @return string[]
*/
public function resolve(): array
{
// same logic as in PHPStan for extension installed - https://github.com/phpstan/phpstan-src/blob/5956ec4f6cd09c8d7db9466ed4e7f25706f37a43/src/Command/CommandHelper.php#L195-L222
if (! class_exists(GeneratedConfig::class)) {
return [];
}

if ($this->cachedExtensionConfigFiles !== []) {
return $this->cachedExtensionConfigFiles;
}

$reflectionClass = new ReflectionClass(GeneratedConfig::class);
$generatedConfigClassFileName = $reflectionClass->getFileName();
if ($generatedConfigClassFileName === false) {
throw new ShouldNotHappenException();
}

$generatedConfigDirectory = dirname($generatedConfigClassFileName);

$extensionConfigFiles = [];

foreach (GeneratedConfig::EXTENSIONS as $extension) {
$fileNames = $extension['extra']['includes'] ?? [];
foreach ($fileNames as $fileName) {
$configFilePath = $generatedConfigDirectory . '/' . $extension['relative_install_path'] . '/' . $fileName;

$absoluteConfigFilePath = realpath($configFilePath);
if (! is_string($absoluteConfigFilePath)) {
continue;
}

$extensionConfigFiles[] = $absoluteConfigFilePath;
}
}

$this->cachedExtensionConfigFiles = $extensionConfigFiles;

return $extensionConfigFiles;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@
use PHPStan\Dependency\DependencyResolver;
use PHPStan\DependencyInjection\Container;
use PHPStan\DependencyInjection\ContainerFactory;
use PHPStan\ExtensionInstaller\GeneratedConfig;
use PHPStan\File\FileHelper;
use PHPStan\Parser\Parser;
use PHPStan\PhpDoc\TypeNodeResolver;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Configuration\Option;
use Rector\Core\Configuration\Parameter\ParameterProvider;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
use ReflectionClass;

/**
* Factory so Symfony app can use services from PHPStan container
Expand All @@ -28,8 +25,10 @@ final class PHPStanServicesFactory
{
private readonly Container $container;

public function __construct(ParameterProvider $parameterProvider)
{
public function __construct(
ParameterProvider $parameterProvider,
PHPStanExtensionsConfigResolver $phpStanExtensionsConfigResolver,
) {
$containerFactory = new ContainerFactory(getcwd());

$additionalConfigFiles = [];
Expand All @@ -42,7 +41,7 @@ public function __construct(ParameterProvider $parameterProvider)
$additionalConfigFiles[] = __DIR__ . '/../../../config/phpstan/better-infer.neon';
$additionalConfigFiles[] = __DIR__ . '/../../../config/phpstan/parser.neon';

$extensionConfigFiles = $this->resolveExtensionConfigs();
$extensionConfigFiles = $phpStanExtensionsConfigResolver->resolve();
$additionalConfigFiles = array_merge($additionalConfigFiles, $extensionConfigFiles);

$existingAdditionalConfigFiles = array_filter($additionalConfigFiles, 'file_exists');
Expand Down Expand Up @@ -121,39 +120,4 @@ public function createDynamicSourceLocatorProvider(): DynamicSourceLocatorProvid
{
return $this->container->getByType(DynamicSourceLocatorProvider::class);
}

/**
* @return string[]
*/
private function resolveExtensionConfigs(): array
{
// same logic as in PHPStan for extension installed - https://github.com/phpstan/phpstan-src/blob/5956ec4f6cd09c8d7db9466ed4e7f25706f37a43/src/Command/CommandHelper.php#L195-L222
if (! class_exists(GeneratedConfig::class)) {
return [];
}

$reflectionClass = new ReflectionClass(GeneratedConfig::class);
$generatedConfigClassFileName = $reflectionClass->getFileName();
if ($generatedConfigClassFileName === false) {
throw new ShouldNotHappenException();
}

$generatedConfigDirectory = dirname($generatedConfigClassFileName);

$extensionConfigFiles = [];

foreach (GeneratedConfig::EXTENSIONS as $extension) {
$fileNames = $extension['extra']['includes'] ?? [];
foreach ($fileNames as $fileName) {
$configFilePath = $generatedConfigDirectory . '/' . $extension['relative_install_path'] . '/' . $fileName;
if (! file_exists($configFilePath)) {
continue;
}

$extensionConfigFiles[] = $configFilePath;
}
}

return $extensionConfigFiles;
}
}
1 change: 1 addition & 0 deletions packages/Testing/PHPUnit/AbstractRectorTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ protected function setUp(): void
/** @var BootstrapFilesIncluder $bootstrapFilesIncluder */
$bootstrapFilesIncluder = $this->getService(BootstrapFilesIncluder::class);
$bootstrapFilesIncluder->includeBootstrapFiles();
$bootstrapFilesIncluder->includePHPStanExtensionsBoostrapFiles();
}

protected function tearDown(): void
Expand Down
8 changes: 3 additions & 5 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ parameters:
# known value
- '#Property PhpParser\\Node\\Stmt\\Foreach_\:\:\$valueVar \(PhpParser\\Node\\Expr\) does not accept PhpParser\\Node\\Expr\|null#'

- '#Parameter \#1 \$variable of class Rector\\Php70\\ValueObject\\VariableAssignPair constructor expects PhpParser\\Node\\Expr\\ArrayDimFetch\|PhpParser\\Node\\Expr\\PropertyFetch\|PhpParser\\Node\\Expr\\StaticPropertyFetch\|PhpParser\\Node\\Expr\\Variable, PhpParser\\Node\\Expr given#'

# is nested expr
- '#Access to an undefined property PhpParser\\Node\\Expr\:\:\$expr#'

Expand Down Expand Up @@ -432,9 +430,9 @@ parameters:
paths:
# autoload check in bin file
- bin/rector.php
- src/Bootstrap/ExtensionConfigResolver.php
- packages/NodeTypeResolver/DependencyInjection/PHPStanExtensionsConfigResolver.php
# for config class reflection
- packages/NodeTypeResolver/DependencyInjection/PHPStanServicesFactory.php
- src/Bootstrap/ExtensionConfigResolver.php
- src/DependencyInjection/CompilerPass/AutowireArrayParameterCompilerPass.php
- src/DependencyInjection/Skipper/ParameterSkipper.php
- src/DependencyInjection/DefinitionFinder.php
Expand Down Expand Up @@ -691,8 +689,8 @@ parameters:
-
message: '#Offset (.*?)includes(.*?) always exists and is not nullable#'
paths:
- packages/NodeTypeResolver/DependencyInjection/PHPStanServicesFactory.php
- src/Bootstrap/ExtensionConfigResolver.php
- packages/NodeTypeResolver/DependencyInjection/PHPStanExtensionsConfigResolver.php

# returns bool for notifications
- '#Method "renamePropertyPromotion\(\)" returns bool type, so the name should start with is/has/was#'
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ArrayStatic extends \DateTime

public function __construct(DateTime $dateTime)
{
$this->dateTime = rand(0,1)
$this->dateTime = rand(0, 15)
? [$dateTime]
: null;
}
Expand All @@ -38,7 +38,7 @@ class ArrayStatic extends \DateTime

public function __construct(\DateTimeInterface $dateTime)
{
$this->dateTime = rand(0,1)
$this->dateTime = rand(0, 15)
? [$dateTime]
: null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\Fixture;
use DateTime;
use DateTimeInterface;

class VarStaticInNullable extends \DateTime
class VarStaticInNullable2 extends \DateTime
{
/**
* @var ?static
Expand All @@ -14,7 +14,7 @@ class VarStaticInNullable extends \DateTime

public function __construct(DateTime $dateTime)
{
$this->dateTime = rand(0,1)
$this->dateTime = rand(0,45)
? $dateTime
: null;
}
Expand All @@ -29,7 +29,7 @@ namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\Fixture;
use DateTime;
use DateTimeInterface;

class VarStaticInNullable extends \DateTime
class VarStaticInNullable2 extends \DateTime
{
/**
* @var ?static
Expand All @@ -38,7 +38,7 @@ class VarStaticInNullable extends \DateTime

public function __construct(\DateTimeInterface $dateTime)
{
$this->dateTime = rand(0,1)
$this->dateTime = rand(0,45)
? $dateTime
: null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class VarStaticInUnion extends \DateTime

public function __construct(DateTime $dateTime)
{
$this->dateTime = rand(0,1)
$this->dateTime = rand(0,30)
? $dateTime
: null;
}
Expand All @@ -38,7 +38,7 @@ class VarStaticInUnion extends \DateTime

public function __construct(\DateTimeInterface $dateTime)
{
$this->dateTime = rand(0,1)
$this->dateTime = rand(0,30)
? $dateTime
: null;
}
Expand Down
Loading

0 comments on commit 48228ed

Please sign in to comment.