github carthage-software/mago 1.17.0
Mago 1.17.0

9 hours ago

Mago 1.17.0

Mago 1.17.0 continues the focus on analyzer accuracy with 20+ bug fixes and several new features. Highlights include detection of array access on non-array types (false, scalars), support for PHP 8.4's #[\Deprecated] attribute, literal float arithmetic tracking, a new @suspends-fiber annotation for async code, and invalidation of memoized $this properties on self-method calls. The linter gains new rules for fully-qualified global imports and ambiguous constant access, plus an auto-fixer for redundant parentheses.

✨ Features

Analyzer

  • Detect array access on non-array types: New false-array-access, possibly-false-array-access, possibly-invalid-array-access, and invalid-array-access issue codes report when array access is performed on false, scalars, or other non-array types, including assignment contexts (#1542)
  • Support #[\Deprecated] PHP attribute: Functions, methods, classes, constants, and enums with the #[\Deprecated] attribute are now recognized as deprecated (#1541)
  • @suspends-fiber annotation: A new docblock tag @suspends-fiber marks methods that suspend fibers. Calls to these methods invalidate all memoized $this property narrowings, preventing false positives in async code. Revolt\EventLoop\Suspension::suspend() is recognized automatically (#1536)
  • Invalidate memoized properties on self-method calls: Non-pure $this->method() calls now clear memoized $this-> property types, fixing false positives where property narrowings survived across method calls that could modify them (#1536)
  • Extend min/max/abs providers to Psl\Math functions: Psl\Math\max, Psl\Math\maxva, Psl\Math\min, Psl\Math\minva, and Psl\Math\abs now use the same precise integer range providers as the built-in functions
  • Check reference constraints on array modifications: Array append ($arr[] = $val) and indexed assignment ($arr[$k] = $val) on by-reference parameters now validate against the parameter's type constraint (#1539)

Linter

  • no-fully-qualified-global-function, no-fully-qualified-global-constant, no-fully-qualified-global-class rules: New rules that flag fully-qualified references (#1494)
  • ambiguous-constant-access rule: Detects ambiguous constant access patterns (#1508)
  • Auto-fixer for redundant parentheses: The redundant-parentheses rule now has an auto-fixer (#1549)

🐛 Bug Fixes

Analyzer

  • Fixed false positives from truthy/falsy-mixed absorbing literals: The type combiner no longer absorbs falsy literal strings like string('') into truthy-mixed, which caused false redundant-condition warnings (#1534)
  • Fixed false positive for isset on string offsets: isset($s[0]) on a generic string no longer returns true unconditionally - empty strings have no characters, so the result is correctly bool (#1537)
  • Fixed parse_url component return types: parse_url() with a component argument now correctly includes false in the return type, since malformed URLs return false regardless of the component (#1546)
  • Fixed empty array variants lost in loops with break: Infinite loops with break no longer drop the pre-loop empty array variant, fixing false positives where count($arr) was always truthy after a while(true) loop (#1535)
  • Fixed empty array variants not removed after isset check: When if (!isset($arr[$key])) { throw; } exits, empty array variants are now removed from the base variable since isset proves the array is non-empty
  • Fixed switch fall-through after never-returning call: Cases after a never-returning call (like exit()) without break are no longer incorrectly marked as unreachable - the switch can still jump directly to those cases (#1531)
  • Fixed if-body clauses leaking to post-if context: Clauses from non-exiting if-bodies (e.g., if ($m === 0) { echo; }) no longer leak to subsequent code, preventing incorrect type narrowing (#1509)
  • Fixed by-reference argument types not propagated through &&: Variables passed by reference in function calls on the left side of && now correctly update their type for the right side evaluation (#1524)
  • Fixed dynamic key array assignment overwriting known items: $arr[$dynamic] = value no longer replaces the value types of existing known keys in the array (#1527)
  • Fixed isset/empty checks on union types with lists: The impossible-isset check now considers TArray::List variants in union types, and non-empty arrays with literal key types no longer produce false possibly-undefined warnings (#1512)
  • Fixed nested array keys not marked definite after loops: The post-loop key-definiteness fix now recurses into nested arrays (#1522)
  • Fixed integer type unions in min/max/abs providers: Multi-integer unions like int|int(0) are now properly handled by computing combined bounds (#1526)
  • Fixed literal float arithmetic: Operations between literal ints and floats (e.g., 1000 * 0.5) now compute the actual result (float(500.0)) instead of returning unspecified float (#1540)
  • Fixed non-empty array with literal key type access: Accessing a non-empty generic array with its exact literal key type no longer produces possibly-undefined warnings (#1512)

Formatter

  • Fixed fits() handling of LineSuffix: Corrected line-suffix width calculation in the formatter (#1516)

Prelude

  • Fixed getimagesize/getimagesizefromstring param-out: Added @param-out ?array annotation matching the nullable parameter type (#1523)

Codex

  • Fixed truthy/falsy-mixed containment: truthy-mixed no longer contains falsy values and falsy-mixed no longer contains truthy values in type comparisons (#1534)
  • Recognized #[\Deprecated] attribute: The codex scanner now sets the deprecated flag from PHP attributes in addition to @deprecated docblock tags (#1541)

Composer

  • Fixed race condition in binary download: Concurrent Composer installations no longer corrupt the binary (#1544)
  • Formatted internal binary download code: Cleaned up the Composer wrapper's download logic (#1545)

🏗️ Internal

  • Ignored analyzer test files from typos check

🙏 Thank You

Contributors

A huge thank you to everyone who contributed code to this release:

Issue Reporters

Thank you to everyone who reported issues that shaped this release:


Full Changelog: 1.16.0...1.17.0

Don't miss a new mago release

NewReleases is sending notifications on new releases.