Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into array_builder_fix
Browse files Browse the repository at this point in the history
* upstream/master:
  Fix array_filter with callback that always evaluates to false
  Support for --memory-limit CLI option in ClearResultCacheCommand
  • Loading branch information
voku committed Jan 24, 2022
2 parents ca47adf + d8dc6d0 commit 66d13eb
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/Command/ClearResultCacheCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,20 @@ protected function configure(): void
->setDefinition([
new InputOption('configuration', 'c', InputOption::VALUE_REQUIRED, 'Path to project configuration file'),
new InputOption('autoload-file', 'a', InputOption::VALUE_REQUIRED, 'Project\'s additional autoload file path'),
new InputOption('memory-limit', null, InputOption::VALUE_REQUIRED, 'Memory limit for clearing result cache'),
]);
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$autoloadFile = $input->getOption('autoload-file');
$configuration = $input->getOption('configuration');
$memoryLimit = $input->getOption('memory-limit');

if (
(!is_string($autoloadFile) && $autoloadFile !== null)
|| (!is_string($configuration) && $configuration !== null)
|| (!is_string($memoryLimit) && $memoryLimit !== null)
) {
throw new ShouldNotHappenException();
}
Expand All @@ -52,7 +55,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$input,
$output,
['.'],
null,
$memoryLimit,
$autoloadFile,
$this->composerAutoloaderProjectPaths,
$configuration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
$scope = $scope->assignVariable($itemVariableName, $itemType);
$scope = $scope->filterByTruthyValue($expr);
$itemType = $scope->getVariableType($itemVariableName);
if ($itemType instanceof NeverType) {
return new ConstantArrayType([], []);
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Methods/data/infer-array-key.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/offset-value-after-assign.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2112.php');

yield from $this->gatherAssertTypes(__DIR__ . '/data/array-filter.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-filter-callables.php');
if (PHP_VERSION_ID >= 70400) {
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-filter-arrow-functions.php');
}

yield from $this->gatherAssertTypes(__DIR__ . '/data/array-flip.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-map.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-map-closure.php');
Expand Down
39 changes: 39 additions & 0 deletions tests/PHPStan/Analyser/data/array-filter-arrow-functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php // lint >= 7.4

namespace ArrayFilter;

use function PHPStan\Testing\assertType;

/**
* @param int[] $list1
* @param int[] $list2
* @param int[] $list3
*/
function alwaysEvaluatesToFalse(array $list1, array $list2, array $list3): void
{
$filtered1 = array_filter($list1, static fn($item): bool => is_string($item));
assertType('array{}', $filtered1);

$filtered2 = array_filter($list2, static fn($item): bool => is_string($item), ARRAY_FILTER_USE_KEY);
assertType('array<int>', $filtered2); // not supported yet

$filtered3 = array_filter($list3, static fn($item, $key): bool => is_string($item) && is_string($key), ARRAY_FILTER_USE_BOTH);
assertType('array<int>', $filtered3); // not supported yet
}

/**
* @param array<int|string, int|string> $map1
* @param array<int|string, int|string> $map2
* @param array<int|string, int|string> $map3
*/
function filtersString(array $map1, array $map2, array $map3, array $map4): void
{
$filtered1 = array_filter($map1, static fn($item): bool => is_string($item));
assertType('array<int|string, string>', $filtered1);

$filtered2 = array_filter($map2, static fn($item): bool => is_string($item), ARRAY_FILTER_USE_KEY);
assertType('array<int|string, int|string>', $filtered2); // not supported yet

$filtered3 = array_filter($map3, static fn($item, $key): bool => is_string($item) && is_string($key), ARRAY_FILTER_USE_BOTH);
assertType('array<int|string, int|string>', $filtered3); // not supported yet
}
39 changes: 39 additions & 0 deletions tests/PHPStan/Analyser/data/array-filter-callables.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace ArrayFilter;

use function PHPStan\Testing\assertType;

/**
* @param int[] $list1
* @param int[] $list2
* @param int[] $list3
*/
function alwaysEvaluatesToFalse(array $list1, array $list2, array $list3): void
{
$filtered1 = array_filter($list1, static function ($item): bool { return is_string($item); });
assertType('array{}', $filtered1);

$filtered2 = array_filter($list2, static function ($item): bool { return is_string($item); }, ARRAY_FILTER_USE_KEY);
assertType('array<int>', $filtered2); // not supported yet

$filtered3 = array_filter($list3, static function ($item, $key): bool { return is_string($item) && is_string($key); }, ARRAY_FILTER_USE_BOTH);
assertType('array<int>', $filtered3); // not supported yet
}

/**
* @param array<int|string, int|string> $map1
* @param array<int|string, int|string> $map2
* @param array<int|string, int|string> $map3
*/
function filtersString(array $map1, array $map2, array $map3): void
{
$filtered1 = array_filter($map1, static function ($item): bool { return is_string($item); });
assertType('array<int|string, string>', $filtered1);

$filtered2 = array_filter($map2, static function ($item): bool { return is_string($item); }, ARRAY_FILTER_USE_KEY);
assertType('array<int|string, int|string>', $filtered2); // not supported yet

$filtered3 = array_filter($map3, static function ($item, $key): bool { return is_string($item) && is_string($key); }, ARRAY_FILTER_USE_BOTH);
assertType('array<int|string, int|string>', $filtered3); // not supported yet
}
37 changes: 37 additions & 0 deletions tests/PHPStan/Analyser/data/array-filter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace ArrayFilter;

use function PHPStan\Testing\assertType;

function withoutAnyArgs(): void
{
$filtered1 = array_filter();
assertType('array', $filtered1);
}

/**
* @param $var1 $mixed
*/
function withMixedInsteadOfArray($var1): void
{
$filtered1 = array_filter($var1);
assertType('(array|null)', $filtered1);
}

/**
* @param array<string, bool|float|int|string> $map1
* @param array<string, bool|float|int|string> $map2
* @param array<string, bool|float|int|string> $map3
*/
function withoutCallback(array $map1, array $map2, array $map3): void
{
$filtered1 = array_filter($map1);
assertType('array<string, float|int<min, -1>|int<1, max>|non-empty-string|true>', $filtered1);

$filtered2 = array_filter($map2, null, ARRAY_FILTER_USE_KEY);
assertType('array<string, bool|float|int|string>', $filtered2); // not supported yet

$filtered3 = array_filter($map3, null, ARRAY_FILTER_USE_BOTH);
assertType('array<string, bool|float|int|string>', $filtered3); // not supported yet
}

0 comments on commit 66d13eb

Please sign in to comment.