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

Remove unused getPropertiesFromMethods method #109

Merged
merged 1 commit into from
Aug 31, 2020

Conversation

brendt
Copy link
Contributor

@brendt brendt commented Aug 26, 2020

This PR fixes #98 .

The empty getPropertiesFromMethods method is clearly a bug, since it adds crucial information to the ide helper models file.

By removing it, the original implementation is used again, and that works fine. I've tested this in our own Laravel project, and it fixes the issue described in #98.

@brendt
Copy link
Contributor Author

brendt commented Aug 26, 2020

There might be one related side effect, so I'll discuss it here.

This piece of docblock is taken from the generated models file:

namespace App\Context\Product\Models{
/**
 * …
 *
 * @method static \App\Context\Product\QueryBuilders\CourseQueryBuilder|Course newModelQuery()
 * @method static \App\Context\Product\QueryBuilders\CourseQueryBuilder|Course newQuery()
 * @method static \App\Context\Product\QueryBuilders\CourseQueryBuilder|Course query()
 */
	class Course extends \Eloquent implements \App\Context\Product\Models\Concerns\WithCompliance, \App\Support\ActivityLog\ActivityLoggable, \App\Support\IsModel {}
}

Notice how Course::query() returns a union of \App\Context\Product\QueryBuilders\CourseQueryBuilder|Course (and also note that Course doesn't need its FQCN since we're already in its namespace).

Psalm reports the following error:

Magic method App\Context\Product\Models\Course::whereisparent does not exist (see https://psalm.dev/219)
        parent::__construct(Course::query()->whereIsParent(), $request);

Now sure, CourseQueryBuilder::whereIsParent does exist. So I did some testing, and discovered that if I remove the |Course part of the docblock, psalm works just fine.

-@method static \App\Context\Product\QueryBuilders\CourseQueryBuilder|Course query()
+@method static \App\Context\Product\QueryBuilders\CourseQueryBuilder query()

So whenever the union type \App\Context\Product\QueryBuilders\CourseQueryBuilder|Course is used, psalm doesn't recognise the methods on CourseQueryBuilder. If we're only using CourseQueryBuilder, psalm does.

I think this is a standalone error, but it only popped up after using this PR's implementation of FakeModelCommand, so I think the broken implementation was hiding another bug. If someone can confirm that's probably the case, I'll make a separate issue.

@mr-feek
Copy link
Collaborator

mr-feek commented Aug 31, 2020

Yeah, I think the tests are legitimately failing. I don't have much free time right now to help with a solution, but I did this over at larastan a while ago larastan/larastan#479

Basically it parses the docblock and turns it into a typed collection instead

@muglug
Copy link
Member

muglug commented Aug 31, 2020

@brendt so the docblock should just be \App\Context\Product\QueryBuilders\CourseQueryBuilder? That's something Psalm could be told to understand with the Model class's MethodReturnTypeProvider. I'll merge and fix it live.

@muglug muglug merged commit d0a5fa4 into psalm:master Aug 31, 2020
@mr-feek
Copy link
Collaborator

mr-feek commented Aug 31, 2020

I believe it should be \App\Context\Product\QueryBuilders\CourseQueryBuilder<Course> off the top of my head

@muglug
Copy link
Member

muglug commented Aug 31, 2020

Yeah, this is definitely a bug on Psalm's side

@muglug
Copy link
Member

muglug commented Sep 1, 2020

Actually not a Psalm bug – the plugin is providing a generic stub for the parent class with the correct return type, and one for the child class generated via laravel-ide-helper that is incorrect.

I resorted to a slightly nasty hack where I'm just removing the docblock-provided methods before Psalm has a chance to use them: acbfcaa#diff-9f7143a3a98cd6114dd5e4a17d64faa9R128

@mr-feek
Copy link
Collaborator

mr-feek commented Sep 1, 2020

Appreciate the assistance @muglug .

And thanks for the contribution @brendt !!!

@brendt
Copy link
Contributor Author

brendt commented Sep 1, 2020

Awesome, will test this later today :)

@brendt brendt deleted the properties-from-methods-fix branch September 1, 2020 11:44
@brendt
Copy link
Contributor Author

brendt commented Sep 1, 2020

Hm, I've now encountered a fatal error when running psalm, but I'm not entirely sure whether it's related or not:

Exception

  Not a string literal
Stack trace in the forked worker:
#0 <PROJECT>/vendor/psalm/plugin-laravel/src/ContainerResolver.php(72): Psalm\Type\Union->getSingleStringLiteral()
#1 <PROJECT>/vendor/psalm/plugin-laravel/src/ReturnTypeProvider/AppReturnTypeProvider.php(42): Psalm\LaravelPlugin\ContainerResolver::resolvePsalmTypeFromApplicationContainerViaArgs(Object(Psalm\Internal\Provider\NodeDataProvider), Array)
#2 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Provider/FunctionReturnTypeProvider.php(111): Psalm\LaravelPlugin\ReturnTypeProvider\AppReturnTypeProvider::getFunctionReturnType(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), 'app', Array, Object(Psalm\Context), Object(Psalm\CodeLocation))
#3 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php(924): Psalm\Internal\Provider\FunctionReturnTypeProvider->getReturnType(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), 'app', Array, Object(Psalm\Context), Object(Psalm\CodeLocation))
#4 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php(351): Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallAnalyzer::getFunctionCallReturnType(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Codebase), Object(PhpParser\Node\Expr\FuncCall), Object(PhpParser\Node\Name), 'app', false, true, Object(Psalm\Storage\FunctionStorage), Object(Psalm\Internal\Type\TemplateResult), Object(Psalm\Context))
#5 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(262): Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context))
#6 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(45): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context), false, NULL, false)
#7 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php(50): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context))
#8 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(150): Psalm\Internal\Analyzer\Statements\Expression\Call\MethodCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\MethodCall), Object(Psalm\Context))
#9 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(45): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\MethodCall), Object(Psalm\Context), false, NULL, false)
#10 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php(164): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\MethodCall), Object(Psalm\Context))
#11 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(131): Psalm\Internal\Analyzer\Statements\Expression\AssignmentAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Variable), Object(PhpParser\Node\Expr\MethodCall), NULL, Object(Psalm\Context), NULL)
#12 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(45): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Assign), Object(Psalm\Context), false, Object(Psalm\Context), true)
#13 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(500): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Assign), Object(Psalm\Context), false, Object(Psalm\Context), true)
#14 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(169): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), Object(Psalm\Context))
#15 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(597): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#16 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClosureAnalyzer.php(173): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context), false, Array)
#17 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(285): Psalm\Internal\Analyzer\ClosureAnalyzer::analyzeExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Closure), Object(Psalm\Context))
#18 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(45): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Closure), Object(Psalm\Context), false, NULL, false)
#19 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php(293): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Closure), Object(Psalm\Context))
#20 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php(294): Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Array, Array, 'array_reduce', Object(Psalm\Context))
#21 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(262): Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context))
#22 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(45): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context), false, NULL, false)
#23 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php(164): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context))
#24 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(131): Psalm\Internal\Analyzer\Statements\Expression\AssignmentAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Array_), Object(PhpParser\Node\Expr\FuncCall), NULL, Object(Psalm\Context), NULL)
#25 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(45): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Assign), Object(Psalm\Context), false, Object(Psalm\Context), true)
#26 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(500): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Assign), Object(Psalm\Context), false, Object(Psalm\Context), true)
#27 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(169): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), Object(Psalm\Context))
#28 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(597): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#29 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(1918): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#30 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(748): Psalm\Internal\Analyzer\ClassAnalyzer->analyzeClassMethod(Object(PhpParser\Node\Stmt\ClassMethod), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Internal\Analyzer\ClassAnalyzer), Object(Psalm\Context), Object(Psalm\Context))
#31 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(221): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#32 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(357): Psalm\Internal\Analyzer\FileAnalyzer->analyze(NULL)
#33 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(193): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase\{closure}(36, '/Users/brent/de...')
#34 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(423): Psalm\Internal\Fork\Pool->__construct(Array, Object(Closure), Object(Closure), Object(Closure), Object(Closure))
#35 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(283): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 4)
#36 <PROJECT>/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(648): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 4, false, true)
#37 <PROJECT>/vendor/vimeo/psalm/src/psalm.php(680): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/Users/brent/de...', false)
#38 <PROJECT>/vendor/vimeo/psalm/psalm(2): require_once('/Users/brent/de...')
#39 {main}

I'm using the following commits:

        "psalm/plugin-laravel": "dev-master#d4c9daf2a589c9ad76000eae42c62ea09d3b0e72",
        "vimeo/psalm": "dev-master#548ac1129c7a9bd80ab2bddd02068dcc2191a16d as 3.15.0",

@muglug
Copy link
Member

muglug commented Sep 1, 2020

@brendt fixed in 05fccc7

@brendt
Copy link
Contributor Author

brendt commented Sep 2, 2020

I'm happy to say all works now, thanks for the help both!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

models.stubphp out of sync
3 participants