Ouccchhhh I spent 1h30 trying to reproduce this issue and found how to do that youpiii:
<?php
namespace Devsense\Helper;
/**
* @property-read myClassA $myPropertyA
*/
class myClassA {}
/**
* @property-read myClassB $myPropertyB
*/
class myClassB {}
/**
* @property-read myClassA $myPropertyA
*/
abstract class AbstractTest
{
public function __get(string $name)
{
return $this->_store[$name];
}
}
/**
* @property-read myClassB $myPropertyB
*/
final class Test extends AbstractTest {}
/**
* @template P of AbstractPlugin
*/
abstract class AbstractHelper
{
/**
* @var P
*/
public AbstractPlugin $plugin;
}
/**
* @extends AbstractHelper<Plugin>
*/
final class Helper extends AbstractHelper {}
/**
* @template T of AbstractTest
*/
abstract class AbstractPlugin
{
/**
* @var T
*/
public AbstractTest $test;
}
/**
* @extends AbstractPlugin<Test>
*/
abstract class MyPlugin extends AbstractPlugin
{
}
final class Plugin extends MyPlugin
{
}
$helper = new Helper();
$helper->plugin->test->myPropertyA->myPropertyA->myPropertyA;
$helper->plugin->test->myPropertyB->myPropertyB->myPropertyB;
function fctTestHelper(AbstractHelper $helper) {
}
fctTestHelper($helper);
function fctTestPlugin(Plugin $plugin) {
}
fctTestPlugin($helper->plugin);
Be careful I don't understand why but, can you check the lines 69 and 70:
$helper->plugin->test->myPropertyA->myPropertyA->myPropertyA;
$helper->plugin->test->myPropertyB->myPropertyB->myPropertyB;
PHP Tools is able to resolve myPropertyA (loop is expected) but not myPropertyB.
If you remove the method __get in the class AbstractTest, it works and myPropertyB can be resolved in loop.
I tested in my project and if I remove a __get function in my helpers class, the resolver works correctly.
(The __get method has not any return type in this example but in my project there is one, removing it does not change anything)
Hope you will be able to find the bug with this example ^^
Thank you @JakubMisek