phpinspectionsea icon indicating copy to clipboard operation
phpinspectionsea copied to clipboard

[EA] Null pointer exception may occur here. False positive.

Open Chemaclass opened this issue 3 years ago • 2 comments

Subject Details
Plugin Php Inspections (EA Extended), 4.0.7.1
Language level PHP 7.4

I think this is related to https://www.giters.com/kalessil/phpinspectionsea/issues/1560 or at least, pretty similar (by @voku)

Current behaviour

When using "Person.ageNullable" property, then there is a complain about a possible null although the method Person->getName() has a non-nullable return type of /** @return Age */.

Screenshot 2022-02-22 at 18 03 10

The reason seems to be that it's getting the return type from the property /** @var Age|null */ and not from the method /** @return Age */.

Screenshot 2022-02-22 at 18 05 34

Expected behaviour

I would expect to don't have this warning of "Possible NULL" when the method has a specific non-nullable return type.

Screenshot 2022-02-22 at 18 06 47

Environment details

This applies to all PHP versions. But especially from PHP >=7.4

The code used to reproduce the example

<?php declare(strict_types = 1);

class Age
{
    private int $value;

    public static function fromInt(int $age): self
    {
        if ($age < 0) {
            throw new \RuntimeException('Impossible');
        }
        $self = new self();
        $self->value = $age;
        return $self;
    }

    public function value(): int
    {
        return $this->value;
    }
}

class Person
{
    /** @var Age|null */
    private $ageNullable;

    /** @var Age */
    private $ageForced;

    public static function withAge(int $age): self
    {
        $self = new self();
        $self->age = Age::fromInt($age);
        return $self;
    }

    /** @return Age */
    public function getAge()
    {
        return $this->ageNullable;
    }
}

class MainExample
{
    public static function main(): void
    {
        $person = Person::withAge(28);
        $age = $person->getAge();

        self::printAge($age); # <---- THIS IS A FALSE POSITIVE
    }

    private static function printAge(Age $age): void
    {
        echo 'Age value: ' . $age->value();
    }
}

I'm sorry for the code, it's not ideal I know... but this is the quickest way to share the problem. Using real return types at level function is (unfortunately) not an option in this context. That's why I think it's a pretty nice edge case...

Chemaclass avatar Feb 22 '22 17:02 Chemaclass

Exactly the same issue with older Symfony code:

abstract class ContainerAwareCommand extends Command implements ContainerAwareInterface
{
    /**
     * @var ContainerInterface|null
     */
    private $container;

    /**
     * @return ContainerInterface
     *
     * @throws \LogicException
     */
    protected function getContainer()

then in any extending class:

$this->getContainer()->getParameter('kernel.environment')

ends with Null pointer exception may occur here. The plugin should respect the annotations if you ask me as this is the ultimate source of truth provider by the developer.

mike-zukowski avatar Mar 03 '22 10:03 mike-zukowski

The same thing occurs in Doctrine:

        $criteria = Criteria::create()
            ->where(Criteria::expr()->eq('active', 1)) // <---- THIS IS A FALSE POSITIVE
        ;

Снимок экрана 2022-04-04 180501

Doctrine Code:

    /**
     * Returns the expression builder.
     *
     * @return \Doctrine\Common\Collections\ExpressionBuilder
     */
    public static function expr()
    {
        if (self::$expressionBuilder === null) {
            self::$expressionBuilder = new ExpressionBuilder();
        }

        return self::$expressionBuilder;
    }

alsii avatar Apr 04 '22 16:04 alsii