Completed
Push — master ( f32f45...e7b229 )
by Arne
45:20 queued 19:37
created

AbstractUnitObject::usesTrait()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/**
3
 * Copyright (c) 2010-2018 Arne Blankerts <[email protected]>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without modification,
7
 * are permitted provided that the following conditions are met:
8
 *
9
 *   * Redistributions of source code must retain the above copyright notice,
10
 *     this list of conditions and the following disclaimer.
11
 *
12
 *   * Redistributions in binary form must reproduce the above copyright notice,
13
 *     this list of conditions and the following disclaimer in the documentation
14
 *     and/or other materials provided with the distribution.
15
 *
16
 *   * Neither the name of Arne Blankerts nor the names of contributors
17
 *     may be used to endorse or promote products derived from this software
18
 *     without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  * NOT LIMITED TO,
22
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
24
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
 * POSSIBILITY OF SUCH DAMAGE.
31
 *
32
 * @package    phpDox
33
 * @author     Arne Blankerts <[email protected]>
34
 * @copyright  Arne Blankerts <[email protected]>, All rights reserved.
35
 * @license    BSD License
36
 */
37
namespace TheSeer\phpDox\Collector {
38
39
    use TheSeer\fDOM\fDOMDocument;
40
    use TheSeer\fDOM\fDOMElement;
41
    use TheSeer\phpDox\DocBlock\DocBlock;
42
    use TheSeer\phpDox\FileInfo;
43
44
    /**
45
     *
46
     */
47
    abstract class AbstractUnitObject {
48
49
        /**
50
         * PHPDOX Namespace
51
         */
52
        const XMLNS = 'http://xml.phpdox.net/src';
53
54
        /**
55
         * @var fDOMDocument
56
         */
57
        private $dom;
58
59
        /**
60
         * @var fDOMElement
61
         */
62
        private $rootNode;
63
64
        /**
65
         * @var string
66
         */
67
        protected $rootName = NULL;
68
69
        /**
70
         * @param string       $name
0 ignored issues
show
Documentation introduced by Arne Blankerts
Should the type for parameter $name not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
71
         * @param \SplFileInfo $file
0 ignored issues
show
Documentation introduced by Arne Blankerts
Should the type for parameter $file not be null|SourceFile?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
72
         */
73
        public function __construct($name = NULL, SourceFile $file = NULL) {
74
            if ($this->rootName === NULL) {
75
                throw new UnitObjectException('No or invalid rootname set', UnitObjectException::InvalidRootname);
76
            }
77
            $this->dom = new fDOMDocument('1.0', 'UTF-8');
78
            $this->dom->registerNamespace('phpdox', self::XMLNS);
79
            $this->rootNode = $this->dom->createElementNS(self::XMLNS, $this->rootName);
80
            $this->dom->appendChild($this->rootNode);
81
            if ($name !== NULL) {
82
                $this->setName($name, $this->rootNode);
83
            }
84
            if ($file !== NULL) {
85
                $this->rootNode->appendChild($file->asNode($this->rootNode));
86
            }
87
            $this->setAbstract(FALSE);
88
            $this->setFinal(FALSE);
89
        }
90
91
        /**
92
         * @param $name
93
         */
94
        protected function setName($name, fDOMElement $ctx) {
95
            $parts = explode('\\', $name);
96
            $local = array_pop($parts);
97
            $namespace = join('\\', $parts);
98
            $ctx->setAttribute('full', $name);
99
            $ctx->setAttribute('namespace', $namespace);
100
            $ctx->setAttribute('name', $local);
101
        }
102
103
104
        protected function getRootNode() {
105
            return $this->rootNode;
106
        }
107
108
        /**
109
         * @return \TheSeer\fDOM\fDOMDocument
110
         */
111
        public function export() {
112
            return $this->dom;
113
        }
114
115
        /**
116
         * @param \TheSeer\fDOM\fDOMDocument $dom
117
         */
118
        public function import(fDOMDocument $dom) {
119
            $this->dom = $dom;
120
            $this->rootNode = $dom->documentElement;
0 ignored issues
show
Documentation Bug introduced by Arne Blankerts
$dom->documentElement is of type object<DOMElement>, but the property $rootNode was declared to be of type object<TheSeer\fDOM\fDOMElement>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
121
            $this->dom->registerNamespace('phpdox', self::XMLNS);
122
        }
123
124
        public function getType() {
125
            return $this->rootNode->localName;
126
        }
127
128
        /**
129
         * @return string
130
         */
131
        public function getLocalName() {
132
            return $this->rootNode->getAttribute('name');
133
        }
134
135
        /**
136
         * @return string
137
         */
138
        public function getName() {
139
            return $this->rootNode->getAttribute('full');
140
        }
141
142
        /**
143
         * @return string
144
         */
145
        public function getNamespace() {
146
            return $this->rootNode->getAttribute('namespace');
147
        }
148
149
        /**
150
         * @return FileInfo
151
         */
152
        public function getSourceFilename() {
153
            $file = $this->rootNode->queryOne('phpdox:file');
154
            if (!$file) {
155
                return '';
156
            }
157
            return new FileInfo($file->getAttribute('path') . '/' . $file->getAttribute('file'));
158
        }
159
160
        /**
161
         * @return string
162
         */
163
        public function getCompactDescription() {
164
            $desc = $this->rootNode->queryOne('phpdox:docblock/phpdox:description');
165
            if (!$desc || !$desc->hasAttribute('compact')) {
166
                return '';
167
            }
168
            return $desc->getAttribute('compact');
169
        }
170
171
        /**
172
         * @param int $endLine
173
         */
174
        public function setEndLine($endLine) {
175
            $this->rootNode->setAttribute('end', $endLine);
176
        }
177
178
        /**
179
         * @param int $startLine
180
         */
181
        public function setStartLine($startLine) {
182
            $this->rootNode->setAttribute('start', $startLine);
183
        }
184
185
        /**
186
         * @param boolean $isAbstract
187
         */
188
        public function setAbstract($isAbstract) {
189
            $this->rootNode->setAttribute('abstract', $isAbstract ? 'true' : 'false');
190
        }
191
192
        /**
193
         * @param boolean $isFinal
194
         */
195
        public function setFinal($isFinal) {
196
            $this->rootNode->setAttribute('final', $isFinal ? 'true' : 'false');
197
        }
198
199
        /**
200
         * @param \TheSeer\phpDox\DocBlock\DocBlock $docblock
201
         */
202
        public function setDocBlock(DocBlock $docblock) {
203
            $docNode = $docblock->asDom($this->dom);
204
            $this->rootNode->appendChild($docNode);
205
        }
206
207
        /**
208
         * @param $name
209
         */
210
        public function addExtends($name) {
211
            $extends = $this->rootNode->appendElementNS(self::XMLNS, 'extends');
212
            $this->setName($name, $extends);
213
        }
214
215
        /**
216
         * @return bool
217
         */
218
        public function hasExtends() {
219
            return $this->rootNode->queryOne('phpdox:extends') !== NULL;
220
        }
221
222
        /**
223
         * @return mixed
224
         * @throws UnitObjectException
225
         */
226 View Code Duplication
        public function getExtends() {
227
            if(!$this->hasExtends()) {
228
                throw new UnitObjectException('This unit does not extend any unit', UnitObjectException::NoExtends);
229
            }
230
            $result = array();
231
            foreach($this->rootNode->query('phpdox:extends') as $ext) {
232
                $result[] = $ext->getAttribute('full');
233
            }
234
            return $result;
235
        }
236
237
        /**
238
         * @param AbstractUnitObject $unit
239
         */
240
        public function addExtender(AbstractUnitObject $unit) {
241
            if ($this->rootNode->queryOne(sprintf('phpdox:extenders/phpdox:*[@full = "%s"]', $unit->getName())) !== NULL) {
242
                return;
243
            }
244
            $extender = $this->addToContainer('extenders', 'extender');
245
            $this->setName($unit->getName(), $extender);
246
        }
247
248
        /**
249
         * @param $name
250
         */
251
        public function addImplements($name) {
252
            $implements = $this->rootNode->appendElementNS(self::XMLNS, 'implements');
253
            $this->setName($name, $implements);
254
        }
255
256
        /**
257
         * @return bool
258
         */
259
        public function hasImplements() {
260
            return $this->rootNode->query('phpdox:implements')->length > 0;
261
        }
262
263
        /**
264
         * @return array
265
         * @throws UnitObjectException
266
         */
267 View Code Duplication
        public function getImplements() {
268
            if (!$this->hasImplements()) {
269
                throw new UnitObjectException('This unit does not implement any interfaces', UnitObjectException::NoImplements);
270
            }
271
            $result = array();
272
            foreach($this->rootNode->query('phpdox:implements') as $impl) {
273
                $result[] = $impl->getAttribute('full');
274
            }
275
            return $result;
276
        }
277
278
        /**
279
         * @return bool
280
         */
281
        public function usesTraits() {
282
            return $this->rootNode->query('phpdox:uses')->length > 0;
283
        }
284
285
        /**
286
         * @param $name
287
         *
288
         * @return bool
289
         */
290
        public function usesTrait($name) {
291
            return $this->rootNode->query(sprintf('phpdox:uses[@full="%s"]', $name))->length > 0;
292
        }
293
294
        /**
295
         * @param string $name
296
         *
297
         * @return TraitUseObject
298
         */
299
        public function addTrait($name) {
300
            $traituse = new TraitUseObject($this->rootNode->appendElementNS(self::XMLNS, 'uses'));
301
            $traituse->setName($name);
302
            return $traituse;
303
        }
304
305
        /**
306
         * @return array
307
         * @throws UnitObjectException
308
         */
309 View Code Duplication
        public function getUsedTraits() {
310
            if (!$this->usesTraits()) {
311
                throw new UnitObjectException('This unit does not use any traits', UnitObjectException::NoTraitsUsed);
312
            }
313
            $result = array();
314
            foreach($this->rootNode->query('phpdox:uses') as $trait) {
315
                $result[] = $trait->getAttribute('full');
316
            }
317
            return $result;
318
        }
319
320
        /**
321
         * @param $name
322
         *
323
         * @return TraitUseObject
324
         * @throws UnitObjectException
325
         */
326
        public function getTraitUse($name) {
327
            $node = $this->rootNode->queryOne(
328
                sprintf('phpdox:uses[@full="%s"]', $name)
329
            );
330
            if (!$node) {
331
                throw new UnitObjectException(
332
                    sprintf('Trait "%s" not used', $name),
333
                    UnitObjectException::NoSuchTrait
334
                );
335
            }
336
            return new TraitUseObject($node);
0 ignored issues
show
Documentation introduced by Arne Blankerts
$node is of type object<TheSeer\fDOM\fDOMNode>, but the function expects a object<TheSeer\fDOM\fDOMElement>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
337
        }
338
339
        public function getAmbiguousTraitUse() {
340
            $node = $this->rootNode->queryOne('phpdox:ambiguous[@type="trait-alias"]');
341
            if (!$node) {
342
                $node = $this->rootNode->appendElementNS(self::XMLNS, 'ambiguous');
343
                $node->setAttribute('type','trait-alias');
344
            }
345
            return new TraitUseObject($node);
0 ignored issues
show
Bug introduced by Arne Blankerts
It seems like $node defined by $this->rootNode->queryOn...[@type="trait-alias"]') on line 340 can also be of type object<TheSeer\fDOM\fDOMNode>; however, TheSeer\phpDox\Collector...seObject::__construct() does only seem to accept object<TheSeer\fDOM\fDOMElement>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
346
        }
347
348
        /**
349
         * @param string $dependency
350
         */
351
        public function markDependencyAsUnresolved($dependency) {
352
            $depNode = $this->rootNode->queryOne(
353
                sprintf('//phpdox:implements[@full="%1$s"]|//phpdox:extends[@full="%1$s"]|//phpdox:uses[@full="%1$s"]', $dependency)
354
            );
355
            if (!$depNode) {
356
                throw new UnitObjectException(
357
                    sprintf('No dependency "%s" found in unit %s', $dependency, $this->getName()),
358
                    UnitObjectException::NoSuchDependency
359
                );
360
            }
361
            $depNode->setAttribute('unresolved', 'true');
362
        }
363
364
        /**
365
         *
366
         */
367
        public function addMethod($name) {
368
            switch ($name) {
369
                case '__construct':
0 ignored issues
show
Coding Style introduced by Arne Blankerts
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
370
                {
371
                    $nodeName = 'constructor';
372
                    break;
373
                }
374
                case '__destruct':
0 ignored issues
show
Coding Style introduced by Arne Blankerts
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
375
                {
376
                    $nodeName = 'destructor';
377
                    break;
378
                }
379
                default:
380
                    $nodeName = 'method';
381
            }
382
            $method = new MethodObject($this, $this->rootNode->appendElementNS(self::XMLNS, $nodeName));
383
            $method->setName($name);
384
            return $method;
385
        }
386
387
        /**
388
         * @return MethodObject[]
389
         */
390 View Code Duplication
        public function getExportedMethods() {
391
            $result = array();
392
            $xpath = '(phpdox:constructor|phpdox:destructor|phpdox:method)[@visibility="public" or @visibility="protected"]';
393
            foreach($this->rootNode->query($xpath) as $node) {
394
                $result[] = new MethodObject($this, $node);
395
            }
396
            return $result;
397
        }
398
399
        /**
400
         * @param $name
401
         *
402
         * @return MemberObject
403
         */
404
        public function addMember($name) {
405
            $member = new MemberObject($this->rootNode->appendElementNS(self::XMLNS, 'member'));
406
            $member->setName($name);
407
            return $member;
408
        }
409
410
        /**
411
         * @return array
412
         */
413 View Code Duplication
        public function getExportedMembers() {
414
            $result = array();
415
            $xpath = 'phpdox:member[@visibility="public" or @visibility="protected"]';
416
            foreach($this->rootNode->query($xpath) as $node) {
417
                $result[] = new MemberObject($node);
418
            }
419
            return $result;
420
        }
421
422
        /**
423
         * @param $name
424
         *
425
         * @return ConstantObject
426
         */
427
        public function addConstant($name) {
428
            $const = new ConstantObject($this->rootNode->appendElementNS(self::XMLNS, 'constant'));
429
            $const->setName($name);
430
            return $const;
431
        }
432
433
        /**
434
         * @return array
435
         */
436
        public function getConstants() {
437
            $result = array();
438
            $xpath = 'phpdox:constant';
439
            foreach($this->rootNode->query($xpath) as $node) {
440
                $result[] = new ConstantObject($node);
441
            }
442
            return $result;
443
        }
444
445
        /**
446
         * @param AbstractUnitObject $unit
447
         */
448
        public function importExports(AbstractUnitObject $unit, $container = 'parent') {
449
450
            $parent = $this->rootNode->queryOne(sprintf('//phpdox:%s[@full="%s"]', $container, $unit->getName()));
451
            if ($parent instanceof fDOMElement) {
452
                $parent->parentNode->removeChild($parent);
453
            }
454
455
            $parent = $this->rootNode->appendElementNS( self::XMLNS, $container);
456
            $parent->setAttribute('full', $unit->getName());
457
            $parent->setAttribute('namespace', $unit->getNamespace());
458
            $parent->setAttribute('name', $unit->getLocalName());
459
460
            if ($unit->hasExtends()) {
461
                foreach($unit->getExtends() as $name) {
462
                    $extends = $parent->appendElementNS( self::XMLNS, 'extends');
463
                    $this->setName($name, $extends);
464
                }
465
            }
466
467
            if ($unit->hasImplements()) {
468
                foreach($unit->getImplements() as $name) {
469
                    $implements = $parent->appendElementNS( self::XMLNS, 'implements');
470
                    $this->setName($name, $implements);
471
                }
472
            }
473
474
            if ($unit->usesTraits()) {
475
                foreach($unit->getUsedTraits() as $name) {
476
                    $uses = $parent->appendElementNS( self::XMLNS, 'uses');
477
                    $this->setName($name, $uses);
478
                }
479
            }
480
481
            foreach($unit->getConstants() as $constant) {
482
                $parent->appendChild( $this->dom->importNode($constant->export(), TRUE) );
483
            }
484
485
            foreach($unit->getExportedMembers() as $member) {
486
                $memberNode = $this->dom->importNode($member->export(), TRUE);
487
                $this->adjustStaticResolution($memberNode);
0 ignored issues
show
Compatibility introduced by Arne Blankerts
$memberNode of type object<DOMNode> is not a sub-type of object<TheSeer\fDOM\fDOMElement>. It seems like you assume a child class of the class DOMNode to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
488
                $parent->appendChild($memberNode);
489
            }
490
491
            foreach($unit->getExportedMethods() as $method) {
492
                $methodNode = $this->dom->importNode($method->export(), TRUE);
493
                $this->adjustStaticResolution($methodNode);
0 ignored issues
show
Compatibility introduced by Arne Blankerts
$methodNode of type object<DOMNode> is not a sub-type of object<TheSeer\fDOM\fDOMElement>. It seems like you assume a child class of the class DOMNode to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
494
                $parent->appendChild( $methodNode );
495
                if ($this->hasMethod($method->getName())) {
496
                    $unitMethod = $this->getMethod($method->getName());
497
                    if ($unitMethod->hasInheritDoc()) {
498
                        $unitMethod->inhertDocBlock($method);
499
                    }
500
                }
501
            }
502
        }
503
504
        public function importTraitExports(AbstractUnitObject $trait, TraitUseObject $use) {
505
506
            $container = $this->rootNode->queryOne(
507
                sprintf(
508
                    'phpdox:trait[@full="%s"]',
509
                    $trait->getName()
510
                )
511
            );
512
            if ($container instanceof fDOMElement) {
513
                $container->parentNode->removeChild($container);
514
            }
515
516
            $container = $this->rootNode->appendElementNS( self::XMLNS, 'trait');
517
            $this->setName($trait->getName(), $container);
518
519
            if ($trait->hasExtends()) {
520
                foreach($trait->getExtends() as $name) {
521
                    $extends = $container->appendElementNS( self::XMLNS, 'extends');
522
                    $this->setName($name, $extends);
523
                }
524
            }
525
526
            if ($trait->usesTraits()) {
527
                foreach($trait->getUsedTraits() as $name) {
528
                    $used = $container->appendElementNS( self::XMLNS, 'uses');
529
                    $this->setName($name, $used);
530
                }
531
            }
532
533
            foreach($trait->getConstants() as $constant) {
534
                $container->appendChild( $this->dom->importNode($constant->export(), TRUE) );
535
            }
536
537
            foreach($trait->getExportedMembers() as $member) {
538
                $memberNode = $this->dom->importNode($member->export(), TRUE);
539
                $this->adjustStaticResolution($memberNode);
0 ignored issues
show
Compatibility introduced by Arne Blankerts
$memberNode of type object<DOMNode> is not a sub-type of object<TheSeer\fDOM\fDOMElement>. It seems like you assume a child class of the class DOMNode to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
540
                $container->appendChild($memberNode);
541
            }
542
543
            $ambiguousContainer = $this->dom->queryOne('//phpdox:ambiguous[@type="trait-alias"]');
544
            foreach($trait->getExportedMethods() as $method) {
545
                $methodName = $method->getName();
546
                $methodNode = $this->dom->importNode($method->export(), TRUE);
547
548
                if (!$use->isExcluded($methodName)) {
549
                    $container->appendChild($methodNode);
550
                }
551
552
                $this->adjustStaticResolution($methodNode);
0 ignored issues
show
Compatibility introduced by Arne Blankerts
$methodNode of type object<DOMNode> is not a sub-type of object<TheSeer\fDOM\fDOMElement>. It seems like you assume a child class of the class DOMNode to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
553
554
                if ($ambiguousContainer !== NULL) {
555
                    $ambiguousMethod = $ambiguousContainer->queryOne(
556
                        sprintf('phpdox:alias[@method="%s"]', $methodName)
557
                    );
558
                    if ($ambiguousMethod !== null) {
559
                        $usesNode = $this->dom->queryOne(
560
                            sprintf('//phpdox:uses[@full="%s"]', $trait->getName())
561
                        );
562
                        $usesNode->appendChild($ambiguousMethod);
563
                        if ($ambiguousContainer->query('phpdox:alias')->length === 0) {
564
                            $ambiguousContainer->parentNode->removeChild($ambiguousContainer);
565
                            $ambiguousContainer = NULL;
566
                        }
567
                    }
568
                }
569
570
                $aliasNode = NULL;
0 ignored issues
show
Unused Code introduced by Arne Blankerts
$aliasNode is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
571
                if ($use->isAliased($methodName)) {
572
                    $aliasNode = $methodNode->cloneNode(true);
573
                    $aliasNode->setAttribute('original', $aliasNode->getAttribute('name'));
574
                    $aliasNode->setAttribute('name', $use->getAliasedName($methodName));
575
                    if ($use->hasAliasedModifier($methodName)) {
576
                        $aliasNode->setAttribute('visibility', $use->getAliasedModifier($methodName));
577
                    }
578
                    $container->appendChild($aliasNode);
579
                }
580
            }
581
582
        }
583
584
        private function hasMethod($name) {
585
            return $this->dom->query(
586
                sprintf('phpdox:method[@name="%s"]', $name)
587
            )->length > 0;
588
        }
589
590
        private function getMethod($name) {
591
            $ctx = $this->dom->queryOne(
592
                sprintf('phpdox:method[@name="%s"]', $name)
593
            );
594
            if (!$ctx) {
595
                throw new UnitObjectException(
596
                    sprintf('Method "%s" not found', $name),
597
                    UnitObjectException::NoSuchMethod
598
                );
599
            }
600
            return new MethodObject($this, $ctx);
0 ignored issues
show
Documentation introduced by Arne Blankerts
$ctx is of type object<TheSeer\fDOM\fDOMNode>, but the function expects a object<TheSeer\fDOM\fDOMElement>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
601
        }
602
603
        private function adjustStaticResolution(fDOMElement $ctx) {
604
            $container = $ctx->queryOne('.//phpdox:docblock/phpdox:return|.//phpdox:docblock/phpdox:var');
605
            if (!$container || $container->getAttribute('resolution') !== 'static') {
606
                return;
607
            }
608
            $type = $container->queryOne('phpdox:type');
609
            if (!$type) {
610
                return;
611
            }
612
            foreach(array('full','namespace','name') as $attribute) {
613
                $type->setAttribute($attribute, $this->rootNode->getAttribute($attribute));
614
            }
615
        }
616
617
        /**
618
         * @param $containerName
619
         * @param $elementName
620
         *
621
         * @return fDOMElement
622
         */
623
        protected function addToContainer($containerName, $elementName) {
624
            $container = $this->rootNode->queryOne('phpdox:' . $containerName);
625
            if (!$container) {
626
                $container = $this->rootNode->appendElementNS(self::XMLNS, $containerName);
627
            }
628
            return $container->appendElementNS(self::XMLNS, $elementName);
629
        }
630
631
    }
632
633
}
634