1
0
Fork 0

Make ParserHelper a module of functions, not a static class

pull/357/head
Rob Lourens 2017-06-07 17:26:03 -07:00
parent eda52a893f
commit 1d314deff0
7 changed files with 134 additions and 138 deletions

View File

@ -54,7 +54,8 @@
}, },
"files" : [ "files" : [
"src/utils.php", "src/utils.php",
"src/FqnUtilities.php" "src/FqnUtilities.php",
"src/ParserHelpers.php"
] ]
}, },
"autoload-dev": { "autoload-dev": {

View File

@ -228,7 +228,7 @@ class CompletionProvider
} }
} }
} }
} elseif (ParserHelpers::isConstantFetch($node) || } elseif (ParserHelpers\isConstantFetch($node) ||
($creation = $node->parent) instanceof Node\Expression\ObjectCreationExpression || ($creation = $node->parent) instanceof Node\Expression\ObjectCreationExpression ||
(($creation = $node) instanceof Node\Expression\ObjectCreationExpression)) { (($creation = $node) instanceof Node\Expression\ObjectCreationExpression)) {
$class = isset($creation) ? $creation->classTypeDesignator : $node; $class = isset($creation) ? $creation->classTypeDesignator : $node;
@ -296,7 +296,7 @@ class CompletionProvider
$list->items[] = $item; $list->items[] = $item;
} }
} }
} elseif (ParserHelpers::isConstantFetch($node)) { } elseif (ParserHelpers\isConstantFetch($node)) {
$prefix = (string) ($node->getResolvedName() ?? PhpParser\ResolvedName::buildName($node->nameParts, $node->getFileContents())); $prefix = (string) ($node->getResolvedName() ?? PhpParser\ResolvedName::buildName($node->nameParts, $node->getFileContents()));
foreach (self::KEYWORDS as $keyword) { foreach (self::KEYWORDS as $keyword) {
$item = new CompletionItem($keyword, CompletionItemKind::KEYWORD); $item = new CompletionItem($keyword, CompletionItemKind::KEYWORD);
@ -353,7 +353,7 @@ class CompletionProvider
// Walk the AST upwards until a scope boundary is met // Walk the AST upwards until a scope boundary is met
$level = $node; $level = $node;
while ($level && !ParserHelpers::isFunctionLike($level)) { while ($level && !ParserHelpers\isFunctionLike($level)) {
// Walk siblings before the node // Walk siblings before the node
$sibling = $level; $sibling = $level;
while ($sibling = $sibling->getPreviousSibling()) { while ($sibling = $sibling->getPreviousSibling()) {
@ -367,7 +367,7 @@ class CompletionProvider
// If the traversal ended because a function was met, // If the traversal ended because a function was met,
// also add its parameters and closure uses to the result list // also add its parameters and closure uses to the result list
if ($level && ParserHelpers::isFunctionLike($level) && $level->parameters !== null) { if ($level && ParserHelpers\isFunctionLike($level) && $level->parameters !== null) {
foreach ($level->parameters->getValues() as $param) { foreach ($level->parameters->getValues() as $param) {
$paramName = $param->getName(); $paramName = $param->getName();
if (empty($namePrefix) || strpos($paramName, $namePrefix) !== false) { if (empty($namePrefix) || strpos($paramName, $namePrefix) !== false) {

View File

@ -56,8 +56,8 @@ class DefinitionResolver
// - [PropertyDeclaration] // public $a, [$b = 3], $c; => public $b = 3; // - [PropertyDeclaration] // public $a, [$b = 3], $c; => public $b = 3;
// - [ConstDeclaration | ClassConstDeclaration] // "const A = 3, [B = 4];" => "const B = 4;" // - [ConstDeclaration | ClassConstDeclaration] // "const A = 3, [B = 4];" => "const B = 4;"
if ( if (
($declaration = ParserHelpers::tryGetPropertyDeclaration($node)) && ($elements = $declaration->propertyElements) || ($declaration = ParserHelpers\tryGetPropertyDeclaration($node)) && ($elements = $declaration->propertyElements) ||
($declaration = ParserHelpers::tryGetConstOrClassConstDeclaration($node)) && ($elements = $declaration->constElements) ($declaration = ParserHelpers\tryGetConstOrClassConstDeclaration($node)) && ($elements = $declaration->constElements)
) { ) {
$defLine = $declaration->getText(); $defLine = $declaration->getText();
$defLineStart = $declaration->getStart(); $defLineStart = $declaration->getStart();
@ -95,7 +95,7 @@ class DefinitionResolver
// For properties and constants, set the node to the declaration node, rather than the individual property. // For properties and constants, set the node to the declaration node, rather than the individual property.
// This is because they get defined as part of a list. // This is because they get defined as part of a list.
$constOrPropertyDeclaration = ParserHelpers::tryGetPropertyDeclaration($node) ?? ParserHelpers::tryGetConstOrClassConstDeclaration($node); $constOrPropertyDeclaration = ParserHelpers\tryGetPropertyDeclaration($node) ?? ParserHelpers\tryGetConstOrClassConstDeclaration($node);
if ($constOrPropertyDeclaration !== null) { if ($constOrPropertyDeclaration !== null) {
$node = $constOrPropertyDeclaration; $node = $constOrPropertyDeclaration;
} }
@ -104,7 +104,7 @@ class DefinitionResolver
if ($node instanceof Node\Parameter) { if ($node instanceof Node\Parameter) {
$variableName = $node->getName(); $variableName = $node->getName();
$functionLikeDeclaration = ParserHelpers::getFunctionLikeDeclarationFromParameter($node); $functionLikeDeclaration = ParserHelpers\getFunctionLikeDeclarationFromParameter($node);
$docBlock = $this->getDocBlock($functionLikeDeclaration); $docBlock = $this->getDocBlock($functionLikeDeclaration);
$parameterDocBlockTag = $this->tryGetDocBlockTagForParameter($docBlock, $variableName); $parameterDocBlockTag = $this->tryGetDocBlockTagForParameter($docBlock, $variableName);
@ -193,7 +193,7 @@ class DefinitionResolver
$def->isStatic = ( $def->isStatic = (
($node instanceof Node\MethodDeclaration && $node->isStatic()) || ($node instanceof Node\MethodDeclaration && $node->isStatic()) ||
(($propertyDeclaration = ParserHelpers::tryGetPropertyDeclaration($node)) !== null (($propertyDeclaration = ParserHelpers\tryGetPropertyDeclaration($node)) !== null
&& $propertyDeclaration->isStatic()) && $propertyDeclaration->isStatic())
); );
@ -258,7 +258,7 @@ class DefinitionResolver
// If the node is a function or constant, it could be namespaced, but PHP falls back to global // If the node is a function or constant, it could be namespaced, but PHP falls back to global
// http://php.net/manual/en/language.namespaces.fallback.php // http://php.net/manual/en/language.namespaces.fallback.php
// TODO - verify that this is not a method // TODO - verify that this is not a method
$globalFallback = ParserHelpers::isConstantFetch($node) || $parent instanceof Node\Expression\CallExpression; $globalFallback = ParserHelpers\isConstantFetch($node) || $parent instanceof Node\Expression\CallExpression;
// Return the Definition object from the index index // Return the Definition object from the index index
return $this->index->getDefinition($fqn, $globalFallback); return $this->index->getDefinition($fqn, $globalFallback);
} }
@ -277,7 +277,7 @@ class DefinitionResolver
return $this->resolveQualifiedNameNodeToFqn($node); return $this->resolveQualifiedNameNodeToFqn($node);
} else if ($node instanceof Node\Expression\MemberAccessExpression) { } else if ($node instanceof Node\Expression\MemberAccessExpression) {
return $this->resolveMemberAccessExpressionNodeToFqn($node); return $this->resolveMemberAccessExpressionNodeToFqn($node);
} else if (ParserHelpers::isConstantFetch($node)) { } else if (ParserHelpers\isConstantFetch($node)) {
return (string)($node->getNamespacedName()); return (string)($node->getNamespacedName());
} else if ( } else if (
// A\B::C - constant access expression // A\B::C - constant access expression
@ -497,7 +497,7 @@ class DefinitionResolver
// Traverse the AST up // Traverse the AST up
do { do {
// If a function is met, check the parameters and use statements // If a function is met, check the parameters and use statements
if (ParserHelpers::isFunctionLike($n)) { if (ParserHelpers\isFunctionLike($n)) {
if ($n->parameters !== null) { if ($n->parameters !== null) {
foreach ($n->parameters->getElements() as $param) { foreach ($n->parameters->getElements() as $param) {
if ($param->getName() === $name) { if ($param->getName() === $name) {
@ -611,7 +611,7 @@ class DefinitionResolver
// CONSTANT FETCH // CONSTANT FETCH
// Resolve constants by retrieving corresponding definition type from FQN // Resolve constants by retrieving corresponding definition type from FQN
if (ParserHelpers::isConstantFetch($expr)) { if (ParserHelpers\isConstantFetch($expr)) {
$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) {
@ -728,7 +728,7 @@ class DefinitionResolver
// isset($var) // isset($var)
// >, >=, <, <=, &&, ||, AND, OR, XOR, ==, ===, !=, !== // >, >=, <, <=, &&, ||, AND, OR, XOR, ==, ===, !=, !==
if ( if (
ParserHelpers::isBooleanExpression($expr) ParserHelpers\isBooleanExpression($expr)
|| ($expr instanceof Node\Expression\CastExpression && $expr->castType->kind === PhpParser\TokenKind::BoolCastToken) || ($expr instanceof Node\Expression\CastExpression && $expr->castType->kind === PhpParser\TokenKind::BoolCastToken)
|| ($expr instanceof Node\Expression\UnaryOpExpression && $expr->operator->kind === PhpParser\TokenKind::ExclamationToken) || ($expr instanceof Node\Expression\UnaryOpExpression && $expr->operator->kind === PhpParser\TokenKind::ExclamationToken)
@ -933,7 +933,7 @@ class DefinitionResolver
*/ */
public function getTypeFromNode($node) public function getTypeFromNode($node)
{ {
if (ParserHelpers::isConstDefineExpression($node)) { if (ParserHelpers\isConstDefineExpression($node)) {
// constants with define() like // constants with define() like
// define('TEST_DEFINE_CONSTANT', false); // define('TEST_DEFINE_CONSTANT', false);
return $this->resolveExpressionNodeToType($node->argumentExpressionList->children[2]->expression); return $this->resolveExpressionNodeToType($node->argumentExpressionList->children[2]->expression);
@ -950,7 +950,7 @@ class DefinitionResolver
// * @param MyClass $myParam // * @param MyClass $myParam
// */ // */
// function foo($a) // function foo($a)
$functionLikeDeclaration = ParserHelpers::getFunctionLikeDeclarationFromParameter($node); $functionLikeDeclaration = ParserHelpers\getFunctionLikeDeclarationFromParameter($node);
$variableName = $node->getName(); $variableName = $node->getName();
$docBlock = $this->getDocBlock($functionLikeDeclaration); $docBlock = $this->getDocBlock($functionLikeDeclaration);
@ -987,7 +987,7 @@ class DefinitionResolver
// 1. doc block // 1. doc block
// 2. return type hint // 2. return type hint
// 3. TODO: infer from return statements // 3. TODO: infer from return statements
if (ParserHelpers::isFunctionLike($node)) { if (ParserHelpers\isFunctionLike($node)) {
// Functions/methods // Functions/methods
$docBlock = $this->getDocBlock($node); $docBlock = $this->getDocBlock($node);
if ( if (
@ -1014,8 +1014,8 @@ class DefinitionResolver
// Get the documented type the assignment resolves to. // Get the documented type the assignment resolves to.
if ( if (
($declarationNode = ($declarationNode =
ParserHelpers::tryGetPropertyDeclaration($node) ?? ParserHelpers\tryGetPropertyDeclaration($node) ??
ParserHelpers::tryGetConstOrClassConstDeclaration($node) ParserHelpers\tryGetConstOrClassConstDeclaration($node)
) !== null || ) !== null ||
($node = $node->parent) instanceof Node\Expression\AssignmentExpression) { ($node = $node->parent) instanceof Node\Expression\AssignmentExpression) {
$declarationNode = $declarationNode ?? $node; $declarationNode = $declarationNode ?? $node;
@ -1123,7 +1123,7 @@ class DefinitionResolver
// $a = 4, $b = 4 A\B\C->$a, A\B\C->$b // TODO verify variable name // $a = 4, $b = 4 A\B\C->$a, A\B\C->$b // TODO verify variable name
// } // }
if ( if (
($propertyDeclaration = ParserHelpers::tryGetPropertyDeclaration($node)) !== null && ($propertyDeclaration = ParserHelpers\tryGetPropertyDeclaration($node)) !== null &&
($classDeclaration = ($classDeclaration =
$node->getFirstAncestor( $node->getFirstAncestor(
Node\Expression\ObjectCreationExpression::class, Node\Expression\ObjectCreationExpression::class,
@ -1148,7 +1148,7 @@ class DefinitionResolver
// class C { // class C {
// const $a, $b = 4 A\B\C::$a(), A\B\C::$b // const $a, $b = 4 A\B\C::$a(), A\B\C::$b
// } // }
if (($constDeclaration = ParserHelpers::tryGetConstOrClassConstDeclaration($node)) !== null) { if (($constDeclaration = ParserHelpers\tryGetConstOrClassConstDeclaration($node)) !== null) {
if ($constDeclaration instanceof Node\Statement\ConstDeclaration) { if ($constDeclaration instanceof Node\Statement\ConstDeclaration) {
// Basic constant: use CONSTANT_NAME as name // Basic constant: use CONSTANT_NAME as name
return (string)$node->getNamespacedName(); return (string)$node->getNamespacedName();
@ -1168,7 +1168,7 @@ class DefinitionResolver
return (string)$classDeclaration->getNamespacedName() . '::' . $node->getName(); return (string)$classDeclaration->getNamespacedName() . '::' . $node->getName();
} }
if (ParserHelpers::isConstDefineExpression($node)) { if (ParserHelpers\isConstDefineExpression($node)) {
return $node->argumentExpressionList->children[0]->expression->getStringContentsText(); return $node->argumentExpressionList->children[0]->expression->getStringContentsText();
} }

View File

@ -5,8 +5,6 @@ namespace LanguageServer\FqnUtilities;
use phpDocumentor\Reflection\{Type, Types}; use phpDocumentor\Reflection\{Type, Types};
use Microsoft\PhpParser; use Microsoft\PhpParser;
echo "FQN_UTILIIES" . PHP_EOL;
/** /**
* Returns all possible FQNs in a type * Returns all possible FQNs in a type
* *

View File

@ -1,15 +1,13 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LanguageServer; namespace LanguageServer\ParserHelpers;
use Microsoft\PhpParser; use Microsoft\PhpParser;
use Microsoft\PhpParser\Node; use Microsoft\PhpParser\Node;
class ParserHelpers function isConstantFetch(Node $node) : bool
{ {
public static function isConstantFetch(Node $node) : bool
{
$parent = $node->parent; $parent = $node->parent;
return return
( (
@ -27,29 +25,29 @@ class ParserHelpers
$parent instanceof Node\Expression\CallExpression || $parent instanceof Node\Expression\CallExpression ||
$parent instanceof Node\Expression\ObjectCreationExpression || $parent instanceof Node\Expression\ObjectCreationExpression ||
$parent instanceof Node\Expression\ScopedPropertyAccessExpression || $parent instanceof Node\Expression\ScopedPropertyAccessExpression ||
self::isFunctionLike($parent) || isFunctionLike($parent) ||
( (
$parent instanceof Node\Expression\BinaryExpression && $parent instanceof Node\Expression\BinaryExpression &&
$parent->operator->kind === PhpParser\TokenKind::InstanceOfKeyword $parent->operator->kind === PhpParser\TokenKind::InstanceOfKeyword
) )
)); ));
} }
public static function getFunctionLikeDeclarationFromParameter(Node\Parameter $node) function getFunctionLikeDeclarationFromParameter(Node\Parameter $node)
{ {
return $node->parent->parent; return $node->parent->parent;
} }
public static function isFunctionLike(Node $node) function isFunctionLike(Node $node)
{ {
return return
$node instanceof Node\Statement\FunctionDeclaration || $node instanceof Node\Statement\FunctionDeclaration ||
$node instanceof Node\MethodDeclaration || $node instanceof Node\MethodDeclaration ||
$node instanceof Node\Expression\AnonymousFunctionCreationExpression; $node instanceof Node\Expression\AnonymousFunctionCreationExpression;
} }
public static function isBooleanExpression($expression) : bool function isBooleanExpression($expression) : bool
{ {
if (!($expression instanceof Node\Expression\BinaryExpression)) { if (!($expression instanceof Node\Expression\BinaryExpression)) {
return false; return false;
} }
@ -73,16 +71,16 @@ class ParserHelpers
return true; return true;
} }
return false; return false;
} }
/** /**
* Tries to get the parent property declaration given a Node * Tries to get the parent property declaration given a Node
* @param Node $node * @param Node $node
* @return Node\PropertyDeclaration | null $node * @return Node\PropertyDeclaration | null $node
*/ */
public static function tryGetPropertyDeclaration(Node $node) function tryGetPropertyDeclaration(Node $node)
{ {
if ($node instanceof Node\Expression\Variable && if ($node instanceof Node\Expression\Variable &&
(($propertyDeclaration = $node->parent->parent) instanceof Node\PropertyDeclaration || (($propertyDeclaration = $node->parent->parent) instanceof Node\PropertyDeclaration ||
($propertyDeclaration = $propertyDeclaration->parent) instanceof Node\PropertyDeclaration) ($propertyDeclaration = $propertyDeclaration->parent) instanceof Node\PropertyDeclaration)
@ -90,15 +88,15 @@ class ParserHelpers
return $propertyDeclaration; return $propertyDeclaration;
} }
return null; return null;
} }
/** /**
* Tries to get the parent ConstDeclaration or ClassConstDeclaration given a Node * Tries to get the parent ConstDeclaration or ClassConstDeclaration given a Node
* @param Node $node * @param Node $node
* @return Node\Statement\ConstDeclaration | Node\ClassConstDeclaration | null $node * @return Node\Statement\ConstDeclaration | Node\ClassConstDeclaration | null $node
*/ */
public static function tryGetConstOrClassConstDeclaration(Node $node) function tryGetConstOrClassConstDeclaration(Node $node)
{ {
if ( if (
$node instanceof Node\ConstElement && ( $node instanceof Node\ConstElement && (
($constDeclaration = $node->parent->parent) instanceof Node\ClassConstDeclaration || ($constDeclaration = $node->parent->parent) instanceof Node\ClassConstDeclaration ||
@ -107,21 +105,20 @@ class ParserHelpers
return $constDeclaration; return $constDeclaration;
} }
return null; return null;
} }
/** /**
* Returns true if the node is a usage of `define`. * Returns true if the node is a usage of `define`.
* e.g. define('TEST_DEFINE_CONSTANT', false); * e.g. define('TEST_DEFINE_CONSTANT', false);
* @param Node $node * @param Node $node
* @return bool * @return bool
*/ */
public static function isConstDefineExpression(Node $node): bool function isConstDefineExpression(Node $node): bool
{ {
return $node instanceof Node\Expression\CallExpression return $node instanceof Node\Expression\CallExpression
&& $node->callableExpression instanceof Node\QualifiedName && $node->callableExpression instanceof Node\QualifiedName
&& strtolower($node->callableExpression->getText()) === 'define' && strtolower($node->callableExpression->getText()) === 'define'
&& isset($node->argumentExpressionList->children[0]) && isset($node->argumentExpressionList->children[0])
&& $node->argumentExpressionList->children[0]->expression instanceof Node\StringLiteral && $node->argumentExpressionList->children[0]->expression instanceof Node\StringLiteral
&& isset($node->argumentExpressionList->children[2]); && isset($node->argumentExpressionList->children[2]);
}
} }

View File

@ -54,7 +54,7 @@ class SymbolInformation
$symbol->kind = SymbolKind::CLASS_; $symbol->kind = SymbolKind::CLASS_;
} else if ($node instanceof Node\Statement\TraitDeclaration) { } else if ($node instanceof Node\Statement\TraitDeclaration) {
$symbol->kind = SymbolKind::CLASS_; $symbol->kind = SymbolKind::CLASS_;
} else if (\LanguageServer\ParserHelpers::isConstDefineExpression($node)) { } else if (\LanguageServer\ParserHelpers\isConstDefineExpression($node)) {
// constants with define() like // constants with define() like
// define('TEST_DEFINE_CONSTANT', false); // define('TEST_DEFINE_CONSTANT', false);
$symbol->kind = SymbolKind::CONSTANT; $symbol->kind = SymbolKind::CONSTANT;

View File

@ -137,7 +137,7 @@ class TreeAnalyzer
// Namespaced constant access and function calls also need to register a reference // Namespaced constant access and function calls also need to register a reference
// to the global version because PHP falls back to global at runtime // to the global version because PHP falls back to global at runtime
// http://php.net/manual/en/language.namespaces.fallback.php // http://php.net/manual/en/language.namespaces.fallback.php
if (ParserHelpers::isConstantFetch($node) || if (ParserHelpers\isConstantFetch($node) ||
($parent instanceof Node\Expression\CallExpression ($parent instanceof Node\Expression\CallExpression
&& !( && !(
$node instanceof Node\Expression\ScopedPropertyAccessExpression || $node instanceof Node\Expression\ScopedPropertyAccessExpression ||