File tree Expand file tree Collapse file tree 4 files changed +74
-7
lines changed Expand file tree Collapse file tree 4 files changed +74
-7
lines changed Original file line number Diff line number Diff line change @@ -530,12 +530,8 @@ public function isCallMapFunctionPure(
530
530
if ($ function_id === 'serialize ' && isset ($ args [0 ]) && $ type_provider ) {
531
531
$ serialize_type = $ type_provider ->getType ($ args [0 ]->value );
532
532
533
- if ($ serialize_type ) {
534
- foreach ($ serialize_type ->getAtomicTypes () as $ atomic_serialize_type ) {
535
- if ($ atomic_serialize_type ->isObjectType ()) {
536
- return false ;
537
- }
538
- }
533
+ if ($ serialize_type && $ serialize_type ->canContainObjectType ($ codebase )) {
534
+ return false ;
539
535
}
540
536
}
541
537
Original file line number Diff line number Diff line change
1
+ <?php
2
+
3
+ namespace Psalm \Internal \TypeVisitor ;
4
+
5
+ use Psalm \Codebase ;
6
+ use Psalm \Internal \Type \Comparator \AtomicTypeComparator ;
7
+ use Psalm \Internal \Type \Comparator \UnionTypeComparator ;
8
+ use Psalm \Type \Atomic ;
9
+ use Psalm \Type \Atomic \TObject ;
10
+ use Psalm \Type \NodeVisitor ;
11
+ use Psalm \Type \TypeNode ;
12
+ use Psalm \Type \Union ;
13
+
14
+ class CanContainObjectTypeVisitor extends NodeVisitor
15
+ {
16
+ /**
17
+ * @var bool
18
+ */
19
+ private $ contains_object_type = false ;
20
+
21
+ /**
22
+ * @var Codebase
23
+ */
24
+ private $ codebase ;
25
+
26
+ public function __construct (Codebase $ codebase )
27
+ {
28
+ $ this ->codebase = $ codebase ;
29
+ }
30
+
31
+ protected function enterNode (TypeNode $ type ): ?int
32
+ {
33
+ if ($ type instanceof Union
34
+ && (
35
+ UnionTypeComparator::canBeContainedBy ($ this ->codebase , new Union ([new TObject ()]), $ type )
36
+ && UnionTypeComparator::canBeContainedBy ($ this ->codebase , $ type , new Union ([new TObject ()]))
37
+ )
38
+ ||
39
+ $ type instanceof Atomic
40
+ && (
41
+ AtomicTypeComparator::isContainedBy ($ this ->codebase , new TObject (), $ type )
42
+ || AtomicTypeComparator::isContainedBy ($ this ->codebase , $ type , new TObject ())
43
+ )
44
+ ) {
45
+ $ this ->contains_object_type = true ;
46
+ return NodeVisitor::STOP_TRAVERSAL ;
47
+ }
48
+
49
+ return null ;
50
+ }
51
+
52
+ public function matches (): bool
53
+ {
54
+ return $ this ->contains_object_type ;
55
+ }
56
+ }
Original file line number Diff line number Diff line change 7
7
use Psalm \Codebase ;
8
8
use Psalm \Internal \DataFlow \DataFlowNode ;
9
9
use Psalm \Internal \Type \TypeCombiner ;
10
+ use Psalm \Internal \TypeVisitor \CanContainObjectTypeVisitor ;
10
11
use Psalm \Internal \TypeVisitor \ContainsClassLikeVisitor ;
11
12
use Psalm \Internal \TypeVisitor \ContainsLiteralVisitor ;
12
13
use Psalm \Internal \TypeVisitor \FromDocblockSetter ;
@@ -1492,6 +1493,15 @@ public function containsAnyLiteral(): bool
1492
1493
return $ literal_visitor ->matches ();
1493
1494
}
1494
1495
1496
+ public function canContainObjectType (Codebase $ codebase ): bool
1497
+ {
1498
+ $ object_type_visitor = new CanContainObjectTypeVisitor ($ codebase );
1499
+
1500
+ $ object_type_visitor ->traverseArray ($ this ->types );
1501
+
1502
+ return $ object_type_visitor ->matches ();
1503
+ }
1504
+
1495
1505
/**
1496
1506
* @return list<TTemplateParam>
1497
1507
*/
Original file line number Diff line number Diff line change @@ -751,9 +751,14 @@ public function __wakeup(): void
751
751
}
752
752
}
753
753
754
- function test(): bool {
754
+ function test(Foo|int $foo, mixed $bar, iterable $baz ): bool {
755
755
try {
756
756
serialize(new Foo());
757
+ serialize([new Foo()]);
758
+ serialize([[new Foo()]]);
759
+ serialize($foo);
760
+ serialize($bar);
761
+ serialize($baz);
757
762
unserialize("");
758
763
} catch (\Throwable) {
759
764
return false;
You can’t perform that action at this time.
0 commit comments