phan icon indicating copy to clipboard operation
phan copied to clipboard

Warn about mismatch of callables passed to usort, array_filter, array_map, etc

Open TysonAndre opened this issue 6 years ago • 2 comments

Related to #726

Also, warn about using uksort with a callable that doesn't accept int or strings, depending on the real array type.

TysonAndre avatar Nov 12 '19 16:11 TysonAndre

Here a example source code I wanted using on a new issue for uasort:

<?php
class ValueObject {
    private $value;
    public function __construct( $value ) {
        $this->value = $value;
    }
    public function getSomething() {
        return $this->value;
    }
}
class ValueObject2 {
    private $value2;
    public function __construct( $value2 ) {
        $this->value2 = $value2;
    }
    public function getSomething2() {
        return $this->value2;
    }
}

class TestUasort {
  /** @var ValueObject[] */
  protected $valueObjects;

  /**
   * @param ValueObject[] $valueObjects
   */
  public function __construct( $valueObjects ) {
    $this->valueObjects = $valueObjects;
  }

  public function doSomething() {
    // Could phan infer the types inside the closures to check the function names?
    usort( $this->valueObjects, static function ( $a, $b ) {
      '@phan-debug-var $a, $b';
      return $b->getSomething2() <=> $a->getSomething();
    } );
    // Or to check the type hints against the array?
    usort( $this->valueObjects, static function ( ValueObject2 $a, ValueObject2 $b ) {
      '@phan-debug-var $a, $b';
      return $b->getSomething2() <=> $a->getSomething2();
    } );
    // Mixing types in the sort closures are mistakes
    usort( $this->valueObjects, static function ( ValueObject2 $a, ValueObject $b ) {
       '@phan-debug-var $a, $b';
      return $b->getSomething() <=> $a->getSomething2();
    } );
    // Fully typehinted is working:
    usort( $this->valueObjects, static function ( ValueObject $a, ValueObject $b ) {
      '@phan-debug-var $a, $b';
      return $b->getSomething() <=> $a->getSomething();
    } );
    $valueObjects = $this->valueObjects;
    '@phan-debug-var $valueObjects';
  }
}

(new TestUasort( [
  new ValueObject(1),
  new ValueObject(2),
]))->doSomething();

umherirrender avatar Aug 30 '21 23:08 umherirrender

It's probably doable by changing src/Phan/Plugin/Internal/MiscParamPlugin.php to analyze the function when called with two args of the types of elements (if !UnionType->isEmpty()) - an example that could be used as a reference would be src/Phan/Plugin/Internal/ClosureReturnTypeOverridePlugin.php for how arguments are built to be passed to ArgumentType::analyzeForCallback (etc.)

Similar approach is already taken for array_map in src/Phan/Plugin/Internal/ArrayReturnTypeOverridePlugin.php for #726

TysonAndre avatar Aug 31 '21 01:08 TysonAndre