Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notices when analyzing some PDO-related code #4836

Closed
morozov opened this issue Dec 13, 2020 · 14 comments · Fixed by #5337
Closed

Notices when analyzing some PDO-related code #4836

morozov opened this issue Dec 13, 2020 · 14 comments · Fixed by #5337

Comments

@morozov
Copy link
Contributor

morozov commented Dec 13, 2020

The issue can be observed on doctrine/dbal#4465 and is reproducible on any Psalm version from 4.1.1 to 4.3.1. Running psalm --debug-by-line yields the following:

Notice: Undefined offset: 0 in /Users/smorozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php on line 1264
Notice: Trying to get property 'default' of non-object in /Users/smorozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php on line 1328
Notice: Undefined offset: 1 in /Users/smorozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php on line 1264
Notice: Trying to get property 'default' of non-object in /Users/smorozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php on line 1328
Notice: Undefined offset: 2 in /Users/smorozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php on line 1264
Notice: Trying to get property 'default' of non-object in /Users/smorozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php on line 1328
/Users/smorozov/Projects/dbal/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php:36

Where the code in question looks like this:

    /**
     * @internal
     */
    trait PDOQueryImplementation
    {
        /**
         * @return PDOStatement
         */
        public function query()
        {
            return $this->doQuery(...func_get_args());
        }
    }

This looks related to JetBrains/phpstorm-stubs#950 which introduces two methods with the same name and different signatures for different PHP versions.

@psalm-github-bot
Copy link

Hey @morozov, can you reproduce the issue on https://psalm.dev ?

@muglug
Copy link
Collaborator

muglug commented Dec 13, 2020

That definitely makes sense – I assume you're using those stubs?

@morozov
Copy link
Contributor Author

morozov commented Dec 13, 2020

Yes (psalm.xml.dist):

    <stubs>
        <file name="vendor/jetbrains/phpstorm-stubs/PDO/PDO.php" />
        <file name="vendor/jetbrains/phpstorm-stubs/ibm_db2/ibm_db2.php" />
        <file name="vendor/jetbrains/phpstorm-stubs/mysqli/mysqli.php" />
        <file name="vendor/jetbrains/phpstorm-stubs/oci8/oci8.php" />
        <file name="vendor/jetbrains/phpstorm-stubs/pgsql/pgsql.php" />
        <file name="vendor/jetbrains/phpstorm-stubs/sqlsrv/sqlsrv.php" />
    </stubs>

Primarily on CI in order to avoid having to install all DB extensions for static analysis.

@muglug
Copy link
Collaborator

muglug commented Dec 14, 2020

Currently the populator processes dupllicate methods if it's in the stub phase, but that assumes that the duplicates are in a different file, not the same one. That'll have to change. Not sure about that PHPStorm-only attribute. Hmm.

@morozov
Copy link
Contributor Author

morozov commented Dec 14, 2020

Not sure about that PHPStorm-only attribute.

Whether it's a proprietary PhpStorm attribute or not, I believe it's still relevant that a given signature may look differently depending on the PHP and/or extension version.

To version the stubs, one approach might be to use a separate file for each version and then feed only the relevant ones to the static analyzer or the IDE. It wouldn't require any changes in Psalm but be harder to manage by the maintainers of the stubs and by their users. Another approach would be to have all the stubs in one file annotated with a version constraint (e.g. there's a more classic @since annotation).

At this point, it looks reasonable that Psalm introduces the support of the stub version awareness – be it based on the PhpStorm attribute, or @since, it doesn't matter.

@muglug
Copy link
Collaborator

muglug commented Dec 14, 2020

Yeah, it's not a massive adjustment to support that attribute. Pretty straightforward, and beats picking one arbitrarily.

@morozov
Copy link
Contributor Author

morozov commented Mar 6, 2021

@muglug if it's not a huge effort, could it be prioritized? This issue prevents Doctrine DBAL from upgrading to the latest version of stubs which in turn requires adding more items on the issue suppression list every time when a mistake is found in the old stubbed API.

@morozov
Copy link
Contributor Author

morozov commented Mar 7, 2021

Thanks for the fix, @weirdan. It seems to be working well with PHP 8.0 (the build on the PR in the description passes) but with PHP 7.4 I still see some similar errors:

$ psalm
Scanning files...
Analyzing files...

░░░░░░░░░░░░░░░░░░░░░░░░░░░░EE░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  60 / 506 (11%)
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 120 / 506 (23%)
░░░░░░░░░░░░Uncaught Exception: PHP Error: Undefined offset: 0 in /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php:1037
Stack trace in the forked worker:
#0 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(1037): Psalm\Internal\ErrorHandler::Psalm\Internal\{closure}(8, 'Undefined offse...', '/home/morozov/P...', 1037, Array)
#1 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(317): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->processParams(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Storage\MethodStorage), 'Doctrine\\DBAL\\D...', Array, Object(Psalm\Context), false)
#2 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(1703): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#3 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(1371): Psalm\Internal\Analyzer\ClassAnalyzer->analyzeClassMethod(Object(PhpParser\Node\Stmt\ClassMethod), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Internal\Analyzer\TraitAnalyzer), Object(Psalm\Context), Object(Psalm\Context))
#4 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(410): Psalm\Internal\Analyzer\ClassAnalyzer->analyzeTraitUse(Object(Psalm\Aliases), Object(PhpParser\Node\Stmt\TraitUse), Object(Psalm\Internal\Analyzer\ProjectAnalyzer), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Context), Object(Psalm\Context), NULL)
#5 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(213): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#6 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(341): Psalm\Internal\Analyzer\FileAnalyzer->analyze(NULL)
#7 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(193): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase\{closure}(48, '/home/morozov/P...')
#8 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(407): Psalm\Internal\Fork\Pool->__construct(Array, Object(Closure), Object(Closure), Object(Closure), Object(Closure))
#9 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(270): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3)
#10 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(636): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3, false, true)
#11 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/psalm.php(683): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/home/morozov/P...', true)
#12 /home/morozov/Projects/dbal/vendor/vimeo/psalm/psalm(2): require_once('/home/morozov/P...')
#13 {main} in /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php:357
Stack trace:
#0 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(389): Psalm\Internal\Fork\Pool->readResultsFromChildren()
#1 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(474): Psalm\Internal\Fork\Pool->wait()
#2 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(270): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3)
#3 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(636): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3, false, true)
#4 /home/morozov/Projects/dbal/vendor/vimeo/psalm/src/psalm.php(683): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/home/morozov/P...', true)
#5 /home/morozov/Projects/dbal/vendor/vimeo/psalm/psalm(2): require_once('/home/morozov/P...')
#6 {main}
(Psalm dev-master@3c66b755e2468b0976979768972d298f4ba25651 crashed due to an uncaught Throwable)

@weirdan
Copy link
Collaborator

weirdan commented Mar 7, 2021

Does the stub in question have @since tags?

@morozov
Copy link
Contributor Author

morozov commented Mar 7, 2021

Some of the stubs seem to have the annotations. E.g.: PDO/PDO.php:

        /**
         * @since 8.0
         */
        public function getIterator(){}

Not sure what exactly is failing now. If you believe the problem is on the stubs side, I'll try to debug and provide more details.

@weirdan
Copy link
Collaborator

weirdan commented Mar 7, 2021

v2020.2 you're updating to does not have multiple versions of query() method. So the fix was for the problem you described, but apparently not the one you were having 🤷‍♂️

@weirdan
Copy link
Collaborator

weirdan commented Mar 7, 2021

I think it's actually caused by Psalm being confused by version-conditional trait implementation. It uses params and parser params (whatever that is), and expects them to come from the same implementation. But when it analyzes implementation from the false branch it uses param list from the true branch.

@weirdan weirdan reopened this Mar 7, 2021
@Chekote
Copy link

Chekote commented Mar 16, 2021

I think this is fixed by 817d1cf.

@morozov
Copy link
Contributor Author

morozov commented Mar 16, 2021

It looks like that. The notices above aren't reproducible on 2777b62 with PHP 7.4 or PHP 8.0.

@weirdan I believe this issue can be closed given its subject. As for being able to use the JetBrains stubs which have PHP versions annotated with their proprietary annotations, I want to get rid of the dependency on them entirely since both Psalm and PHPStan have their own stubs.

Thank you and @muglug for taking care of the issue.

@weirdan weirdan closed this as completed Mar 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants