Completed
Push — master ( 0ff4f4...35f374 )
by Alex
38s
created

verifyFunctionCallOpArguments()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.9713
c 0
b 0
f 0
cc 3
eloc 16
nc 3
nop 3
1
<?php
2
3
namespace POData\UriProcessor\QueryProcessor;
4
5
use POData\Common\ODataException;
6
use POData\Common\Messages;
7
use POData\Common\ODataConstants;
8
use POData\Providers\Metadata\Type\Null1;
9
use POData\Providers\Metadata\Type\Int64;
10
use POData\Providers\Metadata\Type\Int16;
11
use POData\Providers\Metadata\Type\Guid;
12
use POData\Providers\Metadata\Type\Single;
13
use POData\Providers\Metadata\Type\Double;
14
use POData\Providers\Metadata\Type\Decimal;
15
use POData\Providers\Metadata\Type\DateTime;
16
use POData\Providers\Metadata\Type\Int32;
17
use POData\Providers\Metadata\Type\StringType;
18
use POData\Providers\Metadata\Type\Boolean;
19
use POData\Providers\Metadata\Type\Binary;
20
use POData\Providers\Metadata\Type\IType;
21
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\AbstractExpression;
22
use POData\UriProcessor\QueryProcessor\ExpressionParser\ExpressionToken;
23
24
/**
25
 * Class FunctionDescription.
26
 *
27
 * Class to represent function signature including function-name
28
 */
29
class FunctionDescription
30
{
31
    /**
32
     * @var string
33
     */
34
    public $name;
35
36
    /**
37
     * @var IType
38
     */
39
    public $returnType;
40
41
    /**
42
     * @var IType[]
43
     */
44
    public $argumentTypes;
45
46
    /**
47
     * Create new instance of FunctionDescription.
48
     *
49
     * @param string  $name          Name of the function
50
     * @param IType   $returnType    Return type
51
     * @param IType[] $argumentTypes Parameter type
52
     */
53
    public function __construct($name, $returnType, $argumentTypes)
54
    {
55
        $this->name = $name;
56
        $this->returnType = $returnType;
57
        $this->argumentTypes = $argumentTypes;
58
    }
59
60
    /**
61
     * Get the function prototype as string.
62
     *
63
     * @return string
64
     */
65
    public function getPrototypeAsString()
66
    {
67
        $str = $this->returnType->getFullTypeName() . ' ' . $this->name . '(';
68
69
        foreach ($this->argumentTypes as $argumentType) {
70
            $str .= $argumentType->getFullTypeName() . ', ';
71
        }
72
73
        return rtrim($str, ', ') . ')';
74
    }
75
76
    /**
77
     * Create function descriptions for supported function-calls in $filter option.
78
     *
79
     * TODO: FIGURE OUT WHAT THE HECK THIS IS RETURNING!?!?
80
     *
81
     * @return array indexed by function name
82
     */
83
    public static function filterFunctionDescriptions()
84
    {
85
        $functions = array(
86
            //EdmString Functions
87
            'endswith' => array(
88
                    new self(
89
                        'endswith',
90
                        new Boolean(),
91
                        array(new StringType(), new StringType())
92
                    ),
93
                ),
94
            'indexof' => array(
95
                    new self(
96
                        'indexof',
97
                        new Int32(),
98
                        array(new StringType(), new StringType())
99
                    ),
100
                ),
101
            'replace' => array(
102
                    new self(
103
                        'replace',
104
                        new StringType(),
105
                        array(new StringType(), new StringType(), new StringType())
106
                    ),
107
                ),
108
            'startswith' => array(
109
                    new self(
110
                        'startswith',
111
                        new Boolean(),
112
                        array(new StringType(), new StringType())
113
                    ),
114
                ),
115
            'tolower' => array(
116
                    new self(
117
                        'tolower',
118
                        new StringType(),
119
                        array(new StringType())
120
                    ),
121
                ),
122
            'toupper' => array(
123
                    new self(
124
                        'toupper',
125
                        new StringType(),
126
                        array(new StringType())
127
                    ),
128
                ),
129
            'trim' => array(
130
                    new self(
131
                        'trim',
132
                        new StringType(),
133
                        array(new StringType())
134
                    ),
135
                ),
136
            'substring' => array(
137
                    new self(
138
139
                        'substring',
140
                        new StringType(),
141
                        array(new StringType(), new Int32())
142
                    ),
143
                    new self(
144
                        'substring',
145
                        new StringType(),
146
                        array(new StringType(), new Int32(), new Int32())
147
                    ),
148
                ),
149
            'substringof' => array(
150
                    new self(
151
                        'substringof',
152
                        new Boolean(),
153
                        array(new StringType(), new StringType())
154
                    ),
155
                ),
156
            'concat' => array(
157
                    new self(
158
                        'concat',
159
                        new StringType(),
160
                        array(new StringType(), new StringType())
161
                    ),
162
                ),
163
            'length' => array(
164
                    new self(
165
                        'length',
166
                        new Int32(),
167
                        array(new StringType())
168
                    ),
169
                ),
170
            //DateTime functions
171
            'year' => array(
172
                    new self(
173
                        'year',
174
                        new Int32(),
175
                        array(new DateTime())
176
                    ),
177
                ),
178
            'month' => array(
179
                    new self(
180
                        'month',
181
                        new Int32(),
182
                        array(new DateTime())
183
                    ),
184
                ),
185
            'day' => array(
186
                    new self(
187
                        'day',
188
                        new Int32(),
189
                        array(new DateTime())
190
                    ),
191
                ),
192
            'hour' => array(
193
                    new self(
194
                        'hour',
195
                        new Int32(),
196
                        array(new DateTime())
197
                    ),
198
                ),
199
            'minute' => array(
200
                    new self(
201
                        'minute',
202
                        new Int32(),
203
                        array(new DateTime())
204
                    ),
205
                ),
206
            'second' => array(
207
                    new self(
208
                        'second',
209
                        new Int32(),
210
                        array(new DateTime())
211
                    ),
212
                ),
213
            //Math Functions
214
            'round' => array(
215
                    new self(
216
                        'round',
217
                        new Decimal(),
218
                        array(new Decimal())
219
                    ),
220
                    new self(
221
                        'round',
222
                        new Double(),
223
                        array(new Double())
224
                    ),
225
                ),
226
            'ceiling' => array(
227
                    new self(
228
                        'ceiling',
229
                        new Decimal(),
230
                        array(new Decimal())
231
                    ),
232
                    new self(
233
                        'ceiling',
234
                        new Double(),
235
                        array(new Double())
236
                    ),
237
                ),
238
            'floor' => array(
239
                    new self(
240
                        'floor',
241
                        new Decimal(),
242
                        array(new Decimal())
243
                    ),
244
                    new self(
245
                        'floor',
246
                        new Double(),
247
                        array(new Double())
248
                    ),
249
                ),
250
            );
251
252
        return $functions;
253
    }
254
255
    /**
256
     * Get function description for string comparison.
257
     *
258
     * @return FunctionDescription[]
259
     */
260
    public static function stringComparisonFunctions()
261
    {
262
        return array(
263
            new self(
264
                'strcmp',
265
                new Int32(),
266
                array(new StringType(), new StringType())
267
            ),
268
        );
269
    }
270
271
    /**
272
     * Get function description for datetime comparison.
273
     *
274
     * @return FunctionDescription[]
275
     */
276
    public static function dateTimeComparisonFunctions()
277
    {
278
        return array(
279
            new self(
280
                'dateTimeCmp',
281
                new Int32(),
282
                array(new DateTime(), new DateTime())
283
            ),
284
        );
285
    }
286
287
    /**
288
     * Get function description for guid equality check.
289
     *
290
     * @return FunctionDescription[]
291
     */
292
    public static function guidEqualityFunctions()
293
    {
294
        return array(
295
            new self(
296
                'guidEqual',
297
                new Boolean(),
298
                array(new Guid(), new Guid())
299
            ),
300
        );
301
    }
302
303
    /**
304
     * Get function description for binary equality check.
305
     *
306
     * @return FunctionDescription[]
307
     */
308
    public static function binaryEqualityFunctions()
309
    {
310
        return array(
311
            new self(
312
                'binaryEqual',
313
                new Boolean(),
314
                array(new Binary(), new Binary())
315
            ),
316
        );
317
    }
318
319
    /**
320
     * Get function descriptions for arithmetic operations.
321
     *
322
     * @return FunctionDescription[]
323
     */
324
    public static function arithmeticOperationFunctions()
325
    {
326
        return array(
327
            new self(
328
                'F',
329
                new int16(),
330
                array(new int16(), new int16())
331
            ),
332
            new self(
333
                'F',
334
                new int32(),
335
                array(new int32(), new int32())
336
            ),
337
            new self(
338
                'F',
339
                new int64(),
340
                array(new int64(), new int64())
341
            ),
342
            new self(
343
                'F',
344
                new Single(),
345
                array(new Single(), new Single())
346
            ),
347
            new self(
348
                'F',
349
                new Double(),
350
                array(new Double(), new Double())
351
            ),
352
            new self(
353
                'F',
354
                new Decimal(),
355
                array(new Decimal(), new Decimal())
356
            ),
357
        );
358
    }
359
360
    /**
361
     * Get function descriptions for arithmetic add operations.
362
     *
363
     * @return FunctionDescription[] indexed by function name
364
     */
365
    public static function addOperationFunctions()
366
    {
367
        return self::arithmeticOperationFunctions();
368
    }
369
370
    /**
371
     * Get function descriptions for arithmetic subtract operations.
372
     *
373
     * @return FunctionDescription[] indexed by function name
374
     */
375
    public static function subtractOperationFunctions()
376
    {
377
        return self::arithmeticOperationFunctions();
378
    }
379
380
    /**
381
     * Get function descriptions for logical operations.
382
     *
383
     * @return FunctionDescription[]
384
     */
385
    public static function logicalOperationFunctions()
386
    {
387
        return array(
388
            new self(
389
                'F',
390
                new Boolean(),
391
                array(new Boolean(), new Boolean())
392
            ),
393
        );
394
    }
395
396
    /**
397
     * Get function descriptions for relational operations.
398
     *
399
     * @return FunctionDescription[]
400
     */
401
    public static function relationalOperationFunctions()
402
    {
403
        return array_merge(
404
            self::arithmeticOperationFunctions(),
405
            array(
406
                new self(
407
                    'F',
408
                    new Boolean(),
409
                    array(new Boolean(), new Boolean())
410
                ),
411
                new self(
412
                    'F',
413
                    new DateTime(),
414
                    array(new DateTime(), new DateTime())
415
                ),
416
                new self(
417
                    'F',
418
                    new Guid(),
419
                    array(new Guid(), new Guid())
420
                ),
421
                new self(
422
                    'F',
423
                    new Boolean(),
424
                    array(new Binary(), new Binary())
425
                ),
426
            )
427
        );
428
    }
429
430
    /**
431
     * Get function descriptions for unary not operation.
432
     *
433
     * @return FunctionDescription[]
434
     */
435
    public static function notOperationFunctions()
436
    {
437
        return array(
438
            new self(
439
                'F',
440
                new Boolean(),
441
                array(new Boolean())
442
            ),
443
        );
444
    }
445
446
    /**
447
     * Get function description for checking an operand is null or not.
448
     *
449
     * @param IType $type Type of the argument to null check function
450
     *
451
     * @return \POData\UriProcessor\QueryProcessor\FunctionDescription
452
     */
453
    public static function isNullCheckFunction(IType $type)
454
    {
455
        return new self('is_null', new Boolean(), array($type));
456
    }
457
458
    /**
459
     * Get function description for unary negate operator.
460
     *
461
     * @return FunctionDescription[]
462
     */
463
    public static function negateOperationFunctions()
464
    {
465
        return array(
466
            new self('F', new Int16(), array(new Int16())),
467
            new self('F', new Int32(), array(new Int32())),
468
            new self('F', new Int64(), array(new Int64())),
469
            new self('F', new Single(), array(new Single())),
470
            new self('F', new Double(), array(new Double())),
471
            new self('F', new Decimal(), array(new Decimal())),
472
        );
473
    }
474
475
    /**
476
     * To throw ODataException for incompatible types.
477
     *
478
     * @param ExpressionToken      $expressionToken Expression token
479
     * @param AbstractExpression[] $argExpressions  Array of argument expression
480
     *
481
     * @throws ODataException
482
     */
483
    public static function incompatibleError($expressionToken, $argExpressions)
484
    {
485
        $string = null;
486
        foreach ($argExpressions as $argExpression) {
487
            $string .= $argExpression->getType()->getFullTypeName() . ', ';
488
        }
489
490
        $string = rtrim($string, ', ');
491
        $pos = strrpos($string, ', ');
492
        if ($pos !== false) {
493
            $string = substr_replace($string, ' and ', strrpos($string, ', '), 2);
494
        }
495
496
        throw ODataException::createSyntaxError(
497
            Messages::expressionParserInCompatibleTypes(
498
                $expressionToken->Text,
499
                $string,
500
                $expressionToken->Position
501
            )
502
        );
503
    }
504
505
    /**
506
     * Validate operands of an arithmetic operation and promote if required.
507
     *
508
     * @param ExpressionToken    $expressionToken The expression token
509
     * @param AbstractExpression $leftArgument    The left expression
510
     * @param AbstractExpression $rightArgument   The right expression
511
     *
512
     * @return IType
513
     */
514 View Code Duplication
    public static function verifyAndPromoteArithmeticOpArguments(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
515
        $expressionToken,
516
        $leftArgument,
517
        $rightArgument
518
    ) {
519
        $function
520
            = self::findFunctionWithPromotion(
521
                self::arithmeticOperationFunctions(),
522
                array($leftArgument, $rightArgument)
523
            );
524
        if ($function == null) {
525
            self::incompatibleError(
526
                $expressionToken,
527
                array($leftArgument, $rightArgument)
528
            );
529
        }
530
531
        return $function->returnType;
532
    }
533
534
    /**
535
     * Validate operands of an logical operation.
536
     *
537
     * @param ExpressionToken    $expressionToken The expression token
538
     * @param AbstractExpression $leftArgument    The left expression
539
     * @param AbstractExpression $rightArgument   The right expression
540
     *
541
     * @throws ODataException
542
     */
543 View Code Duplication
    public static function verifyLogicalOpArguments(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
544
        $expressionToken,
545
        $leftArgument,
546
        $rightArgument
547
    ) {
548
        $function = self::findFunctionWithPromotion(
549
            self::logicalOperationFunctions(),
550
            array($leftArgument, $rightArgument),
551
            false
552
        );
553
        if ($function == null) {
554
            self::incompatibleError(
555
                $expressionToken,
556
                array($leftArgument, $rightArgument)
557
            );
558
        }
559
    }
560
561
    /**
562
     * Validate operands of an relational operation.
563
     *
564
     * @param ExpressionToken    $expressionToken The expression token
565
     * @param AbstractExpression $leftArgument    The left argument expression
566
     * @param AbstractExpression $rightArgument   The right argument expression
567
     */
568
    public static function verifyRelationalOpArguments(
569
        $expressionToken,
570
        $leftArgument,
571
        $rightArgument
572
    ) {
573
        //for null operands only equality operators are allowed
574
        $null = new Null1();
575 View Code Duplication
        if ($leftArgument->typeIs($null) || $rightArgument->typeIs($null)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
576
            if ((strcmp($expressionToken->Text, ODataConstants::KEYWORD_EQUAL) != 0)
577
                && (strcmp($expressionToken->Text, ODataConstants::KEYWORD_NOT_EQUAL) != 0)
578
            ) {
579
                throw ODataException::createSyntaxError(
580
                    Messages::expressionParserOperatorNotSupportNull(
581
                        $expressionToken->Text,
582
                        $expressionToken->Position
583
                    )
584
                );
585
            }
586
587
            return;
588
        }
589
590
        //for guid operands only equality operators are allowed
591
        $guid = new Guid();
592 View Code Duplication
        if ($leftArgument->typeIs($guid) && $rightArgument->typeIs($guid)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
593
            if ((strcmp($expressionToken->Text, ODataConstants::KEYWORD_EQUAL) != 0)
594
                && (strcmp($expressionToken->Text, ODataConstants::KEYWORD_NOT_EQUAL) != 0)
595
            ) {
596
                throw ODataException::createSyntaxError(
597
                    Messages::expressionParserOperatorNotSupportGuid(
598
                        $expressionToken->Text,
599
                        $expressionToken->Position
600
                    )
601
                );
602
            }
603
604
            return;
605
        }
606
607
        //for binary operands only equality operators are allowed
608
        $binary = new Binary();
609 View Code Duplication
        if ($leftArgument->typeIs($binary) && $rightArgument->typeIs($binary)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
610
            if ((strcmp($expressionToken->Text, ODataConstants::KEYWORD_EQUAL) != 0)
611
                && (strcmp($expressionToken->Text, ODataConstants::KEYWORD_NOT_EQUAL) != 0)
612
            ) {
613
                throw ODataException::createSyntaxError(
614
                    Messages::expressionParserOperatorNotSupportBinary(
615
                        $expressionToken->Text,
616
                        $expressionToken->Position
617
                    )
618
                );
619
            }
620
621
            return;
622
        }
623
624
        //TODO: eq and ne is valid for 'resource reference'
625
        //navigation also verify here
626
627
        $functions = array_merge(
628
            self::relationalOperationFunctions(),
629
            self::stringComparisonFunctions()
630
        );
631
        $function = self::findFunctionWithPromotion(
632
            $functions,
633
            array($leftArgument, $rightArgument),
634
            false
635
        );
636
        if ($function == null) {
637
            self::incompatibleError(
638
                $expressionToken,
639
                array($leftArgument, $rightArgument)
640
            );
641
        }
642
    }
643
644
    /**
645
     * Validate operands of a unary  operation.
646
     *
647
     * @param ExpressionToken    $expressionToken The expression token
648
     * @param AbstractExpression $argExpression   Argument expression
649
     *
650
     * @throws ODataException
651
     */
652
    public static function validateUnaryOpArguments($expressionToken, $argExpression)
653
    {
654
        //Unary not
655 View Code Duplication
        if (strcmp($expressionToken->Text, ODataConstants::KEYWORD_NOT) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
656
            $function = self::findFunctionWithPromotion(
657
                self::notOperationFunctions(),
658
                array($argExpression)
659
            );
660
            if ($function == null) {
661
                self::incompatibleError($expressionToken, array($argExpression));
662
            }
663
664
            return;
665
        }
666
667
        //Unary minus (negation)
668 View Code Duplication
        if (strcmp($expressionToken->Text, '-') == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
669
            if (self::findFunctionWithPromotion(self::negateOperationFunctions(), array($argExpression)) == null) {
670
                self::incompatibleError($expressionToken, array($argExpression));
671
            }
672
        }
673
    }
674
675
    /**
676
     * Check am identifier is a valid filter function.
677
     *
678
     * @param ExpressionToken $expressionToken The expression token
679
     *
680
     * @throws ODataException
681
     *
682
     * @return FunctionDescription[] Array of matching functions
683
     */
684
    public static function verifyFunctionExists($expressionToken)
685
    {
686
        if (!array_key_exists($expressionToken->Text, self::filterFunctionDescriptions())) {
687
            throw ODataException::createSyntaxError(
688
                Messages::expressionParserUnknownFunction(
689
                    $expressionToken->Text,
690
                    $expressionToken->Position
691
                )
692
            );
693
        }
694
695
        $filterFunctions = self::filterFunctionDescriptions();
696
697
        return $filterFunctions[$expressionToken->Text];
698
    }
699
700
    /**
701
     * Validate operands (arguments) of a function call operation and return
702
     * matching function.
703
     *
704
     * @param \POData\UriProcessor\QueryProcessor\FunctionDescription[] $functions       List of functions to be checked
705
     * @param AbstractExpression[]                                      $argExpressions  Function argument expressions
706
     * @param ExpressionToken                                           $expressionToken Expression token
707
     *
708
     * @throws ODataException
709
     *
710
     * @return \POData\UriProcessor\QueryProcessor\FunctionDescription
711
     */
712
    public static function verifyFunctionCallOpArguments(
713
        $functions,
714
        $argExpressions,
715
        $expressionToken
716
    ) {
717
        $function
718
            = self::findFunctionWithPromotion($functions, $argExpressions, false);
719
        if ($function == null) {
720
            $protoTypes = null;
721
            foreach ($functions as $function) {
722
                $protoTypes .= $function->getPrototypeAsString() . '; ';
723
            }
724
725
            throw ODataException::createSyntaxError(
726
                Messages::expressionLexerNoApplicableFunctionsFound(
727
                    $expressionToken->Text,
728
                    $protoTypes,
729
                    $expressionToken->Position
730
                )
731
            );
732
        }
733
734
        return $function;
735
    }
736
737
    /**
738
     * Finds a function from the list of functions whose argument types matches
739
     * with types of expressions.
740
     *
741
     * @param \POData\UriProcessor\QueryProcessor\FunctionDescription[] $functionDescriptions List of functions
742
     * @param AbstractExpression[]                                      $argExpressions       Function argument expressions
743
     * @param bool                                                      $promoteArguments     Function argument
744
     *
745
     * @return \POData\UriProcessor\QueryProcessor\FunctionDescription|null Reference to the matching function if
746
     *                                                                      found else NULL
747
     */
748
    public static function findFunctionWithPromotion(
749
        $functionDescriptions,
750
        $argExpressions,
751
        $promoteArguments = true
752
    ) {
753
        $argCount = count($argExpressions);
754
        $applicableFunctions = array();
755
        foreach ($functionDescriptions as $functionDescription) {
756
            if (count($functionDescription->argumentTypes) == $argCount) {
757
                $applicableFunctions[] = $functionDescription;
758
            }
759
        }
760
761
        if (empty($applicableFunctions)) {
762
            return null;
763
        }
764
765
        //Check for exact match
766
        foreach ($applicableFunctions as $function) {
767
            $i = 0;
768
            foreach ($function->argumentTypes as $argumentType) {
769
                if (!$argExpressions[$i]->typeIs($argumentType)) {
770
                    break;
771
                }
772
773
                ++$i;
774
            }
775
776
            if ($i == $argCount) {
777
                return $function;
778
            }
779
        }
780
781
        //Check match with promotion
782
        $promotedTypes = array();
0 ignored issues
show
Unused Code introduced by
$promotedTypes 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...
783
        foreach ($applicableFunctions as $function) {
784
            $i = 0;
785
            $promotedTypes = array();
786
            foreach ($function->argumentTypes as $argumentType) {
787
                if (!$argumentType->isCompatibleWith($argExpressions[$i]->getType())) {
788
                    break;
789
                }
790
791
                $promotedTypes[] = $argumentType;
792
                ++$i;
793
            }
794
795
            if ($i == $argCount) {
796
                $i = 0;
797
                if ($promoteArguments) {
798
                    //Promote Argument Expressions
799
                    foreach ($argExpressions as $expression) {
800
                        $expression->setType($promotedTypes[$i++]);
801
                    }
802
                }
803
804
                return $function;
805
            }
806
        }
807
808
        return null;
809
    }
810
}
811