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:
parent
65947e5808
commit
3005d2e1d7
@ -452,7 +452,7 @@ class Config
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $max_avg_path_length = 60;
|
||||
public $max_avg_path_length = 70;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
|
@ -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>
|
||||
*/
|
||||
|
@ -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 method’s complexity is greater than the project limit'
|
||||
. ' (method graph size = ' . $count .', average path length = ' . round($mean) . ')',
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user