mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Add support for checking inherited constants
This commit is contained in:
parent
fd63f3e056
commit
defc4cebc1
@ -4,6 +4,7 @@ namespace Psalm\Checker;
|
||||
|
||||
use PhpParser;
|
||||
use Psalm\StatementsSource;
|
||||
use Psalm\Context;
|
||||
|
||||
class ClassChecker extends ClassLikeChecker
|
||||
{
|
||||
@ -21,14 +22,62 @@ class ClassChecker extends ClassLikeChecker
|
||||
|
||||
self::$class_implements[$absolute_class] = [];
|
||||
|
||||
if ($this->class->extends) {
|
||||
$this->parent_class = self::getAbsoluteClassFromName($this->class->extends, $this->namespace, $this->aliased_classes);
|
||||
}
|
||||
|
||||
foreach ($class->implements as $interface_name) {
|
||||
$absolute_interface_name = self::getAbsoluteClassFromName($interface_name, $this->namespace, $this->aliased_classes);
|
||||
|
||||
|
||||
|
||||
self::$class_implements[$absolute_class][$absolute_interface_name] = true;
|
||||
self::registerClass($absolute_interface_name);
|
||||
}
|
||||
}
|
||||
|
||||
public function check($check_methods = true, Context $class_context = null)
|
||||
{
|
||||
if ($this->parent_class) {
|
||||
if (self::checkAbsoluteClassOrInterface(
|
||||
$this->parent_class,
|
||||
$this->file_name,
|
||||
$this->class->getLine(),
|
||||
$this->getSuppressedIssues()
|
||||
) === false
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset(self::$public_class_properties[$this->parent_class])
|
||||
|| !isset(self::$public_class_constants[$this->parent_class])
|
||||
|| !isset(self::$class_implements[$this->parent_class])
|
||||
) {
|
||||
self::registerClass($this->parent_class);
|
||||
}
|
||||
|
||||
$this->registerInheritedMethods($this->parent_class);
|
||||
|
||||
self::$class_implements[$this->absolute_class] += self::$class_implements[$this->parent_class];
|
||||
}
|
||||
|
||||
foreach (self::$class_implements[$this->absolute_class] as $interface_name => $_) {
|
||||
if (self::checkAbsoluteClassOrInterface(
|
||||
$interface_name,
|
||||
$this->file_name,
|
||||
$this->class->getLine(),
|
||||
$this->getSuppressedIssues()
|
||||
) === false
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self::registerClass($interface_name);
|
||||
}
|
||||
|
||||
parent::check($check_methods, $class_context);
|
||||
}
|
||||
|
||||
|
||||
public static function classExists($absolute_class)
|
||||
{
|
||||
if (isset(self::$existing_classes_ci[strtolower($absolute_class)])) {
|
||||
@ -89,7 +138,11 @@ class ClassChecker extends ClassLikeChecker
|
||||
|
||||
public static function getInterfacesForClass($absolute_class)
|
||||
{
|
||||
return isset(self::$class_implements[$absolute_class]) ? self::$class_implements[$absolute_class] : [];
|
||||
if (!isset(self::$class_implements[$absolute_class])) {
|
||||
self::$class_implements[$absolute_class] = class_implements($absolute_class);
|
||||
}
|
||||
|
||||
return self::$class_implements[$absolute_class];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,14 +166,8 @@ class ClassChecker extends ClassLikeChecker
|
||||
return false;
|
||||
}
|
||||
|
||||
$class_implementations = class_implements($absolute_class);
|
||||
$class_implementations = self::getInterfacesForClass($absolute_class);
|
||||
|
||||
if (!isset($class_implementations[$interface])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$class_implements[$absolute_class] = $class_implementations;
|
||||
|
||||
return true;
|
||||
return isset($class_implementations[$interface]);
|
||||
}
|
||||
}
|
||||
|
@ -68,10 +68,6 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
|
||||
$this->suppressed_issues = $source->getSuppressedIssues();
|
||||
|
||||
$this->parent_class = $this->class->extends
|
||||
? self::getAbsoluteClassFromName($this->class->extends, $this->namespace, $this->aliased_classes)
|
||||
: null;
|
||||
|
||||
if (self::$this_class || $class instanceof PhpParser\Node\Stmt\Trait_) {
|
||||
self::$class_checkers[$absolute_class] = $this;
|
||||
}
|
||||
@ -79,24 +75,6 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
|
||||
public function check($check_methods = true, Context $class_context = null)
|
||||
{
|
||||
if ($this->parent_class) {
|
||||
if (self::checkAbsoluteClassOrInterface(
|
||||
$this->parent_class,
|
||||
$this->file_name,
|
||||
$this->class->getLine(),
|
||||
$this->getSuppressedIssues()
|
||||
) === false
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset(self::$public_class_properties[$this->parent_class]) || !isset(self::$public_class_constants[$this->parent_class])) {
|
||||
self::registerClass($this->parent_class);
|
||||
}
|
||||
|
||||
$this->registerInheritedMethods($this->parent_class);
|
||||
}
|
||||
|
||||
$config = Config::getInstance();
|
||||
|
||||
$leftover_stmts = [];
|
||||
@ -115,17 +93,17 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
|
||||
self::$public_class_constants[$this->absolute_class] = [];
|
||||
|
||||
if ($this->parent_class) {
|
||||
self::$public_class_properties[$this->absolute_class] = self::$public_class_properties[$this->parent_class];
|
||||
self::$protected_class_properties[$this->absolute_class] = self::$protected_class_properties[$this->parent_class];
|
||||
|
||||
self::$public_static_class_properties[$this->absolute_class] = self::$public_static_class_properties[$this->parent_class];
|
||||
self::$protected_static_class_properties[$this->absolute_class] = self::$protected_static_class_properties[$this->parent_class];
|
||||
|
||||
self::$public_class_constants[$this->absolute_class] = self::$public_class_constants[$this->parent_class];
|
||||
}
|
||||
|
||||
if ($this instanceof ClassChecker) {
|
||||
if ($this->parent_class) {
|
||||
self::$public_class_properties[$this->absolute_class] = self::$public_class_properties[$this->parent_class];
|
||||
self::$protected_class_properties[$this->absolute_class] = self::$protected_class_properties[$this->parent_class];
|
||||
|
||||
self::$public_static_class_properties[$this->absolute_class] = self::$public_static_class_properties[$this->parent_class];
|
||||
self::$protected_static_class_properties[$this->absolute_class] = self::$protected_static_class_properties[$this->parent_class];
|
||||
|
||||
self::$public_class_constants[$this->absolute_class] = self::$public_class_constants[$this->parent_class];
|
||||
}
|
||||
|
||||
foreach (ClassChecker::getInterfacesForClass($this->absolute_class) as $interface_name => $_) {
|
||||
self::$public_class_constants[$this->absolute_class] += self::$public_class_constants[$interface_name];
|
||||
}
|
||||
@ -531,7 +509,6 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
self::$private_class_properties[$class_name][$class_property->getName()] = Type::getMixed();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$class_constants = $reflected_class->getConstants();
|
||||
@ -570,6 +547,10 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
|
||||
self::$public_class_constants[$class_name][$name] = $const_type;
|
||||
}
|
||||
|
||||
if (!$reflected_class->isTrait() && !$reflected_class->isInterface()) {
|
||||
ClassChecker::getInterfacesForClass($class_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ use Psalm\Issue\InvalidDocblock;
|
||||
use Psalm\Issue\InvalidReturnType;
|
||||
use Psalm\StatementsSource;
|
||||
use Psalm\Type;
|
||||
use Psalm\Config;
|
||||
use Psalm\Context;
|
||||
use Psalm\IssueBuffer;
|
||||
|
||||
|
@ -8,6 +8,8 @@ use Psalm\Context;
|
||||
|
||||
class InterfaceChecker extends ClassLikeChecker
|
||||
{
|
||||
protected $parent_interfaces = [];
|
||||
|
||||
protected static $existing_interfaces = [];
|
||||
protected static $existing_interfaces_ci = [];
|
||||
|
||||
@ -17,6 +19,10 @@ class InterfaceChecker extends ClassLikeChecker
|
||||
|
||||
self::$existing_interfaces[$absolute_class] = true;
|
||||
self::$existing_interfaces_ci[strtolower($absolute_class)] = true;
|
||||
|
||||
foreach ($interface->extends as $extended_interface) {
|
||||
$this->parent_interfaces[] = self::getAbsoluteClassFromName($extended_interface, $this->namespace, $this->aliased_classes);
|
||||
}
|
||||
}
|
||||
|
||||
public static function interfaceExists($absolute_class)
|
||||
|
@ -7,6 +7,7 @@ use RecursiveIteratorIterator;
|
||||
|
||||
use Psalm\Config;
|
||||
use Psalm\IssueBuffer;
|
||||
use Psalm\Exception;
|
||||
|
||||
class ProjectChecker
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user