1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Simplify more things

This commit is contained in:
Matt Brown 2020-11-27 17:48:39 -05:00 committed by Daniil Gentili
parent 65947e5808
commit 3005d2e1d7
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
5 changed files with 91 additions and 67 deletions

View File

@ -452,7 +452,7 @@ class Config
/**
* @var int
*/
public $max_avg_path_length = 60;
public $max_avg_path_length = 70;
/**
* @var string[]

View File

@ -2,6 +2,7 @@
namespace Psalm\Internal\Analyzer\FunctionLike;
use PhpParser;
use Psalm\Codebase;
use Psalm\Internal\Analyzer\Statements\Block\ForeachAnalyzer;
use Psalm\Type;
use Psalm\Type\Atomic;
@ -21,7 +22,7 @@ class ReturnTypeCollector
* @return list<Type\Union> a list of return types
*/
public static function getReturnTypes(
\Psalm\Codebase $codebase,
Codebase $codebase,
\Psalm\Internal\Provider\NodeDataProvider $nodes,
array $stmts,
array &$yield_types,
@ -193,65 +194,78 @@ class ReturnTypeCollector
if ($collapse_types) {
// if it's a generator, boil everything down to a single generator return type
if ($yield_types) {
$key_type = null;
$value_type = null;
$yield_type = Type::combineUnionTypeArray($yield_types, null);
foreach ($yield_type->getAtomicTypes() as $type) {
if ($type instanceof Type\Atomic\TKeyedArray) {
$type = $type->getGenericArrayType();
}
if ($type instanceof Type\Atomic\TList) {
$type = new Type\Atomic\TArray([Type::getInt(), $type->type_param]);
}
if ($type instanceof Type\Atomic\TArray) {
[$key_type_param, $value_type_param] = $type->type_params;
if (!$key_type) {
$key_type = clone $key_type_param;
} else {
$key_type = Type::combineUnionTypes($key_type_param, $key_type);
}
if (!$value_type) {
$value_type = clone $value_type_param;
} else {
$value_type = Type::combineUnionTypes($value_type_param, $value_type);
}
} elseif ($type instanceof Type\Atomic\TIterable
|| $type instanceof Type\Atomic\TNamedObject
) {
ForeachAnalyzer::getKeyValueParamsForTraversableObject(
$type,
$codebase,
$key_type,
$value_type
);
}
}
$yield_types = [
new Type\Union([
new Atomic\TGenericObject(
'Generator',
[
$key_type ?: Type::getMixed(),
$value_type ?: Type::getMixed(),
Type::getMixed(),
$return_types ? Type::combineUnionTypeArray($return_types, null) : Type::getVoid()
]
),
])
];
$yield_types = self::processYieldTypes($codebase, $return_types, $yield_types);
}
}
return $return_types;
}
/**
* @param list<Type\Union> $return_types
* @param non-empty-list<Type\Union> $yield_types
* @return non-empty-list<Type\Union>
*/
private static function processYieldTypes(
Codebase $codebase,
array $return_types,
array $yield_types
) : array {
$key_type = null;
$value_type = null;
$yield_type = Type::combineUnionTypeArray($yield_types, null);
foreach ($yield_type->getAtomicTypes() as $type) {
if ($type instanceof Type\Atomic\TKeyedArray) {
$type = $type->getGenericArrayType();
}
if ($type instanceof Type\Atomic\TList) {
$type = new Type\Atomic\TArray([Type::getInt(), $type->type_param]);
}
if ($type instanceof Type\Atomic\TArray) {
[$key_type_param, $value_type_param] = $type->type_params;
if (!$key_type) {
$key_type = clone $key_type_param;
} else {
$key_type = Type::combineUnionTypes($key_type_param, $key_type);
}
if (!$value_type) {
$value_type = clone $value_type_param;
} else {
$value_type = Type::combineUnionTypes($value_type_param, $value_type);
}
} elseif ($type instanceof Type\Atomic\TIterable
|| $type instanceof Type\Atomic\TNamedObject
) {
ForeachAnalyzer::getKeyValueParamsForTraversableObject(
$type,
$codebase,
$key_type,
$value_type
);
}
}
return [
new Type\Union([
new Atomic\TGenericObject(
'Generator',
[
$key_type ?: Type::getMixed(),
$value_type ?: Type::getMixed(),
Type::getMixed(),
$return_types ? Type::combineUnionTypeArray($return_types, null) : Type::getVoid()
]
),
])
];
}
/**
* @return list<Type\Union>
*/

View File

@ -704,11 +704,13 @@ class StatementsAnalyzer extends SourceAnalyzer
&& $function_storage
&& $function_storage->location
) {
[$count, $branching, $mean] = $this->data_flow_graph->getEdgeStats();
[$count, , $unique_destinations, $mean] = $this->data_flow_graph->getEdgeStats();
$average_destination_branches_converging = $unique_destinations > 0 ? $count / $unique_destinations : 0;
if ($count > $codebase->config->max_graph_size
&& $mean > $codebase->config->max_avg_path_length
&& $branching > 1.1
&& $average_destination_branches_converging > 1.1
) {
if ($source instanceof FunctionAnalyzer) {
if (IssueBuffer::accepts(
@ -723,7 +725,7 @@ class StatementsAnalyzer extends SourceAnalyzer
// fall through
}
} elseif ($source instanceof MethodAnalyzer) {
if (IssueBuffer::accepts(
if (IssueBuffer::accepts(
new ComplexMethod(
'This methods complexity is greater than the project limit'
. ' (method graph size = ' . $count .', average path length = ' . round($mean) . ')',

View File

@ -97,38 +97,41 @@ abstract class DataFlowGraph
}
/**
* @return array{int, float, float}
* @return array{int, int, int, float}
*/
public function getEdgeStats() : array
{
$lengths = 0;
$destination_counts = [];
$origin_counts = [];
foreach ($this->forward_edges as $destinations) {
foreach ($destinations as $id => $path) {
foreach ($this->forward_edges as $from_id => $destinations) {
foreach ($destinations as $to_id => $path) {
if ($path->length === 0) {
continue;
}
$lengths += $path->length;
if (!isset($destination_counts[$id])) {
$destination_counts[$id] = 0;
if (!isset($destination_counts[$to_id])) {
$destination_counts[$to_id] = 0;
}
$destination_counts[$id]++;
$destination_counts[$to_id]++;
$origin_counts[$from_id] = true;
}
}
$count = array_sum($destination_counts);
if (!$count) {
return [0, 0, 0.0, 0.0];
return [0, 0, 0, 0.0];
}
$mean = $lengths / $count;
return [$count, $count / \count($destination_counts), $mean];
return [$count, \count($origin_counts), \count($destination_counts), $mean];
}
}

View File

@ -84,7 +84,12 @@ class TypeTokenizer
private static $memoized_tokens = [];
/**
* @return list<array{0: string, 1: int}>
* Tokenises a type string into an array of tuples where the first element
* contains the string token and the second element contains its offset,
*
* @return list<array{string, int}>
*
* @psalm-suppress ComplexMethod
*/
public static function tokenize(string $string_type, bool $ignore_space = true): array
{