1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-14 02:07:37 +01:00
psalm/src/Psalm/Checker/ClassChecker.php

169 lines
4.7 KiB
PHP
Raw Normal View History

<?php
namespace Psalm\Checker;
use PhpParser;
use Psalm\StatementsSource;
class ClassChecker extends ClassLikeChecker
{
2016-10-10 07:35:12 +02:00
/**
* @var PhpParser\Node\Stmt\Class_
*/
protected $class;
2016-10-31 20:42:20 +01:00
/**
* @var integer
*/
2016-10-21 02:54:17 +02:00
protected static $anonymous_class_count = 0;
2016-09-09 15:13:41 +02:00
/**
2016-11-02 07:29:00 +01:00
* @param PhpParser\Node\Stmt\ClassLike $class
* @param StatementsSource $source
* @param string|null $fq_class_name
2016-09-09 15:13:41 +02:00
*/
public function __construct(PhpParser\Node\Stmt\ClassLike $class, StatementsSource $source, $fq_class_name)
{
2016-10-23 07:57:11 +02:00
if (!$class instanceof PhpParser\Node\Stmt\Class_) {
throw new \InvalidArgumentException('Bad');
}
if ($fq_class_name === null) {
$fq_class_name = 'PsalmAnonymousClass' . (self::$anonymous_class_count++);
$class->name = $fq_class_name;
2016-10-21 02:54:17 +02:00
}
parent::__construct($class, $source, $fq_class_name);
2017-01-09 05:58:06 +01:00
$fq_class_name_lower = strtolower($fq_class_name);
2017-01-09 05:58:06 +01:00
$storage = self::$storage[$fq_class_name_lower];
$project_checker = $source->getFileChecker()->project_checker;
$project_checker->addFullyQualifiedClassName($fq_class_name);
self::$class_extends[$this->fq_class_name] = [];
if ($this->class->extends) {
2017-01-07 20:35:07 +01:00
$this->parent_fq_class_name = self::getFQCLNFromNameObject(
2016-11-02 07:29:00 +01:00
$this->class->extends,
2017-01-07 20:35:07 +01:00
$this->source
2016-11-02 07:29:00 +01:00
);
}
foreach ($class->implements as $interface_name) {
2016-11-08 01:16:51 +01:00
$fq_interface_name = self::getFQCLNFromNameObject(
2016-11-02 07:29:00 +01:00
$interface_name,
2017-01-07 20:35:07 +01:00
$this->source
2016-11-02 07:29:00 +01:00
);
$storage->class_implements[strtolower($fq_interface_name)] = $fq_interface_name;
}
}
2016-09-09 15:13:41 +02:00
/**
* Determine whether or not a given class exists
*
* @param string $fq_class_name
* @param FileChecker $file_checker
2017-01-09 05:58:06 +01:00
* @param bool $visit_file
2016-09-09 15:13:41 +02:00
* @return bool
*/
2017-01-09 05:58:06 +01:00
public static function classExists($fq_class_name, FileChecker $file_checker, $visit_file = false)
{
if (isset(self::$SPECIAL_TYPES[$fq_class_name])) {
return false;
}
2017-01-09 05:58:06 +01:00
if ($fq_class_name === 'Generator') {
return true;
}
2017-01-09 05:58:06 +01:00
if ($file_checker->evaluateClassLike($fq_class_name, $visit_file) === false) {
return false;
}
2017-01-09 05:58:06 +01:00
return $file_checker->project_checker->hasFullyQualifiedClassName($fq_class_name);
}
2016-09-09 15:13:41 +02:00
/**
* Determine whether or not a class has the correct casing
*
* @param string $fq_class_name
2017-01-09 05:58:06 +01:00
* @param FileChecker $file_checker
2016-09-09 15:13:41 +02:00
* @return bool
*/
2017-01-09 05:58:06 +01:00
public static function hasCorrectCasing($fq_class_name, FileChecker $file_checker)
{
2017-01-09 05:58:06 +01:00
if ($fq_class_name === 'Generator') {
return true;
}
2017-01-09 05:58:06 +01:00
return isset($file_checker->project_checker->existing_classes[$fq_class_name]);
}
/**
2016-09-09 15:13:41 +02:00
* Determine whether or not a class extends a parent
*
* @param string $fq_class_name
* @param string $possible_parent
* @return bool
*/
public static function classExtends($fq_class_name, $possible_parent)
{
2017-01-09 05:58:06 +01:00
$fq_class_name = strtolower($fq_class_name);
if (!isset(self::$storage[$fq_class_name])) {
throw new \UnexpectedValueException('$storage should not be null for ' . $fq_class_name);
}
return in_array($possible_parent, self::$storage[$fq_class_name]->parent_classes);
}
2016-09-09 15:13:41 +02:00
/**
* Get all the interfaces a given class implements
*
* @param string $fq_class_name
2016-09-09 15:13:41 +02:00
* @return array<string>
*/
public static function getInterfacesForClass($fq_class_name)
{
2017-01-09 05:58:06 +01:00
return self::$storage[strtolower($fq_class_name)]->class_implements;
}
/**
2016-09-09 15:13:41 +02:00
* Check whether a class implements an interface
*
* @param string $fq_class_name
* @param string $interface
* @return bool
*/
public static function classImplements($fq_class_name, $interface)
{
$interface_id = strtolower($interface);
2017-01-09 07:48:55 +01:00
$fq_class_name = strtolower($fq_class_name);
if ($interface_id === 'callable' && $fq_class_name === 'closure') {
2016-10-21 00:05:28 +02:00
return true;
}
2017-01-09 07:48:55 +01:00
if (isset(self::$SPECIAL_TYPES[$interface_id]) || isset(self::$SPECIAL_TYPES[$fq_class_name])) {
return false;
}
2017-01-09 07:48:55 +01:00
$storage = self::$storage[$fq_class_name];
return isset($storage->class_implements[$interface_id]);
}
2016-08-15 17:01:50 +02:00
2016-11-02 07:29:00 +01:00
/**
* @return void
*/
2016-08-15 17:01:50 +02:00
public static function clearCache()
{
2016-10-21 02:54:17 +02:00
self::$anonymous_class_count = 0;
MethodChecker::clearCache();
2016-08-15 17:01:50 +02:00
}
}