Skip to content

Commit

Permalink
fix some phpstan issues uncovered with checkImplicitMixed
Browse files Browse the repository at this point in the history
  • Loading branch information
schlndh committed Feb 17, 2024
1 parent 088a45d commit 7abef09
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 22 deletions.
9 changes: 2 additions & 7 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ parameters:
- src
- tests
treatPhpDocTypesAsCertain: false
# TODO: enable this
# checkImplicitMixed: true
excludePaths:
- tests/*/data/*
exceptions:
Expand Down Expand Up @@ -41,13 +43,6 @@ parameters:
# we know what we're doing.
- '#bool\|mysqli_result#'
- '#mysqli_result\|false#'
# MariaDbParserOperatorTest.php tries to evaluate expression from AST. We're just hoping for the best.
-
message: '#.*operation.*results in an error#'
path: tests/Parser/MariaDbParserOperatorTest.php
-
message: '# cast #'
path: tests/Parser/MariaDbParserOperatorTest.php
-
# I'm explicitly creating GenericObjectType to append additional information to mysqli_stmt/mysqli_result.
message: '#Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error-prone and deprecated.#'
Expand Down
6 changes: 5 additions & 1 deletion src/Analyser/AnalyserState.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
use function assert;
use function count;
use function in_array;
use function is_string;
use function max;
use function mb_strlen;
use function min;
Expand Down Expand Up @@ -166,7 +167,9 @@ private function dispatchAnalyseSelectQuery(SelectQuery $select): array

return $this->analyseTableValueConstructor($select->tableValueConstructor);
default:
$this->errors[] = new AnalyserError("Unhandled SELECT type {$select::getSelectQueryType()->value}");
$typeVal = $select::getSelectQueryType()->value;
assert(is_string($typeVal));
$this->errors[] = new AnalyserError("Unhandled SELECT type {$typeVal}");

return [[], null];
}
Expand Down Expand Up @@ -629,6 +632,7 @@ private function analyseInsertOrReplaceQuery(InsertQuery|ReplaceQuery $query): a
{
static $mockPosition = null;
$mockPosition ??= new Position(0, 0, 0);
assert($mockPosition instanceof Position);
$tableReferenceNode = new Table($mockPosition, $mockPosition, $query->tableName);

try {
Expand Down
7 changes: 5 additions & 2 deletions src/DbReflection/MariaDbFileDbReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

/**
* @phpcs:ignore
* @phpstan-type SchemaDump array{__version: int, tables: array<string, array{columns: array<array<string, scalar|null>>, foreign_keys: array<array<string, scalar|null>>}>}
* @phpstan-type SchemaDump array{__version: int, tables: array<string, array{columns: array<array<string,
* scalar|null>>, foreign_keys: array<array<string, scalar|null>>}>}
*/
class MariaDbFileDbReflection implements DbReflection
{
Expand All @@ -25,7 +26,7 @@ class MariaDbFileDbReflection implements DbReflection
private readonly array $schemaDump;

/** @var array<string, Table> table name => schema */
private array $parsedSchemas;
private array $parsedSchemas = [];

public function __construct(string $dumpFile, private readonly InformationSchemaParser $schemaParser)
{
Expand Down Expand Up @@ -95,6 +96,7 @@ public static function dumpSchema(\mysqli $db, string $database): string
$stmt->execute([$database]);
$columns = $stmt->get_result()->fetch_all(\MYSQLI_ASSOC);

/** @var array<string, scalar|null> $col */
foreach ($columns as $col) {
$result['tables'][$col['TABLE_NAME']]['columns'][] = $col;
}
Expand All @@ -108,6 +110,7 @@ public static function dumpSchema(\mysqli $db, string $database): string
$stmt->execute([$database]);
$foreignKeys = $stmt->get_result()->fetch_all(\MYSQLI_ASSOC);

/** @var array<string, scalar|null> $fk */
foreach ($foreignKeys as $fk) {
$result['tables'][$fk['TABLE_NAME']]['foreign_keys'][] = $fk;
}
Expand Down
4 changes: 3 additions & 1 deletion src/DbReflection/MariaDbOnlineDbReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class MariaDbOnlineDbReflection implements DbReflection
private readonly string $database;

/** @var array<string, Table> table name => schema */
private array $parsedSchemas;
private array $parsedSchemas = [];

public function __construct(private readonly mysqli $mysqli, private readonly InformationSchemaParser $schemaParser)
{
Expand All @@ -37,6 +37,7 @@ public function findTableSchema(string $table): Table
'SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?',
);
$stmt->execute([$this->database, $table]);
/** @var array<array<string, scalar|null>> $tableCols */
$tableCols = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);

$stmt = $this->mysqli->prepare('
Expand All @@ -46,6 +47,7 @@ public function findTableSchema(string $table): Table
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND tc.CONSTRAINT_TYPE = "FOREIGN KEY"
');
$stmt->execute([$this->database, $table]);
/** @var array<array<string, scalar|null>> $foreignKeys */
$foreignKeys = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
} catch (mysqli_sql_exception $e) {
throw new DatabaseException($e->getMessage(), $e->getCode(), $e);
Expand Down
4 changes: 3 additions & 1 deletion src/PHPStan/Helper/PHPStanReturnTypeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public function createPhpstanParamsFromMultipleAnalyserResults(array $analyserRe
return new AnalyserResultPHPStanParams($rowTypes, $placeholderCounts);
}

/** @return array<Type> */
/** @return list<Type> */
public function packPHPStanParamsIntoTypes(?AnalyserResultPHPStanParams $params): array
{
return $params !== null
Expand Down Expand Up @@ -122,6 +122,8 @@ public function getRowTypeFromFields(?array $resultFields): ConstantArrayType
$keys = [];
$values = [];
$i = 0;

/** @var array{ConstantIntegerType, ConstantIntegerType} $colKeyTypes */
static $colKeyTypes = [
new ConstantIntegerType(0),
new ConstantIntegerType(1),
Expand Down
3 changes: 3 additions & 0 deletions src/Parser/MariaDbParserState.php
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,7 @@ private function parseRestOfBetweenOperator(Expr $left, Expr $min): Between
{
static $precedence = null;
// BETWEEN is right-associative so no + 1
/** @phpstan-var int $precedence */
$precedence ??= $this->getOperatorPrecedence(SpecialOpTypeEnum::BETWEEN);
$this->expectToken(TokenTypeEnum::AND);
$max = $this->parseExpression($precedence);
Expand All @@ -1248,6 +1249,7 @@ private function parseRestOfLikeOperator(Expr $expression, Expr $pattern): Like
$escapeChar = null;

if ($this->acceptToken(TokenTypeEnum::ESCAPE)) {
/** @phpstan-var int $precedence */
$precedence ??= $this->getOperatorPrecedence(SpecialOpTypeEnum::LIKE) + 1;
$escapeChar = $this->parseExpression($precedence);
}
Expand Down Expand Up @@ -2816,6 +2818,7 @@ private function cleanStringLiteral(string $contents): string
}
}

/** @phpstan-var array<string, string> $map */
return strtr($contents, $map);
}

Expand Down
5 changes: 3 additions & 2 deletions src/Parser/TokenTypeEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,10 @@ enum TokenTypeEnum: string
/** @return array<value-of<self>, self> upper-case keyword => enum type */
public static function getKeywordsMap(): array
{
static $result = null;
/** @var array<value-of<self>, self> $result */
static $result;

if ($result === null) {
if (! isset($result)) {
$result = self::cases();
$eoiIdx = array_search(self::END_OF_INPUT, $result, true);
assert($eoiIdx !== false);
Expand Down
45 changes: 37 additions & 8 deletions tests/Parser/MariaDbParserOperatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use function assert;
use function in_array;
use function is_array;
use function is_string;
use function preg_match;
use function str_contains;

Expand Down Expand Up @@ -102,6 +103,27 @@ private function getValueFromAstExpression(Expr $expr): int|string|float|array|n
$left = $this->getValueFromAstExpression($expr->left);
$right = $this->getValueFromAstExpression($expr->right);

if ($left === null || $right === null) {
return null;
}

$this->assertIsNotArray($left);
$this->assertIsNotArray($right);

if ($expr->operation === BinaryOpTypeEnum::REGEXP) {
$right = (string) $right;
$left = (string) $left;

return match (preg_match('/' . $right . '/', $left)) {
1 => 1,
0 => 0,
false => throw new RuntimeException("Invalid {$left} REGEXP {$right}"),
};
}

$this->assertIsNumeric($left);
$this->assertIsNumeric($right);

return match ($expr->operation) {
BinaryOpTypeEnum::PLUS => $left + $right,
BinaryOpTypeEnum::MINUS => $left - $right,
Expand All @@ -117,16 +139,20 @@ private function getValueFromAstExpression(Expr $expr): int|string|float|array|n
BinaryOpTypeEnum::BITWISE_XOR => ((int) $left) ^ ((int) $right),
BinaryOpTypeEnum::SHIFT_LEFT => ((int) $left) << ((int) $right),
BinaryOpTypeEnum::SHIFT_RIGHT => ((int) $left) >> ((int) $right),
BinaryOpTypeEnum::REGEXP => match (preg_match('/' . $right . '/', (string) $left)) {
1 => 1,
0 => 0,
false => throw new RuntimeException("Invalid {$left} REGEXP {$right}"),
},
default => throw new RuntimeException("{$expr->operation->value} is not implemented yet."),
};
case ExprTypeEnum::UNARY_OP:
assert($expr instanceof UnaryOp);
$inner = $this->getValueFromAstExpression($expr->expression);
$this->assertIsNotArray($inner);

if ($inner === null) {
return null;
}

if (is_string($inner)) {
$inner = (float) $inner;
}

return match ($expr->operation) {
UnaryOpTypeEnum::PLUS => $inner,
Expand Down Expand Up @@ -193,10 +219,13 @@ private function getValueFromAstExpression(Expr $expr): int|string|float|array|n
return null;
}

// @phpstan-ignore-next-line
assert(! str_contains($pattern, '%') && ! str_contains($pattern, '_'));
$this->assertIsNotArray($left);
$this->assertIsNotArray($pattern);
$left = (string) $left;
$pattern = (string) $pattern;
$this->assertTrue(! str_contains($pattern, '%') && ! str_contains($pattern, '_'));

return str_contains((string) $left, (string) $pattern)
return str_contains($left, $pattern)
? 1
: 0;
default:
Expand Down

0 comments on commit 7abef09

Please sign in to comment.