Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

check generic mixed type based on config #2809

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Analyser/DirectInternalScopeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Properties\PropertyReflectionFinder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\ShouldNotHappenException;
use function is_a;

Expand All @@ -38,6 +39,7 @@ public function __construct(
private bool $explicitMixedInUnknownGenericNew,
private bool $explicitMixedForGlobalVariables,
private ConstantResolver $constantResolver,
private RuleLevelHelper $ruleLevelHelper,
)
{
}
Expand Down Expand Up @@ -86,6 +88,7 @@ public function create(
$this->parser,
$this->nodeScopeResolver,
$this->constantResolver,
$this->ruleLevelHelper,
$context,
$this->phpVersion,
$declareStrictTypes,
Expand Down
2 changes: 2 additions & 0 deletions src/Analyser/LazyInternalScopeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Properties\PropertyReflectionFinder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\ShouldNotHappenException;
use function is_a;

Expand Down Expand Up @@ -80,6 +81,7 @@ public function create(
$this->container->getService('currentPhpVersionSimpleParser'),
$this->container->getByType(NodeScopeResolver::class),
$this->container->getByType(ConstantResolver::class),
$this->container->getByType(RuleLevelHelper::class),
$context,
$this->container->getByType(PhpVersion::class),
$declareStrictTypes,
Expand Down
4 changes: 3 additions & 1 deletion src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Reflection\TrivialParametersAcceptor;
use PHPStan\Rules\Properties\PropertyReflectionFinder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Accessory\AccessoryArrayListType;
Expand Down Expand Up @@ -188,6 +189,7 @@ public function __construct(
private Parser $parser,
private NodeScopeResolver $nodeScopeResolver,
private ConstantResolver $constantResolver,
private RuleLevelHelper $ruleLevelHelper,
private ScopeContext $context,
private PhpVersion $phpVersion,
private bool $declareStrictTypes = false,
Expand Down Expand Up @@ -2772,7 +2774,7 @@ private function enterFunctionLike(
}
}
$parameterNode = new Variable($parameter->getName());
$expressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($parameterNode, $parameterType);
$expressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($parameterNode, $this->ruleLevelHelper->transformCommonType($parameterType));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this because Scope shouldn't depend on rules. Type inference is rules and rule level-agnostic. Rules already depend on Scope. There shouldn't be a dependency in the other direction.


$nativeParameterType = $parameter->getNativeType();
if ($parameter->isVariadic()) {
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/RuleLevelHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function accepts(Type $acceptingType, Type $acceptedType, bool $strictTyp
return $this->acceptsWithReason($acceptingType, $acceptedType, $strictTypes)->result;
}

private function transformCommonType(Type $type): Type
public function transformCommonType(Type $type): Type
{
if (!$this->checkExplicitMixed && !$this->checkImplicitMixed) {
return $type;
Expand Down
47 changes: 46 additions & 1 deletion src/Testing/PHPStanTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PHPStan\Testing;

use Nette\Neon\Neon;
use PHPStan\Analyser\ConstantResolver;
use PHPStan\Analyser\DirectInternalScopeFactory;
use PHPStan\Analyser\Error;
Expand Down Expand Up @@ -32,18 +33,24 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Reflection\ReflectionProvider\DirectReflectionProviderProvider;
use PHPStan\Rules\Properties\PropertyReflectionFinder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\Constant\OversizedArrayBuilder;
use PHPStan\Type\TypeAliasResolver;
use PHPStan\Type\UsefulTypeAliasResolver;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\TestCase;
use function array_merge;
use function count;
use function file_put_contents;
use function implode;
use function is_array;
use function ksort;
use function rand;
use function rtrim;
use function sha1;
use function sprintf;
use function sys_get_temp_dir;
use function unlink;
use const DIRECTORY_SEPARATOR;
use const PHP_VERSION_ID;

Expand All @@ -57,12 +64,36 @@ abstract class PHPStanTestCase extends TestCase
/** @var array<string, Container> */
private static array $containers = [];

private static ?string $testCaseConfig = null;

protected function tearDown(): void
{
parent::tearDown();

self::$testCaseConfig = null;
}

/** @param array<string, mixed>|null $config */
protected function setTestCaseConfig(?array $config): void
{
if ($config === null) {
self::$testCaseConfig = null;
return;
}
// Normalize the config to avoid creating unnecessary containers
if (isset($config['parameters']) && is_array($config['parameters'])) {
ksort($config['parameters']);
}

self::$testCaseConfig = Neon::encode($config);
}

/** @api */
public static function getContainer(): Container
{
$additionalConfigFiles = static::getAdditionalConfigFiles();
$additionalConfigFiles[] = __DIR__ . '/TestCase.neon';
$cacheKey = sha1(implode("\n", $additionalConfigFiles));
$cacheKey = sha1(implode("\n", $additionalConfigFiles) . self::$testCaseConfig);

if (!isset(self::$containers[$cacheKey])) {
$tmpDir = sys_get_temp_dir() . '/phpstan-tests';
Expand All @@ -72,6 +103,15 @@ public static function getContainer(): Container
self::fail($e->getMessage());
}

$testCaseConfigFile = null;
if (self::$testCaseConfig !== null) {
$testCaseConfigFile = $tmpDir . '/test_case_config_' . rand() . '.neon';
if (file_put_contents($testCaseConfigFile, self::$testCaseConfig) === false) {
self::fail('Failed to write test case config to temp file.');
}
$additionalConfigFiles[] = $testCaseConfigFile;
}

$rootDir = __DIR__ . '/../..';
$fileHelper = new FileHelper($rootDir);
$rootDir = $fileHelper->normalizePath($rootDir, '/');
Expand All @@ -94,6 +134,10 @@ public static function getContainer(): Container
require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnumUnitCase.php';
require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnumBackedCase.php';
}

if ($testCaseConfigFile !== null) {
unlink($testCaseConfigFile);
}
} else {
ContainerFactory::postInitializeContainer(self::$containers[$cacheKey]);
}
Expand Down Expand Up @@ -191,6 +235,7 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider
$container->getParameter('featureToggles')['explicitMixedInUnknownGenericNew'],
$container->getParameter('featureToggles')['explicitMixedForGlobalVariables'],
$constantResolver,
self::getContainer()->getByType(RuleLevelHelper::class),
),
);
}
Expand Down
2 changes: 2 additions & 0 deletions tests/PHPStan/Analyser/AnalyserTraitsIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class AnalyserTraitsIntegrationTest extends PHPStanTestCase

protected function setUp(): void
{
parent::setUp();

$this->fileHelper = self::getContainer()->getByType(FileHelper::class);
}

Expand Down
2 changes: 2 additions & 0 deletions tests/PHPStan/Analyser/TypeSpecifierTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class TypeSpecifierTest extends PHPStanTestCase

protected function setUp(): void
{
parent::setUp();

$reflectionProvider = $this->createReflectionProvider();
$this->printer = new Printer();
$this->typeSpecifier = self::getContainer()->getService('typeSpecifier');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class TraitsCachingIssueIntegrationTest extends PHPStanTestCase

public function tearDown(): void
{
parent::tearDown();

$this->deleteCache();

if ($this->originalTraitOneContents !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ class TableErrorFormatterTest extends ErrorFormatterTestCase

protected function setUp(): void
{
parent::setUp();

putenv('GITHUB_ACTIONS');
}

protected function tearDown(): void
{
parent::tearDown();

putenv('COLUMNS');
}

Expand Down
2 changes: 2 additions & 0 deletions tests/PHPStan/PhpDoc/DefaultStubFilesProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class DefaultStubFilesProviderTest extends PHPStanTestCase

protected function setUp(): void
{
parent::setUp();

$this->currentWorkingDirectory = $this->getContainer()->getParameter('currentWorkingDirectory');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ protected function getRule(): Rule

protected function tearDown(): void
{
parent::tearDown();

@unlink(__DIR__ . '/composer.json');
}

Expand Down
Loading
Loading