mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Swap in Fully-Qualified for Absolute terms
This commit is contained in:
parent
5046caa240
commit
622a0794c3
@ -80,7 +80,7 @@ class TemplateChecker extends Psalm\Checker\FileChecker
|
||||
{
|
||||
$class = explode('::', $method_id)[0];
|
||||
|
||||
if (ClassLikeChecker::checkAbsoluteClassOrInterface($class, $this->short_file_name, 1, []) === false) {
|
||||
if (ClassLikeChecker::checkFullQualifiedClassOrInterface($class, $this->short_file_name, 1, []) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -40,27 +40,27 @@ class ClassChecker extends ClassLikeChecker
|
||||
/**
|
||||
* @param PhpParser\Node\Stmt\ClassLike $class
|
||||
* @param StatementsSource $source
|
||||
* @param string|null $absolute_class
|
||||
* @param string|null $fq_class_name
|
||||
*/
|
||||
public function __construct(PhpParser\Node\Stmt\ClassLike $class, StatementsSource $source, $absolute_class)
|
||||
public function __construct(PhpParser\Node\Stmt\ClassLike $class, StatementsSource $source, $fq_class_name)
|
||||
{
|
||||
if (!$class instanceof PhpParser\Node\Stmt\Class_) {
|
||||
throw new \InvalidArgumentException('Bad');
|
||||
}
|
||||
|
||||
if ($absolute_class === null) {
|
||||
$absolute_class = 'PsalmAnonymousClass' . (self::$anonymous_class_count++);
|
||||
if ($fq_class_name === null) {
|
||||
$fq_class_name = 'PsalmAnonymousClass' . (self::$anonymous_class_count++);
|
||||
}
|
||||
|
||||
parent::__construct($class, $source, $absolute_class);
|
||||
parent::__construct($class, $source, $fq_class_name);
|
||||
|
||||
self::$existing_classes[$absolute_class] = true;
|
||||
self::$existing_classes_ci[strtolower($absolute_class)] = true;
|
||||
self::$existing_classes[$fq_class_name] = true;
|
||||
self::$existing_classes_ci[strtolower($fq_class_name)] = true;
|
||||
|
||||
self::$class_implements[$absolute_class] = [];
|
||||
self::$class_implements[$fq_class_name] = [];
|
||||
|
||||
if ($this->class->extends) {
|
||||
$this->parent_class = self::getAbsoluteClassFromName(
|
||||
$this->parent_class = self::getFullQualifiedClassFromName(
|
||||
$this->class->extends,
|
||||
$this->namespace,
|
||||
$this->aliased_classes
|
||||
@ -68,51 +68,51 @@ class ClassChecker extends ClassLikeChecker
|
||||
}
|
||||
|
||||
foreach ($class->implements as $interface_name) {
|
||||
$absolute_interface_name = self::getAbsoluteClassFromName(
|
||||
$fq_interface_name = self::getFullQualifiedClassFromName(
|
||||
$interface_name,
|
||||
$this->namespace,
|
||||
$this->aliased_classes
|
||||
);
|
||||
|
||||
self::$class_implements[$absolute_class][strtolower($absolute_interface_name)] = $absolute_interface_name;
|
||||
self::$class_implements[$fq_class_name][strtolower($fq_interface_name)] = $fq_interface_name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not a given class exists
|
||||
*
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return bool
|
||||
*/
|
||||
public static function classExists($absolute_class)
|
||||
public static function classExists($fq_class_name)
|
||||
{
|
||||
if (isset(self::$existing_classes_ci[strtolower($absolute_class)])) {
|
||||
return self::$existing_classes_ci[strtolower($absolute_class)];
|
||||
if (isset(self::$existing_classes_ci[strtolower($fq_class_name)])) {
|
||||
return self::$existing_classes_ci[strtolower($fq_class_name)];
|
||||
}
|
||||
|
||||
if (in_array($absolute_class, self::$SPECIAL_TYPES)) {
|
||||
if (in_array($fq_class_name, self::$SPECIAL_TYPES)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$old_level = error_reporting();
|
||||
error_reporting(0);
|
||||
$class_exists = class_exists($absolute_class);
|
||||
$class_exists = class_exists($fq_class_name);
|
||||
error_reporting($old_level);
|
||||
|
||||
if ($class_exists) {
|
||||
$old_level = error_reporting();
|
||||
error_reporting(0);
|
||||
$reflected_class = new \ReflectionClass($absolute_class);
|
||||
$reflected_class = new \ReflectionClass($fq_class_name);
|
||||
error_reporting($old_level);
|
||||
|
||||
self::$existing_classes_ci[strtolower($absolute_class)] = true;
|
||||
self::$existing_classes_ci[strtolower($fq_class_name)] = true;
|
||||
self::$existing_classes[$reflected_class->getName()] = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// we can only be sure that the case-sensitive version does not exist
|
||||
self::$existing_classes[$absolute_class] = false;
|
||||
self::$existing_classes[$fq_class_name] = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -120,90 +120,90 @@ class ClassChecker extends ClassLikeChecker
|
||||
/**
|
||||
* Determine whether or not a class has the correct casing
|
||||
*
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasCorrectCasing($absolute_class)
|
||||
public static function hasCorrectCasing($fq_class_name)
|
||||
{
|
||||
if (!self::classExists($absolute_class)) {
|
||||
throw new \InvalidArgumentException('Cannot check casing on nonexistent class ' . $absolute_class);
|
||||
if (!self::classExists($fq_class_name)) {
|
||||
throw new \InvalidArgumentException('Cannot check casing on nonexistent class ' . $fq_class_name);
|
||||
}
|
||||
|
||||
return isset(self::$existing_classes[$absolute_class]);
|
||||
return isset(self::$existing_classes[$fq_class_name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not a class extends a parent
|
||||
*
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @param string $possible_parent
|
||||
* @return bool
|
||||
*/
|
||||
public static function classExtends($absolute_class, $possible_parent)
|
||||
public static function classExtends($fq_class_name, $possible_parent)
|
||||
{
|
||||
if (isset(self::$class_extends[$absolute_class][$possible_parent])) {
|
||||
return self::$class_extends[$absolute_class][$possible_parent];
|
||||
if (isset(self::$class_extends[$fq_class_name][$possible_parent])) {
|
||||
return self::$class_extends[$fq_class_name][$possible_parent];
|
||||
}
|
||||
|
||||
if (!self::classExists($absolute_class) || !self::classExists($possible_parent)) {
|
||||
if (!self::classExists($fq_class_name) || !self::classExists($possible_parent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset(self::$class_extends[$absolute_class])) {
|
||||
self::$class_extends[$absolute_class] = [];
|
||||
if (!isset(self::$class_extends[$fq_class_name])) {
|
||||
self::$class_extends[$fq_class_name] = [];
|
||||
}
|
||||
|
||||
self::$class_extends[$absolute_class][$possible_parent] = is_subclass_of($absolute_class, $possible_parent);
|
||||
self::$class_extends[$fq_class_name][$possible_parent] = is_subclass_of($fq_class_name, $possible_parent);
|
||||
|
||||
return self::$class_extends[$absolute_class][$possible_parent];
|
||||
return self::$class_extends[$fq_class_name][$possible_parent];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the interfaces a given class implements
|
||||
*
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function getInterfacesForClass($absolute_class)
|
||||
public static function getInterfacesForClass($fq_class_name)
|
||||
{
|
||||
if (!isset(self::$class_implements[$absolute_class])) {
|
||||
if (!isset(self::$class_implements[$fq_class_name])) {
|
||||
/** @var string[] */
|
||||
$class_implements = class_implements($absolute_class);
|
||||
$class_implements = class_implements($fq_class_name);
|
||||
|
||||
self::$class_implements[$absolute_class] = [];
|
||||
self::$class_implements[$fq_class_name] = [];
|
||||
|
||||
foreach ($class_implements as $interface) {
|
||||
self::$class_implements[$absolute_class][strtolower($interface)] = $interface;
|
||||
self::$class_implements[$fq_class_name][strtolower($interface)] = $interface;
|
||||
}
|
||||
}
|
||||
|
||||
return self::$class_implements[$absolute_class];
|
||||
return self::$class_implements[$fq_class_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a class implements an interface
|
||||
*
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @param string $interface
|
||||
* @return bool
|
||||
*/
|
||||
public static function classImplements($absolute_class, $interface)
|
||||
public static function classImplements($fq_class_name, $interface)
|
||||
{
|
||||
$interface_id = strtolower($interface);
|
||||
|
||||
if ($interface_id === 'callable' && $absolute_class === 'Closure') {
|
||||
if ($interface_id === 'callable' && $fq_class_name === 'Closure') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset(self::$class_implements[$absolute_class][$interface_id])) {
|
||||
if (isset(self::$class_implements[$fq_class_name][$interface_id])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset(self::$class_implements[$absolute_class])) {
|
||||
if (isset(self::$class_implements[$fq_class_name])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ClassChecker::classExists($absolute_class)) {
|
||||
if (!ClassChecker::classExists($fq_class_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ class ClassChecker extends ClassLikeChecker
|
||||
return false;
|
||||
}
|
||||
|
||||
$class_implementations = self::getInterfacesForClass($absolute_class);
|
||||
$class_implementations = self::getInterfacesForClass($fq_class_name);
|
||||
|
||||
return isset($class_implementations[$interface_id]);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $absolute_class;
|
||||
protected $fq_class_name;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
@ -197,24 +197,24 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
/**
|
||||
* @param PhpParser\Node\Stmt\ClassLike $class
|
||||
* @param StatementsSource $source
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
*/
|
||||
public function __construct(PhpParser\Node\Stmt\ClassLike $class, StatementsSource $source, $absolute_class)
|
||||
public function __construct(PhpParser\Node\Stmt\ClassLike $class, StatementsSource $source, $fq_class_name)
|
||||
{
|
||||
$this->class = $class;
|
||||
$this->namespace = $source->getNamespace();
|
||||
$this->aliased_classes = $source->getAliasedClasses();
|
||||
$this->file_name = $source->getFileName();
|
||||
$this->include_file_name = $source->getIncludeFileName();
|
||||
$this->absolute_class = $absolute_class;
|
||||
$this->fq_class_name = $fq_class_name;
|
||||
|
||||
$this->suppressed_issues = $source->getSuppressedIssues();
|
||||
|
||||
self::$class_files[$absolute_class] = $this->file_name;
|
||||
self::$file_classes[$this->file_name][] = $absolute_class;
|
||||
self::$class_files[$fq_class_name] = $this->file_name;
|
||||
self::$file_classes[$this->file_name][] = $fq_class_name;
|
||||
|
||||
if (self::$this_class) {
|
||||
self::$class_checkers[$absolute_class] = $this;
|
||||
self::$class_checkers[$fq_class_name] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,15 +227,15 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
{
|
||||
if (!$check_methods &&
|
||||
!($this instanceof TraitChecker) &&
|
||||
isset(self::$registered_classes[$this->absolute_class])
|
||||
isset(self::$registered_classes[$this->fq_class_name])
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$config = Config::getInstance();
|
||||
|
||||
self::$registered_classes[$this->absolute_class] = true;
|
||||
self::$user_defined[$this->absolute_class] = true;
|
||||
self::$registered_classes[$this->fq_class_name] = true;
|
||||
self::$user_defined[$this->fq_class_name] = true;
|
||||
|
||||
$leftover_stmts = [];
|
||||
|
||||
@ -244,22 +244,22 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
|
||||
$long_file_name = Config::getInstance()->getBaseDir() . $this->file_name;
|
||||
|
||||
self::$class_methods[$this->absolute_class] = [];
|
||||
self::$class_methods[$this->fq_class_name] = [];
|
||||
|
||||
self::$public_class_properties[$this->absolute_class] = [];
|
||||
self::$protected_class_properties[$this->absolute_class] = [];
|
||||
self::$private_class_properties[$this->absolute_class] = [];
|
||||
self::$public_class_properties[$this->fq_class_name] = [];
|
||||
self::$protected_class_properties[$this->fq_class_name] = [];
|
||||
self::$private_class_properties[$this->fq_class_name] = [];
|
||||
|
||||
self::$public_static_class_properties[$this->absolute_class] = [];
|
||||
self::$protected_static_class_properties[$this->absolute_class] = [];
|
||||
self::$private_static_class_properties[$this->absolute_class] = [];
|
||||
self::$public_static_class_properties[$this->fq_class_name] = [];
|
||||
self::$protected_static_class_properties[$this->fq_class_name] = [];
|
||||
self::$private_static_class_properties[$this->fq_class_name] = [];
|
||||
|
||||
self::$public_class_constants[$this->absolute_class] = [];
|
||||
self::$public_class_constants[$this->fq_class_name] = [];
|
||||
|
||||
if (!$class_context) {
|
||||
$class_context = new Context($this->file_name, $this->absolute_class);
|
||||
$class_context = new Context($this->file_name, $this->fq_class_name);
|
||||
$class_context->parent = $this->parent_class;
|
||||
$class_context->vars_in_scope['$this'] = new Type\Union([new Type\Atomic($this->absolute_class)]);
|
||||
$class_context->vars_in_scope['$this'] = new Type\Union([new Type\Atomic($this->fq_class_name)]);
|
||||
}
|
||||
|
||||
// set all constants first
|
||||
@ -278,8 +278,8 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
|
||||
$extra_interfaces = [];
|
||||
|
||||
foreach (self::$class_implements[$this->absolute_class] as $interface_id => $interface_name) {
|
||||
if (self::checkAbsoluteClassOrInterface(
|
||||
foreach (self::$class_implements[$this->fq_class_name] as $interface_id => $interface_name) {
|
||||
if (self::checkFullQualifiedClassOrInterface(
|
||||
$interface_name,
|
||||
$this->file_name,
|
||||
$this->class->getLine(),
|
||||
@ -301,7 +301,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
foreach ($extra_interfaces as $extra_interface_name) {
|
||||
FileChecker::addFileInheritanceToClass($long_file_name, $extra_interface_name);
|
||||
|
||||
self::$class_implements[$this->absolute_class][strtolower($extra_interface_name)] =
|
||||
self::$class_implements[$this->fq_class_name][strtolower($extra_interface_name)] =
|
||||
$extra_interface_name;
|
||||
}
|
||||
}
|
||||
@ -332,7 +332,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
}
|
||||
}
|
||||
|
||||
if (MethodChecker::methodExists($this->absolute_class . '::__get')) {
|
||||
if (MethodChecker::methodExists($this->fq_class_name . '::__get')) {
|
||||
$this->has_custom_get = true;
|
||||
}
|
||||
|
||||
@ -341,9 +341,9 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
}
|
||||
|
||||
$all_instance_properties = array_merge(
|
||||
self::$public_class_properties[$this->absolute_class],
|
||||
self::$protected_class_properties[$this->absolute_class],
|
||||
self::$private_class_properties[$this->absolute_class]
|
||||
self::$public_class_properties[$this->fq_class_name],
|
||||
self::$protected_class_properties[$this->fq_class_name],
|
||||
self::$private_class_properties[$this->fq_class_name]
|
||||
);
|
||||
|
||||
foreach ($all_instance_properties as $property_name => $property_type) {
|
||||
@ -351,34 +351,34 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
}
|
||||
|
||||
$all_static_properties = array_merge(
|
||||
self::$public_static_class_properties[$this->absolute_class],
|
||||
self::$protected_static_class_properties[$this->absolute_class],
|
||||
self::$private_static_class_properties[$this->absolute_class]
|
||||
self::$public_static_class_properties[$this->fq_class_name],
|
||||
self::$protected_static_class_properties[$this->fq_class_name],
|
||||
self::$private_static_class_properties[$this->fq_class_name]
|
||||
);
|
||||
|
||||
foreach ($all_static_properties as $property_name => $property_type) {
|
||||
$class_context->vars_in_scope[$this->absolute_class . '::$' . $property_name] = $property_type
|
||||
$class_context->vars_in_scope[$this->fq_class_name . '::$' . $property_name] = $property_type
|
||||
?: Type::getMixed();
|
||||
}
|
||||
|
||||
$config = Config::getInstance();
|
||||
|
||||
if ($this instanceof ClassChecker) {
|
||||
foreach (ClassChecker::getInterfacesForClass($this->absolute_class) as $interface_id => $interface_name) {
|
||||
foreach (ClassChecker::getInterfacesForClass($this->fq_class_name) as $interface_id => $interface_name) {
|
||||
if (isset(self::$public_class_constants[$interface_name])) {
|
||||
self::$public_class_constants[$this->absolute_class] +=
|
||||
self::$public_class_constants[$this->fq_class_name] +=
|
||||
self::$public_class_constants[$interface_name];
|
||||
}
|
||||
|
||||
foreach (self::$class_methods[$interface_name] as $method_name => $_) {
|
||||
$mentioned_method_id = $interface_name . '::' . $method_name;
|
||||
$implemented_method_id = $this->absolute_class . '::' . $method_name;
|
||||
$implemented_method_id = $this->fq_class_name . '::' . $method_name;
|
||||
MethodChecker::setOverriddenMethodId($implemented_method_id, $mentioned_method_id);
|
||||
|
||||
if (!isset(self::$class_methods[$this->absolute_class])) {
|
||||
if (!isset(self::$class_methods[$this->fq_class_name])) {
|
||||
if (IssueBuffer::accepts(
|
||||
new UnimplementedInterfaceMethod(
|
||||
'Method ' . $method_name . ' is not defined on class ' . $this->absolute_class,
|
||||
'Method ' . $method_name . ' is not defined on class ' . $this->fq_class_name,
|
||||
$this->file_name,
|
||||
$this->class->getLine()
|
||||
),
|
||||
@ -409,7 +409,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
}
|
||||
|
||||
if (!$this->class->name) {
|
||||
$this->class->name = $this->absolute_class;
|
||||
$this->class->name = $this->fq_class_name;
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -421,7 +421,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
*/
|
||||
protected function registerParentClassProperties($parent_class)
|
||||
{
|
||||
if (self::checkAbsoluteClassOrInterface(
|
||||
if (self::checkFullQualifiedClassOrInterface(
|
||||
$parent_class,
|
||||
$this->file_name,
|
||||
$this->class->getLine(),
|
||||
@ -437,20 +437,20 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
|
||||
FileChecker::addFileInheritanceToClass(Config::getInstance()->getBaseDir() . $this->file_name, $parent_class);
|
||||
|
||||
self::$class_implements[$this->absolute_class] += self::$class_implements[$parent_class];
|
||||
self::$class_implements[$this->fq_class_name] += self::$class_implements[$parent_class];
|
||||
|
||||
self::$public_class_properties[$this->absolute_class] = self::$public_class_properties[$parent_class];
|
||||
self::$protected_class_properties[$this->absolute_class] = self::$protected_class_properties[$parent_class];
|
||||
self::$public_class_properties[$this->fq_class_name] = self::$public_class_properties[$parent_class];
|
||||
self::$protected_class_properties[$this->fq_class_name] = self::$protected_class_properties[$parent_class];
|
||||
|
||||
self::$public_static_class_properties[$this->absolute_class] =
|
||||
self::$public_static_class_properties[$this->fq_class_name] =
|
||||
self::$public_static_class_properties[$parent_class];
|
||||
|
||||
self::$protected_static_class_properties[$this->absolute_class] =
|
||||
self::$protected_static_class_properties[$this->fq_class_name] =
|
||||
self::$protected_static_class_properties[$parent_class];
|
||||
|
||||
self::$public_class_constants[$this->absolute_class] = array_merge(
|
||||
self::$public_class_constants[$this->fq_class_name] = array_merge(
|
||||
self::$public_class_constants[$parent_class],
|
||||
self::$public_class_constants[$this->absolute_class]
|
||||
self::$public_class_constants[$this->fq_class_name]
|
||||
);
|
||||
|
||||
return null;
|
||||
@ -469,7 +469,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
array &$method_checkers,
|
||||
$cache_method_checker
|
||||
) {
|
||||
$method_id = $this->absolute_class . '::' . strtolower($stmt->name);
|
||||
$method_id = $this->fq_class_name . '::' . strtolower($stmt->name);
|
||||
|
||||
if (!isset(self::$method_checkers[$method_id])) {
|
||||
$method_checker = new MethodChecker($stmt, $this);
|
||||
@ -514,7 +514,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
}
|
||||
|
||||
foreach ($stmt->traits as $trait) {
|
||||
$trait_name = self::getAbsoluteClassFromName(
|
||||
$trait_name = self::getFullQualifiedClassFromName(
|
||||
$trait,
|
||||
$this->namespace,
|
||||
$this->aliased_classes
|
||||
@ -585,7 +585,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
} elseif (!$comment && $check_property_types) {
|
||||
if (IssueBuffer::accepts(
|
||||
new MissingPropertyType(
|
||||
'Property ' . $this->absolute_class . '::$' . $stmt->props[0]->name . ' does not have a ' .
|
||||
'Property ' . $this->fq_class_name . '::$' . $stmt->props[0]->name . ' does not have a ' .
|
||||
'declared type',
|
||||
$this->file_name,
|
||||
$stmt->getLine()
|
||||
@ -681,7 +681,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
|
||||
foreach ($class_checker->class->stmts as $stmt) {
|
||||
if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) {
|
||||
if ($declaring_method_id === $class_checker->absolute_class . '::' . strtolower($stmt->name)) {
|
||||
if ($declaring_method_id === $class_checker->fq_class_name . '::' . strtolower($stmt->name)) {
|
||||
$method_checker = new MethodChecker($stmt, $class_checker);
|
||||
self::$method_checkers[$method_id] = $method_checker;
|
||||
return $method_checker;
|
||||
@ -710,51 +710,51 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
/**
|
||||
* Check whether a class/interface exists
|
||||
*
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return bool
|
||||
*/
|
||||
public static function classOrInterfaceExists($absolute_class)
|
||||
public static function classOrInterfaceExists($fq_class_name)
|
||||
{
|
||||
return ClassChecker::classExists($absolute_class) || InterfaceChecker::interfaceExists($absolute_class);
|
||||
return ClassChecker::classExists($fq_class_name) || InterfaceChecker::interfaceExists($fq_class_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @param string $possible_parent
|
||||
* @return bool
|
||||
*/
|
||||
public static function classExtendsOrImplements($absolute_class, $possible_parent)
|
||||
public static function classExtendsOrImplements($fq_class_name, $possible_parent)
|
||||
{
|
||||
return ClassChecker::classExtends($absolute_class, $possible_parent)
|
||||
|| ClassChecker::classImplements($absolute_class, $possible_parent);
|
||||
return ClassChecker::classExtends($fq_class_name, $possible_parent)
|
||||
|| ClassChecker::classImplements($fq_class_name, $possible_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @param string $file_name
|
||||
* @param int $line_number
|
||||
* @param array<string> $suppressed_issues
|
||||
* @return bool|null
|
||||
*/
|
||||
public static function checkAbsoluteClassOrInterface(
|
||||
$absolute_class,
|
||||
public static function checkFullQualifiedClassOrInterface(
|
||||
$fq_class_name,
|
||||
$file_name,
|
||||
$line_number,
|
||||
array $suppressed_issues
|
||||
) {
|
||||
if (empty($absolute_class)) {
|
||||
if (empty($fq_class_name)) {
|
||||
throw new \InvalidArgumentException('$class cannot be empty');
|
||||
}
|
||||
|
||||
$absolute_class = preg_replace('/^\\\/', '', $absolute_class);
|
||||
$fq_class_name = preg_replace('/^\\\/', '', $fq_class_name);
|
||||
|
||||
$class_exists = ClassChecker::classExists($absolute_class);
|
||||
$interface_exists = InterfaceChecker::interfaceExists($absolute_class);
|
||||
$class_exists = ClassChecker::classExists($fq_class_name);
|
||||
$interface_exists = InterfaceChecker::interfaceExists($fq_class_name);
|
||||
|
||||
if (!$class_exists && !$interface_exists) {
|
||||
if (IssueBuffer::accepts(
|
||||
new UndefinedClass(
|
||||
'Class or interface ' . $absolute_class . ' does not exist',
|
||||
'Class or interface ' . $fq_class_name . ' does not exist',
|
||||
$file_name,
|
||||
$line_number
|
||||
),
|
||||
@ -766,12 +766,12 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
return null;
|
||||
}
|
||||
|
||||
if (($class_exists && !ClassChecker::hasCorrectCasing($absolute_class))
|
||||
|| ($interface_exists && !InterfaceChecker::hasCorrectCasing($absolute_class))
|
||||
if (($class_exists && !ClassChecker::hasCorrectCasing($fq_class_name))
|
||||
|| ($interface_exists && !InterfaceChecker::hasCorrectCasing($fq_class_name))
|
||||
) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InvalidClass(
|
||||
'Class or interface ' . $absolute_class . ' has wrong casing',
|
||||
'Class or interface ' . $fq_class_name . ' has wrong casing',
|
||||
$file_name,
|
||||
$line_number
|
||||
),
|
||||
@ -781,7 +781,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
}
|
||||
}
|
||||
|
||||
FileChecker::addFileReferenceToClass(Config::getInstance()->getBaseDir() . $file_name, $absolute_class);
|
||||
FileChecker::addFileReferenceToClass(Config::getInstance()->getBaseDir() . $file_name, $fq_class_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -794,7 +794,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
* @param array<int,string> $aliased_classes
|
||||
* @return string
|
||||
*/
|
||||
public static function getAbsoluteClassFromName(
|
||||
public static function getFullQualifiedClassFromName(
|
||||
PhpParser\Node\Name $class_name,
|
||||
$namespace,
|
||||
array $aliased_classes
|
||||
@ -803,7 +803,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
return implode('\\', $class_name->parts);
|
||||
}
|
||||
|
||||
return self::getAbsoluteClassFromString(implode('\\', $class_name->parts), $namespace, $aliased_classes);
|
||||
return self::getFullQualifiedClassFromString(implode('\\', $class_name->parts), $namespace, $aliased_classes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -812,7 +812,7 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
* @param array<string, string> $imported_namespaces
|
||||
* @return string
|
||||
*/
|
||||
public static function getAbsoluteClassFromString($class, $namespace, array $imported_namespaces)
|
||||
public static function getFullQualifiedClassFromString($class, $namespace, array $imported_namespaces)
|
||||
{
|
||||
if (empty($class)) {
|
||||
throw new \InvalidArgumentException('$class cannot be empty');
|
||||
@ -855,9 +855,9 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsoluteClass()
|
||||
public function getFullQualifiedClass()
|
||||
{
|
||||
return $this->absolute_class;
|
||||
return $this->fq_class_name;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1138,11 +1138,11 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
$parent_method_id = $parent_class . '::' . $method_name;
|
||||
/** @var string */
|
||||
$declaring_method_id = MethodChecker::getDeclaringMethodId($parent_method_id);
|
||||
$implemented_method_id = $this->absolute_class . '::' . $method_name;
|
||||
$implemented_method_id = $this->fq_class_name . '::' . $method_name;
|
||||
|
||||
if (!isset(self::$class_methods[$this->absolute_class][$method_name])) {
|
||||
if (!isset(self::$class_methods[$this->fq_class_name][$method_name])) {
|
||||
MethodChecker::setDeclaringMethodId($implemented_method_id, $declaring_method_id);
|
||||
self::$class_methods[$this->absolute_class][$method_name] = true;
|
||||
self::$class_methods[$this->fq_class_name][$method_name] = true;
|
||||
MethodChecker::setOverriddenMethodId($implemented_method_id, $declaring_method_id);
|
||||
}
|
||||
}
|
||||
@ -1302,13 +1302,13 @@ abstract class ClassLikeChecker implements StatementsSource
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isUserDefined($absolute_class)
|
||||
public static function isUserDefined($fq_class_name)
|
||||
{
|
||||
self::registerClass($absolute_class);
|
||||
return isset(self::$user_defined[$absolute_class]);
|
||||
self::registerClass($fq_class_name);
|
||||
return isset(self::$user_defined[$fq_class_name]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,7 +41,7 @@ class CommentChecker
|
||||
if ($line_parts && $line_parts[0]) {
|
||||
$type_in_comments = FunctionLikeChecker::fixUpLocalType(
|
||||
$line_parts[0],
|
||||
$source->getAbsoluteClass(),
|
||||
$source->getFullQualifiedClass(),
|
||||
$source->getNamespace(),
|
||||
$source->getAliasedClasses()
|
||||
);
|
||||
|
@ -194,7 +194,7 @@ class FileChecker implements StatementsSource
|
||||
$class_checker = ClassLikeChecker::getClassLikeCheckerFromClass($stmt->name)
|
||||
?: new ClassChecker($stmt, $this, $stmt->name);
|
||||
|
||||
$this->declared_classes[] = $class_checker->getAbsoluteClass();
|
||||
$this->declared_classes[] = $class_checker->getFullQualifiedClass();
|
||||
$class_checker->check($check_functions);
|
||||
}
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\Interface_) {
|
||||
@ -202,7 +202,7 @@ class FileChecker implements StatementsSource
|
||||
$class_checker = ClassLikeChecker::getClassLikeCheckerFromClass($stmt->name)
|
||||
?: new InterfaceChecker($stmt, $this, $stmt->name);
|
||||
|
||||
$this->declared_classes[] = $class_checker->getAbsoluteClass();
|
||||
$this->declared_classes[] = $class_checker->getFullQualifiedClass();
|
||||
$class_checker->check(false);
|
||||
}
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\Trait_) {
|
||||
@ -260,7 +260,7 @@ class FileChecker implements StatementsSource
|
||||
* @param string $file_name
|
||||
* @return string
|
||||
*/
|
||||
public static function getAbsoluteClassFromNameInFile($class, $namespace, $file_name)
|
||||
public static function getFullQualifiedClassFromNameInFile($class, $namespace, $file_name)
|
||||
{
|
||||
if (isset(self::$file_checkers[$file_name])) {
|
||||
$aliased_classes = self::$file_checkers[$file_name]->getAliasedClasses($namespace);
|
||||
@ -270,7 +270,7 @@ class FileChecker implements StatementsSource
|
||||
$aliased_classes = $file_checker->getAliasedClasses($namespace);
|
||||
}
|
||||
|
||||
return ClassLikeChecker::getAbsoluteClassFromString($class, $namespace, $aliased_classes);
|
||||
return ClassLikeChecker::getFullQualifiedClassFromString($class, $namespace, $aliased_classes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -440,7 +440,7 @@ class FileChecker implements StatementsSource
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getAbsoluteClass()
|
||||
public function getFullQualifiedClass()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@ -583,23 +583,23 @@ class FileChecker implements StatementsSource
|
||||
|
||||
/**
|
||||
* @param string $source_file
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return void
|
||||
*/
|
||||
public static function addFileReferenceToClass($source_file, $absolute_class)
|
||||
public static function addFileReferenceToClass($source_file, $fq_class_name)
|
||||
{
|
||||
self::$referencing_files[$source_file] = true;
|
||||
self::$file_references_to_class[$absolute_class][$source_file] = true;
|
||||
self::$file_references_to_class[$fq_class_name][$source_file] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source_file
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return void
|
||||
*/
|
||||
public static function addFileInheritanceToClass($source_file, $absolute_class)
|
||||
public static function addFileInheritanceToClass($source_file, $fq_class_name)
|
||||
{
|
||||
self::$files_inheriting_classes[$absolute_class][$source_file] = true;
|
||||
self::$files_inheriting_classes[$fq_class_name][$source_file] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,7 +194,7 @@ class FunctionChecker extends FunctionLikeChecker
|
||||
foreach ($function->getParams() as $param) {
|
||||
$param_array = self::getTranslatedParam(
|
||||
$param,
|
||||
$this->absolute_class,
|
||||
$this->fq_class_name,
|
||||
$this->namespace,
|
||||
$this->getAliasedClasses()
|
||||
);
|
||||
@ -239,7 +239,7 @@ class FunctionChecker extends FunctionLikeChecker
|
||||
$return_type = Type::parseString(
|
||||
is_string($function->returnType)
|
||||
? $function->returnType
|
||||
: ClassLikeChecker::getAbsoluteClassFromName(
|
||||
: ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$function->returnType,
|
||||
$this->namespace,
|
||||
$this->getAliasedClasses()
|
||||
|
@ -48,7 +48,7 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $absolute_class;
|
||||
protected $fq_class_name;
|
||||
|
||||
/**
|
||||
* @var StatementsChecker|null
|
||||
@ -102,7 +102,7 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
$this->class_extends = $source->getParentClass();
|
||||
$this->file_name = $source->getFileName();
|
||||
$this->include_file_name = $source->getIncludeFileName();
|
||||
$this->absolute_class = $source->getAbsoluteClass();
|
||||
$this->fq_class_name = $source->getFullQualifiedClass();
|
||||
$this->source = $source;
|
||||
$this->suppressed_issues = $source->getSuppressedIssues();
|
||||
}
|
||||
@ -218,7 +218,7 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
foreach ($this->function->getParams() as $param) {
|
||||
$function_params[] = self::getTranslatedParam(
|
||||
$param,
|
||||
$this->absolute_class,
|
||||
$this->fq_class_name,
|
||||
$this->namespace,
|
||||
$this->getAliasedClasses()
|
||||
);
|
||||
@ -237,7 +237,7 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
if ($atomic_type->isObjectType()
|
||||
&& !$atomic_type->isObject()
|
||||
&& $this->function instanceof PhpParser\Node
|
||||
&& ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
&& ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$atomic_type->value,
|
||||
$this->file_name,
|
||||
$this->function->getLine(),
|
||||
@ -327,7 +327,7 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
{
|
||||
if ($this->function instanceof Function_ || $this->function instanceof ClassMethod) {
|
||||
return ($this instanceof MethodChecker
|
||||
? $this->absolute_class . '::'
|
||||
? $this->fq_class_name . '::'
|
||||
: '') . strtolower($this->function->name);
|
||||
}
|
||||
|
||||
@ -353,9 +353,9 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsoluteClass()
|
||||
public function getFullQualifiedClass()
|
||||
{
|
||||
return $this->absolute_class;
|
||||
return $this->fq_class_name;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -488,7 +488,7 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
$declared_return_type = ExpressionChecker::fleshOutTypes(
|
||||
$method_return_types,
|
||||
[],
|
||||
$this->absolute_class,
|
||||
$this->fq_class_name,
|
||||
$method_id
|
||||
);
|
||||
|
||||
@ -560,7 +560,7 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
if (!TypeChecker::hasIdenticalTypes(
|
||||
$declared_return_type,
|
||||
$inferred_return_type,
|
||||
$this->absolute_class
|
||||
$this->fq_class_name
|
||||
)) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InvalidReturnType(
|
||||
@ -659,14 +659,14 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
|
||||
/**
|
||||
* @param PhpParser\Node\Param $param
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @param string $namespace
|
||||
* @param array<string> $aliased_classes
|
||||
* @return FunctionLikeParameter
|
||||
*/
|
||||
public static function getTranslatedParam(
|
||||
PhpParser\Node\Param $param,
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
$namespace,
|
||||
array $aliased_classes
|
||||
) {
|
||||
@ -683,9 +683,9 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
} elseif ($param->type instanceof PhpParser\Node\Name\FullyQualified) {
|
||||
$param_type_string = implode('\\', $param->type->parts);
|
||||
} elseif ($param->type->parts === ['self']) {
|
||||
$param_type_string = $absolute_class;
|
||||
$param_type_string = $fq_class_name;
|
||||
} else {
|
||||
$param_type_string = ClassLikeChecker::getAbsoluteClassFromString(
|
||||
$param_type_string = ClassLikeChecker::getFullQualifiedClassFromString(
|
||||
implode('\\', $param->type->parts),
|
||||
$namespace,
|
||||
$aliased_classes
|
||||
@ -778,12 +778,12 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
|
||||
/**
|
||||
* @param string $return_type
|
||||
* @param string|null $absolute_class
|
||||
* @param string|null $fq_class_name
|
||||
* @param string $namespace
|
||||
* @param array $aliased_classes
|
||||
* @return string
|
||||
*/
|
||||
public static function fixUpLocalType($return_type, $absolute_class, $namespace, array $aliased_classes)
|
||||
public static function fixUpLocalType($return_type, $fq_class_name, $namespace, array $aliased_classes)
|
||||
{
|
||||
if (strpos($return_type, '[') !== false) {
|
||||
$return_type = Type::convertSquareBrackets($return_type);
|
||||
@ -816,7 +816,7 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
continue;
|
||||
}
|
||||
|
||||
$return_type_token = ClassLikeChecker::getAbsoluteClassFromString(
|
||||
$return_type_token = ClassLikeChecker::getFullQualifiedClassFromString(
|
||||
$return_type_token,
|
||||
$namespace,
|
||||
$aliased_classes
|
||||
@ -947,15 +947,15 @@ abstract class FunctionLikeChecker implements StatementsSource
|
||||
*/
|
||||
public static function getParamsById($method_id, array $args, $file_name)
|
||||
{
|
||||
$absolute_class = strpos($method_id, '::') !== false ? explode('::', $method_id)[0] : null;
|
||||
$fq_class_name = strpos($method_id, '::') !== false ? explode('::', $method_id)[0] : null;
|
||||
|
||||
if ($absolute_class && ClassLikeChecker::isUserDefined($absolute_class)) {
|
||||
if ($fq_class_name && ClassLikeChecker::isUserDefined($fq_class_name)) {
|
||||
/** @var array<\Psalm\FunctionLikeParameter> */
|
||||
return MethodChecker::getMethodParams($method_id);
|
||||
} elseif (!$absolute_class && FunctionChecker::inCallMap($method_id)) {
|
||||
} elseif (!$fq_class_name && FunctionChecker::inCallMap($method_id)) {
|
||||
/** @var array<array<FunctionLikeParameter>> */
|
||||
$function_param_options = FunctionChecker::getParamsFromCallMap($method_id);
|
||||
} elseif ($absolute_class) {
|
||||
} elseif ($fq_class_name) {
|
||||
if ($method_params = MethodChecker::getMethodParams($method_id)) {
|
||||
// fall back to using reflected params anyway
|
||||
return $method_params;
|
||||
|
@ -41,7 +41,7 @@ class InterfaceChecker extends ClassLikeChecker
|
||||
self::$parent_interfaces[$interface_name] = [];
|
||||
|
||||
foreach ($interface->extends as $extended_interface) {
|
||||
$extended_interface_name = self::getAbsoluteClassFromName(
|
||||
$extended_interface_name = self::getFullQualifiedClassFromName(
|
||||
$extended_interface,
|
||||
$this->namespace,
|
||||
$this->aliased_classes
|
||||
|
@ -255,8 +255,8 @@ class MethodChecker extends FunctionLikeChecker
|
||||
*/
|
||||
protected function registerMethod(PhpParser\Node\Stmt\ClassMethod $method)
|
||||
{
|
||||
$method_id = $this->absolute_class . '::' . strtolower($method->name);
|
||||
$cased_method_id = self::$cased_method_ids[$method_id] = $this->absolute_class . '::' . $method->name;
|
||||
$method_id = $this->fq_class_name . '::' . strtolower($method->name);
|
||||
$cased_method_id = self::$cased_method_ids[$method_id] = $this->fq_class_name . '::' . $method->name;
|
||||
|
||||
if (isset(self::$have_reflected[$method_id]) || isset(self::$have_registered[$method_id])) {
|
||||
$this->suppressed_issues = self::$method_suppress[$method_id];
|
||||
@ -287,7 +287,7 @@ class MethodChecker extends FunctionLikeChecker
|
||||
foreach ($method->getParams() as $param) {
|
||||
$param_array = $this->getTranslatedParam(
|
||||
$param,
|
||||
$this->absolute_class,
|
||||
$this->fq_class_name,
|
||||
$this->namespace,
|
||||
$this->getAliasedClasses()
|
||||
);
|
||||
@ -307,7 +307,7 @@ class MethodChecker extends FunctionLikeChecker
|
||||
$return_type = Type::parseString(
|
||||
is_string($method->returnType)
|
||||
? $method->returnType
|
||||
: ClassLikeChecker::getAbsoluteClassFromName(
|
||||
: ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$method->returnType,
|
||||
$this->namespace,
|
||||
$this->getAliasedClasses()
|
||||
@ -349,7 +349,7 @@ class MethodChecker extends FunctionLikeChecker
|
||||
$return_type = Type::parseString(
|
||||
$this->fixUpLocalType(
|
||||
(string)$docblock_info['return_type'],
|
||||
$this->absolute_class,
|
||||
$this->fq_class_name,
|
||||
$this->namespace,
|
||||
$this->getAliasedClasses()
|
||||
)
|
||||
@ -402,14 +402,14 @@ class MethodChecker extends FunctionLikeChecker
|
||||
$return_type_token = Type::fixScalarTerms($return_type_token);
|
||||
|
||||
if ($return_type_token[0] === strtoupper($return_type_token[0])) {
|
||||
$absolute_class = explode('::', $method_id)[0];
|
||||
$fq_class_name = explode('::', $method_id)[0];
|
||||
|
||||
if ($return_type_token === '$this') {
|
||||
$return_type_token = $absolute_class;
|
||||
$return_type_token = $fq_class_name;
|
||||
continue;
|
||||
}
|
||||
|
||||
$return_type_token = FileChecker::getAbsoluteClassFromNameInFile(
|
||||
$return_type_token = FileChecker::getFullQualifiedClassFromNameInFile(
|
||||
$return_type_token,
|
||||
self::$method_namespaces[$method_id],
|
||||
self::$method_files[$method_id]
|
||||
@ -541,7 +541,7 @@ class MethodChecker extends FunctionLikeChecker
|
||||
}
|
||||
}
|
||||
|
||||
if ($source->getSource() instanceof TraitChecker && $method_class === $source->getAbsoluteClass()) {
|
||||
if ($source->getSource() instanceof TraitChecker && $method_class === $source->getFullQualifiedClass()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -67,29 +67,29 @@ class NamespaceChecker implements StatementsSource
|
||||
|
||||
foreach ($this->namespace->stmts as $stmt) {
|
||||
if ($stmt instanceof PhpParser\Node\Stmt\ClassLike) {
|
||||
$absolute_class = ClassLikeChecker::getAbsoluteClassFromString($stmt->name, $this->namespace_name, []);
|
||||
$fq_class_name = ClassLikeChecker::getFullQualifiedClassFromString($stmt->name, $this->namespace_name, []);
|
||||
|
||||
if ($stmt instanceof PhpParser\Node\Stmt\Class_) {
|
||||
$this->declared_classes[$absolute_class] = 1;
|
||||
$this->declared_classes[$fq_class_name] = 1;
|
||||
|
||||
if ($check_classes) {
|
||||
$class_checker = ClassLikeChecker::getClassLikeCheckerFromClass($absolute_class)
|
||||
?: new ClassChecker($stmt, $this, $absolute_class);
|
||||
$class_checker = ClassLikeChecker::getClassLikeCheckerFromClass($fq_class_name)
|
||||
?: new ClassChecker($stmt, $this, $fq_class_name);
|
||||
|
||||
$class_checker->check($check_class_statements);
|
||||
}
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\Interface_) {
|
||||
if ($check_classes) {
|
||||
$class_checker = ClassLikeChecker::getClassLikeCheckerFromClass($stmt->name)
|
||||
?: new InterfaceChecker($stmt, $this, $absolute_class);
|
||||
$this->declared_classes[] = $class_checker->getAbsoluteClass();
|
||||
?: new InterfaceChecker($stmt, $this, $fq_class_name);
|
||||
$this->declared_classes[] = $class_checker->getFullQualifiedClass();
|
||||
$class_checker->check(false);
|
||||
}
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\Trait_) {
|
||||
if ($check_classes) {
|
||||
// register the trait checker
|
||||
ClassLikeChecker::getClassLikeCheckerFromClass($absolute_class)
|
||||
?: new TraitChecker($stmt, $this, $absolute_class);
|
||||
ClassLikeChecker::getClassLikeCheckerFromClass($fq_class_name)
|
||||
?: new TraitChecker($stmt, $this, $fq_class_name);
|
||||
}
|
||||
}
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\Use_) {
|
||||
@ -148,7 +148,7 @@ class NamespaceChecker implements StatementsSource
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getAbsoluteClass()
|
||||
public function getFullQualifiedClass()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class ForeachChecker
|
||||
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$stmt->expr,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -157,7 +157,7 @@ class ForeachChecker
|
||||
if ($return_type->value !== 'Traversable' &&
|
||||
$return_type->value !== $statements_checker->getClassName()
|
||||
) {
|
||||
if (ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
if (ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$return_type->value,
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine(),
|
||||
|
@ -75,21 +75,21 @@ class IfChecker
|
||||
if ($stmt->cond instanceof PhpParser\Node\Expr\BinaryOp) {
|
||||
$reconcilable_if_types = TypeChecker::getReconcilableTypeAssertions(
|
||||
$stmt->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
$negatable_if_types = TypeChecker::getNegatableTypeAssertions(
|
||||
$stmt->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
} else {
|
||||
$reconcilable_if_types = $negatable_if_types = TypeChecker::getTypeAssertions(
|
||||
$stmt->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -258,21 +258,21 @@ class IfChecker
|
||||
if ($elseif->cond instanceof PhpParser\Node\Expr\BinaryOp) {
|
||||
$reconcilable_elseif_types = TypeChecker::getReconcilableTypeAssertions(
|
||||
$elseif->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
$negatable_elseif_types = TypeChecker::getNegatableTypeAssertions(
|
||||
$elseif->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
} else {
|
||||
$reconcilable_elseif_types = $negatable_elseif_types = TypeChecker::getTypeAssertions(
|
||||
$elseif->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
@ -32,17 +32,17 @@ class TryChecker
|
||||
foreach ($stmt->catches as $catch) {
|
||||
$catch_context = clone $original_context;
|
||||
|
||||
$catch_class = ClassLikeChecker::getAbsoluteClassFromName(
|
||||
$catch_class = ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$catch->type,
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
if ($context->check_classes) {
|
||||
$absolute_class = $catch_class;
|
||||
$fq_class_name = $catch_class;
|
||||
|
||||
if (ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
$absolute_class,
|
||||
if (ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$fq_class_name,
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine(),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
|
@ -29,7 +29,7 @@ class WhileChecker
|
||||
|
||||
$while_types = TypeChecker::getTypeAssertions(
|
||||
$stmt->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
@ -46,14 +46,14 @@ class AssignmentChecker
|
||||
) {
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$assign_var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
$array_var_id = ExpressionChecker::getArrayVarId(
|
||||
$assign_var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -113,7 +113,7 @@ class AssignmentChecker
|
||||
|
||||
$list_var_id = ExpressionChecker::getVarId(
|
||||
$var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -248,7 +248,7 @@ class AssignmentChecker
|
||||
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$stmt,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -515,30 +515,30 @@ class AssignmentChecker
|
||||
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$stmt,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
$absolute_class = (string)$stmt->class->inferredType;
|
||||
$fq_class_name = (string)$stmt->class->inferredType;
|
||||
|
||||
if (($stmt->class instanceof PhpParser\Node\Name && $stmt->class->parts[0] === 'this') ||
|
||||
$absolute_class === $context->self
|
||||
$fq_class_name === $context->self
|
||||
) {
|
||||
$class_visibility = \ReflectionProperty::IS_PRIVATE;
|
||||
} elseif ($context->self && ClassChecker::classExtends($absolute_class, $context->self)) {
|
||||
} elseif ($context->self && ClassChecker::classExtends($fq_class_name, $context->self)) {
|
||||
$class_visibility = \ReflectionProperty::IS_PROTECTED;
|
||||
} else {
|
||||
$class_visibility = \ReflectionProperty::IS_PUBLIC;
|
||||
}
|
||||
|
||||
$class_properties = ClassLikeChecker::getStaticPropertiesForClass(
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
$class_visibility
|
||||
);
|
||||
|
||||
$all_class_properties = ClassLikeChecker::getStaticPropertiesForClass(
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
$class_visibility
|
||||
);
|
||||
|
||||
@ -549,7 +549,7 @@ class AssignmentChecker
|
||||
|
||||
if ($class_visibility !== \ReflectionProperty::IS_PRIVATE) {
|
||||
$all_class_properties = ClassLikeChecker::getStaticPropertiesForClass(
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
\ReflectionProperty::IS_PRIVATE
|
||||
);
|
||||
}
|
||||
@ -601,7 +601,7 @@ class AssignmentChecker
|
||||
if ($class_property_type === false) {
|
||||
if (IssueBuffer::accepts(
|
||||
new MissingPropertyType(
|
||||
'Property ' . $absolute_class . '::$' . $prop_name . ' does not have a declared type',
|
||||
'Property ' . $fq_class_name . '::$' . $prop_name . ' does not have a declared type',
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine()
|
||||
),
|
||||
@ -623,7 +623,7 @@ class AssignmentChecker
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_property_type = ExpressionChecker::fleshOutTypes($class_property_type, [], $absolute_class);
|
||||
$class_property_type = ExpressionChecker::fleshOutTypes($class_property_type, [], $fq_class_name);
|
||||
|
||||
if (!$assignment_type->isIn($class_property_type)) {
|
||||
if (IssueBuffer::accepts(
|
||||
@ -682,7 +682,7 @@ class AssignmentChecker
|
||||
$nesting = 0;
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$stmt->var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses(),
|
||||
$nesting
|
||||
@ -711,7 +711,7 @@ class AssignmentChecker
|
||||
|
||||
$array_var_id = ExpressionChecker::getArrayVarId(
|
||||
$stmt->var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
@ -98,7 +98,7 @@ class CallChecker
|
||||
$method_id = implode('', $stmt->name->parts);
|
||||
|
||||
if ($context->self) {
|
||||
//$method_id = $statements_checker->getAbsoluteClass() . '::' . $method_id;
|
||||
//$method_id = $statements_checker->getFullQualifiedClass() . '::' . $method_id;
|
||||
}
|
||||
|
||||
$in_call_map = FunctionChecker::inCallMap($method_id);
|
||||
@ -162,23 +162,23 @@ class CallChecker
|
||||
PhpParser\Node\Expr\New_ $stmt,
|
||||
Context $context
|
||||
) {
|
||||
$absolute_class = null;
|
||||
$fq_class_name = null;
|
||||
|
||||
if ($stmt->class instanceof PhpParser\Node\Name) {
|
||||
if (!in_array($stmt->class->parts[0], ['self', 'static', 'parent'])) {
|
||||
if ($context->check_classes) {
|
||||
$absolute_class = ClassLikeChecker::getAbsoluteClassFromName(
|
||||
$fq_class_name = ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$stmt->class,
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
if ($context->isPhantomClass($absolute_class)) {
|
||||
if ($context->isPhantomClass($fq_class_name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
$absolute_class,
|
||||
if (ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$fq_class_name,
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine(),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
@ -189,31 +189,31 @@ class CallChecker
|
||||
} else {
|
||||
switch ($stmt->class->parts[0]) {
|
||||
case 'self':
|
||||
$absolute_class = $context->self;
|
||||
$fq_class_name = $context->self;
|
||||
break;
|
||||
|
||||
case 'parent':
|
||||
$absolute_class = $context->parent;
|
||||
$fq_class_name = $context->parent;
|
||||
break;
|
||||
|
||||
case 'static':
|
||||
// @todo maybe we can do better here
|
||||
$absolute_class = $context->self;
|
||||
$fq_class_name = $context->self;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif ($stmt->class instanceof PhpParser\Node\Stmt\Class_) {
|
||||
$statements_checker->check([$stmt->class], $context);
|
||||
$absolute_class = $stmt->class->name;
|
||||
$fq_class_name = $stmt->class->name;
|
||||
} else {
|
||||
ExpressionChecker::check($statements_checker, $stmt->class, $context);
|
||||
}
|
||||
|
||||
if ($absolute_class) {
|
||||
$stmt->inferredType = new Type\Union([new Type\Atomic($absolute_class)]);
|
||||
if ($fq_class_name) {
|
||||
$stmt->inferredType = new Type\Union([new Type\Atomic($fq_class_name)]);
|
||||
|
||||
if (MethodChecker::methodExists($absolute_class . '::__construct')) {
|
||||
$method_id = $absolute_class . '::__construct';
|
||||
if (MethodChecker::methodExists($fq_class_name . '::__construct')) {
|
||||
$method_id = $fq_class_name . '::__construct';
|
||||
|
||||
if (self::checkFunctionArguments(
|
||||
$statements_checker,
|
||||
@ -225,7 +225,7 @@ class CallChecker
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($absolute_class === 'ArrayIterator' && isset($stmt->args[0]->value->inferredType)) {
|
||||
if ($fq_class_name === 'ArrayIterator' && isset($stmt->args[0]->value->inferredType)) {
|
||||
/** @var Type\Union */
|
||||
$first_arg_type = $stmt->args[0]->value->inferredType;
|
||||
|
||||
@ -257,7 +257,7 @@ class CallChecker
|
||||
|
||||
$stmt->inferredType = new Type\Union([
|
||||
new Type\Generic(
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
[
|
||||
$key_type,
|
||||
$value_type
|
||||
@ -311,7 +311,7 @@ class CallChecker
|
||||
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$stmt->var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -336,12 +336,12 @@ class CallChecker
|
||||
|
||||
if (($this_class = ClassLikeChecker::getThisClass()) &&
|
||||
(
|
||||
$this_class === $statements_checker->getAbsoluteClass() ||
|
||||
ClassChecker::classExtends($this_class, $statements_checker->getAbsoluteClass()) ||
|
||||
TraitChecker::traitExists($statements_checker->getAbsoluteClass())
|
||||
$this_class === $statements_checker->getFullQualifiedClass() ||
|
||||
ClassChecker::classExtends($this_class, $statements_checker->getFullQualifiedClass()) ||
|
||||
TraitChecker::traitExists($statements_checker->getFullQualifiedClass())
|
||||
)
|
||||
) {
|
||||
$method_id = $statements_checker->getAbsoluteClass() . '::' . strtolower($stmt->name);
|
||||
$method_id = $statements_checker->getFullQualifiedClass() . '::' . strtolower($stmt->name);
|
||||
|
||||
if ($statements_checker->checkInsideMethod($method_id, $context) === false) {
|
||||
return false;
|
||||
@ -360,13 +360,13 @@ class CallChecker
|
||||
$return_type = null;
|
||||
|
||||
foreach ($class_type->types as $type) {
|
||||
$absolute_class = $type->value;
|
||||
$fq_class_name = $type->value;
|
||||
|
||||
$is_mock = ExpressionChecker::isMock($absolute_class);
|
||||
$is_mock = ExpressionChecker::isMock($fq_class_name);
|
||||
|
||||
$has_mock = $has_mock || $is_mock;
|
||||
|
||||
switch ($absolute_class) {
|
||||
switch ($fq_class_name) {
|
||||
case 'null':
|
||||
if (IssueBuffer::accepts(
|
||||
new NullReference(
|
||||
@ -412,20 +412,20 @@ class CallChecker
|
||||
break;
|
||||
|
||||
case 'static':
|
||||
$absolute_class = (string) $context->self;
|
||||
$fq_class_name = (string) $context->self;
|
||||
// fall through to default
|
||||
|
||||
default:
|
||||
if (MethodChecker::methodExists($absolute_class . '::__call') ||
|
||||
if (MethodChecker::methodExists($fq_class_name . '::__call') ||
|
||||
$is_mock ||
|
||||
$context->isPhantomClass($absolute_class)
|
||||
$context->isPhantomClass($fq_class_name)
|
||||
) {
|
||||
$return_type = Type::getMixed();
|
||||
continue;
|
||||
}
|
||||
|
||||
$does_class_exist = ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
$absolute_class,
|
||||
$does_class_exist = ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$fq_class_name,
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine(),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
@ -435,8 +435,8 @@ class CallChecker
|
||||
return $does_class_exist;
|
||||
}
|
||||
|
||||
$method_id = $absolute_class . '::' . strtolower($stmt->name);
|
||||
$cased_method_id = $absolute_class . '::' . $stmt->name;
|
||||
$method_id = $fq_class_name . '::' . strtolower($stmt->name);
|
||||
$cased_method_id = $fq_class_name . '::' . $stmt->name;
|
||||
|
||||
$does_method_exist = MethodChecker::checkMethodExists(
|
||||
$cased_method_id,
|
||||
@ -478,7 +478,7 @@ class CallChecker
|
||||
$return_type_candidate = ExpressionChecker::fleshOutTypes(
|
||||
$return_type_candidate,
|
||||
$stmt->args,
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
$method_id
|
||||
);
|
||||
|
||||
@ -530,18 +530,18 @@ class CallChecker
|
||||
}
|
||||
|
||||
$method_id = null;
|
||||
$absolute_class = null;
|
||||
$fq_class_name = null;
|
||||
|
||||
$lhs_type = null;
|
||||
|
||||
if ($stmt->class instanceof PhpParser\Node\Name) {
|
||||
$absolute_class = null;
|
||||
$fq_class_name = null;
|
||||
|
||||
if (count($stmt->class->parts) === 1 && in_array($stmt->class->parts[0], ['self', 'static', 'parent'])) {
|
||||
if ($stmt->class->parts[0] === 'parent') {
|
||||
$absolute_class = $statements_checker->getParentClass();
|
||||
$fq_class_name = $statements_checker->getParentClass();
|
||||
|
||||
if ($absolute_class === null) {
|
||||
if ($fq_class_name === null) {
|
||||
if (IssueBuffer::accepts(
|
||||
new ParentNotFound(
|
||||
'Cannot call method on parent as this class does not extend another',
|
||||
@ -560,25 +560,25 @@ class CallChecker
|
||||
? $statements_checker->getNamespace() . '\\'
|
||||
: '';
|
||||
|
||||
$absolute_class = $namespace . $statements_checker->getClassName();
|
||||
$fq_class_name = $namespace . $statements_checker->getClassName();
|
||||
}
|
||||
|
||||
if ($context->isPhantomClass($absolute_class)) {
|
||||
if ($context->isPhantomClass($fq_class_name)) {
|
||||
return null;
|
||||
}
|
||||
} elseif ($context->check_classes) {
|
||||
$absolute_class = ClassLikeChecker::getAbsoluteClassFromName(
|
||||
$fq_class_name = ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$stmt->class,
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
if ($context->isPhantomClass($absolute_class)) {
|
||||
if ($context->isPhantomClass($fq_class_name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$does_class_exist = ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
$absolute_class,
|
||||
$does_class_exist = ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$fq_class_name,
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine(),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
@ -591,7 +591,7 @@ class CallChecker
|
||||
|
||||
if ($stmt->class->parts === ['parent'] && is_string($stmt->name)) {
|
||||
if (ClassLikeChecker::getThisClass()) {
|
||||
$method_id = $absolute_class . '::' . strtolower($stmt->name);
|
||||
$method_id = $fq_class_name . '::' . strtolower($stmt->name);
|
||||
|
||||
if ($statements_checker->checkInsideMethod($method_id, $context) === false) {
|
||||
return false;
|
||||
@ -599,8 +599,8 @@ class CallChecker
|
||||
}
|
||||
}
|
||||
|
||||
if ($absolute_class) {
|
||||
$lhs_type = new Type\Union([new Type\Atomic($absolute_class)]);
|
||||
if ($fq_class_name) {
|
||||
$lhs_type = new Type\Union([new Type\Atomic($fq_class_name)]);
|
||||
}
|
||||
} else {
|
||||
ExpressionChecker::check($statements_checker, $stmt->class, $context);
|
||||
@ -616,18 +616,18 @@ class CallChecker
|
||||
$has_mock = false;
|
||||
|
||||
foreach ($lhs_type->types as $lhs_type_part) {
|
||||
$absolute_class = $lhs_type_part->value;
|
||||
$fq_class_name = $lhs_type_part->value;
|
||||
|
||||
$is_mock = ExpressionChecker::isMock($absolute_class);
|
||||
$is_mock = ExpressionChecker::isMock($fq_class_name);
|
||||
|
||||
$has_mock = $has_mock || $is_mock;
|
||||
|
||||
if (is_string($stmt->name) &&
|
||||
!MethodChecker::methodExists($absolute_class . '::__callStatic') &&
|
||||
!MethodChecker::methodExists($fq_class_name . '::__callStatic') &&
|
||||
!$is_mock
|
||||
) {
|
||||
$method_id = $absolute_class . '::' . strtolower($stmt->name);
|
||||
$cased_method_id = $absolute_class . '::' . $stmt->name;
|
||||
$method_id = $fq_class_name . '::' . strtolower($stmt->name);
|
||||
$cased_method_id = $fq_class_name . '::' . $stmt->name;
|
||||
|
||||
$does_method_exist = MethodChecker::checkMethodExists(
|
||||
$cased_method_id,
|
||||
@ -653,7 +653,7 @@ class CallChecker
|
||||
if ($stmt->class instanceof PhpParser\Node\Name
|
||||
&& $stmt->class->parts[0] !== 'parent'
|
||||
&& $context->self
|
||||
&& ($statements_checker->isStatic() || !ClassChecker::classExtends($context->self, $absolute_class))
|
||||
&& ($statements_checker->isStatic() || !ClassChecker::classExtends($context->self, $fq_class_name))
|
||||
) {
|
||||
if (MethodChecker::checkMethodStatic(
|
||||
$method_id,
|
||||
@ -681,8 +681,8 @@ class CallChecker
|
||||
$return_types,
|
||||
$stmt->args,
|
||||
$stmt->class instanceof PhpParser\Node\Name && $stmt->class->parts === ['parent']
|
||||
? $statements_checker->getAbsoluteClass()
|
||||
: $absolute_class,
|
||||
? $statements_checker->getFullQualifiedClass()
|
||||
: $fq_class_name,
|
||||
$method_id
|
||||
);
|
||||
|
||||
@ -730,7 +730,7 @@ class CallChecker
|
||||
|
||||
$is_variadic = false;
|
||||
|
||||
$absolute_class = null;
|
||||
$fq_class_name = null;
|
||||
|
||||
$in_call_map = $method_id ? FunctionChecker::inCallMap($method_id) : false;
|
||||
|
||||
@ -744,7 +744,7 @@ class CallChecker
|
||||
if ($in_call_map || !strpos($method_id, '::')) {
|
||||
$is_variadic = FunctionChecker::isVariadic(strtolower($method_id), $statements_checker->getFileName());
|
||||
} else {
|
||||
$absolute_class = explode('::', $method_id)[0];
|
||||
$fq_class_name = explode('::', $method_id)[0];
|
||||
$is_variadic = $is_mock || MethodChecker::isVariadic($method_id);
|
||||
}
|
||||
}
|
||||
@ -774,7 +774,7 @@ class CallChecker
|
||||
} else {
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$arg->value,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -868,7 +868,7 @@ class CallChecker
|
||||
ExpressionChecker::fleshOutTypes(
|
||||
clone $param_type,
|
||||
[],
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
$method_id
|
||||
),
|
||||
$cased_method_id,
|
||||
@ -948,7 +948,7 @@ class CallChecker
|
||||
|
||||
$translated_param = FunctionLikeChecker::getTranslatedParam(
|
||||
$closure_param,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
@ -57,14 +57,14 @@ class FetchChecker
|
||||
|
||||
$stmt_var_id = ExpressionChecker::getVarId(
|
||||
$stmt->var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$stmt,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -162,7 +162,7 @@ class FetchChecker
|
||||
if (!$lhs_type_part->isObjectType()) {
|
||||
$stmt_var_id = ExpressionChecker::getVarId(
|
||||
$stmt->var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -230,7 +230,7 @@ class FetchChecker
|
||||
|| $lhs_type_part->value === $context->self
|
||||
|| (
|
||||
$statements_checker->getSource()->getSource() instanceof TraitChecker &&
|
||||
$lhs_type_part->value === $statements_checker->getSource()->getAbsoluteClass()
|
||||
$lhs_type_part->value === $statements_checker->getSource()->getFullQualifiedClass()
|
||||
)
|
||||
) {
|
||||
$class_visibility = \ReflectionProperty::IS_PRIVATE;
|
||||
@ -372,16 +372,16 @@ class FetchChecker
|
||||
$stmt->class->parts !== ['static']
|
||||
) {
|
||||
if ($stmt->class->parts === ['self']) {
|
||||
$absolute_class = (string)$context->self;
|
||||
$fq_class_name = (string)$context->self;
|
||||
} else {
|
||||
$absolute_class = ClassLikeChecker::getAbsoluteClassFromName(
|
||||
$fq_class_name = ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$stmt->class,
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
if (ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
$absolute_class,
|
||||
if (ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$fq_class_name,
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine(),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
@ -390,14 +390,14 @@ class FetchChecker
|
||||
}
|
||||
}
|
||||
|
||||
$const_id = $absolute_class . '::' . $stmt->name;
|
||||
$const_id = $fq_class_name . '::' . $stmt->name;
|
||||
|
||||
if ($stmt->name === 'class') {
|
||||
$stmt->inferredType = Type::getString();
|
||||
return null;
|
||||
}
|
||||
|
||||
$class_constants = ClassLikeChecker::getConstantsForClass($absolute_class, \ReflectionProperty::IS_PUBLIC);
|
||||
$class_constants = ClassLikeChecker::getConstantsForClass($fq_class_name, \ReflectionProperty::IS_PUBLIC);
|
||||
|
||||
if (!isset($class_constants[$stmt->name])) {
|
||||
if (IssueBuffer::accepts(
|
||||
@ -445,14 +445,14 @@ class FetchChecker
|
||||
}
|
||||
|
||||
$method_id = null;
|
||||
$absolute_class = null;
|
||||
$fq_class_name = null;
|
||||
|
||||
if ($stmt->class instanceof PhpParser\Node\Name) {
|
||||
if (count($stmt->class->parts) === 1 && in_array($stmt->class->parts[0], ['self', 'static', 'parent'])) {
|
||||
if ($stmt->class->parts[0] === 'parent') {
|
||||
$absolute_class = $statements_checker->getParentClass();
|
||||
$fq_class_name = $statements_checker->getParentClass();
|
||||
|
||||
if ($absolute_class === null) {
|
||||
if ($fq_class_name === null) {
|
||||
if (IssueBuffer::accepts(
|
||||
new ParentNotFound(
|
||||
'Cannot check property fetch on parent as this class does not extend another',
|
||||
@ -467,27 +467,27 @@ class FetchChecker
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$absolute_class = ($statements_checker->getNamespace()
|
||||
$fq_class_name = ($statements_checker->getNamespace()
|
||||
? $statements_checker->getNamespace() . '\\'
|
||||
: '') . $statements_checker->getClassName();
|
||||
}
|
||||
|
||||
if ($context->isPhantomClass($absolute_class)) {
|
||||
if ($context->isPhantomClass($fq_class_name)) {
|
||||
return null;
|
||||
}
|
||||
} elseif ($context->check_classes) {
|
||||
$absolute_class = ClassLikeChecker::getAbsoluteClassFromName(
|
||||
$fq_class_name = ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$stmt->class,
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
if ($context->isPhantomClass($absolute_class)) {
|
||||
if ($context->isPhantomClass($fq_class_name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
$absolute_class,
|
||||
if (ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$fq_class_name,
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine(),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
@ -496,17 +496,17 @@ class FetchChecker
|
||||
}
|
||||
}
|
||||
|
||||
$stmt->class->inferredType = $absolute_class ? new Type\Union([new Type\Atomic($absolute_class)]) : null;
|
||||
$stmt->class->inferredType = $fq_class_name ? new Type\Union([new Type\Atomic($fq_class_name)]) : null;
|
||||
}
|
||||
|
||||
if ($absolute_class &&
|
||||
if ($fq_class_name &&
|
||||
$context->check_variables &&
|
||||
is_string($stmt->name) &&
|
||||
!ExpressionChecker::isMock($absolute_class)
|
||||
!ExpressionChecker::isMock($fq_class_name)
|
||||
) {
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$stmt,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -517,30 +517,30 @@ class FetchChecker
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($absolute_class === $context->self
|
||||
if ($fq_class_name === $context->self
|
||||
|| (
|
||||
$statements_checker->getSource()->getSource() instanceof TraitChecker &&
|
||||
$absolute_class === $statements_checker->getSource()->getAbsoluteClass()
|
||||
$fq_class_name === $statements_checker->getSource()->getFullQualifiedClass()
|
||||
)
|
||||
) {
|
||||
$class_visibility = \ReflectionProperty::IS_PRIVATE;
|
||||
} elseif ($context->self && ClassChecker::classExtends($context->self, $absolute_class)) {
|
||||
} elseif ($context->self && ClassChecker::classExtends($context->self, $fq_class_name)) {
|
||||
$class_visibility = \ReflectionProperty::IS_PROTECTED;
|
||||
} else {
|
||||
$class_visibility = \ReflectionProperty::IS_PUBLIC;
|
||||
}
|
||||
|
||||
$visible_class_properties = ClassLikeChecker::getStaticPropertiesForClass(
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
$class_visibility
|
||||
);
|
||||
|
||||
if (!isset($visible_class_properties[$stmt->name])) {
|
||||
$all_class_properties = [];
|
||||
|
||||
if ($absolute_class !== $context->self) {
|
||||
if ($fq_class_name !== $context->self) {
|
||||
$all_class_properties = ClassLikeChecker::getStaticPropertiesForClass(
|
||||
$absolute_class,
|
||||
$fq_class_name,
|
||||
\ReflectionProperty::IS_PRIVATE
|
||||
);
|
||||
}
|
||||
@ -604,7 +604,7 @@ class FetchChecker
|
||||
$nesting = 0;
|
||||
$var_id = ExpressionChecker::getVarId(
|
||||
$stmt->var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses(),
|
||||
$nesting
|
||||
@ -617,7 +617,7 @@ class FetchChecker
|
||||
|
||||
$array_var_id = ExpressionChecker::getArrayVarId(
|
||||
$stmt->var,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
@ -192,7 +192,7 @@ class ExpressionChecker
|
||||
if (!$statements_checker->isStatic()) {
|
||||
$this_class = ClassLikeChecker::getThisClass();
|
||||
$this_class = $this_class &&
|
||||
ClassChecker::classExtends($this_class, $statements_checker->getAbsoluteClass())
|
||||
ClassChecker::classExtends($this_class, $statements_checker->getFullQualifiedClass())
|
||||
? $this_class
|
||||
: $context->self;
|
||||
|
||||
@ -301,14 +301,14 @@ class ExpressionChecker
|
||||
!in_array($stmt->class->parts[0], ['self', 'static', 'parent'])
|
||||
) {
|
||||
if ($context->check_classes) {
|
||||
$absolute_class = ClassLikeChecker::getAbsoluteClassFromName(
|
||||
$fq_class_name = ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$stmt->class,
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
if (ClassLikeChecker::checkAbsoluteClassOrInterface(
|
||||
$absolute_class,
|
||||
if (ClassLikeChecker::checkFullQualifiedClassOrInterface(
|
||||
$fq_class_name,
|
||||
$statements_checker->getCheckedFileName(),
|
||||
$stmt->getLine(),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
@ -519,7 +519,7 @@ class ExpressionChecker
|
||||
) {
|
||||
$var_id = self::getVarId(
|
||||
$stmt,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -633,7 +633,7 @@ class ExpressionChecker
|
||||
} elseif ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) {
|
||||
$left_type_assertions = TypeChecker::getReconcilableTypeAssertions(
|
||||
$stmt->left,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -679,7 +679,7 @@ class ExpressionChecker
|
||||
} elseif ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) {
|
||||
$left_type_assertions = TypeChecker::getNegatableTypeAssertions(
|
||||
$stmt->left,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -809,16 +809,16 @@ class ExpressionChecker
|
||||
&& $stmt->class instanceof PhpParser\Node\Name
|
||||
) {
|
||||
if (count($stmt->class->parts) === 1 && in_array($stmt->class->parts[0], ['self', 'static', 'parent'])) {
|
||||
$absolute_class = $this_class_name;
|
||||
$fq_class_name = $this_class_name;
|
||||
} else {
|
||||
$absolute_class = ClassLikeChecker::getAbsoluteClassFromName(
|
||||
$fq_class_name = ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$stmt->class,
|
||||
$namespace,
|
||||
$aliased_classes
|
||||
);
|
||||
}
|
||||
|
||||
return $absolute_class . '::$' . $stmt->name;
|
||||
return $fq_class_name . '::$' . $stmt->name;
|
||||
}
|
||||
|
||||
if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch && is_string($stmt->name)) {
|
||||
@ -1079,21 +1079,21 @@ class ExpressionChecker
|
||||
if ($stmt->cond instanceof PhpParser\Node\Expr\BinaryOp) {
|
||||
$reconcilable_if_types = TypeChecker::getReconcilableTypeAssertions(
|
||||
$stmt->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
|
||||
$negatable_if_types = TypeChecker::getNegatableTypeAssertions(
|
||||
$stmt->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
} else {
|
||||
$reconcilable_if_types = $negatable_if_types = TypeChecker::getTypeAssertions(
|
||||
$stmt->cond,
|
||||
$statements_checker->getAbsoluteClass(),
|
||||
$statements_checker->getFullQualifiedClass(),
|
||||
$statements_checker->getNamespace(),
|
||||
$statements_checker->getAliasedClasses()
|
||||
);
|
||||
@ -1231,12 +1231,12 @@ class ExpressionChecker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isMock($absolute_class)
|
||||
public static function isMock($fq_class_name)
|
||||
{
|
||||
return in_array($absolute_class, Config::getInstance()->getMockClasses());
|
||||
return in_array($fq_class_name, Config::getInstance()->getMockClasses());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,7 +75,7 @@ class StatementsChecker
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $absolute_class;
|
||||
protected $fq_class_name;
|
||||
|
||||
/**
|
||||
* @var TypeChecker
|
||||
@ -105,7 +105,7 @@ class StatementsChecker
|
||||
$this->aliased_classes = $this->source->getAliasedClasses();
|
||||
$this->namespace = $this->source->getNamespace();
|
||||
$this->is_static = $this->source->isStatic();
|
||||
$this->absolute_class = $this->source->getAbsoluteClass();
|
||||
$this->fq_class_name = $this->source->getFullQualifiedClass();
|
||||
$this->class_name = $this->source->getClassName();
|
||||
$this->parent_class = $this->source->getParentClass();
|
||||
$this->suppressed_issues = $this->source->getSuppressedIssues();
|
||||
@ -181,7 +181,7 @@ class StatementsChecker
|
||||
foreach ($stmt->vars as $var) {
|
||||
$var_id = ExpressionChecker::getArrayVarId(
|
||||
$var,
|
||||
$this->absolute_class,
|
||||
$this->fq_class_name,
|
||||
$this->namespace,
|
||||
$this->aliased_classes
|
||||
);
|
||||
@ -288,7 +288,7 @@ class StatementsChecker
|
||||
|
||||
if (isset($const->value->inferredType) && !$const->value->inferredType->isMixed()) {
|
||||
ClassLikeChecker::setConstantType(
|
||||
$this->absolute_class,
|
||||
$this->fq_class_name,
|
||||
$const->name,
|
||||
$const->value->inferredType
|
||||
);
|
||||
@ -463,11 +463,11 @@ class StatementsChecker
|
||||
*/
|
||||
protected static function getMethodFromCallBlock($call, array $args, $method_id)
|
||||
{
|
||||
$absolute_class = explode('::', $method_id)[0];
|
||||
$fq_class_name = explode('::', $method_id)[0];
|
||||
|
||||
$original_call = $call;
|
||||
|
||||
$call = preg_replace('/^\$this(->|::)/', $absolute_class . '::', $call);
|
||||
$call = preg_replace('/^\$this(->|::)/', $fq_class_name . '::', $call);
|
||||
|
||||
$call = preg_replace('/\(\)$/', '', $call);
|
||||
|
||||
@ -857,9 +857,9 @@ class StatementsChecker
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsoluteClass()
|
||||
public function getFullQualifiedClass()
|
||||
{
|
||||
return $this->absolute_class;
|
||||
return $this->fq_class_name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,9 +15,9 @@ class TraitChecker extends ClassLikeChecker
|
||||
/**
|
||||
* @param PhpParser\Node\Stmt\ClassLike $class
|
||||
* @param StatementsSource $source
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
*/
|
||||
public function __construct(PhpParser\Node\Stmt\ClassLike $class, StatementsSource $source, $absolute_class)
|
||||
public function __construct(PhpParser\Node\Stmt\ClassLike $class, StatementsSource $source, $fq_class_name)
|
||||
{
|
||||
if (!$class instanceof PhpParser\Node\Stmt\Trait_) {
|
||||
throw new \InvalidArgumentException('Trait checker must be passed a trait');
|
||||
@ -27,13 +27,13 @@ class TraitChecker extends ClassLikeChecker
|
||||
$this->namespace = $source->getNamespace();
|
||||
$this->aliased_classes = $source->getAliasedClasses();
|
||||
$this->file_name = $source->getFileName();
|
||||
$this->absolute_class = $absolute_class;
|
||||
$this->fq_class_name = $fq_class_name;
|
||||
|
||||
$this->parent_class = null;
|
||||
|
||||
$this->suppressed_issues = $source->getSuppressedIssues();
|
||||
|
||||
self::$class_checkers[$absolute_class] = $this;
|
||||
self::$class_checkers[$fq_class_name] = $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -832,7 +832,7 @@ class TypeChecker
|
||||
) {
|
||||
if ($stmt->class instanceof PhpParser\Node\Name) {
|
||||
if (!in_array($stmt->class->parts[0], ['self', 'static', 'parent'])) {
|
||||
$instanceof_class = ClassLikeChecker::getAbsoluteClassFromName(
|
||||
$instanceof_class = ClassLikeChecker::getFullQualifiedClassFromName(
|
||||
$stmt->class,
|
||||
$namespace,
|
||||
$aliased_classes
|
||||
@ -1565,10 +1565,10 @@ class TypeChecker
|
||||
/**
|
||||
* @param Type\Union $declared_type
|
||||
* @param Type\Union $inferred_type
|
||||
* @param string $absolute_class
|
||||
* @param string $fq_class_name
|
||||
* @return boolean
|
||||
*/
|
||||
public static function hasIdenticalTypes(Type\Union $declared_type, Type\Union $inferred_type, $absolute_class)
|
||||
public static function hasIdenticalTypes(Type\Union $declared_type, Type\Union $inferred_type, $fq_class_name)
|
||||
{
|
||||
if ($declared_type->isMixed() || $inferred_type->isEmpty()) {
|
||||
return true;
|
||||
@ -1578,7 +1578,7 @@ class TypeChecker
|
||||
return false;
|
||||
}
|
||||
|
||||
$inferred_type = ExpressionChecker::fleshOutTypes($inferred_type, [], $absolute_class, '');
|
||||
$inferred_type = ExpressionChecker::fleshOutTypes($inferred_type, [], $fq_class_name, '');
|
||||
|
||||
$simple_declared_types = array_filter(
|
||||
array_keys($declared_type->types),
|
||||
@ -1651,7 +1651,7 @@ class TypeChecker
|
||||
if (!self::hasIdenticalTypes(
|
||||
$declared_atomic_type->type_params[$offset],
|
||||
$inferred_atomic_type->type_params[$offset],
|
||||
$absolute_class
|
||||
$fq_class_name
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
@ -1682,7 +1682,7 @@ class TypeChecker
|
||||
if (!self::hasIdenticalTypes(
|
||||
$type_param,
|
||||
$inferred_atomic_type->properties[$property_name],
|
||||
$absolute_class
|
||||
$fq_class_name
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ interface StatementsSource
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsoluteClass();
|
||||
public function getFullQualifiedClass();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
Loading…
Reference in New Issue
Block a user