Passed
Branch master (950424)
by Christopher
11:06
created

ExpressionLexer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace POData\UriProcessor\QueryProcessor\ExpressionParser;
4
5
use POData\Common\Messages;
6
use POData\Common\ODataConstants;
7
use POData\Common\ODataException;
8
use POData\Providers\Metadata\Type\Char;
0 ignored issues
show
Bug introduced by
The type POData\Providers\Metadata\Type\Char was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
10
/**
11
 * Class ExpressionLexer.
12
 *
13
 * Lexical analyzer for Astoria URI expression parsing
14
 * Literals        Representation
15
 * --------------------------------------------------------------------
16
 * Null            null
17
 * Boolean         true | false
18
 * Int32           (digit+)
19
 * Int64           (digit+)(L|l)
20
 * Decimal         (digit+ ['.' digit+])(M|m)
21
 * Float (Single)  (digit+ ['.' digit+][e|E [+|-] digit+)(f|F)
22
 * Double          (digit+ ['.' digit+][e|E [+|-] digit+)
23
 * String          "'" .* "'"
24
 * DateTime        datetime"'"dddd-dd-dd[T|' ']dd:mm[ss[.fffffff]]"'"
25
 * Binary          (binary|X)'digit*'
26
 * GUID            guid'digit*
27
 */
28
class ExpressionLexer
29
{
30
    /**
31
     * Suffix for single literals.
32
     *
33
     * @var char
34
     */
35
    const SINGLE_SUFFIX_LOWER = 'f';
36
37
    /**
38
     * Suffix for single literals.
39
     *
40
     * @var char
41
     */
42
    const SINGLE_SUFFIX_UPPER = 'F';
43
44
    /**
45
     * Text being parsed.
46
     *
47
     * @var string
48
     */
49
    private $text;
50
51
    /**
52
     * Length of text being parsed.
53
     *
54
     * @var int
55
     */
56
    private $textLen;
57
58
    /**
59
     * Position on text being parsed.
60
     *
61
     * @var int
62
     */
63
    private $textPos;
64
65
    /**
66
     * Character being processed.
67
     *
68
     * @var string
69
     */
70
    private $ch;
71
72
    /**
73
     * ExpressionToken being processed.
74
     *
75
     * @var ExpressionToken
76
     */
77
    private $token;
78
79
    /**
80
     * Initialize a new instance of ExpressionLexer.
81
     *
82
     * @param string $expression Expression to parse
83
     */
84
    public function __construct($expression)
85
    {
86
        $this->text = $expression;
87
        $this->textLen = strlen($this->text);
88
        $this->token = new ExpressionToken();
89
        $this->setTextPos(0);
90
        $this->nextToken();
91
    }
92
93
    /**
94
     * To get the expression token being processed.
95
     *
96
     * @return ExpressionToken
97
     */
98
    public function getCurrentToken()
99
    {
100
        return $this->token;
101
    }
102
103
    /**
104
     * To set the token being processed.
105
     *
106
     * @param ExpressionToken $token The expression token to set as current
107
     */
108
    public function setCurrentToken(ExpressionToken $token)
109
    {
110
        $this->token = $token;
111
    }
112
113
    /**
114
     * To get the text being parsed.
115
     *
116
     * @return string
117
     */
118
    public function getExpressionText()
119
    {
120
        return $this->text;
121
    }
122
123
    /**
124
     * Position of the current token in the text being parsed.
125
     *
126
     * @return int
127
     */
128
    public function getPosition()
129
    {
130
        return $this->token->Position;
131
    }
132
133
    /**
134
     * Whether the specified token identifier is a numeric literal.
135
     *
136
     * @param ExpressionTokenId $id Token identifier to check
137
     *
138
     * @return bool true if it's a numeric literal; false otherwise
139
     */
140
    public static function isNumeric($id)
141
    {
142
        return
143
            $id == ExpressionTokenId::INTEGER_LITERAL
144
            || $id == ExpressionTokenId::DECIMAL_LITERAL
145
            || $id == ExpressionTokenId::DOUBLE_LITERAL
146
            || $id == ExpressionTokenId::INT64_LITERAL
147
            || $id == ExpressionTokenId::SINGLE_LITERAL;
148
    }
149
150
    /**
151
     * Reads the next token, skipping whitespace as necessary.
152
     */
153
    public function nextToken()
154
    {
155
        while (Char::isWhiteSpace($this->ch)) {
156
            $this->nextChar();
157
        }
158
159
        $t = null;
160
        $tokenPos = $this->textPos;
161
        switch ($this->ch) {
162
            case '(':
163
                $this->nextChar();
164
                $t = ExpressionTokenId::OPENPARAM;
165
                break;
166
            case ')':
167
                $this->nextChar();
168
                $t = ExpressionTokenId::CLOSEPARAM;
169
                break;
170
            case ',':
171
                $this->nextChar();
172
                $t = ExpressionTokenId::COMMA;
173
                break;
174
            case '-':
175
                $hasNext = $this->textPos + 1 < $this->textLen;
176
                if ($hasNext && Char::isDigit($this->text[$this->textPos + 1])) {
177
                    $this->nextChar();
178
                    $t = $this->parseFromDigit();
179
                    if (self::isNumeric($t)) {
180
                        break;
181
                    }
182
                } elseif ($hasNext && $this->text[$tokenPos + 1] == 'I') {
183
                    $this->nextChar();
184
                    $this->parseIdentifier();
185
                    $currentIdentifier = substr($this->text, $tokenPos + 1, $this->textPos - $tokenPos - 1);
186
187
                    if (self::isInfinityLiteralDouble($currentIdentifier)) {
0 ignored issues
show
Bug introduced by
It seems like $currentIdentifier can also be of type false; however, parameter $text of POData\UriProcessor\Quer...InfinityLiteralDouble() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

187
                    if (self::isInfinityLiteralDouble(/** @scrutinizer ignore-type */ $currentIdentifier)) {
Loading history...
188
                        $t = ExpressionTokenId::DOUBLE_LITERAL;
189
                        break;
190
                    } elseif (self::isInfinityLiteralSingle($currentIdentifier)) {
0 ignored issues
show
Bug introduced by
It seems like $currentIdentifier can also be of type false; however, parameter $text of POData\UriProcessor\Quer...InfinityLiteralSingle() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

190
                    } elseif (self::isInfinityLiteralSingle(/** @scrutinizer ignore-type */ $currentIdentifier)) {
Loading history...
191
                        $t = ExpressionTokenId::SINGLE_LITERAL;
192
                        break;
193
                    }
194
195
                    // If it looked like '-INF' but wasn't we'll rewind and fall through to a simple '-' token.
196
                }
197
                $this->setTextPos($tokenPos);
198
                $this->nextChar();
199
                $t = ExpressionTokenId::MINUS;
200
                break;
201
            case '=':
202
                $this->nextChar();
203
                $t = ExpressionTokenId::EQUAL;
204
                break;
205
            case '/':
206
                $this->nextChar();
207
                $t = ExpressionTokenId::SLASH;
208
                break;
209
            case '?':
210
                $this->nextChar();
211
                $t = ExpressionTokenId::QUESTION;
212
                break;
213
            case '.':
214
                $this->nextChar();
215
                $t = ExpressionTokenId::DOT;
216
                break;
217
            case '\'':
218
                $quote = $this->ch;
219
                do {
220
                    $this->nextChar();
221
                    while ($this->textPos < $this->textLen && $this->ch != $quote) {
222
                        $this->nextChar();
223
                    }
224
225
                    if ($this->textPos == $this->textLen) {
226
                        $this->parseError(
227
                            Messages::expressionLexerUnterminatedStringLiteral(
228
                                $this->textPos,
229
                                $this->text
230
                            )
231
                        );
232
                    }
233
234
                    $this->nextChar();
235
                } while ($this->ch == $quote);
236
                $t = ExpressionTokenId::STRING_LITERAL;
237
                break;
238
            case '*':
239
                $this->nextChar();
240
                $t = ExpressionTokenId::STAR;
241
                break;
242
            default:
243
                if (Char::isLetter($this->ch) || $this->ch == '_') {
244
                    $this->parseIdentifier();
245
                    $t = ExpressionTokenId::IDENTIFIER;
246
                    break;
247
                }
248
249
                if (Char::isDigit($this->ch)) {
250
                    $t = $this->parseFromDigit();
251
                    break;
252
                }
253
254
                if ($this->textPos == $this->textLen) {
255
                    $t = ExpressionTokenId::END;
256
                    break;
257
                }
258
259
                $this->parseError(
260
                    Messages::expressionLexerInvalidCharacter(
261
                        $this->ch,
262
                        $this->textPos
263
                    )
264
                );
265
        }
266
267
        $this->token->Id = $t;
0 ignored issues
show
Documentation Bug introduced by
It seems like $t can also be of type integer. However, the property $Id is declared as type POData\UriProcessor\Quer...arser\ExpressionTokenId. Maybe add an additional type 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 mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
268
        $this->token->Text = substr($this->text, $tokenPos, $this->textPos - $tokenPos);
0 ignored issues
show
Documentation Bug introduced by
It seems like substr($this->text, $tok...s->textPos - $tokenPos) can also be of type false. However, the property $Text is declared as type string. Maybe add an additional type 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 mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
269
        $this->token->Position = $tokenPos;
270
271
        // Handle type-prefixed literals such as binary, datetime or guid.
272
        $this->handleTypePrefixedLiterals();
273
274
        // Handle keywords.
275
        if ($this->token->Id == ExpressionTokenId::IDENTIFIER) {
276
            if (self::isInfinityOrNaNDouble($this->token->Text)) {
0 ignored issues
show
Bug introduced by
It seems like $this->token->Text can also be of type false; however, parameter $tokenText of POData\UriProcessor\Quer...isInfinityOrNaNDouble() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

276
            if (self::isInfinityOrNaNDouble(/** @scrutinizer ignore-type */ $this->token->Text)) {
Loading history...
277
                $this->token->Id = ExpressionTokenId::DOUBLE_LITERAL;
278
            } elseif (self::isInfinityOrNanSingle($this->token->Text)) {
0 ignored issues
show
Bug introduced by
It seems like $this->token->Text can also be of type false; however, parameter $tokenText of POData\UriProcessor\Quer...isInfinityOrNanSingle() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

278
            } elseif (self::isInfinityOrNanSingle(/** @scrutinizer ignore-type */ $this->token->Text)) {
Loading history...
279
                $this->token->Id = ExpressionTokenId::SINGLE_LITERAL;
280
            } elseif ($this->token->Text == ODataConstants::KEYWORD_TRUE
281
                || $this->token->Text == ODataConstants::KEYWORD_FALSE
282
            ) {
283
                $this->token->Id = ExpressionTokenId::BOOLEAN_LITERAL;
284
            } elseif ($this->token->Text == ODataConstants::KEYWORD_NULL) {
285
                $this->token->Id = ExpressionTokenId::NULL_LITERAL;
286
            }
287
        }
288
    }
289
290
    /**
291
     * Returns the next token without advancing the lexer to next token.
292
     *
293
     * @return ExpressionToken
294
     */
295
    public function peekNextToken()
296
    {
297
        $savedTextPos = $this->textPos;
298
        assert(2 >= strlen($this->ch));
0 ignored issues
show
Bug introduced by
The call to assert() has too few arguments starting with description. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

298
        /** @scrutinizer ignore-call */ 
299
        assert(2 >= strlen($this->ch));

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
299
        $savedChar = $this->ch;
300
        $savedToken = clone $this->token;
301
        $this->nextToken();
302
        $result = clone $this->token;
303
        $this->textPos = $savedTextPos;
304
        $this->ch = $savedChar;
305
        $this->token->Id = $savedToken->Id;
306
        $this->token->Position = $savedToken->Position;
307
        $this->token->Text = $savedToken->Text;
308
309
        return $result;
310
    }
311
312
    /**
313
     * Validates the current token is of the specified kind.
314
     *
315
     * @param ExpressionTokenId $tokenId Expected token kind
316
     *
317
     * @throws ODataException if current token is not of the
318
     *                        specified kind
319
     */
320
    public function validateToken($tokenId)
321
    {
322
        if ($this->token->Id != $tokenId) {
323
            $this->parseError(Messages::expressionLexerSyntaxError($this->textPos));
324
        }
325
    }
326
327
    /**
328
     * Starting from an identifier, reads alternate sequence of dots and identifiers
329
     * and returns the text for it.
330
     *
331
     * @return string The dotted identifier starting at the current identifier
332
     */
333
    public function readDottedIdentifier()
334
    {
335
        $this->validateToken(ExpressionTokenId::IDENTIFIER);
0 ignored issues
show
Bug introduced by
POData\UriProcessor\Quer...sionTokenId::IDENTIFIER of type integer is incompatible with the type POData\UriProcessor\Quer...arser\ExpressionTokenId expected by parameter $tokenId of POData\UriProcessor\Quer...nLexer::validateToken(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

335
        $this->validateToken(/** @scrutinizer ignore-type */ ExpressionTokenId::IDENTIFIER);
Loading history...
336
        $identifier = $this->token->Text;
337
        $this->nextToken();
338
        while ($this->token->Id == ExpressionTokenId::DOT) {
339
            $this->nextToken();
340
            $this->validateToken(ExpressionTokenId::IDENTIFIER);
341
            $identifier = $identifier . '.' . $this->token->Text;
342
            $this->nextToken();
343
        }
344
345
        return $identifier;
346
    }
347
348
    /**
349
     * Check if the parameter ($tokenText) is INF or NaN.
350
     *
351
     * @param string $tokenText Text to look in
352
     *
353
     * @return bool true if match found, false otherwise
354
     */
355
    private static function isInfinityOrNaNDouble($tokenText)
356
    {
357
        if (strlen($tokenText) == 3) {
358
            if ($tokenText[0] == 'I') {
359
                return self::isInfinityLiteralDouble($tokenText);
360
            } elseif ($tokenText[0] == 'N') {
361
                return strncmp($tokenText, ODataConstants::XML_NAN_LITERAL, 3) == 0;
362
            }
363
        }
364
365
        return false;
366
    }
367
368
    /**
369
     * Check if the parameter ($text) is INF.
370
     *
371
     * @param string $text Text to look in
372
     *
373
     * @return bool true if match found, false otherwise
374
     */
375
    private static function isInfinityLiteralDouble($text)
376
    {
377
        return strcmp($text, ODataConstants::XML_INFINITY_LITERAL) == 0;
378
    }
379
380
    /**
381
     * Checks if the parameter ($tokenText) is INFf/INFF or NaNf/NaNF.
382
     *
383
     * @param string $tokenText Input token
384
     *
385
     * @return bool true if match found, false otherwise
386
     */
387
    private static function isInfinityOrNanSingle($tokenText)
388
    {
389
        if (strlen($tokenText) == 4) {
390
            if ($tokenText[0] == 'I') {
391
                return self::isInfinityLiteralSingle($tokenText);
392
            } elseif ($tokenText[0] == 'N') {
393
                return ($tokenText[3] == self::SINGLE_SUFFIX_LOWER
394
                    || $tokenText[3] == self::SINGLE_SUFFIX_UPPER)
395
                    && strncmp($tokenText, ODataConstants::XML_NAN_LITERAL, 3) == 0;
396
            }
397
        }
398
399
        return false;
400
    }
401
402
    /**
403
     * Checks whether parameter ($text) EQUALS to 'INFf' or 'INFF' at position.
404
     *
405
     * @param string $text Text to look in
406
     *
407
     * @return bool true if the substring is equal using an ordinal comparison;
408
     *              false otherwise
409
     */
410
    private static function isInfinityLiteralSingle($text)
411
    {
412
        return strlen($text) == 4
413
            && ($text[3] == self::SINGLE_SUFFIX_LOWER
414
            || $text[3] == self::SINGLE_SUFFIX_UPPER)
415
            && strncmp($text, ODataConstants::XML_INFINITY_LITERAL, 3) == 0;
416
    }
417
418
    /**
419
     * Handles the literals that are prefixed by types.
420
     * This method modified the token field as necessary.
421
     *
422
     *
423
     * @throws ODataException
424
     */
425
    private function handleTypePrefixedLiterals()
426
    {
427
        $id = $this->token->Id;
428
        if ($id != ExpressionTokenId::IDENTIFIER) {
429
            return;
430
        }
431
432
        $quoteFollows = $this->ch == '\'';
433
        if (!$quoteFollows) {
434
            return;
435
        }
436
437
        $tokenText = $this->token->Text;
438
439
        if (strcasecmp('datetime', $tokenText) == 0) {
440
            $id = ExpressionTokenId::DATETIME_LITERAL;
441
        } elseif (strcasecmp('guid', $tokenText) == 0) {
442
            $id = ExpressionTokenId::GUID_LITERAL;
443
        } elseif (strcasecmp('binary', $tokenText) == 0
444
            || strcasecmp('X', $tokenText) == 0
445
            || strcasecmp('x', $tokenText) == 0
446
        ) {
447
            $id = ExpressionTokenId::BINARY_LITERAL;
448
        } else {
449
            return;
450
        }
451
452
        $tokenPos = $this->token->Position;
453
        do {
454
            $this->nextChar();
455
        } while ($this->ch != '\0' && $this->ch != '\'');
456
457
        if ($this->ch == '\0') {
458
            $this->parseError(
459
                Messages::expressionLexerUnterminatedStringLiteral(
460
                    $this->textPos,
461
                    $this->text
462
                )
463
            );
464
        }
465
466
        $this->nextChar();
467
        $this->token->Id = $id;
468
        $this->token->Text
469
            = substr($this->text, $tokenPos, $this->textPos - $tokenPos);
470
    }
471
472
    /**
473
     * Parses a token that starts with a digit.
474
     *
475
     * @return ExpressionTokenId The kind of token recognized
476
     */
477
    private function parseFromDigit()
478
    {
479
        $startChar = $this->ch;
480
        $this->nextChar();
481
        if ($startChar == '0' && $this->ch == 'x' || $this->ch == 'X') {
482
            $result = ExpressionTokenId::BINARY_LITERAL;
483
            do {
484
                $this->nextChar();
485
            } while (ctype_xdigit($this->ch));
486
        } else {
487
            $result = ExpressionTokenId::INTEGER_LITERAL;
488
            while (Char::isDigit($this->ch)) {
489
                $this->nextChar();
490
            }
491
492
            if ($this->ch == '.') {
493
                $result = ExpressionTokenId::DOUBLE_LITERAL;
494
                $this->nextChar();
495
                $this->validateDigit();
496
497
                do {
498
                    $this->nextChar();
499
                } while (Char::isDigit($this->ch));
500
            }
501
502
            if ($this->ch == 'E' || $this->ch == 'e') {
503
                $result = ExpressionTokenId::DOUBLE_LITERAL;
504
                $this->nextChar();
505
                if ($this->ch == '+' || $this->ch == '-') {
506
                    $this->nextChar();
507
                }
508
509
                $this->validateDigit();
510
                do {
511
                    $this->nextChar();
512
                } while (Char::isDigit($this->ch));
513
            }
514
515
            if ($this->ch == 'M' || $this->ch == 'm') {
516
                $result = ExpressionTokenId::DECIMAL_LITERAL;
517
                $this->nextChar();
518 View Code Duplication
            } elseif ($this->ch == 'd' || $this->ch == 'D') {
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...
519
                $result = ExpressionTokenId::DOUBLE_LITERAL;
520
                $this->nextChar();
521
            } elseif ($this->ch == 'L' || $this->ch == 'l') {
522
                $result = ExpressionTokenId::INT64_LITERAL;
523
                $this->nextChar();
524 View Code Duplication
            } elseif ($this->ch == 'f' || $this->ch == 'F') {
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...
525
                $result = ExpressionTokenId::SINGLE_LITERAL;
526
                $this->nextChar();
527
            }
528
        }
529
530
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns the type integer which is incompatible with the documented return type POData\UriProcessor\Quer...arser\ExpressionTokenId.
Loading history...
531
    }
532
533
    /**
534
     * Parses an identifier by advancing the current character.
535
     */
536
    private function parseIdentifier()
537
    {
538
        do {
539
            $this->nextChar();
540
        } while (Char::isLetterOrDigit($this->ch) || $this->ch == '_');
541
    }
542
543
    /**
544
     * Advance to next character.
545
     */
546
    private function nextChar()
547
    {
548
        if ($this->textPos < $this->textLen) {
549
            ++$this->textPos;
550
        }
551
552
        $nextChar = $this->textPos < $this->textLen ? $this->text[$this->textPos] : '\0';
553
        assert(2 >= strlen($nextChar));
0 ignored issues
show
Bug introduced by
The call to assert() has too few arguments starting with description. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

553
        /** @scrutinizer ignore-call */ 
554
        assert(2 >= strlen($nextChar));

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
554
        $this->ch = $nextChar;
555
    }
556
557
    /**
558
     * Set the text position.
559
     *
560
     * @param int $pos Value to position
561
     */
562
    private function setTextPos($pos)
563
    {
564
        $this->textPos = $pos;
565
        $nextChar = $this->textPos < $this->textLen ? $this->text[$this->textPos] : '\0';
566
        assert(2 >= strlen($nextChar));
0 ignored issues
show
Bug introduced by
The call to assert() has too few arguments starting with description. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

566
        /** @scrutinizer ignore-call */ 
567
        assert(2 >= strlen($nextChar));

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
567
        $this->ch = $nextChar;
568
    }
569
570
    /**
571
     * Validate current character is a digit.
572
     */
573
    private function validateDigit()
574
    {
575
        if (!Char::isDigit($this->ch)) {
576
            $this->parseError(Messages::expressionLexerDigitExpected($this->textPos));
577
        }
578
    }
579
580
    /**
581
     * Throws parser error.
582
     *
583
     * @param string $message The error message
584
     *
585
     * @throws ODataException
586
     */
587
    private function parseError($message)
588
    {
589
        throw ODataException::createSyntaxError($message);
590
    }
591
}
592