Skip to content

Commit e38b314

Browse files
darthorimarintellij-monorepo-bot
authored andcommitted
[lsp] change the behavior of definition and hover requests
they should also work on the declaration itself the change also modifies how hover works on multiresovling cases (eg, with no specific candidate) and now provides kdocs for all candidates instead of no kdoc at all GitOrigin-RevId: a82774ed780851776d55ec7e6b829a6b98c2aec2
1 parent f5a2e18 commit e38b314

File tree

5 files changed

+60
-26
lines changed

5 files changed

+60
-26
lines changed

features-impl/common/src/com/jetbrains/ls/api/features/impl/common/definitions/LSDefinitionProviderCommonImpl.kt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.jetbrains.ls.api.features.language.LSLanguage
2121
import com.jetbrains.analyzer.java.JavaFilePackageIndex
2222
import com.jetbrains.ls.api.core.project
2323
import com.jetbrains.ls.api.core.withAnalysisContext
24+
import com.jetbrains.ls.api.features.impl.common.utils.getTargetsAtPosition
2425
import com.jetbrains.lsp.protocol.DefinitionParams
2526
import com.jetbrains.lsp.protocol.DocumentUri
2627
import com.jetbrains.lsp.protocol.Location
@@ -39,14 +40,9 @@ class LSDefinitionProviderCommonImpl(
3940
val file = uri.findVirtualFile() ?: return@runReadAction emptyList()
4041
val psiFile = file.findPsiFile(project) ?: return@runReadAction emptyList()
4142
val document = file.findDocument() ?: return@runReadAction emptyList()
42-
val offset = document.offsetByPosition(params.position)
43-
val reference = psiFile.findReferenceAt(offset) ?: return@runReadAction emptyList()
44-
val resolvedTo = when (reference) {
45-
is PsiPolyVariantReference -> reference.multiResolve(false).mapNotNull { it.element }
46-
else -> listOfNotNull(reference.resolve())
47-
}
43+
val targets = psiFile.getTargetsAtPosition(params.position, document)
4844

49-
resolvedTo.mapNotNull {
45+
targets.mapNotNull {
5046
when (it) {
5147
is PsiPackage -> it.directory?.uri?.let { Location(DocumentUri(it), Range.BEGINNING) }
5248
else -> it.getLspLocationForDefinition()

features-impl/common/src/com/jetbrains/ls/api/features/impl/common/hover/LSHoverProviderCommonImpl.kt

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
22
package com.jetbrains.ls.api.features.impl.common.hover
33

4+
import com.intellij.codeInsight.TargetElementUtilBase
45
import com.intellij.lang.Language
56
import com.intellij.lang.LanguageExtension
67
import com.intellij.openapi.application.runReadAction
8+
import com.intellij.openapi.editor.Document
79
import com.intellij.openapi.vfs.VirtualFile
810
import com.intellij.openapi.vfs.findDocument
911
import com.intellij.openapi.vfs.findPsiFile
1012
import com.intellij.psi.PsiElement
11-
import com.intellij.psi.PsiReference
13+
import com.intellij.psi.PsiFile
1214
import com.jetbrains.ls.api.core.util.findVirtualFile
1315
import com.jetbrains.ls.api.core.util.offsetByPosition
1416
import com.jetbrains.ls.api.core.util.toLspRange
@@ -17,10 +19,13 @@ import com.jetbrains.ls.api.core.LSServer
1719
import com.jetbrains.ls.api.core.project
1820
import com.jetbrains.ls.api.core.withAnalysisContext
1921
import com.jetbrains.ls.api.features.hover.LSHoverProvider
22+
import com.jetbrains.ls.api.features.impl.common.utils.getTargetsAtPosition
2023
import com.jetbrains.lsp.protocol.Hover
2124
import com.jetbrains.lsp.protocol.HoverParams
2225
import com.jetbrains.lsp.protocol.MarkupContent
2326
import com.jetbrains.lsp.protocol.MarkupKindType
27+
import com.jetbrains.lsp.protocol.Position
28+
import com.jetbrains.lsp.protocol.Range
2429
import com.jetbrains.lsp.protocol.StringOrMarkupContent
2530

2631
abstract class AbstractLSHoverProvider : LSHoverProvider {
@@ -31,21 +36,31 @@ abstract class AbstractLSHoverProvider : LSHoverProvider {
3136
val file = params.findVirtualFile() ?: return@a null
3237
val psiFile = file.findPsiFile(project) ?: return@a null
3338
val document = file.findDocument() ?: return@a null
34-
val offset = document.offsetByPosition(params.position)
35-
val reference = psiFile.findReferenceAt(offset) ?: return@a null
39+
val targets = psiFile.getTargetsAtPosition(params.position, document)
40+
if (targets.isEmpty()) return@a null
3641

37-
val markdown = generateMarkdownForElementReferencedBy(file, reference) ?: return@a null
42+
43+
val markdown = targets.mapNotNull {
44+
generateMarkdownForPsiElementTarget(it, psiFile)
45+
}.joinToString("\n---\n")
3846

3947
Hover(
4048
Hover.Content.Markup(MarkupContent(MarkupKindType.Markdown, markdown)),
41-
range = reference.element.textRange.toLspRange(document),
49+
range = findRange(psiFile, document, params.position),
4250
)
4351
}
4452
}
4553
}
4654

55+
private fun findRange(psiFile: PsiFile, document: Document, position: Position): Range? {
56+
val offset = document.offsetByPosition(position)
57+
psiFile.findReferenceAt(offset)?.let { return it.element.textRange.toLspRange(document) }
58+
psiFile.findElementAt(offset)?.let { return it.textRange.toLspRange(document) }
59+
return null
60+
}
61+
4762
context(_: LSServer, _: LSAnalysisContext)
48-
abstract fun generateMarkdownForElementReferencedBy(virtualFile: VirtualFile, reference: PsiReference): String?
63+
abstract fun generateMarkdownForPsiElementTarget(target: PsiElement, from: PsiFile): String?
4964

5065
interface LSMarkdownDocProvider {
5166
fun getMarkdownDoc(element: PsiElement): String?

features-impl/common/src/com/jetbrains/ls/api/features/impl/common/references/LSReferencesProviderCommonImpl.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.jetbrains.ls.api.core.util.findVirtualFile
1414
import com.jetbrains.ls.api.core.util.offsetByPosition
1515
import com.jetbrains.ls.api.core.withAnalysisContext
1616
import com.jetbrains.ls.api.features.impl.common.utils.getLspLocationForDefinition
17+
import com.jetbrains.ls.api.features.impl.common.utils.getTargetsAtPosition
1718
import com.jetbrains.ls.api.features.language.LSLanguage
1819
import com.jetbrains.ls.api.features.references.LSReferencesProvider
1920
import com.jetbrains.lsp.protocol.Location
@@ -31,9 +32,7 @@ class LSReferencesProviderCommonImpl(
3132
val file = params.findVirtualFile() ?: return@a
3233
val psiFile = file.findPsiFile(project) ?: return@a
3334
val document = file.findDocument() ?: return@a
34-
val offset = document.offsetByPosition(params.position)
35-
val psiSymbolService = PsiSymbolService.getInstance()
36-
val targets = targetSymbols(psiFile, offset).mapNotNull { psiSymbolService.extractElementFromSymbol(it) }
35+
val targets = psiFile.getTargetsAtPosition(params.position, document)
3736
if (targets.isEmpty()) return@a
3837

3938
val findUsagesManager = FindUsagesManager(project)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
package com.jetbrains.ls.api.features.impl.common.utils
3+
4+
import com.intellij.model.psi.PsiSymbolService
5+
import com.intellij.model.psi.impl.targetSymbols
6+
import com.intellij.openapi.editor.Document
7+
import com.intellij.psi.PsiElement
8+
import com.intellij.psi.PsiFile
9+
import com.jetbrains.ls.api.core.util.offsetByPosition
10+
import com.jetbrains.lsp.protocol.Position
11+
12+
fun PsiFile.getTargetsAtPosition(position: Position, document: Document): List<PsiElement> {
13+
val offset = document.offsetByPosition(position)
14+
val psiSymbolService = PsiSymbolService.getInstance()
15+
return targetSymbols(this, offset).mapNotNull { psiSymbolService.extractElementFromSymbol(it) }
16+
}

features-impl/kotlin/src/com/jetbrains/ls/api/features/impl/common/kotlin/hover/LSHoverProviderKotlinImpl.kt

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
22
package com.jetbrains.ls.api.features.impl.common.kotlin.hover
33

4-
import com.intellij.openapi.vfs.VirtualFile
5-
import com.intellij.openapi.vfs.findPsiFile
6-
import com.intellij.psi.PsiReference
4+
import com.intellij.psi.PsiClass
5+
import com.intellij.psi.PsiElement
6+
import com.intellij.psi.PsiFile
7+
import com.intellij.psi.PsiMember
8+
import com.intellij.psi.PsiPackage
79
import com.jetbrains.ls.api.core.LSAnalysisContext
810
import com.jetbrains.ls.api.core.LSServer
9-
import com.jetbrains.ls.api.core.project
1011
import com.jetbrains.ls.api.features.impl.common.hover.AbstractLSHoverProvider
1112
import com.jetbrains.ls.api.features.impl.common.hover.markdownMultilineCode
1213
import com.jetbrains.ls.api.features.impl.common.kotlin.language.LSKotlinLanguage
@@ -21,19 +22,26 @@ import org.jetbrains.kotlin.analysis.api.symbols.KaConstructorSymbol
2122
import org.jetbrains.kotlin.analysis.api.symbols.KaDeclarationSymbol
2223
import org.jetbrains.kotlin.analysis.api.symbols.KaPackageSymbol
2324
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbol
24-
import org.jetbrains.kotlin.idea.references.KtReference
25+
import org.jetbrains.kotlin.name.FqName
26+
import org.jetbrains.kotlin.psi.KtDeclaration
2527
import org.jetbrains.kotlin.psi.KtFile
2628
import org.jetbrains.kotlin.renderer.render
2729

2830
object LSHoverProviderKotlinImpl : AbstractLSHoverProvider() {
2931
override val supportedLanguages: Set<LSLanguage> get() = setOf(LSKotlinLanguage)
3032

3133
context(_: LSServer, _: LSAnalysisContext)
32-
override fun generateMarkdownForElementReferencedBy(virtualFile: VirtualFile, reference: PsiReference): String? {
33-
if (reference !is KtReference) return null
34-
val ktFile = virtualFile.findPsiFile(project) as? KtFile ?: return null
35-
return analyze(ktFile) {
36-
val symbol = reference.resolveToSymbol() ?: return null
34+
override fun generateMarkdownForPsiElementTarget(target: PsiElement, from: PsiFile): String? {
35+
if (from !is KtFile) return null
36+
37+
return analyze(from) {
38+
val symbol = when (target) {
39+
is KtDeclaration -> target.symbol
40+
is PsiClass -> target.namedClassSymbol
41+
is PsiMember -> target.callableSymbol
42+
is PsiPackage -> findPackage(FqName(target.qualifiedName))
43+
else -> null
44+
} ?: return null
3745
getMarkdownContent(symbol)
3846
}
3947
}

0 commit comments

Comments
 (0)