From a0651cdba7fc233662c1eab0bd10a99afd804e38 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 10 Dec 2020 19:40:38 +0100 Subject: [PATCH] FIR IDE: add Java synthetic properties support for completion --- .../basic/java/JavaSyntheticProperty.kt | 8 ++++++++ .../handlers/basic/SyntheticExtension.kt | 2 ++ .../handlers/basic/SyntheticExtension.kt.after | 2 ++ .../test/JvmBasicCompletionTestGenerated.java | 5 +++++ .../completion/KotlinFirLookupElementFactory.kt | 16 +++++++++++++++- ...ighLevelJvmBasicCompletionTestGenerated.java | 5 +++++ .../api/fir/components/KtFirScopeProvider.kt | 17 ++++++++++++----- 7 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt diff --git a/idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt b/idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt new file mode 100644 index 00000000000..435127e68d1 --- /dev/null +++ b/idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt @@ -0,0 +1,8 @@ +// FIR_COMPARISON + +fun foo(a: java.lang.Thread) { + a.na +} + + +// EXIST: {"lookupString":"name","tailText":" (from getName()/setName())","allLookupStrings":"getName, name, setName","itemText":"name"} diff --git a/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt b/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt index a4f68a36f93..5899e318f8f 100644 --- a/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt +++ b/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt @@ -1,3 +1,5 @@ +// FIR_COMPARISON + import java.io.File fun foo(file: File) { diff --git a/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt.after b/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt.after index 69f9eb2d9b1..f0fdc1ea787 100644 --- a/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt.after +++ b/idea/idea-completion/testData/handlers/basic/SyntheticExtension.kt.after @@ -1,3 +1,5 @@ +// FIR_COMPARISON + import java.io.File fun foo(file: File) { diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index 7a18e4ff642..76be124f413 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -2950,6 +2950,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT runTest("idea/idea-completion/testData/basic/java/JavaPackage.kt"); } + @TestMetadata("JavaSyntheticProperty.kt") + public void testJavaSyntheticProperty() throws Exception { + runTest("idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt"); + } + @TestMetadata("KProperty.kt") public void testKProperty() throws Exception { runTest("idea/idea-completion/testData/basic/java/KProperty.kt"); diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirLookupElementFactory.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirLookupElementFactory.kt index b842a33a884..1b75bed1628 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirLookupElementFactory.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirLookupElementFactory.kt @@ -34,7 +34,7 @@ internal class KotlinFirLookupElementFactory { fun KtAnalysisSession.createLookupElement(symbol: KtNamedSymbol): LookupElement? { val elementBuilder = when (symbol) { is KtFunctionSymbol -> with(functionLookupElementFactory) { createLookup(symbol) } - is KtVariableLikeSymbol -> with(variableLookupElementFactory) { createLookup(symbol) } + is KtVariableLikeSymbol -> with(variableLookupElementFactory) { createLookup(symbol) } is KtClassLikeSymbol -> classLookupElementFactory.createLookup(symbol) is KtTypeParameterSymbol -> typeParameterLookupElementFactory.createLookup(symbol) else -> throw IllegalArgumentException("Cannot create a lookup element for $symbol") @@ -67,9 +67,23 @@ private class VariableLookupElementFactory { fun KtAnalysisSession.createLookup(symbol: KtVariableLikeSymbol): LookupElementBuilder { return LookupElementBuilder.create(UniqueLookupObject(), symbol.name.asString()) .withTypeText(symbol.type.render()) + .markIfSyntheticJavaProperty(symbol) .withInsertHandler(createInsertHandler(symbol)) } + private fun LookupElementBuilder.markIfSyntheticJavaProperty(symbol: KtVariableLikeSymbol): LookupElementBuilder = when (symbol) { + is KtSyntheticJavaPropertySymbol -> { + val getterName = symbol.javaGetterName.asString() + val setterName = symbol.javaSetterName?.asString() + this.withTailText((" (from ${buildSyntheticPropertyTailText(getterName, setterName)})")) + .withLookupStrings(listOfNotNull(getterName, setterName)) + } + else -> this + } + + private fun buildSyntheticPropertyTailText(getterName: String, setterName: String?): String = + if (setterName != null) "$getterName()/$setterName()" else "$getterName()" + private fun createInsertHandler(symbol: KtVariableLikeSymbol): InsertHandler { return QuotedNamesAwareInsertionHandler(symbol.name) } diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelJvmBasicCompletionTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelJvmBasicCompletionTestGenerated.java index e987af8d50a..9e2cc499aff 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelJvmBasicCompletionTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelJvmBasicCompletionTestGenerated.java @@ -2950,6 +2950,11 @@ public class HighLevelJvmBasicCompletionTestGenerated extends AbstractHighLevelJ runTest("idea/idea-completion/testData/basic/java/JavaPackage.kt"); } + @TestMetadata("JavaSyntheticProperty.kt") + public void testJavaSyntheticProperty() throws Exception { + runTest("idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt"); + } + @TestMetadata("KProperty.kt") public void testKProperty() throws Exception { runTest("idea/idea-completion/testData/basic/java/KProperty.kt"); diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt index 6024798f860..ee24918c7de 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt @@ -6,15 +6,14 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertiesScope import org.jetbrains.kotlin.fir.resolve.scope -import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator -import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope -import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.* -import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCompletion import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile @@ -122,9 +121,17 @@ internal class KtFirScopeProvider( firResolveState.firTransformerProvider.getScopeSession(firSession), FakeOverrideTypeCalculator.Forced ) ?: return null - return convertToKtScope(firTypeScope) + return getCompositeScope( + listOf( + convertToKtScope(firTypeScope), + firTypeScope.getSyntheticPropertiesScope(firSession) + ) + ) } + private fun FirTypeScope.getSyntheticPropertiesScope(firSession: FirSession): KtScope = + convertToKtScope(FirSyntheticPropertiesScope(firSession, this)) + override fun getScopeContextForPosition( originalFile: KtFile, positionInFakeFile: KtElement