[FIR] Fix resolve for java synthetic properties in KDoc

^KT-62880 fixed
This commit is contained in:
Egor Kulikov
2024-02-07 13:39:16 +01:00
committed by Space Team
parent 7c8c65d291
commit 36b89f5e84
16 changed files with 250 additions and 18 deletions
@@ -1808,6 +1808,12 @@ public class Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exte
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("NoSyntheticFieldInClass.kt")
public void testNoSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/NoSyntheticFieldInClass.kt");
}
@Test @Test
@TestMetadata("StaticFieldQualified.kt") @TestMetadata("StaticFieldQualified.kt")
public void testStaticFieldQualified() { public void testStaticFieldQualified() {
@@ -1843,6 +1849,24 @@ public class Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exte
public void testStaticFunctionQualifiedWithKotlinSubclass() { public void testStaticFunctionQualifiedWithKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("SyntheticFieldInAnnotationInterface.kt")
public void testSyntheticFieldInAnnotationInterface() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInAnnotationInterface.kt");
}
@Test
@TestMetadata("SyntheticFieldInClass.kt")
public void testSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInClass.kt");
}
@Test
@TestMetadata("SyntheticPropertyInKotlinSubclass.kt")
public void testSyntheticPropertyInKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticPropertyInKotlinSubclass.kt");
}
} }
@Nested @Nested
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import kotlin.reflect.KClass import kotlin.reflect.KClass
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
import org.jetbrains.kotlin.load.java.possibleGetMethodNames
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
internal object KDocReferenceResolver { internal object KDocReferenceResolver {
@@ -122,7 +123,7 @@ internal object KDocReferenceResolver {
} }
context(KtAnalysisSession) context(KtAnalysisSession)
private fun resolveKdocFqName(fqName: FqName, contextElement: KtElement): Collection<ResolveResult> { private fun resolveKdocFqName(fqName: FqName, contextElement: KtElement, trySyntheticGetters: Boolean = true): Collection<ResolveResult> {
getExtensionReceiverSymbolByThisQualifier(fqName, contextElement).ifNotEmpty { return this } getExtensionReceiverSymbolByThisQualifier(fqName, contextElement).ifNotEmpty { return this }
buildList { buildList {
@@ -135,9 +136,21 @@ internal object KDocReferenceResolver {
AdditionalKDocResolutionProvider.resolveKdocFqName(fqName, contextElement).map { it.toResolveResult() }.ifNotEmpty { return this } AdditionalKDocResolutionProvider.resolveKdocFqName(fqName, contextElement).map { it.toResolveResult() }.ifNotEmpty { return this }
if (trySyntheticGetters) {
getSymbolsFromSyntheticProperty(fqName, contextElement).ifNotEmpty { return this }
}
return emptyList() return emptyList()
} }
context(KtAnalysisSession)
private fun getSymbolsFromSyntheticProperty(fqName: FqName, contextElement: KtElement): Collection<ResolveResult> {
val getterNames = possibleGetMethodNames(fqName.shortNameOrSpecial())
return getterNames.flatMap { getterName ->
resolveKdocFqName(fqName.parent().child(getterName), contextElement, trySyntheticGetters = false)
}
}
context(KtAnalysisSession) context(KtAnalysisSession)
private fun getExtensionReceiverSymbolByThisQualifier(fqName: FqName, contextElement: KtElement): Collection<ResolveResult> { private fun getExtensionReceiverSymbolByThisQualifier(fqName: FqName, contextElement: KtElement): Collection<ResolveResult> {
val owner = contextElement.parentOfType<KtDeclaration>() ?: return emptyList() val owner = contextElement.parentOfType<KtDeclaration>() ?: return emptyList()
@@ -5,10 +5,14 @@
package org.jetbrains.kotlin.analysis.api.fir.references package org.jetbrains.kotlin.analysis.api.fir.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSyntheticJavaPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.idea.references.KDocReference import org.jetbrains.kotlin.idea.references.KDocReference
import org.jetbrains.kotlin.idea.references.KtFirReference import org.jetbrains.kotlin.idea.references.KtFirReference
import org.jetbrains.kotlin.idea.references.getPsiDeclarations
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
@@ -18,4 +22,17 @@ internal class KtFirKDocReference(element: KDocName) : KDocReference(element), K
val selectedFqName = element.getQualifiedNameAsFqName() val selectedFqName = element.getQualifiedNameAsFqName()
return KDocReferenceResolver.resolveKdocFqName(selectedFqName, fullFqName, element) return KDocReferenceResolver.resolveKdocFqName(selectedFqName, fullFqName, element)
} }
override fun getResolvedToPsi(
analysisSession: KtAnalysisSession,
referenceTargetSymbols: Collection<KtSymbol>,
): Collection<PsiElement> = with(analysisSession) {
referenceTargetSymbols.flatMap { symbol ->
when (symbol) {
is KtFirSyntheticJavaPropertySymbol -> listOfNotNull(symbol.javaGetterSymbol.psi, symbol.javaSetterSymbol?.psi)
is KtFirSymbol<*> -> getPsiDeclarations(symbol)
else -> listOfNotNull(symbol.psi)
}
}
}
} }
@@ -13,9 +13,6 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.navigationTargetsProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModuleStructureInternals
import org.jetbrains.kotlin.psi.KtFile
interface KtFirReference : KtReference, KtSymbolBasedReference { interface KtFirReference : KtReference, KtSymbolBasedReference {
fun getResolvedToPsi(analysisSession: KtAnalysisSession, referenceTargetSymbols: Collection<KtSymbol>): Collection<PsiElement> = fun getResolvedToPsi(analysisSession: KtAnalysisSession, referenceTargetSymbols: Collection<KtSymbol>): Collection<PsiElement> =
@@ -33,18 +30,18 @@ interface KtFirReference : KtReference, KtSymbolBasedReference {
getResolvedToPsi(analysisSession, resolveToSymbols()) getResolvedToPsi(analysisSession, resolveToSymbols())
} }
private fun KtAnalysisSession.getPsiDeclarations(symbol: KtFirSymbol<*>): Collection<PsiElement> {
val intersectionOverriddenSymbolsOrSingle = when {
symbol.origin == KtSymbolOrigin.INTERSECTION_OVERRIDE && symbol is KtCallableSymbol -> symbol.getIntersectionOverriddenSymbols()
else -> listOf(symbol)
}
return intersectionOverriddenSymbolsOrSingle.mapNotNull { it.findPsiForReferenceResolve() }
}
private fun KtSymbol.findPsiForReferenceResolve(): PsiElement? {
require(this is KtFirSymbol<*>)
return firSymbol.fir.findReferencePsi()
}
override val resolver get() = KtFirReferenceResolver override val resolver get() = KtFirReferenceResolver
} }
internal fun KtAnalysisSession.getPsiDeclarations(symbol: KtFirSymbol<*>): Collection<PsiElement> {
val intersectionOverriddenSymbolsOrSingle = when {
symbol.origin == KtSymbolOrigin.INTERSECTION_OVERRIDE && symbol is KtCallableSymbol -> symbol.getIntersectionOverriddenSymbols()
else -> listOf(symbol)
}
return intersectionOverriddenSymbolsOrSingle.mapNotNull { it.findPsiForReferenceResolve() }
}
private fun KtSymbol.findPsiForReferenceResolve(): PsiElement? {
require(this is KtFirSymbol<*>)
return firSymbol.fir.findReferencePsi()
}
@@ -1808,6 +1808,12 @@ public class FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated ex
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("NoSyntheticFieldInClass.kt")
public void testNoSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/NoSyntheticFieldInClass.kt");
}
@Test @Test
@TestMetadata("StaticFieldQualified.kt") @TestMetadata("StaticFieldQualified.kt")
public void testStaticFieldQualified() { public void testStaticFieldQualified() {
@@ -1843,6 +1849,24 @@ public class FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated ex
public void testStaticFunctionQualifiedWithKotlinSubclass() { public void testStaticFunctionQualifiedWithKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("SyntheticFieldInAnnotationInterface.kt")
public void testSyntheticFieldInAnnotationInterface() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInAnnotationInterface.kt");
}
@Test
@TestMetadata("SyntheticFieldInClass.kt")
public void testSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInClass.kt");
}
@Test
@TestMetadata("SyntheticPropertyInKotlinSubclass.kt")
public void testSyntheticPropertyInKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticPropertyInKotlinSubclass.kt");
}
} }
@Nested @Nested
@@ -1692,6 +1692,12 @@ public class FirIdeNormalAnalysisLibrarySourceModuleReferenceResolveTestGenerate
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("NoSyntheticFieldInClass.kt")
public void testNoSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/NoSyntheticFieldInClass.kt");
}
@Test @Test
@TestMetadata("StaticFieldQualified.kt") @TestMetadata("StaticFieldQualified.kt")
public void testStaticFieldQualified() { public void testStaticFieldQualified() {
@@ -1727,6 +1733,24 @@ public class FirIdeNormalAnalysisLibrarySourceModuleReferenceResolveTestGenerate
public void testStaticFunctionQualifiedWithKotlinSubclass() { public void testStaticFunctionQualifiedWithKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("SyntheticFieldInAnnotationInterface.kt")
public void testSyntheticFieldInAnnotationInterface() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInAnnotationInterface.kt");
}
@Test
@TestMetadata("SyntheticFieldInClass.kt")
public void testSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInClass.kt");
}
@Test
@TestMetadata("SyntheticPropertyInKotlinSubclass.kt")
public void testSyntheticPropertyInKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticPropertyInKotlinSubclass.kt");
}
} }
@Nested @Nested
@@ -1808,6 +1808,12 @@ public class FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exten
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("NoSyntheticFieldInClass.kt")
public void testNoSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/NoSyntheticFieldInClass.kt");
}
@Test @Test
@TestMetadata("StaticFieldQualified.kt") @TestMetadata("StaticFieldQualified.kt")
public void testStaticFieldQualified() { public void testStaticFieldQualified() {
@@ -1843,6 +1849,24 @@ public class FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exten
public void testStaticFunctionQualifiedWithKotlinSubclass() { public void testStaticFunctionQualifiedWithKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("SyntheticFieldInAnnotationInterface.kt")
public void testSyntheticFieldInAnnotationInterface() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInAnnotationInterface.kt");
}
@Test
@TestMetadata("SyntheticFieldInClass.kt")
public void testSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInClass.kt");
}
@Test
@TestMetadata("SyntheticPropertyInKotlinSubclass.kt")
public void testSyntheticPropertyInKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticPropertyInKotlinSubclass.kt");
}
} }
@Nested @Nested
@@ -1808,6 +1808,12 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerate
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/FunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("NoSyntheticFieldInClass.kt")
public void testNoSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/NoSyntheticFieldInClass.kt");
}
@Test @Test
@TestMetadata("StaticFieldQualified.kt") @TestMetadata("StaticFieldQualified.kt")
public void testStaticFieldQualified() { public void testStaticFieldQualified() {
@@ -1843,6 +1849,24 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerate
public void testStaticFunctionQualifiedWithKotlinSubclass() { public void testStaticFunctionQualifiedWithKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt"); runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/StaticFunctionQualifiedWithKotlinSubclass.kt");
} }
@Test
@TestMetadata("SyntheticFieldInAnnotationInterface.kt")
public void testSyntheticFieldInAnnotationInterface() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInAnnotationInterface.kt");
}
@Test
@TestMetadata("SyntheticFieldInClass.kt")
public void testSyntheticFieldInClass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticFieldInClass.kt");
}
@Test
@TestMetadata("SyntheticPropertyInKotlinSubclass.kt")
public void testSyntheticPropertyInKotlinSubclass() {
runTest("analysis/analysis-api/testData/referenceResolve/kDoc/javaDeclarations/SyntheticPropertyInKotlinSubclass.kt");
}
} }
@Nested @Nested
@@ -0,0 +1,16 @@
// FILE: main.kt
/**
* [Storage.<caret_1>value]
* [Storage.<caret_2>setValue]
* [Storage.<caret_3>prop]
*/
fun usage() {
}
// FILE: Storage.java
class Storage {
void prop() {}
void setValue(String value) {}
String getProp() { return null; }
}
@@ -0,0 +1,8 @@
<caret_1> resolved to:
Nothing (Unresolved reference)
<caret_2> resolved to:
0: (in Storage) open fun setValue(value: kotlin.String!)
<caret_3> resolved to:
0: (in Storage) open fun prop()
@@ -0,0 +1,18 @@
// FILE: main.kt
/**
* [Storage.<caret_1>value]
* [Storage2.<caret_2>value2]
*/
fun usage() {
}
// FILE: Storage.java
@interface Storage {
String value() default "";
}
// FILE: Storage2.java
@interface Storage2 {
String value2();
}
@@ -0,0 +1,5 @@
<caret_1> resolved to:
0: (in Storage) val value: kotlin.String
<caret_2> resolved to:
0: (in Storage2) val value2: kotlin.String
@@ -0,0 +1,13 @@
// FILE: main.kt
/**
* [Storage.<caret_1>value]
* [Storage.<caret_2>getValue]
*/
fun usage() {
}
// FILE: Storage.java
class Storage {
String getValue() { return null; }
}
@@ -0,0 +1,5 @@
<caret_1> resolved to:
0: (in Storage) open fun getValue(): kotlin.String!
<caret_2> resolved to:
0: (in Storage) open fun getValue(): kotlin.String!
@@ -0,0 +1,15 @@
// FILE: main.kt
import dependency.JavaBase
/**
* [<caret_2>prop]
* [KotlinChild.<caret_1>prop]
*/
class KotlinChild : JavaBase()
// FILE: dependency/JavaBase.java
package dependency;
public class JavaBase {
public String getProp() { return null; }
}
@@ -0,0 +1,5 @@
<caret_2> resolved to:
0: (in dependency.JavaBase) open fun getProp(): kotlin.String!
<caret_1> resolved to:
0: (in dependency.JavaBase) open fun getProp(): kotlin.String!