From 5513fcdcff16ac6028c655a52e6c60aa6b3a18b4 Mon Sep 17 00:00:00 2001 From: Brown Date: Sun, 23 Aug 2020 18:50:17 -0400 Subject: [PATCH] Prevent isset on uknown property in pure function --- .../Fetch/InstancePropertyFetchAnalyzer.php | 20 +++++++++ tests/PureAnnotationTest.php | 44 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php index afdc7936e..7d1cfc04e 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php @@ -789,6 +789,26 @@ class InstancePropertyFetchAnalyzer $property_id = $context->self . '::$' . $prop_name; } else { if ($context->inside_isset || $context->collect_initializations) { + $project_analyzer = $statements_analyzer->getProjectAnalyzer(); + + if ($context->pure) { + if (IssueBuffer::accepts( + new ImpurePropertyFetch( + 'Cannot access a property on a mutable object from a pure context', + new CodeLocation($statements_analyzer, $stmt) + ), + $statements_analyzer->getSuppressedIssues() + )) { + // fall through + } + } elseif ($codebase->alter_code + && isset($project_analyzer->getIssuesToFix()['MissingPureAnnotation']) + && $statements_analyzer->getSource() + instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer + ) { + $statements_analyzer->getSource()->inferred_impure = true; + } + return true; } diff --git a/tests/PureAnnotationTest.php b/tests/PureAnnotationTest.php index 61347312b..37a2d8c0d 100644 --- a/tests/PureAnnotationTest.php +++ b/tests/PureAnnotationTest.php @@ -670,6 +670,50 @@ class PureAnnotationTest extends TestCase return true; } + return false; + }', + 'error_message' => 'ImpurePropertyFetch', + ], + 'preventIssetOnMutableClassKnownProperty' => [ + 'a = $a; + } + } + + /** @psalm-pure */ + function filterOdd(A $a) : bool { + if (isset($a->a)) { + return true; + } + + return false; + }', + 'error_message' => 'ImpurePropertyFetch', + ], + 'preventIssetOnMutableClassUnknownProperty' => [ + 'a = $a; + } + } + + /** @psalm-pure */ + function filterOdd(A $a) : bool { + if (isset($a->b)) { + return true; + } + return false; }', 'error_message' => 'ImpurePropertyFetch',