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

Rename support #768

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/Factory/LocationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use LanguageServerProtocol\Position;
use LanguageServerProtocol\Range;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
use Microsoft\PhpParser\PositionUtilities;

class LocationFactory
Expand All @@ -29,4 +30,24 @@ public static function fromNode(Node $node): Location
new Position($range->end->line, $range->end->character)
));
}

/**
* Returns the location of the token
*
* @param Token $node
* @return self
*/
public static function fromToken(Node $node, Token $token): Location
{
$range = PositionUtilities::getRangeFromPosition(
$token->getStartPosition(),
$token->getWidth(),
$node->getFileContents()
);

return new Location($node->getUri(), new Range(
new Position($range->start->line, $range->start->character),
new Position($range->end->line, $range->end->character)
));
}
}
90 changes: 86 additions & 4 deletions src/Server/TextDocument.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
TextDocumentIdentifier,
TextDocumentItem,
VersionedTextDocumentIdentifier,
WorkspaceEdit,
TextEdit,
CompletionContext
};
use Microsoft\PhpParser\Node;
Expand Down Expand Up @@ -179,7 +181,7 @@ public function references(
TextDocumentIdentifier $textDocument,
Position $position
): Promise {
return coroutine(function () use ($textDocument, $position) {
return coroutine(function () use ($context, $textDocument, $position) {
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
$node = $document->getNodeAtPosition($position);
if ($node === null) {
Expand All @@ -190,7 +192,7 @@ public function references(
// by traversing the AST
if (

($node instanceof Node\Expression\Variable && !($node->getParent()->getParent() instanceof Node\PropertyDeclaration))
($node instanceof Node\Expression\Variable && !($node->getParent()->getParent() instanceof Node\PropertyDeclaration) && !($node->getParent()->getParent()->getParent() instanceof Node\PropertyDeclaration))
|| $node instanceof Node\Parameter
|| $node instanceof Node\UseVariableName
) {
Expand All @@ -210,7 +212,14 @@ public function references(
if ($descendantNode instanceof Node\Expression\Variable &&
$descendantNode->getName() === $node->getName()
) {
$locations[] = LocationFactory::fromNode($descendantNode);
$location = LocationFactory::fromNode($descendantNode);
$location->range->start->character++;
$locations[] = $location;
} else if (($descendantNode instanceof Node\Parameter)
&& $context->includeDeclaration && $descendantNode->getName() === $node->getName() ) {
$location = LocationFactory::fromToken($descendantNode, $descendantNode->variableName);
$location->range->start->character++;
$locations[] = $location;
}
}
} else {
Expand All @@ -227,6 +236,10 @@ public function references(
return [];
}
}
$nameParts = preg_split('/[\>\\\:]/', $fqn);
$name = end($nameParts);
$nameParts = explode('(', $name);
$name = $nameParts[0];
$refDocumentPromises = [];
foreach ($this->index->getReferenceUris($fqn) as $uri) {
$refDocumentPromises[] = $this->documentLoader->getOrLoad($uri);
Expand All @@ -236,15 +249,84 @@ public function references(
$refs = $document->getReferenceNodesByFqn($fqn);
if ($refs !== null) {
foreach ($refs as $ref) {
$locations[] = LocationFactory::fromNode($ref);
if ($ref instanceof Node\Expression\MemberAccessExpression) {
$locations[] = LocationFactory::fromToken($ref, $ref -> memberName);
} else {
$locations[] = LocationFactory::fromNode($ref);
}
}
}
if ($context->includeDeclaration) {
$refs = $document->getDefinitionNodeByFqn($fqn);
if ($refs !== null) {
if ($refs instanceof Node\Statement\ClassDeclaration) {
if ($refs->name->getText($refs->getFileContents()) === $node->name->getText($node->getFileContents())) {
$location = LocationFactory::fromToken($refs, $refs->name);
$locations[] = $location;
}
}

foreach ($refs as $ref) {
if ($ref !== null) {
if ($ref instanceof Node\Expression\AssignmentExpression) {
$location = LocationFactory::fromNode($ref->leftOperand);
$location->range->start->character++;
$locations[] = $location;
} elseif ($ref instanceof Node\DelimitedList\ExpressionList) {
$location = LocationFactory::fromNode($ref);
$location->range->start->character++;
$locations[] = $location;
} elseif ($ref instanceof Node\ClassMembersNode) {
foreach ($ref->classMemberDeclarations as $declaration) {
if ($declaration instanceof Node\MethodDeclaration) {
if ($declaration->getName() === $name) {
$location = LocationFactory::fromToken($declaration, $declaration->name);
$locations[] = $location;
}
}
}
}
}
}
}
}

}
}
return $locations;
});
}

/**
* The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol.
*
* @param TextDocumentIdentifier $textDocument The document to rename in.
* @param Position $position The position at which this request was sent.
* @param string $newName The new name of the symbol.
* @return Promise <WorkspaceEdit|null>
*/
public function rename(
TextDocumentIdentifier $textDocument,
Position $position,
string $newName
) : Promise {
return coroutine(function () use ($textDocument, $position, $newName) {
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
$node = $document->getNodeAtPosition($position);
$locations = yield $this->references(new ReferenceContext(true), $textDocument, $position);
$edits = [$textDocument->uri => [] ];
foreach ($locations as $location) {
$textEdit = new TextEdit($location->range, $newName);
if (!isset($edits[$location->uri])) {
$edits[$location->uri] = [];
}
$edits[$location->uri][] = $textEdit;
}
return new WorkspaceEdit($edits);
});
}


/**
* The signature help request is sent from the client to the server to request signature information at a given
* cursor position.
Expand Down