diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 990c196..6d87cae 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -4,6 +4,7 @@ declare(strict_types = 1); namespace LanguageServer; use LanguageServer\Index\ReadableIndex; +use LanguageServer\ProtocolBridge\SymbolInformationFactory; use LanguageServer\Protocol\SymbolInformation; use Microsoft\PhpParser; use Microsoft\PhpParser\Node; @@ -36,12 +37,19 @@ class DefinitionResolver private $docBlockFactory; /** - * Creates SignatureInformation + * Creates SignatureInformation instances * * @var SignatureInformationFactory */ private $signatureInformationFactory; + /** + * Creates SymbolInformation instances + * + * @var SymbolInformationFactory + */ + private $symbolInformationFactory; + /** * @param ReadableIndex $index */ @@ -51,6 +59,7 @@ class DefinitionResolver $this->typeResolver = new TypeResolver; $this->docBlockFactory = DocBlockFactory::createInstance(); $this->signatureInformationFactory = new SignatureInformationFactory($this); + $this->symbolInformationFactory = new SymbolInformationFactory(); } /** @@ -233,7 +242,7 @@ class DefinitionResolver } } - $def->symbolInformation = SymbolInformation::fromNode($node, $fqn); + $def->symbolInformation = $this->symbolInformationFactory->fromNode($node, $fqn); if ($def->symbolInformation !== null) { $def->type = $this->getTypeFromNode($node); diff --git a/src/LanguageServer.php b/src/LanguageServer.php index 46281f5..c456831 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -7,11 +7,11 @@ use LanguageServer\Protocol\{ ServerCapabilities, ClientCapabilities, TextDocumentSyncKind, - Message, InitializeResult, CompletionOptions, SignatureHelpOptions }; +use LanguageServer\ProtocolBridge\Message; use LanguageServer\FilesFinder\{FilesFinder, ClientFilesFinder, FileSystemFilesFinder}; use LanguageServer\ContentRetriever\{ContentRetriever, ClientContentRetriever, FileSystemContentRetriever}; use LanguageServer\Index\{DependenciesIndex, GlobalIndex, Index, ProjectIndex, StubsIndex}; diff --git a/src/ProtocolBridge/LocationFactory.php b/src/ProtocolBridge/LocationFactory.php new file mode 100644 index 0000000..df99adf --- /dev/null +++ b/src/ProtocolBridge/LocationFactory.php @@ -0,0 +1,32 @@ +getStart(), + $node->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) + )); + } +} diff --git a/src/ProtocolBridge/RangeFactory.php b/src/ProtocolBridge/RangeFactory.php new file mode 100644 index 0000000..011bf4b --- /dev/null +++ b/src/ProtocolBridge/RangeFactory.php @@ -0,0 +1,31 @@ +getStart(), + $node->getWidth(), + $node->getFileContents() + ); + + return new Range( + new Position($range->start->line, $range->start->character), + new Position($range->end->line, $range->end->character) + ); + } +} diff --git a/src/ProtocolBridge/SymbolInformationFactory.php b/src/ProtocolBridge/SymbolInformationFactory.php new file mode 100644 index 0000000..54ffdcf --- /dev/null +++ b/src/ProtocolBridge/SymbolInformationFactory.php @@ -0,0 +1,88 @@ +kind = SymbolKind::CLASS_; + } else if ($node instanceof Node\Statement\TraitDeclaration) { + $symbol->kind = SymbolKind::CLASS_; + } else if (\LanguageServer\ParserHelpers\isConstDefineExpression($node)) { + // constants with define() like + // define('TEST_DEFINE_CONSTANT', false); + $symbol->kind = SymbolKind::CONSTANT; + $symbol->name = $node->argumentExpressionList->children[0]->expression->getStringContentsText(); + } else if ($node instanceof Node\Statement\InterfaceDeclaration) { + $symbol->kind = SymbolKind::INTERFACE; + } else if ($node instanceof Node\Statement\NamespaceDefinition) { + $symbol->kind = SymbolKind::NAMESPACE; + } else if ($node instanceof Node\Statement\FunctionDeclaration) { + $symbol->kind = SymbolKind::FUNCTION; + } else if ($node instanceof Node\MethodDeclaration) { + $nameText = $node->getName(); + if ($nameText === '__construct' || $nameText === '__destruct') { + $symbol->kind = SymbolKind::CONSTRUCTOR; + } else { + $symbol->kind = SymbolKind::METHOD; + } + } else if ($node instanceof Node\Expression\Variable && $node->getFirstAncestor(Node\PropertyDeclaration::class) !== null) { + $symbol->kind = SymbolKind::PROPERTY; + } else if ($node instanceof Node\ConstElement) { + $symbol->kind = SymbolKind::CONSTANT; + } else if ( + ( + ($node instanceof Node\Expression\AssignmentExpression) + && $node->leftOperand instanceof Node\Expression\Variable + ) + || $node instanceof Node\UseVariableName + || $node instanceof Node\Parameter + ) { + $symbol->kind = SymbolKind::VARIABLE; + } else { + return null; + } + + if ($node instanceof Node\Expression\AssignmentExpression) { + if ($node->leftOperand instanceof Node\Expression\Variable) { + $symbol->name = $node->leftOperand->getName(); + } elseif ($node->leftOperand instanceof PhpParser\Token) { + $symbol->name = trim($node->leftOperand->getText($node->getFileContents()), "$"); + } + } else if ($node instanceof Node\UseVariableName) { + $symbol->name = $node->getName(); + } else if (isset($node->name)) { + if ($node->name instanceof Node\QualifiedName) { + $symbol->name = (string)PhpParser\ResolvedName::buildName($node->name->nameParts, $node->getFileContents()); + } else { + $symbol->name = ltrim((string)$node->name->getText($node->getFileContents()), "$"); + } + } else if (isset($node->variableName)) { + $symbol->name = $node->variableName->getText($node); + } else if (!isset($symbol->name)) { + return null; + } + + $symbol->location = LocationFactory::fromNode($node); + if ($fqn !== null) { + $parts = preg_split('/(::|->|\\\\)/', $fqn); + array_pop($parts); + $symbol->containerName = implode('\\', $parts); + } + return $symbol; + } +} diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index e5657b3..8085a26 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -7,6 +7,8 @@ use LanguageServer\{ CompletionProvider, SignatureHelpProvider, LanguageClient, PhpDocument, PhpDocumentLoader, DefinitionResolver }; use LanguageServer\Index\ReadableIndex; +use LanguageServer\ProtocolBridge\LocationFactory; +use LanguageServer\ProtocolBridge\RangeFactory; use LanguageServer\Protocol\{ FormattingOptions, Hover, @@ -233,7 +235,7 @@ class TextDocument $refs = $document->getReferenceNodesByFqn($fqn); if ($refs !== null) { foreach ($refs as $ref) { - $locations[] = Location::fromNode($ref); + $locations[] = LocationFactory::fromNode($ref); } } } @@ -332,7 +334,7 @@ class TextDocument } yield waitForEvent($this->index, 'definition-added'); } - $range = Range::fromNode($node); + $range = RangeFactory::fromNode($node); if ($def === null) { return new Hover([], $range); } diff --git a/src/Server/Workspace.php b/src/Server/Workspace.php index 548197b..37bbfe3 100644 --- a/src/Server/Workspace.php +++ b/src/Server/Workspace.php @@ -5,6 +5,7 @@ namespace LanguageServer\Server; use LanguageServer\{LanguageClient, PhpDocumentLoader}; use LanguageServer\Index\{ProjectIndex, DependenciesIndex, Index}; +use LanguageServer\ProtocolBridge\LocationFactory; use LanguageServer\Protocol\{ FileChangeType, FileEvent, @@ -150,7 +151,7 @@ class Workspace $doc = yield $this->documentLoader->getOrLoad($uri); foreach ($doc->getReferenceNodesByFqn($fqn) as $node) { $refInfo = new ReferenceInformation; - $refInfo->reference = Location::fromNode($node); + $refInfo->reference = LocationFactory::fromNode($node); $refInfo->symbol = $query; $refInfos[] = $refInfo; } diff --git a/src/TreeAnalyzer.php b/src/TreeAnalyzer.php index 03ad539..fbb5bb7 100644 --- a/src/TreeAnalyzer.php +++ b/src/TreeAnalyzer.php @@ -3,6 +3,7 @@ declare(strict_types = 1); namespace LanguageServer; +use LanguageServer\ProtocolBridge\RangeFactory; use LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position}; use phpDocumentor\Reflection\DocBlockFactory; use Microsoft\PhpParser; @@ -100,7 +101,7 @@ class TreeAnalyzer if ($method && $method->isStatic()) { $this->diagnostics[] = new Diagnostic( "\$this can not be used in static methods.", - Range::fromNode($node), + RangeFactory::fromNode($node), null, DiagnosticSeverity::ERROR, 'php'