← All changes
|
libraries/vendor/PhpSpreadsheet/Calculation/Calculation.php
+22
-20
3.3.3
→
3.4
View file →
| @@ -565,9 +565,9 @@ | ||
| 565 | 565 | fn (array $matches) => 'ANCHORARRAY(' . substr($matches[0], 0, -1) . ')', |
| 566 | 566 | $value |
| 567 | 567 | ); |
| 568 | 568 | } |
| 569 | - $result = self::unwrapResult($this->_calculateFormulaValue($value, $cell->getCoordinate(), $cell)); //* @phpstan-ignore-line | |
| 569 | + $result = self::unwrapResult($this->_calculateFormulaValue($value, $cell->getCoordinate(), $cell)); //* @phpstan-ignore argument.type ($value can be mixed not string) | |
| 570 | 570 | if ($this->spreadsheet === null) { |
| 571 | 571 | throw new Exception('null spreadsheet in calculateCellValue'); |
| 572 | 572 | } |
| 573 | 573 | $cellAddressAttempted = true; |
| @@ -585,9 +585,9 @@ | ||
| 585 | 585 | if (!$cellAddressAttempted) { |
| 586 | 586 | $cellAddress = array_pop($this->cellStack); |
| 587 | 587 | } |
| 588 | 588 | if ($this->spreadsheet !== null && is_array($cellAddress) && array_key_exists('sheet', $cellAddress)) { |
| 589 | - $sheetName = $cellAddress['sheet'] ?? null; | |
| 589 | + $sheetName = $cellAddress['sheet']; | |
| 590 | 590 | $testSheet = is_string($sheetName) ? $this->spreadsheet->getSheetByName($sheetName) : null; |
| 591 | 591 | if ($testSheet !== null && array_key_exists('cell', $cellAddress)) { |
| 592 | 592 | /** @var array{cell: string} $cellAddress */ |
| 593 | 593 | $testSheet->getCell($cellAddress['cell']); |
| @@ -649,8 +649,10 @@ | ||
| 649 | 649 | $result = $this->internalParseFormula($formula); |
| 650 | 650 | |
| 651 | 651 | // Cache the result when caching is enabled (clear cache if it exceeds the maximum size) |
| 652 | 652 | if ($this->formulaTokenCacheMaxSize > 0) { |
| 653 | + // Phpstan says if condition is always false, | |
| 654 | + // but coverage report says next statement is covered. | |
| 653 | 655 | if (count($this->formulaTokenCache) >= $this->formulaTokenCacheMaxSize) { |
| 654 | 656 | $this->formulaTokenCache = []; |
| 655 | 657 | } |
| 656 | 658 | // Cache key is the original formula string (before ANCHORARRAY transformation) |
| @@ -1007,9 +1009,9 @@ | ||
| 1007 | 1009 | $returnMatrix = []; |
| 1008 | 1010 | $pad = $rpad = ', '; |
| 1009 | 1011 | foreach ($value as $row) { |
| 1010 | 1012 | if (is_array($row)) { |
| 1011 | - $returnMatrix[] = implode($pad, array_map([$this, 'showValue'], $row)); // @phpstan-ignore-line | |
| 1013 | + $returnMatrix[] = implode($pad, array_map([$this, 'showValue'], $row)); // @phpstan-ignore argument.type (array_map can theoretically return array<mixed> not array<string>) | |
| 1012 | 1014 | $rpad = '; '; |
| 1013 | 1015 | } else { |
| 1014 | 1016 | $returnMatrix[] = $this->showValue($row); |
| 1015 | 1017 | } |
| @@ -1409,9 +1411,9 @@ | ||
| 1409 | 1411 | } elseif ($isOperandOrFunction && !$expectingOperatorCopy) { |
| 1410 | 1412 | // do we now have a function/variable/number? |
| 1411 | 1413 | $expectingOperator = true; |
| 1412 | 1414 | $expectingOperand = false; |
| 1413 | - $val = $match[1] ?? ''; //* @phpstan-ignore-line | |
| 1415 | + $val = $match[1] ?? ''; | |
| 1414 | 1416 | $length = strlen($val); |
| 1415 | 1417 | |
| 1416 | 1418 | if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/miu', $val, $matches)) { |
| 1417 | 1419 | // $val is known to be valid unicode from statement above, so Preg::replace is okay even with u modifier |
| @@ -1562,9 +1564,9 @@ | ||
| 1562 | 1564 | $val = "{$rangeWS2}{$endRowColRef}{$val}"; |
| 1563 | 1565 | } elseif (ctype_alpha($val) && strlen($val) <= 3) { |
| 1564 | 1566 | // Column range |
| 1565 | 1567 | $stackItemType = 'Column Reference'; |
| 1566 | - $endRowColRef = ($refSheet !== null) ? $refSheet->getHighestDataRow($val) : AddressRange::MAX_ROW; // Max 1,048,576 rows for Excel2007 | |
| 1568 | + $endRowColRef = ($refSheet !== null) ? $refSheet->getHighestDataRow() : AddressRange::MAX_ROW; // Max 1,048,576 rows for Excel2007 | |
| 1567 | 1569 | $val = "{$rangeWS2}{$val}{$endRowColRef}"; |
| 1568 | 1570 | } |
| 1569 | 1571 | $stackItemReference = $val; |
| 1570 | 1572 | } |
| @@ -1588,9 +1590,9 @@ | ||
| 1588 | 1590 | $stackItemType = 'Row Reference'; |
| 1589 | 1591 | // unescape any apostrophes or double quotes in worksheet name |
| 1590 | 1592 | $val = str_replace(["''", '""'], ["'", '"'], $val); |
| 1591 | 1593 | $column = 'A'; |
| 1592 | - if (($testPrevOp !== null && $testPrevOp['value'] === ':') && $pCellParent !== null) { // @phpstan-ignore-line | |
| 1594 | + if (($testPrevOp !== null && $testPrevOp['value'] === ':') && $pCellParent !== null) { // @phpstan-ignore booleanAnd.alwaysFalse (testPrevop must be non-null), booleanAnd.alwaysFalse (ditto), identical.alwaysFalse (ditto) | |
| 1593 | 1595 | $column = $pCellParent->getHighestDataColumn($val); |
| 1594 | 1596 | } |
| 1595 | 1597 | $val = "{$rowRangeReference[2]}{$column}{$rowRangeReference[7]}"; |
| 1596 | 1598 | $stackItemReference = $val; |
| @@ -1602,9 +1604,9 @@ | ||
| 1602 | 1604 | $stackItemType = 'Column Reference'; |
| 1603 | 1605 | // unescape any apostrophes or double quotes in worksheet name |
| 1604 | 1606 | $val = str_replace(["''", '""'], ["'", '"'], $val); |
| 1605 | 1607 | $row = '1'; |
| 1606 | - if (($testPrevOp !== null && $testPrevOp['value'] === ':') && $pCellParent !== null) { // @phpstan-ignore-line | |
| 1608 | + if (($testPrevOp !== null && $testPrevOp['value'] === ':') && $pCellParent !== null) { // @phpstan-ignore booleanAnd.alwaysFalse (testPrevOp must be non-null?), booleanAnd.alwaysFalse (ditto), identical.alwaysFalse (ditto) | |
| 1607 | 1609 | $row = $pCellParent->getHighestDataRow($val); |
| 1608 | 1610 | } |
| 1609 | 1611 | $val = "{$val}{$row}"; |
| 1610 | 1612 | $stackItemReference = $val; |
| @@ -1754,9 +1756,9 @@ | ||
| 1754 | 1756 | // Loop through each token in turn |
| 1755 | 1757 | foreach ($tokens as $tokenIdx => $tokenData) { |
| 1756 | 1758 | /** @var mixed[] $tokenData */ |
| 1757 | 1759 | $this->processingAnchorArray = false; |
| 1758 | - if ($tokenData['type'] === 'Cell Reference' && isset($tokens[$tokenIdx + 1]) && $tokens[$tokenIdx + 1]['type'] === 'Operand Count for Function ANCHORARRAY()') { //* @phpstan-ignore-line | |
| 1760 | + if ($tokenData['type'] === 'Cell Reference' && isset($tokens[$tokenIdx + 1]) && $tokens[$tokenIdx + 1]['type'] === 'Operand Count for Function ANCHORARRAY()') { //* @phpstan-ignore offsetAccess.nonOffsetAccessible ($tokens might be mixed not array) | |
| 1759 | 1761 | $this->processingAnchorArray = true; |
| 1760 | 1762 | } |
| 1761 | 1763 | $token = $tokenData['value']; |
| 1762 | 1764 | // Branch pruning: skip useless resolutions |
| @@ -1856,9 +1858,9 @@ | ||
| 1856 | 1858 | } else { |
| 1857 | 1859 | return $this->raiseFormulaError($e->getMessage(), $e->getCode(), $e); |
| 1858 | 1860 | } |
| 1859 | 1861 | } |
| 1860 | - } elseif (!is_numeric($token) && !is_object($token) && isset($token, self::BINARY_OPERATORS[$token])) { //* @phpstan-ignore-line | |
| 1862 | + } elseif (!is_numeric($token) && !is_object($token) && isset($token, self::BINARY_OPERATORS[$token])) { //* @phpstan-ignore offsetAccess.invalidOffset ($token is mixed) | |
| 1861 | 1863 | // if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack |
| 1862 | 1864 | // We must have two operands, error if we don't |
| 1863 | 1865 | $operand2Data = $stack->pop(); |
| 1864 | 1866 | if ($operand2Data === null) { |
| @@ -1974,9 +1976,9 @@ | ||
| 1974 | 1976 | } |
| 1975 | 1977 | if ($breakNeeded) { |
| 1976 | 1978 | break; |
| 1977 | 1979 | } |
| 1978 | - $cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow); // @phpstan-ignore-line | |
| 1980 | + $cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow); | |
| 1979 | 1981 | if ($pCellParent !== null && $this->spreadsheet !== null) { |
| 1980 | 1982 | $cellValue = $this->extractCellRange($cellRef, $this->spreadsheet->getSheetByName($sheet1), false); |
| 1981 | 1983 | } else { |
| 1982 | 1984 | return $this->raiseFormulaError('Unable to access Cell Reference'); |
| @@ -2045,9 +2047,9 @@ | ||
| 2045 | 2047 | $result = $operand1; |
| 2046 | 2048 | } elseif (Information\ErrorValue::isError($operand2)) { |
| 2047 | 2049 | $result = $operand2; |
| 2048 | 2050 | } else { |
| 2049 | - $result = str_replace('""', self::FORMULA_STRING_QUOTE, self::unwrapResult($operand1) . self::unwrapResult($operand2)); //* @phpstan-ignore-line | |
| 2051 | + $result = str_replace('""', self::FORMULA_STRING_QUOTE, self::unwrapResult($operand1) . self::unwrapResult($operand2)); //* @phpstan-ignore binaryOp.invalid (unwrapresult can return mixed rather than string) | |
| 2050 | 2052 | $result = StringHelper::substring( |
| 2051 | 2053 | $result, |
| 2052 | 2054 | 0, |
| 2053 | 2055 | DataType::MAX_STRING_LENGTH |
| @@ -2078,10 +2080,10 @@ | ||
| 2078 | 2080 | if (count(Functions::flattenArray($cellIntersect)) === 0) { |
| 2079 | 2081 | $this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails($cellIntersect)); |
| 2080 | 2082 | $stack->push('Error', ExcelError::null(), null); |
| 2081 | 2083 | } else { |
| 2082 | - $cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' // @phpstan-ignore-line | |
| 2083 | - . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow); // @phpstan-ignore-line | |
| 2084 | + $cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' // @phpstan-ignore argument.type ($oCol or $oRow might be empty), argument.type (ditto) | |
| 2085 | + . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow); // @phpstan-ignore argument.type ($oCol or $oRow might be empty), argument.type (ditto) | |
| 2084 | 2086 | $this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails($cellIntersect)); |
| 2085 | 2087 | $stack->push('Value', $cellIntersect, $cellRef); |
| 2086 | 2088 | } |
| 2087 | 2089 | |
| @@ -2094,15 +2096,15 @@ | ||
| 2094 | 2096 | $stack->push('Value', $cellUnion, 'A1'); |
| 2095 | 2097 | |
| 2096 | 2098 | break; |
| 2097 | 2099 | } |
| 2098 | - } elseif (($token === '~') || ($token === '%')) { // @phpstan-ignore-line | |
| 2100 | + } elseif (($token === '~') || ($token === '%')) { // @phpstan-ignore booleanOr.alwaysFalse (phpstan says token can't be plain string), identical.alwaysFalse (ditto), identical.alwaysFalse (ditto) | |
| 2099 | 2101 | // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on |
| 2100 | 2102 | if (($arg = $stack->pop()) === null) { |
| 2101 | 2103 | return $this->raiseFormulaError('Internal error - Operand value missing from stack'); |
| 2102 | 2104 | } |
| 2103 | 2105 | $arg = $arg['value']; |
| 2104 | - if ($token === '~') { // @phpstan-ignore-line | |
| 2106 | + if ($token === '~') { // @phpstan-ignore identical.alwaysFalse (phpstan says token can't be plain string) | |
| 2105 | 2107 | $this->debugLog->writeDebugLog('Evaluating Negation of %s', $this->showValue($arg)); |
| 2106 | 2108 | $multiplier = -1; |
| 2107 | 2109 | } else { |
| 2108 | 2110 | $this->debugLog->writeDebugLog('Evaluating Percentile of %s', $this->showValue($arg)); |
| @@ -2274,9 +2276,9 @@ | ||
| 2274 | 2276 | $arg = $stack->pop(); |
| 2275 | 2277 | $a = $argCount - $i - 1; |
| 2276 | 2278 | if ( |
| 2277 | 2279 | ($passByReference) |
| 2278 | - && (isset($phpSpreadsheetFunctions[$functionName]['passByReference'][$a])) //* @phpstan-ignore-line | |
| 2280 | + && (isset($phpSpreadsheetFunctions[$functionName]['passByReference'][$a])) //* @phpstan-ignore offsetAccess.nonOffsetAccessible (possibly need to pass 2 arguments to isset) | |
| 2279 | 2281 | && ($phpSpreadsheetFunctions[$functionName]['passByReference'][$a]) |
| 2280 | 2282 | ) { |
| 2281 | 2283 | /** @var mixed[] $arg */ |
| 2282 | 2284 | if ($arg['reference'] === null) { |
| @@ -2341,9 +2343,9 @@ | ||
| 2341 | 2343 | |
| 2342 | 2344 | if ($functionName !== 'MKMATRIX') { |
| 2343 | 2345 | if ($this->debugLog->getWriteDebugLog()) { |
| 2344 | 2346 | krsort($argArrayVals); |
| 2345 | - $this->debugLog->writeDebugLog('Evaluating %s ( %s )', self::localeFunc($functionName), implode(self::$localeArgumentSeparator . ' ', Functions::flattenArray($argArrayVals))); // @phpstan-ignore-line | |
| 2347 | + $this->debugLog->writeDebugLog('Evaluating %s ( %s )', self::localeFunc($functionName), implode(self::$localeArgumentSeparator . ' ', Functions::flattenArray($argArrayVals))); // @phpstan-ignore argument.type (flattenArray returns array<mixed> rather than array<string>) | |
| 2346 | 2348 | } |
| 2347 | 2349 | } |
| 2348 | 2350 | |
| 2349 | 2351 | // Process the argument with the appropriate function call |
| @@ -2386,9 +2388,9 @@ | ||
| 2386 | 2388 | if (isset($storeKey)) { |
| 2387 | 2389 | $branchStore[$storeKey] = self::EXCEL_CONSTANTS[$excelConstant]; |
| 2388 | 2390 | } |
| 2389 | 2391 | $this->debugLog->writeDebugLog('Evaluating Constant %s as %s', $excelConstant, $this->showTypeDetails(self::EXCEL_CONSTANTS[$excelConstant])); |
| 2390 | - } elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token[0] == self::FORMULA_STRING_QUOTE) || ($token[0] == '#')) { //* @phpstan-ignore-line | |
| 2392 | + } elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token[0] == self::FORMULA_STRING_QUOTE) || ($token[0] == '#')) { //* @phpstan-ignore function.alreadyNarrowedType (phpstan says is_bool has argument of *NEVER*?), equal.alwaysFalse (ditto) | |
| 2391 | 2393 | /** @var array{type: string, reference: ?string} $tokenData */ |
| 2392 | 2394 | $stack->push($tokenData['type'], $token, $tokenData['reference']); |
| 2393 | 2395 | if (isset($storeKey)) { |
| 2394 | 2396 | $branchStore[$storeKey] = $token; |
| @@ -2517,9 +2519,9 @@ | ||
| 2517 | 2519 | /** @var array<string, mixed> $r */ |
| 2518 | 2520 | $r = $stack->pop(); |
| 2519 | 2521 | $result[$x] = $r['value']; |
| 2520 | 2522 | } |
| 2521 | - } elseif (is_array($operand2) && is_array($operand1)) { | |
| 2523 | + } elseif (is_array($operand2) /*&& is_array($operand1)*/) { | |
| 2522 | 2524 | // Operand 1 and Operand 2 are both arrays |
| 2523 | 2525 | if (!$recursingArrays) { |
| 2524 | 2526 | self::checkMatrixOperands($operand1, $operand2, 2); |
| 2525 | 2527 | } |
| @@ -2530,9 +2532,9 @@ | ||
| 2530 | 2532 | $r = $stack->pop(); |
| 2531 | 2533 | $result[$x] = $r['value']; |
| 2532 | 2534 | } |
| 2533 | 2535 | } else { |
| 2534 | - throw new Exception('Neither operand is an arra'); | |
| 2536 | + throw new Exception('Neither operand is an array'); | |
| 2535 | 2537 | } |
| 2536 | 2538 | // Log the result details |
| 2537 | 2539 | $this->debugLog->writeDebugLog('Comparison Evaluation Result is %s', $this->showTypeDetails($result)); |
| 2538 | 2540 | // And push the result onto the stack |