Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.55% covered (success)
91.55%
195 / 213
84.62% covered (warning)
84.62%
22 / 26
CRAP
0.00% covered (danger)
0.00%
0 / 1
MethodLinks
91.55% covered (success)
91.55%
195 / 213
84.62% covered (warning)
84.62%
22 / 26
122.98
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 newEmpty
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getForDim
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 asValueFirstLevel
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 asKeyForForeach
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setAtDim
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 addKeysLinks
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 asCollapsed
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 mergeWith
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
9
 asMergedWith
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 withAddedOffset
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 asMaybeMovedAtOffset
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 asMergedForAssignment
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
8
 normalize
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
12
 __clone
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 getLinksCollapsing
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 getMethodAndParamTuples
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
7
 isEmpty
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
8
 hasDataForFuncAndParam
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
10
 initializeParamForFunc
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 filterPreservedFlags
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllPreservedFlags
80.00% covered (warning)
80.00%
8 / 10
0.00% covered (danger)
0.00%
0 / 1
5.20
 asPreservedTaintednessForFuncParam
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
9
 asFilteredForFuncAndParam
86.67% covered (warning)
86.67%
13 / 15
0.00% covered (danger)
0.00%
0 / 1
6.09
 toString
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 __toString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php declare( strict_types=1 );
2
3namespace SecurityCheckPlugin;
4
5use ast\Node;
6use Phan\Language\Element\FunctionInterface;
7
8/**
9 * Value object that represents method links.
10 * @todo We might store links inside Taintedness, but the memory usage might skyrocket
11 */
12class MethodLinks {
13    /** @var LinksSet */
14    private $links;
15
16    /** @var self[] */
17    private $dimLinks = [];
18
19    /** @var self|null */
20    private $unknownDimLinks;
21
22    /** @var LinksSet|null */
23    private $keysLinks;
24
25    /**
26     * @param LinksSet|null $links
27     */
28    public function __construct( LinksSet $links = null ) {
29        $this->links = $links ?? new LinksSet();
30    }
31
32    /**
33     * @return self
34     */
35    public static function newEmpty(): self {
36        return new self( new LinksSet );
37    }
38
39    /**
40     * @note This returns a clone
41     * @param mixed $dim
42     * @return self
43     */
44    public function getForDim( $dim ): self {
45        if ( !is_scalar( $dim ) ) {
46            return $this->asValueFirstLevel()->withAddedOffset( $dim );
47        }
48        if ( isset( $this->dimLinks[$dim] ) ) {
49            $ret = clone $this->dimLinks[$dim];
50            $ret->mergeWith( $this->unknownDimLinks ?? self::newEmpty() );
51            $ret->links->mergeWith( $this->links );
52            return $ret->withAddedOffset( $dim );
53        }
54        $ret = $this->unknownDimLinks ? clone $this->unknownDimLinks : self::newEmpty();
55        $ret->links->mergeWith( $this->links );
56        return $ret->withAddedOffset( $dim );
57    }
58
59    /**
60     * @return self
61     */
62    public function asValueFirstLevel(): self {
63        $ret = new self( clone $this->links );
64        $ret->mergeWith( $this->unknownDimLinks ?? self::newEmpty() );
65        foreach ( $this->dimLinks as $links ) {
66            $ret->mergeWith( $links );
67        }
68        return $ret;
69    }
70
71    /**
72     * @return self
73     */
74    public function asKeyForForeach(): self {
75        if ( $this->keysLinks ) {
76            $links = $this->keysLinks->asMergedWith( $this->links );
77        } else {
78            $links = $this->links;
79        }
80        return new self( $links->asAllMovedToKeys() );
81    }
82
83    /**
84     * @param mixed $dim
85     * @param MethodLinks $links
86     */
87    public function setAtDim( $dim, self $links ): void {
88        if ( is_scalar( $dim ) ) {
89            $this->dimLinks[$dim] = $links;
90        } else {
91            $this->unknownDimLinks ??= self::newEmpty();
92            $this->unknownDimLinks->mergeWith( $links );
93        }
94    }
95
96    /**
97     * @param LinksSet $links
98     */
99    public function addKeysLinks( LinksSet $links ): void {
100        if ( !$this->keysLinks ) {
101            $this->keysLinks = $links;
102        } else {
103            $this->keysLinks->mergeWith( $links );
104        }
105    }
106
107    /**
108     * @return self
109     */
110    public function asCollapsed(): self {
111        $ret = new self( $this->links );
112        foreach ( $this->dimLinks as $links ) {
113            $ret->mergeWith( $links->asCollapsed() );
114        }
115        if ( $this->unknownDimLinks ) {
116            $ret->mergeWith( $this->unknownDimLinks->asCollapsed() );
117        }
118        return $ret;
119    }
120
121    /**
122     * Merge this object with $other, recursively and without creating a copy.
123     *
124     * @param self $other
125     */
126    public function mergeWith( self $other ): void {