mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
Add more mixed origin information
This commit is contained in:
parent
7f8d522912
commit
44c6d3035b
@ -359,14 +359,16 @@ class AssignmentAnalyzer
|
||||
? 'Unable to determine the type that ' . $var_id . ' is being assigned to'
|
||||
: 'Unable to determine the type of this assignment';
|
||||
|
||||
if ($origin_location && $origin_location->getLineNumber() === $assign_var->getLine()) {
|
||||
$issue_location = new CodeLocation($statements_analyzer->getSource(), $assign_var);
|
||||
|
||||
if ($origin_location && $origin_location->getHash() === $issue_location->getHash()) {
|
||||
$origin_location = null;
|
||||
}
|
||||
|
||||
if (IssueBuffer::accepts(
|
||||
new MixedAssignment(
|
||||
$message,
|
||||
new CodeLocation($statements_analyzer->getSource(), $assign_var),
|
||||
$issue_location,
|
||||
$origin_location
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
|
@ -14,6 +14,7 @@ use Psalm\Internal\Type\Comparator\CallableTypeComparator;
|
||||
use Psalm\Internal\Type\Comparator\UnionTypeComparator;
|
||||
use Psalm\Internal\DataFlow\DataFlowNode;
|
||||
use Psalm\Internal\Codebase\TaintFlowGraph;
|
||||
use Psalm\Internal\Codebase\VariableUseGraph;
|
||||
use Psalm\Internal\MethodIdentifier;
|
||||
use Psalm\Internal\Scanner\UnresolvedConstantComponent;
|
||||
use Psalm\Internal\Type\TemplateBound;
|
||||
@ -611,13 +612,31 @@ class ArgumentAnalyzer
|
||||
$codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath());
|
||||
}
|
||||
|
||||
$origin_locations = [];
|
||||
|
||||
if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) {
|
||||
foreach ($input_type->parent_nodes as $parent_node) {
|
||||
$origin_locations = array_merge(
|
||||
$origin_locations,
|
||||
$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null;
|
||||
|
||||
if ($origin_location && $origin_location->getHash() === $arg_location->getHash()) {
|
||||
$origin_location = null;
|
||||
}
|
||||
|
||||
if (IssueBuffer::accepts(
|
||||
new MixedArgument(
|
||||
'Argument ' . ($argument_offset + 1) . $method_identifier
|
||||
. ' cannot be ' . $input_type->getId() . ', expecting ' .
|
||||
$param_type,
|
||||
$arg_location,
|
||||
$cased_method_id
|
||||
$cased_method_id,
|
||||
$origin_location
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -11,6 +11,7 @@ use Psalm\Internal\Analyzer\Statements\Expression\Call\ClassTemplateParamCollect
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\Internal\Codebase\InternalCallMapHandler;
|
||||
use Psalm\Internal\Codebase\VariableUseGraph;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Context;
|
||||
@ -44,6 +45,7 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
PhpParser\Node\Expr\MethodCall $stmt,
|
||||
Codebase $codebase,
|
||||
Context $context,
|
||||
Type\Union $lhs_type,
|
||||
Type\Atomic $lhs_type_part,
|
||||
?Type\Atomic $static_type,
|
||||
bool $is_intersection,
|
||||
@ -80,6 +82,7 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
$statements_analyzer,
|
||||
$codebase,
|
||||
$stmt,
|
||||
$lhs_type,
|
||||
$lhs_type_part,
|
||||
$lhs_var_id,
|
||||
$context,
|
||||
@ -269,6 +272,7 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
$stmt,
|
||||
$codebase,
|
||||
$context,
|
||||
$lhs_type,
|
||||
$lhs_type_part,
|
||||
$lhs_var_id,
|
||||
$result,
|
||||
@ -451,6 +455,7 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
PhpParser\Node\Expr\MethodCall $stmt,
|
||||
Codebase $codebase,
|
||||
Context $context,
|
||||
Type\Union $lhs_type,
|
||||
Type\Atomic $lhs_type_part,
|
||||
?string $lhs_var_id,
|
||||
AtomicMethodCallAnalysisResult $result,
|
||||
@ -470,6 +475,7 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
$stmt,
|
||||
$codebase,
|
||||
$context,
|
||||
$lhs_type,
|
||||
$intersection_type,
|
||||
$lhs_type_part,
|
||||
true,
|
||||
@ -544,6 +550,7 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
Codebase $codebase,
|
||||
PhpParser\Node\Expr\MethodCall $stmt,
|
||||
Type\Union $lhs_type,
|
||||
Type\Atomic $lhs_type_part,
|
||||
?string $lhs_var_id,
|
||||
Context $context,
|
||||
@ -600,10 +607,30 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
$origin_locations = [];
|
||||
|
||||
if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) {
|
||||
foreach ($lhs_type->parent_nodes as $parent_node) {
|
||||
$origin_locations = array_merge(
|
||||
$origin_locations,
|
||||
$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null;
|
||||
|
||||
$name_code_location = new CodeLocation($statements_analyzer, $stmt->name);
|
||||
|
||||
if ($origin_location && $origin_location->getHash() === $name_code_location->getHash()) {
|
||||
$origin_location = null;
|
||||
}
|
||||
|
||||
if (IssueBuffer::accepts(
|
||||
new MixedMethodCall(
|
||||
$message,
|
||||
new CodeLocation($statements_analyzer, $stmt->name)
|
||||
$name_code_location,
|
||||
$origin_location
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -185,6 +185,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
$stmt,
|
||||
$codebase,
|
||||
$context,
|
||||
$class_type,
|
||||
$lhs_type_part,
|
||||
$lhs_type_part instanceof Type\Atomic\TNamedObject
|
||||
|| $lhs_type_part instanceof Type\Atomic\TTemplateParam
|
||||
|
@ -16,6 +16,7 @@ use Psalm\Context;
|
||||
use Psalm\Exception\DocblockParseException;
|
||||
use Psalm\Internal\DataFlow\DataFlowNode;
|
||||
use Psalm\Internal\Codebase\TaintFlowGraph;
|
||||
use Psalm\Internal\Codebase\VariableUseGraph;
|
||||
use Psalm\Internal\Type\TemplateResult;
|
||||
use Psalm\Internal\Type\TemplateInferredTypeReplacer;
|
||||
use Psalm\Issue\FalsableReturnStatement;
|
||||
@ -303,10 +304,30 @@ class ReturnAnalyzer
|
||||
}
|
||||
|
||||
if ($stmt_type->isMixed()) {
|
||||
$origin_locations = [];
|
||||
|
||||
if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) {
|
||||
foreach ($stmt_type->parent_nodes as $parent_node) {
|
||||
$origin_locations = array_merge(
|
||||
$origin_locations,
|
||||
$statements_analyzer->data_flow_graph->getOriginLocations($parent_node)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$origin_location = count($origin_locations) === 1 ? reset($origin_locations) : null;
|
||||
|
||||
$return_location = new CodeLocation($source, $stmt->expr);
|
||||
|
||||
if ($origin_location && $origin_location->getHash() === $return_location->getHash()) {
|
||||
$origin_location = null;
|
||||
}
|
||||
|
||||
if (IssueBuffer::accepts(
|
||||
new MixedReturnStatement(
|
||||
'Could not infer a return type',
|
||||
new CodeLocation($source, $stmt->expr)
|
||||
$return_location,
|
||||
$origin_location
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -3176,7 +3176,7 @@ class UnusedVariableTest extends TestCase
|
||||
function takesArray(array $arr) : void {
|
||||
foreach ($arr as $a) {}
|
||||
}',
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:42 - Unable to determine the type that $a is being assigned to, derived from expression at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:47'
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:42 - Unable to determine the type that $a is being assigned to. Consider improving the type at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:47'
|
||||
],
|
||||
'warnAboutOriginalBadFunctionCall' => [
|
||||
'<?php
|
||||
@ -3189,7 +3189,7 @@ class UnusedVariableTest extends TestCase
|
||||
foreach ($arr as $a) {
|
||||
echo $a;
|
||||
}',
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:8:38 - Unable to determine the type that $a is being assigned to, derived from expression at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:44'
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:8:38 - Unable to determine the type that $a is being assigned to. Consider improving the type at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:44'
|
||||
],
|
||||
'warnAboutOriginalBadStaticCall' => [
|
||||
'<?php
|
||||
@ -3204,7 +3204,7 @@ class UnusedVariableTest extends TestCase
|
||||
foreach ($arr as $a) {
|
||||
echo $a;
|
||||
}',
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:38 - Unable to determine the type that $a is being assigned to, derived from expression at src' . DIRECTORY_SEPARATOR . 'somefile.php:3:62'
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:38 - Unable to determine the type that $a is being assigned to. Consider improving the type at src' . DIRECTORY_SEPARATOR . 'somefile.php:3:62'
|
||||
],
|
||||
'warnAboutOriginalBadInstanceCall' => [
|
||||
'<?php
|
||||
@ -3219,7 +3219,7 @@ class UnusedVariableTest extends TestCase
|
||||
foreach ($arr as $a) {
|
||||
echo $a;
|
||||
}',
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:38 - Unable to determine the type that $a is being assigned to, derived from expression at src' . DIRECTORY_SEPARATOR . 'somefile.php:3:55'
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:38 - Unable to determine the type that $a is being assigned to. Consider improving the type at src' . DIRECTORY_SEPARATOR . 'somefile.php:3:55'
|
||||
],
|
||||
'warnAboutDocblockReturnType' => [
|
||||
'<?php
|
||||
@ -3235,7 +3235,53 @@ class UnusedVariableTest extends TestCase
|
||||
echo $a;
|
||||
}
|
||||
}',
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:47 - Unable to determine the type that $a is being assigned to, derived from expression at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:33'
|
||||
'error_message' => 'MixedAssignment - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:47 - Unable to determine the type that $a is being assigned to. Consider improving the type at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:33'
|
||||
],
|
||||
'warnAboutMixedArgument' => [
|
||||
'<?php
|
||||
function makeArray() : array {
|
||||
return ["hello"];
|
||||
}
|
||||
|
||||
$arr = makeArray();
|
||||
|
||||
/** @psalm-suppress MixedAssignment */
|
||||
foreach ($arr as $a) {
|
||||
echo $a;
|
||||
}',
|
||||
'error_message' => 'MixedArgument - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:30 - Argument 1 of echo cannot be mixed, expecting string. Consider improving the type at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:44'
|
||||
],
|
||||
'warnAboutMixedMethodCall' => [
|
||||
'<?php
|
||||
function makeArray() : array {
|
||||
return ["hello"];
|
||||
}
|
||||
|
||||
$arr = makeArray();
|
||||
|
||||
/** @psalm-suppress MixedAssignment */
|
||||
foreach ($arr as $a) {
|
||||
$a->foo();
|
||||
}',
|
||||
'error_message' => 'MixedMethodCall - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:29 - Cannot determine the type of $a when calling method foo. Consider improving the type at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:44'
|
||||
],
|
||||
'warnAboutMixedReturnStatement' => [
|
||||
'<?php
|
||||
function makeArray() : array {
|
||||
return ["hello"];
|
||||
}
|
||||
|
||||
function foo() : string {
|
||||
$arr = makeArray();
|
||||
|
||||
/** @psalm-suppress MixedAssignment */
|
||||
foreach ($arr as $a) {
|
||||
return $a;
|
||||
}
|
||||
|
||||
return "";
|
||||
}',
|
||||
'error_message' => 'MixedReturnStatement - src' . DIRECTORY_SEPARATOR . 'somefile.php:11:36 - Could not infer a return type. Consider improving the type at src' . DIRECTORY_SEPARATOR . 'somefile.php:2:44'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user