From af5cdb4dd45b196c5da60dea36d39cf0aaa2d95c Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Sat, 17 Jul 2021 01:20:35 +0300 Subject: [PATCH] Check deprecated properties on $this->prop reads Fixes vimeo/psalm#6118 --- .../Fetch/AtomicPropertyFetchAnalyzer.php | 48 ++++++++++++++----- .../Fetch/InstancePropertyFetchAnalyzer.php | 17 +++++++ tests/DeprecatedAnnotationTest.php | 32 +++++++++++++ 3 files changed, 84 insertions(+), 13 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php index 07f671cd8..4eb46f490 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/AtomicPropertyFetchAnalyzer.php @@ -344,6 +344,9 @@ class AtomicPropertyFetchAnalyzer } } + // FIXME: the following line look superfluous, but removing it makes + // Psalm\Tests\PropertyTypeTest::testValidCode with data set "callInParentContext" + // fail $declaring_property_class = $codebase->properties->getDeclaringClassForProperty( $property_id, true, @@ -380,20 +383,9 @@ class AtomicPropertyFetchAnalyzer ); if (isset($declaring_class_storage->properties[$prop_name])) { - $property_storage = $declaring_class_storage->properties[$prop_name]; + self::checkPropertyDeprecation($prop_name, $declaring_property_class, $stmt, $statements_analyzer); - if ($property_storage->deprecated) { - if (IssueBuffer::accepts( - new DeprecatedProperty( - $property_id . ' is marked deprecated', - new CodeLocation($statements_analyzer->getSource(), $stmt), - $property_id - ), - $statements_analyzer->getSuppressedIssues() - )) { - // fall through - } - } + $property_storage = $declaring_class_storage->properties[$prop_name]; if ($context->self && !NamespaceAnalyzer::isWithin($context->self, $property_storage->internal)) { if (IssueBuffer::accepts( @@ -481,6 +473,36 @@ class AtomicPropertyFetchAnalyzer } } + public static function checkPropertyDeprecation( + string $prop_name, + string $declaring_property_class, + PhpParser\Node\Expr\PropertyFetch $stmt, + StatementsAnalyzer $statements_analyzer + ): void { + $property_id = $declaring_property_class . '::$' . $prop_name; + $codebase = $statements_analyzer->getCodebase(); + $declaring_class_storage = $codebase->classlike_storage_provider->get( + $declaring_property_class + ); + + if (isset($declaring_class_storage->properties[$prop_name])) { + $property_storage = $declaring_class_storage->properties[$prop_name]; + + if ($property_storage->deprecated) { + if (IssueBuffer::accepts( + new DeprecatedProperty( + $property_id . ' is marked deprecated', + new CodeLocation($statements_analyzer->getSource(), $stmt), + $property_id + ), + $statements_analyzer->getSuppressedIssues() + )) { + // fall through + } + } + } + } + private static function propertyFetchCanBeAnalyzed( StatementsAnalyzer $statements_analyzer, \Psalm\Codebase $codebase, diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php index b83a842ac..964b1ee9d 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/InstancePropertyFetchAnalyzer.php @@ -391,6 +391,7 @@ class InstancePropertyFetchAnalyzer } } + if (($stmt_var_type = $statements_analyzer->node_data->getType($stmt->var)) && $stmt_var_type->hasObjectType() && $stmt->name instanceof PhpParser\Node\Identifier @@ -404,6 +405,7 @@ class InstancePropertyFetchAnalyzer $property_id = $lhs_type_part->value . '::$' . $stmt->name->name; + $class_storage = $codebase->classlike_storage_provider->get($lhs_type_part->value); AtomicPropertyFetchAnalyzer::processTaints( @@ -415,6 +417,21 @@ class InstancePropertyFetchAnalyzer $in_assignment ); + $declaring_property_class = $codebase->properties->getDeclaringClassForProperty( + $property_id, + true, + $statements_analyzer + ); + + if ($declaring_property_class) { + AtomicPropertyFetchAnalyzer::checkPropertyDeprecation( + $stmt->name->name, + $declaring_property_class, + $stmt, + $statements_analyzer + ); + } + $codebase->properties->propertyExists( $property_id, true, diff --git a/tests/DeprecatedAnnotationTest.php b/tests/DeprecatedAnnotationTest.php index db7003a3c..b7845eb0b 100644 --- a/tests/DeprecatedAnnotationTest.php +++ b/tests/DeprecatedAnnotationTest.php @@ -168,6 +168,38 @@ class DeprecatedAnnotationTest extends TestCase $a->foo = 5;', 'error_message' => 'DeprecatedProperty', ], + 'deprecatedPropertyGetFromInsideTheClass' => [ + 'foo; + } + } + ', + 'error_message' => 'DeprecatedProperty', + ], + 'deprecatedPropertySetFromInsideTheClass' => [ + 'foo = $p; + } + } + ', + 'error_message' => 'DeprecatedProperty', + ], 'deprecatedClassConstant' => [ '