mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Improve unique issue solution
This commit is contained in:
parent
00ad09816f
commit
eda426a594
@ -64,7 +64,8 @@ class AlgebraAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
$formula2_clause . ' has already been asserted',
|
||||
new CodeLocation($statements_analyzer, $stmt)
|
||||
new CodeLocation($statements_analyzer, $stmt),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -104,7 +105,8 @@ class AlgebraAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
'Found a redundant condition when evaluating ' . $key,
|
||||
new CodeLocation($statements_analyzer, $stmt)
|
||||
new CodeLocation($statements_analyzer, $stmt),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -1461,9 +1461,10 @@ class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
if ($uninitialized_property->location) {
|
||||
if (IssueBuffer::accepts(
|
||||
new MissingConstructor(
|
||||
$class_storage->name . ' has an uninitialized variable ' . $uninitialized_variables[0] .
|
||||
$class_storage->name . ' has an uninitialized property ' . $uninitialized_variables[0] .
|
||||
', but no constructor',
|
||||
$uninitialized_property->location
|
||||
$uninitialized_property->location,
|
||||
$class_storage->name . '::' . $uninitialized_variables[0]
|
||||
),
|
||||
$storage->suppressed_issues + $this->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -115,6 +115,12 @@ class IssueData
|
||||
*/
|
||||
public $taint_trace;
|
||||
|
||||
/**
|
||||
* @var ?string
|
||||
* @readonly
|
||||
*/
|
||||
private $dupe_key;
|
||||
|
||||
/**
|
||||
* @param ?list<TaintNodeData|array{label: string, entry_path_type: string}> $taint_trace
|
||||
*/
|
||||
@ -136,7 +142,8 @@ class IssueData
|
||||
int $column_to,
|
||||
int $shortcode = 0,
|
||||
int $error_level = -1,
|
||||
?array $taint_trace = null
|
||||
?array $taint_trace = null,
|
||||
?string $dupe_key = null
|
||||
) {
|
||||
$this->severity = $severity;
|
||||
$this->line_from = $line_from;
|
||||
@ -157,5 +164,11 @@ class IssueData
|
||||
$this->error_level = $error_level;
|
||||
$this->link = 'https://psalm.dev/' . \str_pad((string) $shortcode, 3, "0", \STR_PAD_LEFT);
|
||||
$this->taint_trace = $taint_trace;
|
||||
$this->dupe_key = $dupe_key;
|
||||
}
|
||||
|
||||
public function getDupeKey() : ?string
|
||||
{
|
||||
return $this->dupe_key;
|
||||
}
|
||||
}
|
||||
|
@ -706,7 +706,8 @@ class IfAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
'if (false) is impossible',
|
||||
new CodeLocation($statements_analyzer, $cond)
|
||||
new CodeLocation($statements_analyzer, $cond),
|
||||
'false falsy',
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -716,7 +717,8 @@ class IfAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
'if (false) is impossible',
|
||||
new CodeLocation($statements_analyzer, $cond)
|
||||
new CodeLocation($statements_analyzer, $cond),
|
||||
'false falsy',
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -728,7 +730,8 @@ class IfAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantConditionGivenDocblockType(
|
||||
'if (true) is redundant',
|
||||
new CodeLocation($statements_analyzer, $cond)
|
||||
new CodeLocation($statements_analyzer, $cond),
|
||||
'true falsy',
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -738,7 +741,8 @@ class IfAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
'if (true) is redundant',
|
||||
new CodeLocation($statements_analyzer, $cond)
|
||||
new CodeLocation($statements_analyzer, $cond),
|
||||
'true falsy',
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -97,7 +97,8 @@ class AssertionFinder
|
||||
new RedundantConditionGivenDocblockType(
|
||||
$var_type->getId() . ' does not contain '
|
||||
. $instanceof_type->getId(),
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' ' . $instanceof_type->getId()
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -108,7 +109,8 @@ class AssertionFinder
|
||||
new RedundantCondition(
|
||||
$var_type->getId() . ' cannot be identical to '
|
||||
. $instanceof_type->getId(),
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' ' . $instanceof_type->getId()
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -303,7 +305,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
$var_type . ' cannot be greater than ' . $min_comparison,
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
null
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -313,7 +316,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
$var_type . ' cannot be greater than ' . $min_comparison,
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
null
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -591,7 +595,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
$var_type . ' does not contain null',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type . ' null'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -601,7 +606,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainNull(
|
||||
$var_type . ' does not contain null',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId()
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -708,7 +714,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
$var_type . ' does not contain true',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type . ' true'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -718,7 +725,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
$var_type . ' does not contain true',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type . ' true'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -813,7 +821,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
$var_type . ' does not contain false',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type . ' false'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -823,7 +832,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
$var_type . ' does not contain false',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type . ' false'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -876,7 +886,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
$var_type . ' does not contain an empty array',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
null
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -886,7 +897,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
$var_type . ' does not contain empty array',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
null
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1108,7 +1120,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
$var_type->getId() . ' does not contain ' . $other_type->getId(),
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' ' . $other_type->getId()
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1118,7 +1131,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
$var_type->getId() . ' cannot be identical to ' . $other_type->getId(),
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' ' . $other_type->getId()
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1143,7 +1157,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
$var_type->getId() . ' cannot be identical to ' . $other_type->getId(),
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' ' . $other_type->getId()
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1225,8 +1240,9 @@ class AssertionFinder
|
||||
if ($var_type->from_docblock) {
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantConditionGivenDocblockType(
|
||||
'Docblock-asserted type ' . $var_type . ' can never contain null',
|
||||
new CodeLocation($source, $conditional)
|
||||
'Docblock-defined type ' . $var_type . ' can never contain null',
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' null'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1236,7 +1252,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
$var_type . ' can never contain null',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' null'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1324,8 +1341,9 @@ class AssertionFinder
|
||||
if ($var_type->from_docblock) {
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantConditionGivenDocblockType(
|
||||
'Docblock-asserted type ' . $var_type . ' can never contain false',
|
||||
new CodeLocation($source, $conditional)
|
||||
'Docblock-defined type ' . $var_type . ' can never contain false',
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' false'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1335,7 +1353,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
$var_type . ' can never contain false',
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' false'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1433,8 +1452,9 @@ class AssertionFinder
|
||||
if ($var_type->from_docblock) {
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantConditionGivenDocblockType(
|
||||
'Docblock-asserted type ' . $var_type . ' can never contain true',
|
||||
new CodeLocation($source, $conditional)
|
||||
'Docblock-defined type ' . $var_type . ' can never contain true',
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' true'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1444,7 +1464,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
$var_type . ' can never contain ' . $true_type,
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' true'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1527,8 +1548,9 @@ class AssertionFinder
|
||||
if ($var_type->from_docblock) {
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantConditionGivenDocblockType(
|
||||
'Docblock-asserted type ' . $var_type . ' can never contain null',
|
||||
new CodeLocation($source, $conditional)
|
||||
'Docblock-defined type ' . $var_type->getId() . ' can never contain null',
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' null'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1537,8 +1559,9 @@ class AssertionFinder
|
||||
} else {
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
$var_type . ' can never contain null',
|
||||
new CodeLocation($source, $conditional)
|
||||
$var_type->getId() . ' can never contain null',
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' null'
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1743,7 +1766,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
$var_type . ' can never contain ' . $other_type,
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type . ' ' . $other_type
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1753,7 +1777,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
$var_type->getId() . ' can never contain ' . $other_type->getId(),
|
||||
new CodeLocation($source, $conditional)
|
||||
new CodeLocation($source, $conditional),
|
||||
$var_type->getId() . ' ' . $other_type->getId()
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -2215,7 +2240,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantConditionGivenDocblockType(
|
||||
'Docblock type ' . $first_var_type . ' always contains ' . $expected_type,
|
||||
new CodeLocation($source, $expr)
|
||||
new CodeLocation($source, $expr),
|
||||
$first_var_type . ' ' . $expected_type
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -2225,7 +2251,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
$first_var_type . ' always contains ' . $expected_type,
|
||||
new CodeLocation($source, $expr)
|
||||
new CodeLocation($source, $expr),
|
||||
$first_var_type . ' ' . $expected_type
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -2237,7 +2264,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
$first_var_type . ' does not contain ' . $expected_type,
|
||||
new CodeLocation($source, $expr)
|
||||
new CodeLocation($source, $expr),
|
||||
$first_var_type . ' ' . $expected_type
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -2247,7 +2275,8 @@ class AssertionFinder
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
$first_var_type . ' does not contain ' . $expected_type,
|
||||
new CodeLocation($source, $expr)
|
||||
new CodeLocation($source, $expr),
|
||||
$first_var_type . ' ' . $expected_type
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
@ -2474,7 +2503,7 @@ class AssertionFinder
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
protected static function hasNullVariable(
|
||||
PhpParser\Node\Expr\BinaryOp $conditional,
|
||||
FileSource $source
|
||||
@ -2946,7 +2975,7 @@ class AssertionFinder
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected static function hasIsACheck(
|
||||
PhpParser\Node\Expr\FuncCall $stmt,
|
||||
StatementsAnalyzer $source
|
||||
|
@ -139,7 +139,8 @@ class CoalesceAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\DocblockTypeContradiction(
|
||||
$naive_type->getId() . ' does not contain null',
|
||||
new CodeLocation($statements_analyzer, $stmt->left)
|
||||
new CodeLocation($statements_analyzer, $stmt->left),
|
||||
$naive_type->getId() . ' null'
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -149,7 +150,8 @@ class CoalesceAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\TypeDoesNotContainType(
|
||||
$naive_type->getId() . ' is always defined and non-null',
|
||||
new CodeLocation($statements_analyzer, $stmt->left)
|
||||
new CodeLocation($statements_analyzer, $stmt->left),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -215,7 +215,8 @@ class BinaryOpAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\DocblockTypeContradiction(
|
||||
$atomic_right_type . ' string length is not ' . $string_length,
|
||||
new CodeLocation($statements_analyzer, $stmt)
|
||||
new CodeLocation($statements_analyzer, $stmt),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -225,7 +226,8 @@ class BinaryOpAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\TypeDoesNotContainType(
|
||||
$atomic_right_type . ' string length is not ' . $string_length,
|
||||
new CodeLocation($statements_analyzer, $stmt)
|
||||
new CodeLocation($statements_analyzer, $stmt),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -237,7 +239,8 @@ class BinaryOpAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\RedundantConditionGivenDocblockType(
|
||||
$atomic_right_type . ' string length is never ' . $string_length,
|
||||
new CodeLocation($statements_analyzer, $stmt)
|
||||
new CodeLocation($statements_analyzer, $stmt),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -247,7 +250,8 @@ class BinaryOpAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\RedundantCondition(
|
||||
$atomic_right_type . ' string length is never ' . $string_length,
|
||||
new CodeLocation($statements_analyzer, $stmt)
|
||||
new CodeLocation($statements_analyzer, $stmt),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -1593,7 +1593,8 @@ class FunctionCallAnalyzer extends CallAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\RedundantConditionGivenDocblockType(
|
||||
'The call to strtolower is unnecessary given the docblock type',
|
||||
new CodeLocation($statements_analyzer, $function_name)
|
||||
new CodeLocation($statements_analyzer, $function_name),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
@ -1603,7 +1604,8 @@ class FunctionCallAnalyzer extends CallAnalyzer
|
||||
if (IssueBuffer::accepts(
|
||||
new \Psalm\Issue\RedundantCondition(
|
||||
'The call to strtolower is unnecessary',
|
||||
new CodeLocation($statements_analyzer, $function_name)
|
||||
new CodeLocation($statements_analyzer, $function_name),
|
||||
null
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues()
|
||||
)) {
|
||||
|
@ -200,7 +200,8 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
'Cannot allow string comparison to object for ' . $key,
|
||||
$code_location
|
||||
$code_location,
|
||||
null
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -592,7 +593,8 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
|
||||
new DocblockTypeContradiction(
|
||||
'Cannot resolve types for ' . $key . ' - docblock-defined type '
|
||||
. $existing_var_type . ' does not contain null',
|
||||
$code_location
|
||||
$code_location,
|
||||
$existing_var_type->getId() . ' null'
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -603,7 +605,8 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
|
||||
new TypeDoesNotContainNull(
|
||||
'Cannot resolve types for ' . $key . ' - ' . $existing_var_type
|
||||
. ' does not contain null',
|
||||
$code_location
|
||||
$code_location,
|
||||
$existing_var_type->getId()
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -619,7 +622,8 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
|
||||
new DocblockTypeContradiction(
|
||||
'Cannot resolve types for ' . $key . ' - docblock-defined type '
|
||||
. $existing_var_type->getId() . ' does not contain ' . $new_type->getId(),
|
||||
$code_location
|
||||
$code_location,
|
||||
$existing_var_type->getId() . ' ' . $new_type->getId()
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -628,9 +632,10 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
|
||||
} else {
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
'Cannot resolve types for ' . $key . ' - ' . $existing_var_type->getId() .
|
||||
' does not contain ' . $new_type->getId(),
|
||||
$code_location
|
||||
'Cannot resolve types for ' . $key . ' - ' . $existing_var_type->getId()
|
||||
. ' does not contain ' . $new_type->getId(),
|
||||
$code_location,
|
||||
$existing_var_type->getId() . ' ' . $new_type->getId()
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
|
@ -88,7 +88,8 @@ class NegatedAssertionReconciler extends Reconciler
|
||||
new DocblockTypeContradiction(
|
||||
'Cannot resolve types for ' . $key . ' with docblock-defined type '
|
||||
. $existing_var_type . ' and !isset assertion',
|
||||
$code_location
|
||||
$code_location,
|
||||
null
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -99,7 +100,8 @@ class NegatedAssertionReconciler extends Reconciler
|
||||
new TypeDoesNotContainType(
|
||||
'Cannot resolve types for ' . $key . ' with type '
|
||||
. $existing_var_type . ' and !isset assertion',
|
||||
$code_location
|
||||
$code_location,
|
||||
null
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
|
@ -75,7 +75,8 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
'Cannot resolve types for ' . $key . ' on null var',
|
||||
$code_location
|
||||
$code_location,
|
||||
null
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -1981,7 +1982,8 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
|
||||
'Found a redundant condition when evaluating ' . $key
|
||||
. ' of type ' . $existing_var_type->getId()
|
||||
. ' and trying to reconcile it with a ' . $assertion . ' assertion',
|
||||
$code_location
|
||||
$code_location,
|
||||
$existing_var_type->getId() . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)
|
||||
@ -2032,7 +2034,8 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
|
||||
'Found a redundant condition when evaluating ' . $key
|
||||
. ' of type ' . $existing_var_type->getId()
|
||||
. ' and trying to reconcile it with a ' . $assertion . ' assertion',
|
||||
$code_location
|
||||
$code_location,
|
||||
$existing_var_type->getId() . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)
|
||||
|
@ -605,7 +605,8 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
'Found a redundant condition when evaluating ' . $key
|
||||
. ' of type ' . $existing_var_type->getId()
|
||||
. ' and trying to reconcile it with a non-' . $assertion . ' assertion',
|
||||
$code_location
|
||||
$code_location,
|
||||
$existing_var_type->getId() . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)
|
||||
@ -635,7 +636,8 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
'Found a redundant condition when evaluating ' . $key
|
||||
. ' of type ' . $existing_var_type->getId()
|
||||
. ' and trying to reconcile it with a non-' . $assertion . ' assertion',
|
||||
$code_location
|
||||
$code_location,
|
||||
$existing_var_type->getId() . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)
|
||||
@ -671,7 +673,8 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
'Found a redundant condition when evaluating ' . $key
|
||||
. ' of type ' . $existing_var_type->getId()
|
||||
. ' and trying to reconcile it with a non-' . $assertion . ' assertion',
|
||||
$code_location
|
||||
$code_location,
|
||||
$existing_var_type->getId() . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)
|
||||
|
@ -14,13 +14,20 @@ abstract class CodeIssue
|
||||
|
||||
/**
|
||||
* @var CodeLocation
|
||||
* @readonly
|
||||
*/
|
||||
protected $code_location;
|
||||
public $code_location;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @readonly
|
||||
*/
|
||||
protected $message;
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* @var ?string
|
||||
*/
|
||||
public $dupe_key;
|
||||
|
||||
public function __construct(
|
||||
string $message,
|
||||
@ -30,6 +37,10 @@ abstract class CodeIssue
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @psalm-suppress PossiblyUnusedMethod
|
||||
*/
|
||||
public function getLocation(): CodeLocation
|
||||
{
|
||||
return $this->code_location;
|
||||
@ -58,7 +69,7 @@ abstract class CodeIssue
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated
|
||||
* @psalm-suppress PossiblyUnusedMethod for convenience
|
||||
*/
|
||||
public function getFileName(): string
|
||||
@ -66,6 +77,10 @@ abstract class CodeIssue
|
||||
return $this->code_location->file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @psalm-suppress PossiblyUnusedMethod
|
||||
*/
|
||||
public function getMessage(): string
|
||||
{
|
||||
return $this->message;
|
||||
@ -77,7 +92,7 @@ abstract class CodeIssue
|
||||
*/
|
||||
public function toIssueData($severity = Config::REPORT_ERROR): \Psalm\Internal\Analyzer\IssueData
|
||||
{
|
||||
$location = $this->getLocation();
|
||||
$location = $this->code_location;
|
||||
$selection_bounds = $location->getSelectionBounds();
|
||||
$snippet_bounds = $location->getSnippetBounds();
|
||||
|
||||
@ -89,7 +104,7 @@ abstract class CodeIssue
|
||||
$location->getLineNumber(),
|
||||
$location->getEndLineNumber(),
|
||||
$issue_type,
|
||||
$this->getMessage(),
|
||||
$this->message,
|
||||
$location->file_name,
|
||||
$location->file_path,
|
||||
$location->getSnippet(),
|
||||
@ -102,7 +117,8 @@ abstract class CodeIssue
|
||||
$location->getEndColumn(),
|
||||
(int) static::SHORTCODE,
|
||||
(int) static::ERROR_LEVEL,
|
||||
$this instanceof TaintedInput ? $this->getTaintTrace() : null
|
||||
$this instanceof TaintedInput ? $this->getTaintTrace() : null,
|
||||
$this->dupe_key
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,10 @@ class DocblockTypeContradiction extends CodeIssue
|
||||
{
|
||||
const ERROR_LEVEL = 2;
|
||||
const SHORTCODE = 155;
|
||||
|
||||
public function __construct(string $message, \Psalm\CodeLocation $code_location, ?string $dupe_key)
|
||||
{
|
||||
parent::__construct($message, $code_location);
|
||||
$this->dupe_key = $dupe_key;
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,10 @@ class MissingConstructor extends CodeIssue
|
||||
{
|
||||
const ERROR_LEVEL = 2;
|
||||
const SHORTCODE = 73;
|
||||
|
||||
public function __construct(string $message, \Psalm\CodeLocation $code_location, ?string $dupe_key)
|
||||
{
|
||||
parent::__construct($message, $code_location);
|
||||
$this->dupe_key = $dupe_key;
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,13 @@ class PropertyNotSetInConstructor extends PropertyIssue
|
||||
{
|
||||
const ERROR_LEVEL = 2;
|
||||
const SHORTCODE = 74;
|
||||
|
||||
public function __construct(
|
||||
string $message,
|
||||
\Psalm\CodeLocation $code_location,
|
||||
string $property_id
|
||||
) {
|
||||
parent::__construct($message, $code_location, $property_id);
|
||||
$this->dupe_key = $property_id;
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,10 @@ class RedundantCondition extends CodeIssue
|
||||
{
|
||||
const ERROR_LEVEL = 4;
|
||||
const SHORTCODE = 122;
|
||||
|
||||
public function __construct(string $message, \Psalm\CodeLocation $code_location, ?string $dupe_key)
|
||||
{
|
||||
parent::__construct($message, $code_location);
|
||||
$this->dupe_key = $dupe_key;
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,11 @@ class RedundantConditionGivenDocblockType extends CodeIssue
|
||||
{
|
||||
const ERROR_LEVEL = 2;
|
||||
const SHORTCODE = 156;
|
||||
|
||||
public function __construct(string $message, \Psalm\CodeLocation $code_location, ?string $dupe_key)
|
||||
{
|
||||
parent::__construct($message, $code_location);
|
||||
|
||||
$this->dupe_key = $dupe_key;
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,10 @@ class TypeDoesNotContainNull extends CodeIssue
|
||||
{
|
||||
const ERROR_LEVEL = 4;
|
||||
const SHORTCODE = 90;
|
||||
|
||||
public function __construct(string $message, \Psalm\CodeLocation $code_location, ?string $dupe_key)
|
||||
{
|
||||
parent::__construct($message, $code_location);
|
||||
$this->dupe_key = $dupe_key;
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,10 @@ class TypeDoesNotContainType extends CodeIssue
|
||||
{
|
||||
const ERROR_LEVEL = 4;
|
||||
const SHORTCODE = 56;
|
||||
|
||||
public function __construct(string $message, \Psalm\CodeLocation $code_location, ?string $dupe_key)
|
||||
{
|
||||
parent::__construct($message, $code_location);
|
||||
$this->dupe_key = $dupe_key;
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ class IssueBuffer
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($e->getLocation()->getLineNumber() === -1) {
|
||||
if ($e->code_location->getLineNumber() === -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -216,13 +216,13 @@ class IssueBuffer
|
||||
ob_start();
|
||||
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$trace = ob_get_clean();
|
||||
fwrite(STDERR, "\nEmitting {$e->getShortLocation()} $issue_type {$e->getMessage()}\n$trace\n");
|
||||
fwrite(STDERR, "\nEmitting {$e->getShortLocation()} $issue_type {$e->message}\n$trace\n");
|
||||
}
|
||||
|
||||
$emitted_key = $issue_type
|
||||
. '-' . $e->getShortLocation()
|
||||
. ':' . $e->getLocation()->getColumn()
|
||||
. ' ' . $e->getMessage();
|
||||
. ':' . $e->code_location->getColumn()
|
||||
. ' ' . $e->dupe_key;
|
||||
|
||||
if ($reporting_level === Config::REPORT_INFO) {
|
||||
if ($issue_type === 'TaintedInput' || !self::alreadyEmitted($emitted_key)) {
|
||||
@ -237,12 +237,12 @@ class IssueBuffer
|
||||
|
||||
$message = $e instanceof \Psalm\Issue\TaintedInput
|
||||
? $e->getJourneyMessage()
|
||||
: $e->getMessage();
|
||||
: $e->message;
|
||||
|
||||
throw new Exception\CodeException(
|
||||
$issue_type
|
||||
. ' - ' . $e->getShortLocationWithPrevious()
|
||||
. ':' . $e->getLocation()->getColumn()
|
||||
. ':' . $e->code_location->getColumn()
|
||||
. ' - ' . $message
|
||||
);
|
||||
}
|
||||
@ -415,7 +415,7 @@ class IssueBuffer
|
||||
. '-' . $issue->file_name
|
||||
. ':' . $issue->line_from
|
||||
. ':' . $issue->column_from
|
||||
. ' ' . $issue->message;
|
||||
. ' ' . $issue->getDupeKey();
|
||||
|
||||
if (!self::alreadyEmitted($emitted_key)) {
|
||||
self::$issues_data[$file_path][] = $issue;
|
||||
|
@ -821,7 +821,11 @@ class Reconciler
|
||||
CodeLocation $code_location,
|
||||
array $suppressed_issues
|
||||
) {
|
||||
$reconciliation = ' and trying to reconcile type \'' . $old_var_type_string . '\' to ' . $assertion;
|
||||
$never = $assertion[0] === '!';
|
||||
|
||||
if ($never) {
|
||||
$assertion = substr($assertion, 1);
|
||||
}
|
||||
|
||||
$existing_var_atomic_types = $existing_var_type->getAtomicTypes();
|
||||
|
||||
@ -833,9 +837,11 @@ class Reconciler
|
||||
if ($from_docblock) {
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantConditionGivenDocblockType(
|
||||
'Found a redundant condition when evaluating docblock-defined type '
|
||||
. $key . $reconciliation,
|
||||
$code_location
|
||||
'Docblock-defined type ' . $old_var_type_string
|
||||
. ' for ' . $key
|
||||
. ' is ' . ($never ? 'never ' : 'always ') . $assertion,
|
||||
$code_location,
|
||||
$old_var_type_string . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -844,8 +850,11 @@ class Reconciler
|
||||
} else {
|
||||
if (IssueBuffer::accepts(
|
||||
new RedundantCondition(
|
||||
'Found a redundant condition when evaluating ' . $key . $reconciliation,
|
||||
$code_location
|
||||
'Type ' . $old_var_type_string
|
||||
. ' for ' . $key
|
||||
. ' is ' . ($never ? 'never ' : 'always ') . $assertion,
|
||||
$code_location,
|
||||
$old_var_type_string . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -856,9 +865,11 @@ class Reconciler
|
||||
if ($from_docblock) {
|
||||
if (IssueBuffer::accepts(
|
||||
new DocblockTypeContradiction(
|
||||
'Found a contradiction with a docblock-defined type '
|
||||
. 'when evaluating ' . $key . $reconciliation,
|
||||
$code_location
|
||||
'Docblock-defined type ' . $old_var_type_string
|
||||
. ' for ' . $key
|
||||
. ' is ' . ($never ? 'always ' : 'never ') . $assertion,
|
||||
$code_location,
|
||||
$old_var_type_string . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
@ -867,8 +878,11 @@ class Reconciler
|
||||
} else {
|
||||
if (IssueBuffer::accepts(
|
||||
new TypeDoesNotContainType(
|
||||
'Found a contradiction when evaluating ' . $key . $reconciliation,
|
||||
$code_location
|
||||
'Type ' . $old_var_type_string
|
||||
. ' for ' . $key
|
||||
. ' is ' . ($never ? 'always ' : 'never ') . $assertion,
|
||||
$code_location,
|
||||
$old_var_type_string . ' ' . $assertion
|
||||
),
|
||||
$suppressed_issues
|
||||
)) {
|
||||
|
@ -1824,7 +1824,7 @@ class FunctionCallTest extends TestCase
|
||||
function sayHello(string $format): void {
|
||||
if (strpos("u", $format)) {}
|
||||
}',
|
||||
'error_message' => 'InvalidArgument',
|
||||
'error_message' => 'InvalidLiteralArgument',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ class JsonOutputTest extends TestCase
|
||||
$a = $_GET["hello"];
|
||||
assert(is_int($a));
|
||||
if (is_int($a)) {}',
|
||||
'message' => "Found a redundant condition when evaluating docblock-defined type \$a and trying to reconcile type 'int' to int",
|
||||
'message' => 'Docblock-defined type int for $a is always int',
|
||||
'line' => 4,
|
||||
'error' => 'is_int($a)',
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user