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

POC write output for varType and templateType macros #1

Closed
wants to merge 1 commit into from

Conversation

lulco
Copy link
Owner

@lulco lulco commented Jun 25, 2021

No description provided.

@lulco lulco changed the base branch from master to v2.10 June 25, 2021 21:51
@lulco
Copy link
Owner Author

lulco commented Jun 25, 2021

problems:

  1. extract($this->params); is executed in all methods of generated Template, but varType / templateType write their output only in main or one of blocks where they are used in latte file
  2. output of varType / templateType is generated AFTER extract($this->params);, not BEFORE like suggested in Propagate type information in compiled template code to allow static analysis nette/latte#262

$reflectionClass = new ReflectionClass($node->args);
foreach ($reflectionClass->getProperties() as $property) {
$propertyName = $property->getName();
$type = $property->getType();
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this works only for php >= 7.4

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and only for native typed properties (php doc is not read)


$templateType = '';
if ($type) {
$templateType .= "/** @var {$type->getName()} */\n";
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getName() can be called only on ReflectionNamedType, it could be also ReflectionUnionType here

$templateTypes = [];
try {
$reflectionClass = new ReflectionClass($node->args);
foreach ($reflectionClass->getProperties() as $property) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getProperties returns only real properties, it is not working for @property / @property-read annotation


$templateType = '';
if ($type) {
$templateType .= "/** @var {$type->getName()} */\n";
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO handle nullable

if ($type) {
$templateType .= "/** @var {$type->getName()} */\n";
}
$templateType .= "\$$propertyName = \$this->params['$propertyName'];";
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO handle nullable with $this->params['$propertyName'] ?? null


$varName = $variable[0];
$paramName = ltrim($varName, '$');
return $writer->write("/** @var $type */\n$varName = \$this->params['$paramName']");
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO handle nullable with $this->params['$paramName'] ?? null


$varName = $variable[0];
$paramName = ltrim($varName, '$');
return $writer->write("/** @var $type */\n$varName = \$this->params['$paramName']");
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing semicolon at the end of this write

@jakubvojacek
Copy link

looking forward to this 👍

@lulco
Copy link
Owner Author

lulco commented Jul 24, 2021

Nobody wants this :( https://blog.nette.org/cs/vyhodnoceni-nette-pruzkumu

@MartinMystikJonas
Copy link

What needs to be done for this to be merged? Static analysis of templates would be huge help during rectorings.

@lulco
Copy link
Owner Author

lulco commented Sep 25, 2021

There are many problems. I've freezed it. Now I am trying different approach. It is based on running phpstan for latte templates in context of Control (Presenter later). It creates php parser nodes and feed them to phpstan. See https://github.com/efabrica-team/phpstan-latte and follow my Twitter.

@MartinMystikJonas
Copy link

MartinMystikJonas commented Sep 25, 2021

Well that new approach seems a bit overcomplicated to me. and it will work only with phpstan but not other tools. Can you summary what are problems you encountered with this approach? I would like to look at it myself to see if it can be (at least partially) solved. Main problem is propagation of type information to subsequent blocks, right?

@lulco
Copy link
Owner Author

lulco commented Sep 25, 2021

Well that new approach seems a bit overcomplicated to me.

Probably it is, it starts as challenge. It is my first phpstan rule. I really don't know what I'm doing :D previously I used phpstan just as user, not developer.
But I have to say I solve problems with variables, filters and components very quickly.
It also checks latte against its "caller" not as standalone element. So there is no need to have varTypes and templateTypes in latte files. If you have one template for more Controls. You can for example forgot send some variable to it from one of controls.
The main problem in new approach is that I have to implement all tokens of latte. It is also main advantage - while it is not implemented, it will not report errors.
The second is that there is no file generated so phpstan cannot parse types from phpdoc

  • this is imho design fail of phpstan but I have to live with it or send pull request to change it.

and it will work only with phpstan but not other tools.

Yes, I don't use any other tools so I don't care.

Can you summary what are problems you encountered with this approach? I would like to look at it myself to see if it can be (at least partially) solved. Main problem is propagation of type information to subsequent blocks, right?

Yes propagation of types to all blocks is first problem. Next problem will be how to resolve filters, components etc. Then you need to map line numbers from compiled template to latte's line numbers. This is solved with the new approach because nodes are generated with line info from latte.

I believe the best would be some combination of existing compiled template and my approach.

@MartinMystikJonas
Copy link

Ok I will try to look at when I would have some free time. Problem with filters I plan to solve by dumping known filters from app latte engine that I already use to convert latte to php.

@MartinMystikJonas
Copy link

Have you seen macro {parameters} and how it works by modifying Compiler->paramsExtraction? It seems to me that it will be enough to just add generation of phpdoc comments with types there and implement similar behaviour in varType where it will append appropriate phpdoc to paramsExtraction.

@lulco
Copy link
Owner Author

lulco commented Sep 25, 2021

No, I haven't seen it. Go for it :)

@MartinMystikJonas
Copy link

@lulco Check this: nette#275 What do you think? Next step will by support for {templateType} but it should be relatively easy.

I just have one question I saw your note about @Property / @property-read annotations - is it really needed? It seems that it is not propagated to template by Latte anyway. Or am I wrong?

@lulco
Copy link
Owner Author

lulco commented Sep 27, 2021

I think this way (my and also yours) is screwing static analysis. varType nor templateType not propagate variables to latte. They are only for latte plugin. Just control / presenter propagate variables to latte.

It is much better prepare compiled template for static analysis by adding assigned variables to it.

Ad @Property: it was inspired by https://forum.nette.org/en/32893-custom-template-class-for-presenter-and-control-experimental-feature

@lulco
Copy link
Owner Author

lulco commented Sep 27, 2021

Check this repo https://github.com/symplify/symplify/tree/main/packages/phpstan-rules/packages and this rule https://github.com/symplify/symplify/tree/main/packages/phpstan-rules/packages/nette/tests/Rules/LatteCompleteCheckRule

it is similar to my solution in phpstan-latte, but it use compiled template with some changes and postprocessing for mapping php lines back to latte lines.

It can have good results if we teach it to check all controls and presenters. Now it works only if you have ->render(‘template', [params]) in control

@lulco
Copy link
Owner Author

lulco commented Sep 27, 2021

Closing as not relevant anymore

@lulco lulco closed this Sep 27, 2021
@MartinMystikJonas
Copy link

Imho static analysis should be done in two separate layers. First is static analysis of template itself (my approach) that checks internal consistency of template and is independent of used tool and works even for non standard rendering code and second is static analysis of template rendering in caller done by tool plugin.

@MartinMystikJonas
Copy link

Also propagation of known type information to compiled template can be also used to guide these plugins you and Tomáš develops.

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.

3 participants