mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Don’t investigate property mutations if they’re not visible
This commit is contained in:
parent
95553ffc0e
commit
f3bfb089ad
@ -1576,15 +1576,17 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
|||||||
* @param StatementsSource $source
|
* @param StatementsSource $source
|
||||||
* @param CodeLocation $code_location
|
* @param CodeLocation $code_location
|
||||||
* @param array $suppressed_issues
|
* @param array $suppressed_issues
|
||||||
|
* @param bool $emit_issues
|
||||||
*
|
*
|
||||||
* @return false|null
|
* @return bool|null
|
||||||
*/
|
*/
|
||||||
public static function checkPropertyVisibility(
|
public static function checkPropertyVisibility(
|
||||||
$property_id,
|
$property_id,
|
||||||
$calling_context,
|
$calling_context,
|
||||||
StatementsSource $source,
|
StatementsSource $source,
|
||||||
CodeLocation $code_location,
|
CodeLocation $code_location,
|
||||||
array $suppressed_issues
|
array $suppressed_issues,
|
||||||
|
$emit_issues = true
|
||||||
) {
|
) {
|
||||||
$project_checker = $source->getFileChecker()->project_checker;
|
$project_checker = $source->getFileChecker()->project_checker;
|
||||||
|
|
||||||
@ -1601,11 +1603,11 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
|||||||
|
|
||||||
// if the calling class is the same, we know the property exists, so it must be visible
|
// if the calling class is the same, we know the property exists, so it must be visible
|
||||||
if ($appearing_property_class === $calling_context) {
|
if ($appearing_property_class === $calling_context) {
|
||||||
return null;
|
return $emit_issues ? null : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($source->getSource() instanceof TraitChecker && $declaring_property_class === $source->getFQCLN()) {
|
if ($source->getSource() instanceof TraitChecker && $declaring_property_class === $source->getFQCLN()) {
|
||||||
return null;
|
return $emit_issues ? null : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$class_storage = $project_checker->classlike_storage_provider->get($declaring_property_class);
|
$class_storage = $project_checker->classlike_storage_provider->get($declaring_property_class);
|
||||||
@ -1618,11 +1620,12 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
|||||||
|
|
||||||
switch ($storage->visibility) {
|
switch ($storage->visibility) {
|
||||||
case self::VISIBILITY_PUBLIC:
|
case self::VISIBILITY_PUBLIC:
|
||||||
return null;
|
return $emit_issues ? null : true;
|
||||||
|
|
||||||
case self::VISIBILITY_PRIVATE:
|
case self::VISIBILITY_PRIVATE:
|
||||||
if (!$calling_context || $appearing_property_class !== $calling_context) {
|
if (!$calling_context || $appearing_property_class !== $calling_context) {
|
||||||
if (IssueBuffer::accepts(
|
if ($emit_issues
|
||||||
|
&& IssueBuffer::accepts(
|
||||||
new InaccessibleProperty(
|
new InaccessibleProperty(
|
||||||
'Cannot access private property ' . $property_id . ' from context ' . $calling_context,
|
'Cannot access private property ' . $property_id . ' from context ' . $calling_context,
|
||||||
$code_location
|
$code_location
|
||||||
@ -1631,9 +1634,11 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
|||||||
)) {
|
)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return $emit_issues ? null : true;
|
||||||
|
|
||||||
case self::VISIBILITY_PROTECTED:
|
case self::VISIBILITY_PROTECTED:
|
||||||
if ($appearing_property_class === $calling_context) {
|
if ($appearing_property_class === $calling_context) {
|
||||||
@ -1641,7 +1646,8 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$calling_context) {
|
if (!$calling_context) {
|
||||||
if (IssueBuffer::accepts(
|
if ($emit_issues
|
||||||
|
&& IssueBuffer::accepts(
|
||||||
new InaccessibleProperty(
|
new InaccessibleProperty(
|
||||||
'Cannot access protected property ' . $property_id,
|
'Cannot access protected property ' . $property_id,
|
||||||
$code_location
|
$code_location
|
||||||
@ -1655,11 +1661,12 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ClassChecker::classExtends($project_checker, $appearing_property_class, $calling_context)) {
|
if (ClassChecker::classExtends($project_checker, $appearing_property_class, $calling_context)) {
|
||||||
return null;
|
return $emit_issues ? null : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ClassChecker::classExtends($project_checker, $calling_context, $appearing_property_class)) {
|
if (!ClassChecker::classExtends($project_checker, $calling_context, $appearing_property_class)) {
|
||||||
if (IssueBuffer::accepts(
|
if ($emit_issues
|
||||||
|
&& IssueBuffer::accepts(
|
||||||
new InaccessibleProperty(
|
new InaccessibleProperty(
|
||||||
'Cannot access protected property ' . $property_id . ' from context ' . $calling_context,
|
'Cannot access protected property ' . $property_id . ' from context ' . $calling_context,
|
||||||
$code_location
|
$code_location
|
||||||
@ -1668,10 +1675,12 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
|||||||
)) {
|
)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return $emit_issues ? null : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -792,14 +792,27 @@ class AssignmentChecker
|
|||||||
|
|
||||||
$property_exists = true;
|
$property_exists = true;
|
||||||
|
|
||||||
if (ClassLikeChecker::checkPropertyVisibility(
|
if (!$context->collect_mutations) {
|
||||||
$property_id,
|
if (ClassLikeChecker::checkPropertyVisibility(
|
||||||
$context->self,
|
$property_id,
|
||||||
$statements_checker->getSource(),
|
$context->self,
|
||||||
new CodeLocation($statements_checker->getSource(), $stmt),
|
$statements_checker->getSource(),
|
||||||
$statements_checker->getSuppressedIssues()
|
new CodeLocation($statements_checker->getSource(), $stmt),
|
||||||
) === false) {
|
$statements_checker->getSuppressedIssues()
|
||||||
return false;
|
) === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ClassLikeChecker::checkPropertyVisibility(
|
||||||
|
$property_id,
|
||||||
|
$context->self,
|
||||||
|
$statements_checker->getSource(),
|
||||||
|
new CodeLocation($statements_checker->getSource(), $stmt),
|
||||||
|
$statements_checker->getSuppressedIssues(),
|
||||||
|
false
|
||||||
|
) !== true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$declaring_property_class = ClassLikeChecker::getDeclaringClassForProperty(
|
$declaring_property_class = ClassLikeChecker::getDeclaringClassForProperty(
|
||||||
|
@ -643,6 +643,52 @@ class PropertyTypeTest extends TestCase
|
|||||||
'MissingReturnType',
|
'MissingReturnType',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'privatePropertyAccessible' => [
|
||||||
|
'<?php
|
||||||
|
class A {
|
||||||
|
/** @var string */
|
||||||
|
private $foo;
|
||||||
|
|
||||||
|
public function __construct(string $foo) {
|
||||||
|
$this->foo = $foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function bar() : void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
/** @var string */
|
||||||
|
private $foo;
|
||||||
|
|
||||||
|
public function __construct(string $foo) {
|
||||||
|
$this->foo = $foo;
|
||||||
|
parent::__construct($foo);
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
],
|
||||||
|
'privatePropertyAccessibleDifferentType' => [
|
||||||
|
'<?php
|
||||||
|
class A {
|
||||||
|
/** @var int */
|
||||||
|
private $foo;
|
||||||
|
|
||||||
|
public function __construct(string $foo) {
|
||||||
|
$this->foo = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function bar() : void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
/** @var string */
|
||||||
|
private $foo;
|
||||||
|
|
||||||
|
public function __construct(string $foo) {
|
||||||
|
$this->foo = $foo;
|
||||||
|
parent::__construct($foo);
|
||||||
|
}
|
||||||
|
}',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user