small fixes, add diagnostic mode
parent
d3f2bebb40
commit
c18bec0d50
|
@ -0,0 +1,201 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace LanguageServer;
|
||||||
|
|
||||||
|
use LanguageServer\Protocol\TolerantSymbolInformation;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
|
||||||
|
use phpDocumentor\Reflection\{
|
||||||
|
DocBlock, DocBlockFactory, Types, Type, Fqsen, TypeResolver
|
||||||
|
};
|
||||||
|
use LanguageServer\Protocol\SymbolInformation;
|
||||||
|
use LanguageServer\Index\ReadableIndex;
|
||||||
|
use Microsoft\PhpParser as Tolerant;
|
||||||
|
|
||||||
|
class LoggedTolerantDefinitionResolver extends TolerantDefinitionResolver
|
||||||
|
{
|
||||||
|
|
||||||
|
private static $logger = false;
|
||||||
|
|
||||||
|
private static $stackLevel = 0;
|
||||||
|
/**
|
||||||
|
* @param ReadableIndex $index
|
||||||
|
*/
|
||||||
|
public function __construct(ReadableIndex $index)
|
||||||
|
{
|
||||||
|
self::$logger = false;
|
||||||
|
parent::__construct($index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logMethod($methodName, $param1, $param2 = -1) {
|
||||||
|
$callStr = "FUNCTION: $methodName(";
|
||||||
|
if ($param2 !== -1) {
|
||||||
|
$callStr .= $this->getString($param1) . ", " . $this->getString($param2) . ")\n";
|
||||||
|
if (self::$logger === true) {
|
||||||
|
echo $callStr;
|
||||||
|
}
|
||||||
|
$result = parent::$methodName($param1, $param2);
|
||||||
|
} else {
|
||||||
|
$callStr .= $this->getString($param1) . ")\n";
|
||||||
|
if (self::$logger === true) {
|
||||||
|
echo $callStr;
|
||||||
|
}
|
||||||
|
$result = parent::$methodName($param1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::$logger === true) {
|
||||||
|
if ($result instanceof Definition) {
|
||||||
|
$resultText = $result->fqn;
|
||||||
|
} elseif ($result instanceof DocBlock) {
|
||||||
|
$resultText = $result->getDescription();
|
||||||
|
} else {
|
||||||
|
$resultText = $result ?? "NULL";
|
||||||
|
}
|
||||||
|
echo "> RESULT[$methodName]: " . $resultText . "\n";
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getString($param) {
|
||||||
|
if ($param instanceof Tolerant\Node) {
|
||||||
|
return "[" . $param->getNodeKindName() . "] " . $param->getText();
|
||||||
|
}
|
||||||
|
return (string)$param;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the declaration line for a given node.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param Tolerant\Node $node
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDeclarationLineFromNode($node): string
|
||||||
|
{
|
||||||
|
return $this->logMethod('getDeclarationLineFromNode', $node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the documentation string for a node, if it has one
|
||||||
|
*
|
||||||
|
* @param Tolerant\Node $node
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getDocumentationFromNode($node)
|
||||||
|
{
|
||||||
|
return $this->logMethod('getDocumentationFromNode', $node);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDocBlock(Tolerant\Node $node) {
|
||||||
|
return $this->logMethod('getDocBlock', $node);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Definition for a definition node
|
||||||
|
*
|
||||||
|
* @param Tolerant\Node $node
|
||||||
|
* @param string $fqn
|
||||||
|
* @return Definition
|
||||||
|
*/
|
||||||
|
public function createDefinitionFromNode($node, string $fqn = null): Definition
|
||||||
|
{
|
||||||
|
return $this->logMethod('createDefinitionFromNode', $node, $fqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given any node, returns the Definition object of the symbol that is referenced
|
||||||
|
*
|
||||||
|
* @param Tolerant\Node $node Any reference node
|
||||||
|
* @return Definition|null
|
||||||
|
*/
|
||||||
|
public function resolveReferenceNodeToDefinition($node)
|
||||||
|
{
|
||||||
|
self::$logger = true;
|
||||||
|
return $this->logMethod('resolveReferenceNodeToDefinition', $node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given any node, returns the FQN of the symbol that is referenced
|
||||||
|
* Returns null if the FQN could not be resolved or the reference node references a variable
|
||||||
|
*
|
||||||
|
* @param Tolerant\Node $node
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function resolveReferenceNodeToFqn($node) {
|
||||||
|
return $this->logMethod('resolveReferenceNodeToFqn', $node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the assignment or parameter node where a variable was defined
|
||||||
|
*
|
||||||
|
* @param Node\Expr\Variable|Node\Expr\ClosureUse $var The variable access
|
||||||
|
* @return Node\Expr\Assign|Node\Expr\AssignOp|Node\Param|Node\Expr\ClosureUse|null
|
||||||
|
*/
|
||||||
|
public function resolveVariableToNode(Tolerant\Node $var)
|
||||||
|
{
|
||||||
|
return $this->logMethod('resolveVariableToNode', $var);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an expression node, resolves that expression recursively to a type.
|
||||||
|
* If the type could not be resolved, returns Types\Mixed.
|
||||||
|
*
|
||||||
|
* @param \PhpParser\Node\Expr $expr
|
||||||
|
* @return \phpDocumentor\Reflection\Type
|
||||||
|
*/
|
||||||
|
public function resolveExpressionNodeToType($expr): Type
|
||||||
|
{
|
||||||
|
return $this->logMethod('resolveExpressionNodeToType', $expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes any class name node (from a static method call, or new node) and returns a Type object
|
||||||
|
* Resolves keywords like self, static and parent
|
||||||
|
*
|
||||||
|
* @param Tolerant\Node || Tolerant\Token $class
|
||||||
|
* @return Type
|
||||||
|
*/
|
||||||
|
public function resolveClassNameToType($class): Type
|
||||||
|
{
|
||||||
|
return $this->logMethod('resolveClassNameToType', $class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type a reference to this symbol will resolve to.
|
||||||
|
* For properties and constants, this is the type of the property/constant.
|
||||||
|
* For functions and methods, this is the return type.
|
||||||
|
* For parameters, this is the type of the parameter.
|
||||||
|
* For classes and interfaces, this is the class type (object).
|
||||||
|
* For variables / assignments, this is the documented type or type the assignment resolves to.
|
||||||
|
* Can also be a compound type.
|
||||||
|
* If it is unknown, will be Types\Mixed.
|
||||||
|
* Returns null if the node does not have a type.
|
||||||
|
*
|
||||||
|
* @param Tolerant\Node $node
|
||||||
|
* @return \phpDocumentor\Reflection\Type|null
|
||||||
|
*/
|
||||||
|
public function getTypeFromNode($node)
|
||||||
|
{
|
||||||
|
return $this->logMethod('getTypeFromNode', $node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fully qualified name (FQN) that is defined by a node
|
||||||
|
* Returns null if the node does not declare any symbol that can be referenced by an FQN
|
||||||
|
*
|
||||||
|
* @param Tolerant\Node $node
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public static function getDefinedFqn($node)
|
||||||
|
{
|
||||||
|
$result = parent::getDefinedFqn($node);
|
||||||
|
if (self::$logger === true) {
|
||||||
|
echo "FUNCTION: getDefinedFqn(" . $node->getNodeKindName() . ")\n";
|
||||||
|
var_dump($result);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,4 +7,5 @@ class ParserKind
|
||||||
{
|
{
|
||||||
const PHP_PARSER = 1;
|
const PHP_PARSER = 1;
|
||||||
const TOLERANT_PHP_PARSER = 2;
|
const TOLERANT_PHP_PARSER = 2;
|
||||||
|
const DIAGNOSTIC_TOLERANT_PHP_PARSER = 3;
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ use Microsoft\PhpParser as Tolerant;
|
||||||
use LanguageServer\Index\ReadableIndex;
|
use LanguageServer\Index\ReadableIndex;
|
||||||
|
|
||||||
class ParserResourceFactory {
|
class ParserResourceFactory {
|
||||||
const PARSER_KIND = ParserKind::TOLERANT_PHP_PARSER;
|
const PARSER_KIND = ParserKind::DIAGNOSTIC_TOLERANT_PHP_PARSER;
|
||||||
|
|
||||||
public static function getParser() {
|
public static function getParser() {
|
||||||
if (self::PARSER_KIND === ParserKind::PHP_PARSER) {
|
if (self::PARSER_KIND === ParserKind::PHP_PARSER) {
|
||||||
|
@ -19,8 +19,10 @@ class ParserResourceFactory {
|
||||||
public static function getDefinitionResolver(ReadableIndex $index) {
|
public static function getDefinitionResolver(ReadableIndex $index) {
|
||||||
if (self::PARSER_KIND === ParserKind::PHP_PARSER) {
|
if (self::PARSER_KIND === ParserKind::PHP_PARSER) {
|
||||||
return new DefinitionResolver($index);
|
return new DefinitionResolver($index);
|
||||||
} else {
|
} elseif (self::PARSER_KIND === ParserKind::TOLERANT_PHP_PARSER) {
|
||||||
return new TolerantDefinitionResolver($index);
|
return new TolerantDefinitionResolver($index);
|
||||||
|
} elseif (self::PARSER_KIND === ParserKind::DIAGNOSTIC_TOLERANT_PHP_PARSER) {
|
||||||
|
return new LoggedTolerantDefinitionResolver($index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,7 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
$def = new Definition;
|
$def = new Definition;
|
||||||
|
|
||||||
// this determines whether the suggestion will show after "new"
|
// this determines whether the suggestion will show after "new"
|
||||||
|
// TODO name
|
||||||
$def->isClass = $node instanceof Tolerant\Node\Statement\ClassDeclaration;
|
$def->isClass = $node instanceof Tolerant\Node\Statement\ClassDeclaration;
|
||||||
|
|
||||||
$def->isGlobal = (
|
$def->isGlobal = (
|
||||||
|
@ -162,12 +163,13 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
|| $node instanceof Tolerant\Node\Statement\ClassDeclaration
|
|| $node instanceof Tolerant\Node\Statement\ClassDeclaration
|
||||||
|| $node instanceof Tolerant\Node\Statement\TraitDeclaration
|
|| $node instanceof Tolerant\Node\Statement\TraitDeclaration
|
||||||
|
|
||||||
|
// TODO namespaces?
|
||||||
|| $node instanceof Tolerant\Node\Statement\NamespaceDefinition && $node->name !== null
|
|| $node instanceof Tolerant\Node\Statement\NamespaceDefinition && $node->name !== null
|
||||||
|
|
||||||
|| $node instanceof Tolerant\Node\Statement\FunctionDeclaration
|
|| $node instanceof Tolerant\Node\Statement\FunctionDeclaration
|
||||||
|
|
||||||
|| $node instanceof Tolerant\Node\Statement\ConstDeclaration
|
|| $node instanceof Tolerant\Node\Statement\ConstDeclaration
|
||||||
|| $node instanceof Tolerant\Node\ClassConstDeclaration
|
// || $node instanceof Tolerant\Node\ClassConstDeclaration
|
||||||
);
|
);
|
||||||
|
|
||||||
$def->isStatic = (
|
$def->isStatic = (
|
||||||
|
@ -206,14 +208,20 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
*/
|
*/
|
||||||
public function resolveReferenceNodeToDefinition($node)
|
public function resolveReferenceNodeToDefinition($node)
|
||||||
{
|
{
|
||||||
|
$parent = $node->getParent();
|
||||||
|
if ($parent instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression) {
|
||||||
|
$node = $parent;
|
||||||
|
}
|
||||||
// Variables are not indexed globally, as they stay in the file scope anyway
|
// Variables are not indexed globally, as they stay in the file scope anyway
|
||||||
if ($node instanceof Tolerant\Node\Expression\Variable) {
|
if ($node instanceof Tolerant\Node\Expression\Variable) {
|
||||||
// Resolve $this
|
// Resolve $this
|
||||||
if ($node->getName() === 'this' && $fqn = $this->getContainingClassFqn($node)) {
|
if ($node->getName() === 'this' && $fqn = $this->getContainingClassFqn($node)) {
|
||||||
return $this->index->getDefinition($fqn, false);
|
return $this->index->getDefinition($fqn, false);
|
||||||
}
|
}
|
||||||
|
// TODO running throug thid for class constants or properties
|
||||||
|
|
||||||
// Resolve the variable to a definition node (assignment, param or closure use)
|
// Resolve the variable to a definition node (assignment, param or closure use)
|
||||||
$defNode = self::resolveVariableToNode($node);
|
$defNode = $this->resolveVariableToNode($node);
|
||||||
if ($defNode === null) {
|
if ($defNode === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -239,11 +247,11 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
* @param Node $node
|
* @param Node $node
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function resolveReferenceNodeToFqn($node)
|
public function resolveReferenceNodeToFqn($node) {
|
||||||
{
|
|
||||||
// TODO all name tokens should be a part of a node
|
|
||||||
$parent = $node->getParent();
|
|
||||||
|
|
||||||
|
|
||||||
|
$parent = $node->getParent();
|
||||||
|
// TODO all name tokens should be a part of a node
|
||||||
if ($node instanceof Tolerant\Node\QualifiedName) {
|
if ($node instanceof Tolerant\Node\QualifiedName) {
|
||||||
// For extends, implements, type hints and classes of classes of static calls use the name directly
|
// For extends, implements, type hints and classes of classes of static calls use the name directly
|
||||||
$name = (string)$node->getResolvedName() ?? $node->getText();
|
$name = (string)$node->getResolvedName() ?? $node->getText();
|
||||||
|
@ -260,10 +268,14 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($useClause->functionOrConst->kind === Tolerant\TokenKind::FunctionKeyword) {
|
if ($useClause->functionOrConst->kind === Tolerant\TokenKind::FunctionKeyword) {
|
||||||
$name .= "()";
|
$name .= '()';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($node->getFirstAncestor(Tolerant\Node\Expression\CallExpression::class) !== null) {
|
||||||
|
$name .= '()';
|
||||||
|
}
|
||||||
|
// does this work for function calls?
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
/*elseif ($node instanceof Tolerant\Node\Expression\CallExpression || ($node = $node->getFirstAncestor(Tolerant\Node\Expression\CallExpression::class)) !== null) {
|
/*elseif ($node instanceof Tolerant\Node\Expression\CallExpression || ($node = $node->getFirstAncestor(Tolerant\Node\Expression\CallExpression::class)) !== null) {
|
||||||
|
@ -352,7 +364,7 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
}
|
}
|
||||||
return $classFqn . $memberSuffix;
|
return $classFqn . $memberSuffix;
|
||||||
}
|
}
|
||||||
else if ($parent->parent instanceof Tolerant\Node\Expression\CallExpression && $node instanceof Tolerant\Node\DelimitedList\QualifiedNameParts) {
|
else if ($parent instanceof Tolerant\Node\Expression\CallExpression && $node instanceof Tolerant\Node\QualifiedName) {
|
||||||
if ($parent->name instanceof Node\Expr) {
|
if ($parent->name instanceof Node\Expr) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -365,10 +377,10 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
($scoped = $node) instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression
|
($scoped = $node) instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression
|
||||||
|| ($node instanceof Tolerant\Node\Expression\CallExpression && ($scoped = $node->callableExpression) instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression)
|
|| ($node instanceof Tolerant\Node\Expression\CallExpression && ($scoped = $node->callableExpression) instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression)
|
||||||
) {
|
) {
|
||||||
if ($scoped->memberName instanceof Tolerant\Node\Expression) {
|
// if ($scoped->memberName instanceof Tolerant\Node\Expression) {
|
||||||
// Cannot get definition of dynamic names
|
// Cannot get definition of dynamic names
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
$className = (string)$scoped->scopeResolutionQualifier->getText();
|
$className = (string)$scoped->scopeResolutionQualifier->getText();
|
||||||
if ($className === 'self' || $className === 'static' || $className === 'parent') {
|
if ($className === 'self' || $className === 'static' || $className === 'parent') {
|
||||||
// self and static are resolved to the containing class
|
// self and static are resolved to the containing class
|
||||||
|
@ -408,6 +420,7 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
|
|
||||||
private function isConstantFetch(Tolerant\Node $node) : bool {
|
private function isConstantFetch(Tolerant\Node $node) : bool {
|
||||||
return
|
return
|
||||||
|
$node instanceof Tolerant\Node\QualifiedName &&
|
||||||
($node->parent instanceof Tolerant\Node\Statement\ExpressionStatement || $node->parent instanceof Tolerant\Node\Expression) &&
|
($node->parent instanceof Tolerant\Node\Statement\ExpressionStatement || $node->parent instanceof Tolerant\Node\Expression) &&
|
||||||
!(
|
!(
|
||||||
$node->parent instanceof Tolerant\Node\Expression\MemberAccessExpression || $node->parent instanceof Tolerant\Node\Expression\CallExpression ||
|
$node->parent instanceof Tolerant\Node\Expression\MemberAccessExpression || $node->parent instanceof Tolerant\Node\Expression\CallExpression ||
|
||||||
|
@ -439,10 +452,11 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
* @param Node\Expr\Variable|Node\Expr\ClosureUse $var The variable access
|
* @param Node\Expr\Variable|Node\Expr\ClosureUse $var The variable access
|
||||||
* @return Node\Expr\Assign|Node\Expr\AssignOp|Node\Param|Node\Expr\ClosureUse|null
|
* @return Node\Expr\Assign|Node\Expr\AssignOp|Node\Param|Node\Expr\ClosureUse|null
|
||||||
*/
|
*/
|
||||||
private static function resolveVariableToNode(Tolerant\Node $var)
|
public function resolveVariableToNode(Tolerant\Node $var)
|
||||||
{
|
{
|
||||||
$n = $var;
|
$n = $var;
|
||||||
// When a use is passed, start outside the closure to not return immediately
|
// When a use is passed, start outside the closure to not return immediately
|
||||||
|
// Use variable vs variable parsing?
|
||||||
if ($var instanceof Tolerant\Node\UseVariableName) {
|
if ($var instanceof Tolerant\Node\UseVariableName) {
|
||||||
$n = $var->getFirstAncestor(Tolerant\Node\Expression\AnonymousFunctionCreationExpression::class);
|
$n = $var->getFirstAncestor(Tolerant\Node\Expression\AnonymousFunctionCreationExpression::class);
|
||||||
$name = $var->getName();
|
$name = $var->getName();
|
||||||
|
@ -539,7 +553,7 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
|
|
||||||
if ($expr->callableExpression instanceof Tolerant\Node\QualifiedName) {
|
if ($expr->callableExpression instanceof Tolerant\Node\QualifiedName) {
|
||||||
$fqn = $expr->callableExpression->getResolvedName() ?? $expr->callableExpression->getNamespacedName();
|
$fqn = $expr->callableExpression->getResolvedName() ?? $expr->callableExpression->getNamespacedName();
|
||||||
$fqn .= "()";
|
$fqn .= '()';
|
||||||
$def = $this->index->getDefinition($fqn, true);
|
$def = $this->index->getDefinition($fqn, true);
|
||||||
if ($def !== null) {
|
if ($def !== null) {
|
||||||
return $def->type;
|
return $def->type;
|
||||||
|
@ -575,14 +589,12 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
|
|
||||||
if ($this->isConstantFetch($expr)) {
|
if ($this->isConstantFetch($expr)) {
|
||||||
// Resolve constant
|
// Resolve constant
|
||||||
if ($expr instanceof Tolerant\Node\QualifiedName) {
|
|
||||||
$fqn = (string)$expr->getNamespacedName();
|
$fqn = (string)$expr->getNamespacedName();
|
||||||
$def = $this->index->getDefinition($fqn, true);
|
$def = $this->index->getDefinition($fqn, true);
|
||||||
if ($def !== null) {
|
if ($def !== null) {
|
||||||
return $def->type;
|
return $def->type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (($expr instanceof Tolerant\Node\Expression\CallExpression &&
|
if (($expr instanceof Tolerant\Node\Expression\CallExpression &&
|
||||||
($access = $expr->callableExpression) instanceof Tolerant\Node\Expression\MemberAccessExpression)
|
($access = $expr->callableExpression) instanceof Tolerant\Node\Expression\MemberAccessExpression)
|
||||||
|| ($access = $expr) instanceof Tolerant\Node\Expression\MemberAccessExpression) {
|
|| ($access = $expr) instanceof Tolerant\Node\Expression\MemberAccessExpression) {
|
||||||
|
@ -622,7 +634,7 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
$expr instanceof Tolerant\Node\Expression\CallExpression && ($scopedAccess = $expr->callableExpression) instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression
|
$expr instanceof Tolerant\Node\Expression\CallExpression && ($scopedAccess = $expr->callableExpression) instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression
|
||||||
|| ($scopedAccess = $expr) instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression
|
|| ($scopedAccess = $expr) instanceof Tolerant\Node\Expression\ScopedPropertyAccessExpression
|
||||||
) {
|
) {
|
||||||
$classType = self::resolveClassNameToType($scopedAccess->scopeResolutionQualifier);
|
$classType = $this->resolveClassNameToType($scopedAccess->scopeResolutionQualifier);
|
||||||
if (!($classType instanceof Types\Object_) || $classType->getFqsen() === null /*|| $expr->name instanceof Tolerant\Node\Expression*/) {
|
if (!($classType instanceof Types\Object_) || $classType->getFqsen() === null /*|| $expr->name instanceof Tolerant\Node\Expression*/) {
|
||||||
return new Types\Mixed;
|
return new Types\Mixed;
|
||||||
}
|
}
|
||||||
|
@ -641,7 +653,7 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
return $def->type;
|
return $def->type;
|
||||||
}
|
}
|
||||||
if ($expr instanceof Tolerant\Node\Expression\ObjectCreationExpression) {
|
if ($expr instanceof Tolerant\Node\Expression\ObjectCreationExpression) {
|
||||||
return self::resolveClassNameToType($expr->classTypeDesignator);
|
return $this->resolveClassNameToType($expr->classTypeDesignator);
|
||||||
}
|
}
|
||||||
if ($expr instanceof Tolerant\Node\Expression\CloneExpression) {
|
if ($expr instanceof Tolerant\Node\Expression\CloneExpression) {
|
||||||
return $this->resolveExpressionNodeToType($expr->expression);
|
return $this->resolveExpressionNodeToType($expr->expression);
|
||||||
|
@ -812,7 +824,7 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||||
* @param Tolerant\Node || Tolerant\Token $class
|
* @param Tolerant\Node || Tolerant\Token $class
|
||||||
* @return Type
|
* @return Type
|
||||||
*/
|
*/
|
||||||
private static function resolveClassNameToType($class): Type
|
public function resolveClassNameToType($class): Type
|
||||||
{
|
{
|
||||||
if ($class instanceof Tolerant\Node\Expression) {
|
if ($class instanceof Tolerant\Node\Expression) {
|
||||||
return new Types\Mixed;
|
return new Types\Mixed;
|
||||||
|
|
|
@ -195,7 +195,7 @@ abstract class ServerTestCase extends TestCase
|
||||||
3 => new Location($globalReferencesUri, new Range(new Position(39, 0), new Position(39, 49))) // TestClass::$staticTestProperty[123]->testProperty;
|
3 => new Location($globalReferencesUri, new Range(new Position(39, 0), new Position(39, 49))) // TestClass::$staticTestProperty[123]->testProperty;
|
||||||
],
|
],
|
||||||
'TestClass::staticTestProperty' => [
|
'TestClass::staticTestProperty' => [
|
||||||
0 => new Location($globalReferencesUri, new Range(new Position( 8, 5), new Position( 8, 35))), // echo TestClass::$staticTestProperty;
|
0 => new Location($globalReferencesUri, new Range(new Position( 8, 16), new Position( 8, 35))), // echo TestClass::$staticTestProperty;
|
||||||
1 => new Location($globalReferencesUri, new Range(new Position(39, 0), new Position(39, 30))) // TestClass::$staticTestProperty[123]->testProperty;
|
1 => new Location($globalReferencesUri, new Range(new Position(39, 0), new Position(39, 30))) // TestClass::$staticTestProperty[123]->testProperty;
|
||||||
],
|
],
|
||||||
'TestClass::staticTestMethod()' => [
|
'TestClass::staticTestMethod()' => [
|
||||||
|
|
Loading…
Reference in New Issue