Skip to content

Fix unresolvable docblock references and prune the dead baseline entries - #86

Merged
tyrsson merged 4 commits into
0.5.xfrom
tyrsson-prune-resource-baseline-entries
Oct 10, 2026
Merged

tyrsson merged 4 commits into
0.5.xfrom
tyrsson-prune-resource-baseline-entries

Conversation

@tyrsson

@tyrsson tyrsson commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

What this does

Follows up on #85, which fixed the missing use mysqli_result; in src/Driver.php. The unqualified mysqli_result in that file's @param docblock was resolving to the non-existent PhpDb\Mysql\mysqli_result, producing a non-existent-class-like plus a cascading possibly-invalid-argument, and #85 pruned the two baseline entries that fix made dead. That PR is merged as 7685a95, and this branch is based directly on it.

The phpdb $resource contract merge (php-db/phpdb#227, 0c4ed091) then made the committed baseline stale and surfaced 21 pre-existing findings in this repo that had been hidden behind it. All 21 are fixed at source here. No suppression was added, and none was widened. mago pruned the 9 now-dead baseline entries itself via --remove-outdated-baseline-entries, taking analysis-baseline.toml from 87 to 78 blocks. Diffed before/after: exactly 9 removed, 0 added.

The two root causes

1. @throws Exception\ExceptionInterface named a class that does not exist.

Every affected file does use PhpDb\Adapter\Exception;, so the short form resolved to PhpDb\Adapter\Exception\ExceptionInterface, an interface phpdb has never shipped. The only real one is PhpDb\Exception\ExceptionInterface. The annotations were therefore silently inert, and mago correctly reported all those throws as unhandled. All 16 places, across 8 files, now import it as:

use PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface;

and reference that short alias in @throws, so no docblock carries a fully-qualified class name.

Concrete exception classes (Exception\RuntimeException, Exception\InvalidConnectionParametersException, Exception\InvalidArgumentException, PDOException, ...) were deliberately left as short names; those resolve fine, and were not touched.

2. SelectDecorator::processLimit()/processOffset() dereferenced a nullable parameter.

The signature takes ?DriverInterface $driver = null, but the guard tested only $parameterContainer before calling $driver->formatParameterName(...). Added the null check. This is a runtime no-op: AbstractSql::buildSqlString() always supplies a driver, and when one is genuinely absent the code now correctly falls through to the literal branch instead of erroring. Fixing it also let mago resolve the call result, which removed a less-specific-nested-return-statement cascade.

Also

  • processLimit()/processOffset() docblocks tightened from string[]|null to array{0: string}|null, and the LIMIT/OFFSET literals cast to (string). vsprintf renders 10 and '10' identically, so this is behaviour-preserving.
  • Those same (string) casts removed an accidental safety net, and this PR pays it back with real coverage. Previously the two ReturnRemoval mutants in processLimit()/processOffset() were killed by static analysis: removing the return made execution fall through to a type-invalid raw-int return, which mago flagged. Once the literal is cast, that fall-through is type-valid, so mago stops killing the mutant and only a test can. SelectDecoratorTest::prepareStatementBindsLimitAndOffsetParameters already drove that branch, but its setSql expectation was with($this->isString()) -- a tautology that any string satisfies. It now captures the SQL and asserts the bound LIMIT :limit / OFFSET :offset placeholders. Both mutants are killed by the tests instead of by the analyzer.
  • AlterTableDecorator::processAddColumns() docblock corrected to array{0: list<string>}, matching the upstream AlterTable contract, with $sqls[] instead of $sqls[$i]. The parent's createSqlFromSpecificationAndParameters() only iterates by value and calls count(), so the inner keys were never read.
  • 4 redundant @var annotations dropped (mago had no auto-fix for these; --fix --retain-code redundant-docblock-type produced an empty diff).
  • The two em dashes in the tree replaced with semicolons: the @todo at src/Pdo/Connection.php:191, and the trigger comment at the top of .github/workflows/continuous-integration.yml.
  • One existing baseline entry is refreshed positionally, and no entries are added. Importing PhpDbExceptionInterface into src/Connection.php shifts the closure on line 118 down one line, and mago's baselined mixed-return-statement message embeds that position, so the entry is regenerated as {closure:src/Connection.php:119:31}. Same code, same count = 1, 78 blocks before and after. Regenerated by mago and diffed: exactly 1 entry replaced, 0 added.

The lock bump is required, not cosmetic

composer.lock moves phpdb b57f549b → 0c4ed091. CI's qa job runs composer install (locked), so without this the pruned baseline would leave the findings un-suppressed and the job would go red. Measured against the old reference: the pruned baseline leaves 12 findings un-suppressed (9 errors, 3 warnings), including all three $resource-killed entries and seven from the removed @var docblocks.

No repositories alias or other local scaffolding is included.

Deliberately out of scope

The two remaining src/Driver.php baseline entries are both incompatible-parameter-type:

Parameter `$resource` of `PhpDb\Mysql\Driver::createResult()` expects type
`mysqli|mysqli_result|mysqli_stmt` but parent
`PhpDb\Adapter\Driver\DriverInterface::createResult()` expects type `resource`

That is a parameter-contravariance issue owned by phpdb core's DriverInterface (resource is a PHP-7-era type), not by this repo. Left alone pending a separate decision upstream. This PR does not reopen #71.

Verification

  • mago format --check → all files already formatted
  • mago lint → no issues
  • mago analyze → no issues, 108 filtered by baseline (the "outdated entries" warning is now gone)
  • mago guard → no issues
  • vendor/bin/phpunit --testsuite "unit test" → OK (193 tests, 386 assertions)
  • vendor/bin/phpunit --testsuite "integration test" → OK (327 tests, 508 assertions) against MySQL 8.0
  • Infection → 1041 mutations, 28 escaped, MSI 97%, matching the 28 escaped on 0.5.x. This branch previously reported 30 escaped; the two SelectDecorator mutants are the ones now killed by the test above, and no mutant escaped because of this PR.

The integration suite matters here because the change touches generated SQL.

The phpdb $resource contract change (php-db/phpdb#227, 0c4ed091) made the
committed baseline stale and surfaced 21 pre-existing findings. All 21 are
fixed at source: no new suppression was added, and mago pruned the 9
now-dead baseline entries it left behind (87 -> 78 blocks).

Two root causes:

* `@throws Exception\ExceptionInterface` resolved to
  PhpDb\Adapter\Exception\ExceptionInterface, which phpdb does not ship.
  Every affected file imports PhpDb\Adapter\Exception, so the short form
  named a non-existent class and the annotations were silently inert,
  reporting 14 throws as unhandled. Repointed to the real
  \PhpDb\Exception\ExceptionInterface in 16 places.

* SelectDecorator::processLimit()/processOffset() tested only
  $parameterContainer before dereferencing the nullable ?DriverInterface
  $driver parameter. Adding the null check also let mago resolve the call
  result and removed a less-specific-nested-return-statement cascade.
  Runtime no-op: AbstractSql::buildSqlString() always supplies a driver,
  and a null driver now correctly falls through to the literal branch.

Also tightens the LIMIT/OFFSET and ALTER TABLE ADD COLUMN return shapes,
casts the LIMIT/OFFSET literals to string (vsprintf renders 10 and '10'
identically), reindexes the ADD COLUMN sql list (the parent never reads the
inner keys), and drops 4 redundant @var annotations.

The lock is bumped to phpdb 0c4ed091 because CI's qa job installs from the
lock; the previous reference still carried @return resource and would leave
the pruned findings un-suppressed.

Verified: mago format --check, lint, analyze and guard all clean; phpunit
unit suite 193 tests / 385 assertions; integration suite 327 tests / 508
assertions against MySQL 8.0.
@codecov

codecov Bot commented Oct 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Import PhpDb\Exception\ExceptionInterface as PhpDbExceptionInterface in the eight files that reference it, and use the short name in @throws rather than the fully-qualified form.

Replace the two em dashes with semicolons: the @todo in src/Pdo/Connection.php and the trigger comment in the CI workflow.

The added import shifts the closure in src/Connection.php down one line, so mago's baselined mixed-return-statement entry is regenerated at its new position (118:31 -> 119:31). Same finding, same count, no new suppression.
Restore .github/workflows/continuous-integration.yml to its previous state so this PR only touches source files and the baseline.
The setSql expectation was with($this->isString()), which any string satisfies, so the container-and-driver branch of processLimit/processOffset was never actually pinned. Capture the SQL and assert the LIMIT/OFFSET placeholders. This restores the coverage that the (string) casts removed, killing the two ReturnRemoval mutants at lines 53 and 72.

Refs #86.
@tyrsson
tyrsson requested a review from simon-mundy October 8, 2026 10:01
@tyrsson tyrsson self-assigned this Oct 8, 2026
@tyrsson
tyrsson requested review from simon-mundy and removed request for simon-mundy October 9, 2026 21:23
@tyrsson
tyrsson merged commit 98841be into 0.5.x Oct 10, 2026
15 checks passed
@tyrsson
tyrsson deleted the tyrsson-prune-resource-baseline-entries branch October 10, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants