public function getGoToLocations($offset) { $this->run(); $nodes = $this->parser->getNodesAtOffset($offset); $locations = []; foreach ($this->goToComponents as $goto) { $locations = array_merge($locations, $goto->getGoToLocations($offset, $nodes)); } return $locations; }
/** * @param string $fqname * * @return Fix */ private function getFix($fqname) { if ($this->insertRange === null) { $namespace = null; foreach (array_reverse($this->nodePathFromTop) as $ancestor) { if ($ancestor instanceof Stmt\Namespace_) { $namespace = $ancestor; break; } } $lastUse = null; $stmts = $namespace === null ? $this->parser->getNodes() : $namespace->stmts; foreach ($stmts as $stmt) { if ($stmt instanceof Stmt\Use_ || $stmt instanceof Stmt\GroupUse) { $lastUse = $stmt; } } if ($lastUse !== null) { /** @var Range */ $range = Range::fromNode($lastUse, $this->file->getPath()); $startLine = $range->getStart()->getLineAndColumn($this->file)[0]; $insertLocation = OffsetLocation::move($this->file, $range->getEnd()); $indent = $this->fixHelper->getIndentOfLines([$this->file->getLine($startLine)]); $this->insertText = "\n" . $this->fixHelper->makeIndent($indent) . "use %s;"; } else { $insertLocation = LineAndColumnLocation::moveToStartOfLine($this->file, Range::fromNode($stmts[0], $this->file->getPath())->getStart()); $this->insertText = "use %s;\n\n"; } $this->insertRange = new Range($insertLocation, OffsetLocation::move($this->file, $insertLocation, -1)); } $fqname = ltrim($fqname, '\\'); return new Fix([new FixChunk($this->insertRange, sprintf($this->insertText, $fqname))], 'use ' . $fqname); }
public function complete($offset) { $this->run(); $nodes = $this->parser->getNodesAtOffset($offset, true); $node = null; if (count($nodes) > 0) { $node = $nodes[0]; if ($node instanceof Identifier || $node instanceof ErrorNode\Nothing) { $node = count($nodes) > 1 ? $nodes[1] : null; } } $completions = []; $ctxClass = null; foreach ($nodes as $ctxNode) { if ($ctxNode instanceof Stmt\ClassLike) { $ctxClass = $ctxNode->hasAttribute('namespacedName') ? Type::nameToString($ctxNode->getAttribute('namespacedName')) : $node->name; break; } } if ($node instanceof Expr\MethodCall || $node instanceof Expr\PropertyFetch) { $methods = $this->findMethods($node->var->getAttribute('type')); $properties = $this->findProperties($node->var->getAttribute('type')); $methods = $this->reflection->filterAvailableMembers($methods, $ctxClass); $properties = $this->reflection->filterAvailableMembers($properties, $ctxClass); $completions = array_merge($this->formatMethods($methods), $this->formatProperties($properties)); } elseif ($node instanceof Expr\StaticCall || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\ClassConstFetch) { // TODO: Support static call on an object: $object::staticMethod() etc. // TODO: Filter out non-static members outside the inheritance // chain - while static calls to them are allowed in PHP, they // are pretty useless. $staticOnly = true; foreach ($nodes as $ctxNode) { if ($ctxNode instanceof Stmt\ClassMethod) { $staticOnly = $ctxNode->isStatic(); break; } } $methods = $this->findMethods(Type::object_(Type::nameToString($node->class)), $staticOnly); $properties = $this->findProperties(Type::object_(Type::nameToString($node->class)), $staticOnly); $consts = $this->findClassConsts(Type::object_(Type::nameToString($node->class))); $methods = $this->reflection->filterAvailableMembers($methods, $ctxClass); $properties = $this->reflection->filterAvailableMembers($properties, $ctxClass); $completions = array_merge($this->formatMethods($methods), $this->formatClassConsts($consts), $this->formatProperties($properties, true)); } return $completions; }