From 9ed97e646c37e98d3b1187e7d110f59d986d0a97 Mon Sep 17 00:00:00 2001 From: ShiraNai7 Date: Tue, 28 Jan 2020 15:10:42 +0100 Subject: [PATCH 1/2] Fix #2638 - propagate phantom classes to recursive calls to Scanner::queueClassLikeForScanning() --- src/Psalm/Internal/Codebase/Scanner.php | 6 ++++-- src/Psalm/Type/Atomic.php | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Psalm/Internal/Codebase/Scanner.php b/src/Psalm/Internal/Codebase/Scanner.php index ff582a2fe3a..86181db3d16 100644 --- a/src/Psalm/Internal/Codebase/Scanner.php +++ b/src/Psalm/Internal/Codebase/Scanner.php @@ -280,6 +280,7 @@ public function getClassLikeFilePath($fq_classlike_name_lc) * @param string|null $referencing_file_path * @param bool $analyze_too * @param bool $store_failure + * @param array $phantom_classes * * @return void */ @@ -287,7 +288,8 @@ public function queueClassLikeForScanning( $fq_classlike_name, $referencing_file_path = null, $analyze_too = false, - $store_failure = true + $store_failure = true, + array $phantom_classes = [] ) { if ($fq_classlike_name[0] === '\\') { $fq_classlike_name = substr($fq_classlike_name, 1); @@ -325,7 +327,7 @@ public function queueClassLikeForScanning( $property_type->queueClassLikesForScanning( $this->codebase, null, - [$fq_classlike_name_lc => true] + $phantom_classes + [$fq_classlike_name_lc => true] ); } } diff --git a/src/Psalm/Type/Atomic.php b/src/Psalm/Type/Atomic.php index d26b9a1cc1f..cc58188977b 100644 --- a/src/Psalm/Type/Atomic.php +++ b/src/Psalm/Type/Atomic.php @@ -458,7 +458,8 @@ public function queueClassLikesForScanning( $this->value, $file_storage ? $file_storage->file_path : null, false, - !$this->from_docblock + !$this->from_docblock, + $phantom_classes ); if ($file_storage) { @@ -487,7 +488,8 @@ public function queueClassLikesForScanning( $this->fq_classlike_name, $file_storage ? $file_storage->file_path : null, false, - !$this->from_docblock + !$this->from_docblock, + $phantom_classes ); if ($file_storage) { $file_storage->referenced_classlikes[strtolower($this->fq_classlike_name)] = $this->fq_classlike_name; @@ -500,7 +502,8 @@ public function queueClassLikesForScanning( $this->as, $file_storage ? $file_storage->file_path : null, false, - !$this->from_docblock + !$this->from_docblock, + $phantom_classes ); if ($file_storage) { $file_storage->referenced_classlikes[strtolower($this->as)] = $this->as; @@ -521,7 +524,8 @@ public function queueClassLikesForScanning( $this->value, $file_storage ? $file_storage->file_path : null, false, - !$this->from_docblock + !$this->from_docblock, + $phantom_classes ); if ($file_storage) { $file_storage->referenced_classlikes[strtolower($this->value)] = $this->value; From 9f8103e585aebde29081013e90f9486cd52347de Mon Sep 17 00:00:00 2001 From: ShiraNai7 Date: Tue, 28 Jan 2020 15:19:38 +0100 Subject: [PATCH 2/2] Add generic definition of DOMNamedNodeMap --- src/Psalm/Internal/PropertyMap.php | 2 +- .../Internal/Stubs/CoreGenericClasses.php | 26 +++++++++++++++++++ tests/PropertyTypeTest.php | 6 +++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/Psalm/Internal/PropertyMap.php b/src/Psalm/Internal/PropertyMap.php index a35a1a18dcd..3652789e004 100644 --- a/src/Psalm/Internal/PropertyMap.php +++ b/src/Psalm/Internal/PropertyMap.php @@ -268,7 +268,7 @@ 'domelement' => [ 'schemaTypeInfo' => 'bool', 'tagName' => 'string', - 'attributes' => 'DOMNamedNodeMap', + 'attributes' => 'DOMNamedNodeMap', ], 'tidynode' => [ 'value' => 'string', diff --git a/src/Psalm/Internal/Stubs/CoreGenericClasses.php b/src/Psalm/Internal/Stubs/CoreGenericClasses.php index 322f06fa975..9dd437be4cb 100644 --- a/src/Psalm/Internal/Stubs/CoreGenericClasses.php +++ b/src/Psalm/Internal/Stubs/CoreGenericClasses.php @@ -946,6 +946,32 @@ class DOMNodeList implements Traversable, Countable { public function item($index) {} } +/** + * @template-covariant TNode as DOMNode + * @template-implements Traversable + */ +class DOMNamedNodeMap implements Traversable, Countable { + /** + * @var int + */ + public $length; + + /** + * @return TNode|null + */ + public function getNamedItem(string $name): ?DOMNode {} + + /** + * @return TNode|null + */ + public function getNamedItemNS(string $namespaceURI, string $localName): ?DOMNode {} + + /** + * @return TNode|null + */ + public function item(int $index): ?DOMNode {} +} + /** * The SplDoublyLinkedList class provides the main functionalities of a doubly linked list. * @link https://php.net/manual/en/class.spldoublylinkedlist.php diff --git a/tests/PropertyTypeTest.php b/tests/PropertyTypeTest.php index 0118dbdec66..4ed5c2825f9 100644 --- a/tests/PropertyTypeTest.php +++ b/tests/PropertyTypeTest.php @@ -344,6 +344,12 @@ function foo(DOMElement $e) : void { echo $e->attributes->length; }', ], + 'genericTypeFromPropertyMap' => [ + 'attributes->item(0); + }' + ], 'goodArrayProperties' => [ '