1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Add more info to mic drop code

This commit is contained in:
Matt Brown 2020-11-06 21:36:38 -05:00 committed by Daniil Gentili
parent d72e612223
commit a79b7eeca3
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7

View File

@ -146,92 +146,22 @@ class IfAnalyzer
} else {
if (!$has_break_statement) {
$if_scope->reasonable_clauses = [];
}
}
if ($has_leaving_statements && !$has_break_statement && !$stmt->else && !$stmt->elseifs) {
// If we're assigning inside
if ($if_conditional_scope->cond_assigned_var_ids
&& $if_scope->mic_drop_context
) {
self::addConditionallyAssignedVarsToContext(
$statements_analyzer,
$stmt->cond,
$if_scope->mic_drop_context,
$outer_context,
$if_conditional_scope->cond_assigned_var_ids
);
}
if (!$stmt->else && !$stmt->elseifs) {
$mic_drop = self::handleMicDrop(
$statements_analyzer,
$stmt->cond,
$if_scope,
$if_conditional_scope,
$outer_context,
$new_assigned_var_ids
);
if ($if_scope->negated_types) {
$changed_var_ids = [];
$outer_context_vars_reconciled = Reconciler::reconcileKeyedTypes(
$if_scope->negated_types,
[],
$outer_context->vars_in_scope,
$changed_var_ids,
[],
$statements_analyzer,
$statements_analyzer->getTemplateTypeMap() ?: [],
$outer_context->inside_loop,
new CodeLocation(
$statements_analyzer->getSource(),
$stmt->cond instanceof PhpParser\Node\Expr\BooleanNot
? $stmt->cond->expr
: $stmt->cond,
$outer_context->include_location,
false
)
);
foreach ($changed_var_ids as $changed_var_id => $_) {
$outer_context->removeVarFromConflictingClauses($changed_var_id);
}
$changed_var_ids += $new_assigned_var_ids;
foreach ($changed_var_ids as $var_id => $_) {
$if_scope->negated_clauses = Context::filterClauses(
$var_id,
$if_scope->negated_clauses
$outer_context->clauses = Algebra::simplifyCNF(
array_merge($outer_context->clauses, $if_scope->negated_clauses)
);
}
foreach ($changed_var_ids as $var_id => $_) {
$first_appearance = $statements_analyzer->getFirstAppearance($var_id);
if ($first_appearance
&& isset($outer_context->vars_in_scope[$var_id])
&& isset($outer_context_vars_reconciled[$var_id])
&& $outer_context->vars_in_scope[$var_id]->hasMixed()
&& !$outer_context_vars_reconciled[$var_id]->hasMixed()
) {
if (!$outer_context->collect_initializations
&& !$outer_context->collect_mutations
&& $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath()
&& (!(($parent_source = $statements_analyzer->getSource())
instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer)
|| !$parent_source->getSource() instanceof \Psalm\Internal\Analyzer\TraitAnalyzer)
) {
$codebase->analyzer->decrementMixedCount($statements_analyzer->getFilePath());
}
IssueBuffer::remove(
$statements_analyzer->getFilePath(),
'MixedAssignment',
$first_appearance->raw_file_start
);
}
}
$outer_context->vars_in_scope = $outer_context_vars_reconciled;
$mic_drop = true;
}
$outer_context->clauses = Algebra::simplifyCNF(
array_merge($outer_context->clauses, $if_scope->negated_clauses)
);
}
// update the parent context as necessary, but only if we can safely reason about type negation.
@ -306,6 +236,104 @@ class IfAnalyzer
return null;
}
/**
* This handles the situation when returning inside an
* if block with no else or elseifs
*
* @param array<string, int> $new_assigned_var_ids
*/
private static function handleMicDrop(
StatementsAnalyzer $statements_analyzer,
PhpParser\Node\Expr $cond,
IfScope $if_scope,
IfConditionalScope $if_conditional_scope,
Context $outer_context,
array $new_assigned_var_ids
) : bool {
// If we're assigning inside
if ($if_conditional_scope->cond_assigned_var_ids
&& $if_scope->mic_drop_context
) {
self::addConditionallyAssignedVarsToContext(
$statements_analyzer,
$cond,
$if_scope->mic_drop_context,
$outer_context,
$if_conditional_scope->cond_assigned_var_ids
);
}
if (!$if_scope->negated_types) {
return false;
}
$changed_var_ids = [];
$outer_context_vars_reconciled = Reconciler::reconcileKeyedTypes(
$if_scope->negated_types,
[],
$outer_context->vars_in_scope,
$changed_var_ids,
[],
$statements_analyzer,
$statements_analyzer->getTemplateTypeMap() ?: [],
$outer_context->inside_loop,
new CodeLocation(
$statements_analyzer->getSource(),
$cond instanceof PhpParser\Node\Expr\BooleanNot
? $cond->expr
: $cond,
$outer_context->include_location,
false
)
);
foreach ($changed_var_ids as $changed_var_id => $_) {
$outer_context->removeVarFromConflictingClauses($changed_var_id);
}
$changed_var_ids += $new_assigned_var_ids;
foreach ($changed_var_ids as $var_id => $_) {
$if_scope->negated_clauses = Context::filterClauses(
$var_id,
$if_scope->negated_clauses
);
}
foreach ($changed_var_ids as $var_id => $_) {
$first_appearance = $statements_analyzer->getFirstAppearance($var_id);
if ($first_appearance
&& isset($outer_context->vars_in_scope[$var_id])
&& isset($outer_context_vars_reconciled[$var_id])
&& $outer_context->vars_in_scope[$var_id]->hasMixed()
&& !$outer_context_vars_reconciled[$var_id]->hasMixed()
) {
if (!$outer_context->collect_initializations
&& !$outer_context->collect_mutations
&& $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath()
&& (!(($parent_source = $statements_analyzer->getSource())
instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer)
|| !$parent_source->getSource() instanceof \Psalm\Internal\Analyzer\TraitAnalyzer)
) {
$codebase = $statements_analyzer->getCodebase();
$codebase->analyzer->decrementMixedCount($statements_analyzer->getFilePath());
}
IssueBuffer::remove(
$statements_analyzer->getFilePath(),
'MixedAssignment',
$first_appearance->raw_file_start
);
}
}
$outer_context->vars_in_scope = $outer_context_vars_reconciled;
return true;
}
/**
* @param array<string, int> $cond_assigned_var_ids
*/