Merge remote-tracking branch 'felixfbecker/master' into return-self
commit
fcbc729f3f
|
@ -56,5 +56,5 @@ stages:
|
||||||
if: branch = master AND type = push AND fork = false
|
if: branch = master AND type = push AND fork = false
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
except:
|
only:
|
||||||
- /^v\d+\.\d+\.\d+$/
|
- master
|
||||||
|
|
|
@ -14,7 +14,7 @@ use RecursiveIteratorIterator;
|
||||||
|
|
||||||
$totalSize = 0;
|
$totalSize = 0;
|
||||||
|
|
||||||
$frameworks = ["drupal", "wordpress", "php-language-server", "tolerant-php-parser", "math-php", "symfony", "CodeIgniter", "cakephp"];
|
$frameworks = ["drupal", "wordpress", "php-language-server", "tolerant-php-parser", "math-php", "symfony", "codeigniter", "cakephp"];
|
||||||
|
|
||||||
foreach($frameworks as $framework) {
|
foreach($frameworks as $framework) {
|
||||||
$iterator = new RecursiveDirectoryIterator(__DIR__ . "/validation/frameworks/$framework");
|
$iterator = new RecursiveDirectoryIterator(__DIR__ . "/validation/frameworks/$framework");
|
||||||
|
|
|
@ -186,6 +186,7 @@ Example:
|
||||||
- [Eclipse Che](https://eclipse.org/che/)
|
- [Eclipse Che](https://eclipse.org/che/)
|
||||||
- [Eclipse IDE (LSP4E-PHP)](https://github.com/eclipselabs/lsp4e-php)
|
- [Eclipse IDE (LSP4E-PHP)](https://github.com/eclipselabs/lsp4e-php)
|
||||||
- NeoVim: [LanguageServer-php-neovim](https://github.com/roxma/LanguageServer-php-neovim) with [LanguageClient neovim](https://github.com/autozimu/LanguageClient-neovim)
|
- NeoVim: [LanguageServer-php-neovim](https://github.com/roxma/LanguageServer-php-neovim) with [LanguageClient neovim](https://github.com/autozimu/LanguageClient-neovim)
|
||||||
|
- Atom: [ide-php](https://github.com/atom/ide-php)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
|
@ -35,3 +35,12 @@ foreach ($array3 as $key => $value) {
|
||||||
foreach ($bar->test() as $value) {
|
foreach ($bar->test() as $value) {
|
||||||
$
|
$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($unknownArray as $member->access => $unknown) {
|
||||||
|
$unkno
|
||||||
|
|
||||||
|
foreach ($loop as $loop) {
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($loop->getArray() as $loop) {
|
||||||
|
}
|
||||||
|
|
|
@ -545,6 +545,15 @@ class DefinitionResolver
|
||||||
} else {
|
} else {
|
||||||
throw new \InvalidArgumentException('$var must be Variable, Param or ClosureUse, not ' . get_class($var));
|
throw new \InvalidArgumentException('$var must be Variable, Param or ClosureUse, not ' . get_class($var));
|
||||||
}
|
}
|
||||||
|
if (empty($name)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$shouldDescend = function ($nodeToDescand) {
|
||||||
|
// Make sure not to decend into functions or classes (they represent a scope boundary)
|
||||||
|
return !($nodeToDescand instanceof PhpParser\FunctionLike || $nodeToDescand instanceof PhpParser\ClassLike);
|
||||||
|
};
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -569,37 +578,55 @@ class DefinitionResolver
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we get to a ForeachStatement, check the keys and values
|
// Check each previous sibling node and their descendents for a variable assignment to that variable
|
||||||
if ($n instanceof Node\Statement\ForeachStatement) {
|
// Each previous sibling could contain a declaration of the variable
|
||||||
if ($n->foreachKey && $n->foreachKey->expression->getName() === $name) {
|
|
||||||
return $n->foreachKey;
|
|
||||||
}
|
|
||||||
if ($n->foreachValue
|
|
||||||
&& $n->foreachValue->expression instanceof Node\Expression\Variable
|
|
||||||
&& $n->foreachValue->expression->getName() === $name
|
|
||||||
) {
|
|
||||||
return $n->foreachValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check each previous sibling node for a variable assignment to that variable
|
|
||||||
while (($prevSibling = $n->getPreviousSibling()) !== null && $n = $prevSibling) {
|
while (($prevSibling = $n->getPreviousSibling()) !== null && $n = $prevSibling) {
|
||||||
if ($n instanceof Node\Statement\ExpressionStatement) {
|
|
||||||
$n = $n->expression;
|
// Check the sibling itself
|
||||||
}
|
if (self::isVariableDeclaration($n, $name)) {
|
||||||
if (
|
|
||||||
// TODO - clean this up
|
|
||||||
($n instanceof Node\Expression\AssignmentExpression && $n->operator->kind === PhpParser\TokenKind::EqualsToken)
|
|
||||||
&& $n->leftOperand instanceof Node\Expression\Variable && $n->leftOperand->getName() === $name
|
|
||||||
) {
|
|
||||||
return $n;
|
return $n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check descendant of this sibling (e.g. the children of a previous if block)
|
||||||
|
foreach ($n->getDescendantNodes($shouldDescend) as $descendant) {
|
||||||
|
if (self::isVariableDeclaration($descendant, $name)) {
|
||||||
|
return $descendant;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (isset($n) && $n = $n->parent);
|
} while (isset($n) && $n = $n->parent);
|
||||||
// Return null if nothing was found
|
// Return null if nothing was found
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given Node declares the given variable name
|
||||||
|
*
|
||||||
|
* @param Node $n The Node to check
|
||||||
|
* @param string $name The name of the wanted variable
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private static function isVariableDeclaration(Node $n, string $name)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
// TODO - clean this up
|
||||||
|
($n instanceof Node\Expression\AssignmentExpression && $n->operator->kind === PhpParser\TokenKind::EqualsToken)
|
||||||
|
&& $n->leftOperand instanceof Node\Expression\Variable && $n->leftOperand->getName() === $name
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
($n instanceof Node\ForeachValue || $n instanceof Node\ForeachKey)
|
||||||
|
&& $n->expression instanceof Node\Expression\Variable
|
||||||
|
&& $n->expression->getName() === $name
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an expression node, resolves that expression recursively to a type.
|
* Given an expression node, resolves that expression recursively to a type.
|
||||||
* If the type could not be resolved, returns Types\Mixed_.
|
* If the type could not be resolved, returns Types\Mixed_.
|
||||||
|
@ -1122,6 +1149,7 @@ class DefinitionResolver
|
||||||
if ($collectionType instanceof Types\Array_) {
|
if ($collectionType instanceof Types\Array_) {
|
||||||
return $collectionType->getValueType();
|
return $collectionType->getValueType();
|
||||||
}
|
}
|
||||||
|
return new Types\Mixed_();
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROPERTIES, CONSTS, CLASS CONSTS, ASSIGNMENT EXPRESSIONS
|
// PROPERTIES, CONSTS, CLASS CONSTS, ASSIGNMENT EXPRESSIONS
|
||||||
|
|
|
@ -691,6 +691,21 @@ class CompletionTest extends TestCase
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
'foreach unknown type' => [
|
||||||
|
new Position(39, 10),
|
||||||
|
[
|
||||||
|
new CompletionItem(
|
||||||
|
'$unknown',
|
||||||
|
CompletionItemKind::VARIABLE,
|
||||||
|
'mixed',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new TextEdit(new Range(new Position(39, 10), new Position(39, 10)), 'wn')
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue