diff --git a/examples/TemplateChecker.php b/examples/TemplateChecker.php index 021523da7..5caac067a 100644 --- a/examples/TemplateChecker.php +++ b/examples/TemplateChecker.php @@ -82,6 +82,7 @@ class TemplateAnalyzer extends Psalm\Internal\Analyzer\FileAnalyzer $this, $class, new CodeLocation($this, $stmt), + null, [], true ) === false diff --git a/src/Psalm/Internal/Analyzer/ClassAnalyzer.php b/src/Psalm/Internal/Analyzer/ClassAnalyzer.php index 8b6c3ff3d..ea2f67f54 100644 --- a/src/Psalm/Internal/Analyzer/ClassAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ClassAnalyzer.php @@ -225,6 +225,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer $this->getSource(), $parent_fq_class_name, $parent_reference_location, + null, $storage->suppressed_issues + $this->getSuppressedIssues(), false ) === false) { @@ -379,6 +380,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer $this, $fq_interface_name, $interface_location, + null, $this->getSuppressedIssues(), false ) === false) { diff --git a/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php b/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php index eba2bf7c3..d206d8db7 100644 --- a/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php @@ -210,6 +210,7 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer implements StatementsSou StatementsSource $statements_source, string $fq_class_name, CodeLocation $code_location, + ?string $calling_fq_class_name, array $suppressed_issues, bool $inferred = true, bool $allow_trait = false, @@ -262,11 +263,13 @@ abstract class ClassLikeAnalyzer extends SourceAnalyzer implements StatementsSou $class_exists = $codebase->classlikes->classExists( $fq_class_name, - !$inferred ? $code_location : null + !$inferred ? $code_location : null, + $calling_fq_class_name ); $interface_exists = $codebase->classlikes->interfaceExists( $fq_class_name, - !$inferred ? $code_location : null + !$inferred ? $code_location : null, + $calling_fq_class_name ); if (!$class_exists && !$interface_exists) { diff --git a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php index 02ce828b3..46dea3c67 100644 --- a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php @@ -652,6 +652,7 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer $statements_analyzer, $expected_exception, $storage->throw_locations[$expected_exception], + $context->self, $statements_analyzer->getSuppressedIssues(), false, false, diff --git a/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php index e75ccfc57..68bf900f8 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php @@ -557,6 +557,7 @@ class ForeachAnalyzer $statements_analyzer, $iterator_atomic_type->value, new CodeLocation($statements_analyzer->getSource(), $stmt->expr), + $context->self, $statements_analyzer->getSuppressedIssues() ) === false) { return false; diff --git a/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php index 84b0722bc..2e6190160 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php @@ -223,6 +223,7 @@ class TryAnalyzer $statements_analyzer, $fq_catch_class, new CodeLocation($statements_analyzer->getSource(), $catch_type, $context->include_location), + $context->self, $statements_analyzer->getSuppressedIssues(), false ) === false) { diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php b/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php index cf2a0d3d2..4870f3c5e 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php @@ -895,6 +895,7 @@ class AssertionFinder $source, $var_type, new CodeLocation($source, $whichclass_expr), + null, $source->getSuppressedIssues(), false ) === false @@ -1510,6 +1511,7 @@ class AssertionFinder $source, $var_type, new CodeLocation($source, $whichclass_expr), + null, $source->getSuppressedIssues(), false ) === false diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php index 8a1e54619..2e912da15 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php @@ -633,6 +633,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\ $statements_analyzer, $fq_class_name, new CodeLocation($source, $stmt->var), + $context->self, $statements_analyzer->getSuppressedIssues(), true, false, diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php index 1c0874403..90af4f336 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php @@ -295,6 +295,7 @@ class NewAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\CallAna $statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt->class), + $context->self, $statements_analyzer->getSuppressedIssues(), false ) === false) { diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php index fc6c21851..70fc15015 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php @@ -150,6 +150,7 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\ $statements_analyzer, $fq_class_name, new CodeLocation($source, $stmt->class), + $context->self, $statements_analyzer->getSuppressedIssues(), false, false, @@ -209,6 +210,7 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\ $statements_analyzer, $fq_class_name, new CodeLocation($source, $stmt->class), + $context->self, $statements_analyzer->getSuppressedIssues(), $stmt->class instanceof PhpParser\Node\Name && count($stmt->class->parts) === 1 @@ -227,6 +229,7 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\ $statements_analyzer, $fq_class_name, new CodeLocation($source, $stmt->class), + $context->self, $statements_analyzer->getSuppressedIssues(), false )) { @@ -255,6 +258,7 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\ $statements_analyzer, $fq_class_name, new CodeLocation($source, $stmt->class), + $context->self, $statements_analyzer->getSuppressedIssues(), false )) { diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php index 9b988c79f..dba2c416d 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php @@ -2821,6 +2821,7 @@ class CallAnalyzer $statements_analyzer, $input_expr->value, $code_location, + $context->self, $statements_analyzer->getSuppressedIssues() ) === false ) { @@ -2837,6 +2838,7 @@ class CallAnalyzer $statements_analyzer, $item->value->value, $code_location, + $context->self, $statements_analyzer->getSuppressedIssues() ) === false ) { @@ -2885,6 +2887,7 @@ class CallAnalyzer $statements_analyzer, $callable_fq_class_name, $code_location, + $context->self, $statements_analyzer->getSuppressedIssues() ) === false ) { diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ClassConstFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ClassConstFetchAnalyzer.php index a2c33e280..5dad2e699 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ClassConstFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ClassConstFetchAnalyzer.php @@ -79,6 +79,7 @@ class ClassConstFetchAnalyzer $statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt->class), + $context->self, $statements_analyzer->getSuppressedIssues(), false, true diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/PropertyFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/PropertyFetchAnalyzer.php index 233d9bdfe..a248a06b0 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/PropertyFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/PropertyFetchAnalyzer.php @@ -1016,6 +1016,7 @@ class PropertyFetchAnalyzer $statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt->class), + $context->self, $statements_analyzer->getSuppressedIssues(), false ) !== true) { diff --git a/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php index 375f0e916..d11c4e68b 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php @@ -699,6 +699,7 @@ class ExpressionAnalyzer $statements_analyzer, $fq_class_name, new CodeLocation($statements_analyzer->getSource(), $stmt->class), + $context->self, $statements_analyzer->getSuppressedIssues(), false ) === false) { diff --git a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php index 5713fce20..04f00f5ec 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php @@ -330,6 +330,7 @@ class ReturnAnalyzer $statements_analyzer, $stmt->expr->value, new CodeLocation($source, $stmt->expr), + $context->self, $statements_analyzer->getSuppressedIssues() ) === false ) { @@ -348,6 +349,7 @@ class ReturnAnalyzer $statements_analyzer, $item->value->value, new CodeLocation($source, $item->value), + $context->self, $statements_analyzer->getSuppressedIssues() ) === false ) { diff --git a/src/Psalm/Internal/Codebase/ClassLikes.php b/src/Psalm/Internal/Codebase/ClassLikes.php index f0c45490a..33676838b 100644 --- a/src/Psalm/Internal/Codebase/ClassLikes.php +++ b/src/Psalm/Internal/Codebase/ClassLikes.php @@ -303,8 +303,11 @@ class ClassLikes * * @return bool */ - public function hasFullyQualifiedClassName($fq_class_name, CodeLocation $code_location = null) - { + public function hasFullyQualifiedClassName( + $fq_class_name, + CodeLocation $code_location = null, + ?string $calling_fq_class_name = null + ) { $fq_class_name_lc = strtolower($fq_class_name); if (isset($this->classlike_aliases[$fq_class_name_lc])) { @@ -338,6 +341,19 @@ class ClassLikes $code_location->file_path, $fq_class_name_lc ); + + if ($calling_fq_class_name) { + $class_storage = $this->classlike_storage_provider->get($calling_fq_class_name); + + if ($class_storage->location + && $class_storage->location->file_path !== $code_location->file_path + ) { + $this->file_reference_provider->addFileReferenceToClass( + $class_storage->location->file_path, + $fq_class_name_lc + ); + } + } } if ($this->collect_locations && $code_location) { @@ -355,8 +371,11 @@ class ClassLikes * * @return bool */ - public function hasFullyQualifiedInterfaceName($fq_class_name, CodeLocation $code_location = null) - { + public function hasFullyQualifiedInterfaceName( + $fq_class_name, + CodeLocation $code_location = null, + ?string $calling_fq_class_name = null + ) { $fq_class_name_lc = strtolower($fq_class_name); if (isset($this->classlike_aliases[$fq_class_name_lc])) { @@ -390,6 +409,19 @@ class ClassLikes $code_location->file_path, $fq_class_name_lc ); + + if ($calling_fq_class_name) { + $class_storage = $this->classlike_storage_provider->get($calling_fq_class_name); + + if ($class_storage->location + && $class_storage->location->file_path !== $code_location->file_path + ) { + $this->file_reference_provider->addFileReferenceToClass( + $class_storage->location->file_path, + $fq_class_name_lc + ); + } + } } if ($this->collect_locations && $code_location) { @@ -441,10 +473,11 @@ class ClassLikes */ public function classOrInterfaceExists( $fq_class_name, - CodeLocation $code_location = null + CodeLocation $code_location = null, + ?string $calling_fq_class_name = null ) { - if (!$this->classExists($fq_class_name, $code_location) - && !$this->interfaceExists($fq_class_name, $code_location) + if (!$this->classExists($fq_class_name, $code_location, $calling_fq_class_name) + && !$this->interfaceExists($fq_class_name, $code_location, $calling_fq_class_name) ) { return false; } @@ -459,8 +492,11 @@ class ClassLikes * * @return bool */ - public function classExists($fq_class_name, CodeLocation $code_location = null) - { + public function classExists( + $fq_class_name, + CodeLocation $code_location = null, + ?string $calling_fq_class_name = null + ) { if (isset(ClassLikeAnalyzer::SPECIAL_TYPES[$fq_class_name])) { return false; } @@ -469,7 +505,7 @@ class ClassLikes return true; } - return $this->hasFullyQualifiedClassName($fq_class_name, $code_location); + return $this->hasFullyQualifiedClassName($fq_class_name, $code_location, $calling_fq_class_name); } /** @@ -548,13 +584,20 @@ class ClassLikes * * @return bool */ - public function interfaceExists($fq_interface_name, CodeLocation $code_location = null) - { + public function interfaceExists( + $fq_interface_name, + CodeLocation $code_location = null, + ?string $calling_fq_class_name = null + ) { if (isset(ClassLikeAnalyzer::SPECIAL_TYPES[strtolower($fq_interface_name)])) { return false; } - return $this->hasFullyQualifiedInterfaceName($fq_interface_name, $code_location); + return $this->hasFullyQualifiedInterfaceName( + $fq_interface_name, + $code_location, + $calling_fq_class_name + ); } /** diff --git a/src/Psalm/Internal/Provider/FileReferenceProvider.php b/src/Psalm/Internal/Provider/FileReferenceProvider.php index 7950f4d43..41b566ff8 100644 --- a/src/Psalm/Internal/Provider/FileReferenceProvider.php +++ b/src/Psalm/Internal/Provider/FileReferenceProvider.php @@ -313,9 +313,11 @@ class FileReferenceProvider foreach ($file_classes as $file_class_lc => $_) { if (isset(self::$file_references_to_classes[$file_class_lc])) { + $new_files = array_keys(self::$file_references_to_classes[$file_class_lc]); + $referenced_files = array_merge( $referenced_files, - array_keys(self::$file_references_to_classes[$file_class_lc]) + $new_files ); } } diff --git a/src/Psalm/Type/Atomic/HasIntersectionTrait.php b/src/Psalm/Type/Atomic/HasIntersectionTrait.php index eac619521..737147bcc 100644 --- a/src/Psalm/Type/Atomic/HasIntersectionTrait.php +++ b/src/Psalm/Type/Atomic/HasIntersectionTrait.php @@ -163,6 +163,7 @@ trait HasIntersectionTrait $source, $extra_type->value, $code_location, + null, $suppressed_issues, $inferred, false, diff --git a/src/Psalm/Type/Atomic/TClassString.php b/src/Psalm/Type/Atomic/TClassString.php index 215607d3a..3ac8c2af5 100644 --- a/src/Psalm/Type/Atomic/TClassString.php +++ b/src/Psalm/Type/Atomic/TClassString.php @@ -148,6 +148,7 @@ class TClassString extends TString $source, $this->as, $code_location, + null, $suppressed_issues, $inferred, false, diff --git a/src/Psalm/Type/Atomic/TLiteralClassString.php b/src/Psalm/Type/Atomic/TLiteralClassString.php index 72688a0e1..1b555ffa7 100644 --- a/src/Psalm/Type/Atomic/TLiteralClassString.php +++ b/src/Psalm/Type/Atomic/TLiteralClassString.php @@ -140,6 +140,7 @@ class TLiteralClassString extends TLiteralString $source, $this->value, $code_location, + null, $suppressed_issues, $inferred, false, diff --git a/src/Psalm/Type/Atomic/TNamedObject.php b/src/Psalm/Type/Atomic/TNamedObject.php index 307722b02..36e2a1c2b 100644 --- a/src/Psalm/Type/Atomic/TNamedObject.php +++ b/src/Psalm/Type/Atomic/TNamedObject.php @@ -181,6 +181,7 @@ class TNamedObject extends Atomic $source, $this->value, $code_location, + null, $suppressed_issues, $inferred, false, diff --git a/src/Psalm/Type/Atomic/TScalarClassConstant.php b/src/Psalm/Type/Atomic/TScalarClassConstant.php index 85208a4e2..9c9fa2cd8 100644 --- a/src/Psalm/Type/Atomic/TScalarClassConstant.php +++ b/src/Psalm/Type/Atomic/TScalarClassConstant.php @@ -134,6 +134,7 @@ class TScalarClassConstant extends Scalar $source, $fq_classlike_name, $code_location, + null, $suppressed_issues, $inferred, false,