1
0
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:
Brown 2020-09-10 22:44:35 -04:00
parent 00ad09816f
commit eda426a594
24 changed files with 240 additions and 94 deletions

View File

@ -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()
)) {

View File

@ -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()
)) {

View File

@ -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;
}
}

View File

@ -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()
)) {

View File

@ -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

View File

@ -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()
)) {

View File

@ -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()
)) {

View File

@ -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()
)) {

View File

@ -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
)) {

View File

@ -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
)) {

View File

@ -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
)

View File

@ -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
)

View File

@ -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
);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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
)) {

View File

@ -1824,7 +1824,7 @@ class FunctionCallTest extends TestCase
function sayHello(string $format): void {
if (strpos("u", $format)) {}
}',
'error_message' => 'InvalidArgument',
'error_message' => 'InvalidLiteralArgument',
],
];
}

View File

@ -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)',
],