mirror of
https://github.com/danog/psalm.git
synced 2024-12-11 08:49:52 +01:00
Add debug stuff for code complexity
This commit is contained in:
parent
81babf2430
commit
b731b53d5e
@ -438,6 +438,21 @@ class Config
|
||||
*/
|
||||
public $restrict_return_types = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $limit_method_complexity = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $max_graph_size = 200;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $max_avg_path_length = 60;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
@ -841,6 +856,7 @@ class Config
|
||||
'findUnusedPsalmSuppress' => 'find_unused_psalm_suppress',
|
||||
'reportInfo' => 'report_info',
|
||||
'restrictReturnTypes' => 'restrict_return_types',
|
||||
'limitMethodComplexity' => 'limit_method_complexity',
|
||||
];
|
||||
|
||||
foreach ($booleanAttributes as $xmlName => $internalName) {
|
||||
|
@ -1256,7 +1256,9 @@ class ArgumentAnalyzer
|
||||
$cased_method_id,
|
||||
$cased_method_id,
|
||||
$argument_offset,
|
||||
$function_param->location,
|
||||
$statements_analyzer->data_flow_graph instanceof TaintFlowGraph
|
||||
? $function_param->location
|
||||
: null,
|
||||
$function_call_location
|
||||
);
|
||||
} else {
|
||||
@ -1264,7 +1266,9 @@ class ArgumentAnalyzer
|
||||
$cased_method_id,
|
||||
$cased_method_id,
|
||||
$argument_offset,
|
||||
$function_param->location
|
||||
$statements_analyzer->data_flow_graph instanceof TaintFlowGraph
|
||||
? $function_param->location
|
||||
: null
|
||||
);
|
||||
|
||||
if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && strpos($cased_method_id, '::')) {
|
||||
|
@ -172,6 +172,7 @@ class StatementsAnalyzer extends SourceAnalyzer
|
||||
|
||||
if ($root_scope
|
||||
&& !$context->collect_initializations
|
||||
&& !$context->collect_mutations
|
||||
&& $codebase->find_unused_variables
|
||||
&& $context->check_variables
|
||||
) {
|
||||
@ -693,6 +694,21 @@ class StatementsAnalyzer extends SourceAnalyzer
|
||||
|
||||
$unused_var_remover = new Statements\UnusedAssignmentRemover();
|
||||
|
||||
if ($this->data_flow_graph instanceof VariableUseGraph
|
||||
&& $codebase->config->limit_method_complexity
|
||||
&& $source instanceof FunctionLikeAnalyzer
|
||||
&& !$source instanceof ClosureAnalyzer
|
||||
) {
|
||||
[$count, $branching, $mean] = $this->data_flow_graph->getEdgeStats();
|
||||
|
||||
if ($count > $codebase->config->max_graph_size
|
||||
&& $mean > $codebase->config->max_avg_path_length
|
||||
&& $branching > 1.1
|
||||
) {
|
||||
echo($source->getId() . ' ' . $count . ' ' . round($mean) . ' ' . number_format($branching, 2). " \n\n");
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->unused_var_locations as [$var_id, $original_location]) {
|
||||
if (substr($var_id, 0, 2) === '$_') {
|
||||
continue;
|
||||
|
@ -33,7 +33,18 @@ abstract class DataFlowGraph
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forward_edges[$from_id][$to_id] = new Path($path_type, $added_taints, $removed_taints);
|
||||
$length = 0;
|
||||
|
||||
if ($from->code_location
|
||||
&& $to->code_location
|
||||
&& $from->code_location->file_path === $to->code_location->file_path
|
||||
) {
|
||||
$to_line = $to->code_location->raw_line_number;
|
||||
$from_line = $from->code_location->raw_line_number;
|
||||
$length = \abs($to_line - $from_line);
|
||||
}
|
||||
|
||||
$this->forward_edges[$from_id][$to_id] = new Path($path_type, $length, $added_taints, $removed_taints);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,4 +94,40 @@ abstract class DataFlowGraph
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{int, float, float}
|
||||
*/
|
||||
public function getEdgeStats() : array
|
||||
{
|
||||
$lengths = 0;
|
||||
|
||||
$destination_counts = [];
|
||||
|
||||
foreach ($this->forward_edges as $destinations) {
|
||||
foreach ($destinations as $id => $path) {
|
||||
if ($path->length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lengths += $path->length;
|
||||
|
||||
if (!isset($destination_counts[$id])) {
|
||||
$destination_counts[$id] = 0;
|
||||
}
|
||||
|
||||
$destination_counts[$id]++;
|
||||
}
|
||||
}
|
||||
|
||||
$count = array_sum($destination_counts);
|
||||
|
||||
if (!$count) {
|
||||
return [0, 0, 0.0, 0.0];
|
||||
}
|
||||
|
||||
$mean = $lengths / $count;
|
||||
|
||||
return [$count, $count / \count($destination_counts), $mean];
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,16 @@ class Path
|
||||
|
||||
public $escaped_taints;
|
||||
|
||||
public $length;
|
||||
|
||||
/**
|
||||
* @param ?array<string> $unescaped_taints
|
||||
* @param ?array<string> $escaped_taints
|
||||
*/
|
||||
public function __construct(string $type, ?array $unescaped_taints, ?array $escaped_taints)
|
||||
public function __construct(string $type, int $length, ?array $unescaped_taints, ?array $escaped_taints)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->length = $length;
|
||||
$this->unescaped_taints = $unescaped_taints;
|
||||
$this->escaped_taints = $escaped_taints;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user