diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt index 32563d976cd..dc9cd01cd7c 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt @@ -16,34 +16,21 @@ package org.jetbrains.kotlin.idea.completion -import com.intellij.codeInsight.completion.InsertionContext -import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.codeInsight.lookup.LookupElementDecorator -import com.intellij.codeInsight.lookup.LookupElementPresentation import com.intellij.icons.AllIcons -import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.ui.RowIcon import org.jetbrains.kotlin.backend.common.descriptors.isSuspend import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde -import org.jetbrains.kotlin.idea.completion.handlers.indexOfSkippingSpace import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject -import org.jetbrains.kotlin.idea.core.moveCaret -import org.jetbrains.kotlin.idea.core.moveCaretIntoGeneratedElement -import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember -import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType -import javax.swing.Icon class OverridesCompletion( private val collector: LookupElementsCollector, @@ -96,10 +83,9 @@ class OverridesCompletion( baseClassName, baseClassIcon, isConstructorParameter, - classOrObject, memberObject.descriptor.isSuspend, - memberObject::generateMember, - ShortenReferences.DEFAULT::process, + generateMember = { memberObject.generateMember(classOrObject, copyDoc = false) }, + shortenReferences = ShortenReferences.DEFAULT::process, ) lookupElement.assignPriority(if (isImplement) ItemPriority.IMPLEMENT else ItemPriority.OVERRIDE) diff --git a/idea/idea-completion/testData/handlers/basic/override/ExpectClassValOverride.kt b/idea/idea-completion/testData/handlers/basic/override/ExpectClassValOverride.kt index bc93611e5a3..0b2268e0668 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ExpectClassValOverride.kt +++ b/idea/idea-completion/testData/handlers/basic/override/ExpectClassValOverride.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface Interface { var field: Int } diff --git a/idea/idea-completion/testData/handlers/basic/override/ExpectClassValOverride.kt.after b/idea/idea-completion/testData/handlers/basic/override/ExpectClassValOverride.kt.after index 78f4ac83282..6b151f6531d 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ExpectClassValOverride.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/ExpectClassValOverride.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface Interface { var field: Int } diff --git a/idea/idea-completion/testData/handlers/basic/override/ImplementFunction.kt b/idea/idea-completion/testData/handlers/basic/override/ImplementFunction.kt index e3acc578ce6..ad5959e07fc 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ImplementFunction.kt +++ b/idea/idea-completion/testData/handlers/basic/override/ImplementFunction.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { fun foo(p: Int) } diff --git a/idea/idea-completion/testData/handlers/basic/override/ImplementFunction.kt.after b/idea/idea-completion/testData/handlers/basic/override/ImplementFunction.kt.after index 6820d5b8e9b..b0ed0a99ad0 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ImplementFunction.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/ImplementFunction.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { fun foo(p: Int) } diff --git a/idea/idea-completion/testData/handlers/basic/override/ImplementVal.kt b/idea/idea-completion/testData/handlers/basic/override/ImplementVal.kt index ab3435662fc..ad4cf128b4a 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ImplementVal.kt +++ b/idea/idea-completion/testData/handlers/basic/override/ImplementVal.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { val someVal: String? } diff --git a/idea/idea-completion/testData/handlers/basic/override/ImplementVal.kt.after b/idea/idea-completion/testData/handlers/basic/override/ImplementVal.kt.after index b166893a50f..9bf6cf71e81 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ImplementVal.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/ImplementVal.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { val someVal: String? } diff --git a/idea/idea-completion/testData/handlers/basic/override/ImplementVar.kt b/idea/idea-completion/testData/handlers/basic/override/ImplementVar.kt index 7819a8a7ab9..905531c1860 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ImplementVar.kt +++ b/idea/idea-completion/testData/handlers/basic/override/ImplementVar.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { var someVar: String } diff --git a/idea/idea-completion/testData/handlers/basic/override/ImplementVar.kt.after b/idea/idea-completion/testData/handlers/basic/override/ImplementVar.kt.after index 7e8ed235650..ebf0130c001 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ImplementVar.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/ImplementVar.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { var someVar: String } diff --git a/idea/idea-completion/testData/handlers/basic/override/KeepAnnotationBefore.kt b/idea/idea-completion/testData/handlers/basic/override/KeepAnnotationBefore.kt index 2f32113e657..69e836185f7 100644 --- a/idea/idea-completion/testData/handlers/basic/override/KeepAnnotationBefore.kt +++ b/idea/idea-completion/testData/handlers/basic/override/KeepAnnotationBefore.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON class A { @Deprecated("") o diff --git a/idea/idea-completion/testData/handlers/basic/override/KeepAnnotationBefore.kt.after b/idea/idea-completion/testData/handlers/basic/override/KeepAnnotationBefore.kt.after index f34c4cbfc83..55200dfae0d 100644 --- a/idea/idea-completion/testData/handlers/basic/override/KeepAnnotationBefore.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/KeepAnnotationBefore.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON class A { @Deprecated("") override fun equals(other: Any?): Boolean { diff --git a/idea/idea-completion/testData/handlers/basic/override/KeepModifiersBefore.kt b/idea/idea-completion/testData/handlers/basic/override/KeepModifiersBefore.kt index 02383882320..f0915acb697 100644 --- a/idea/idea-completion/testData/handlers/basic/override/KeepModifiersBefore.kt +++ b/idea/idea-completion/testData/handlers/basic/override/KeepModifiersBefore.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON class A { @Deprecated("") // it is deprecated public o diff --git a/idea/idea-completion/testData/handlers/basic/override/KeepModifiersBefore.kt.after b/idea/idea-completion/testData/handlers/basic/override/KeepModifiersBefore.kt.after index 055f2fe7a4b..f08b504e1ca 100644 --- a/idea/idea-completion/testData/handlers/basic/override/KeepModifiersBefore.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/KeepModifiersBefore.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON class A { @Deprecated("") // it is deprecated public override fun equals(other: Any?): Boolean { diff --git a/idea/idea-completion/testData/handlers/basic/override/OverrideFunction.kt b/idea/idea-completion/testData/handlers/basic/override/OverrideFunction.kt index 94523fa7266..53aac5f6d9f 100644 --- a/idea/idea-completion/testData/handlers/basic/override/OverrideFunction.kt +++ b/idea/idea-completion/testData/handlers/basic/override/OverrideFunction.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON class A { o } diff --git a/idea/idea-completion/testData/handlers/basic/override/OverrideFunction.kt.after b/idea/idea-completion/testData/handlers/basic/override/OverrideFunction.kt.after index 8938f4d0427..fb7f12942d5 100644 --- a/idea/idea-completion/testData/handlers/basic/override/OverrideFunction.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/OverrideFunction.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON class A { override fun equals(other: Any?): Boolean { return super.equals(other) diff --git a/idea/idea-completion/testData/handlers/basic/override/PublicValInConstructorParameter.kt b/idea/idea-completion/testData/handlers/basic/override/PublicValInConstructorParameter.kt index b86ef98a962..f997d6b100b 100644 --- a/idea/idea-completion/testData/handlers/basic/override/PublicValInConstructorParameter.kt +++ b/idea/idea-completion/testData/handlers/basic/override/PublicValInConstructorParameter.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { val someVal: java.io.File? } diff --git a/idea/idea-completion/testData/handlers/basic/override/PublicValInConstructorParameter.kt.after b/idea/idea-completion/testData/handlers/basic/override/PublicValInConstructorParameter.kt.after index 55d35d8260b..9a03f02dfc6 100644 --- a/idea/idea-completion/testData/handlers/basic/override/PublicValInConstructorParameter.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/PublicValInConstructorParameter.kt.after @@ -1,5 +1,6 @@ import java.io.File +// FIR_COMPARISON interface I { val someVal: java.io.File? } diff --git a/idea/idea-completion/testData/handlers/basic/override/Suspend.kt b/idea/idea-completion/testData/handlers/basic/override/Suspend.kt index d8d80ab50ca..ea57c3293be 100644 --- a/idea/idea-completion/testData/handlers/basic/override/Suspend.kt +++ b/idea/idea-completion/testData/handlers/basic/override/Suspend.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { suspend fun foo() } diff --git a/idea/idea-completion/testData/handlers/basic/override/Suspend.kt.after b/idea/idea-completion/testData/handlers/basic/override/Suspend.kt.after index 0facc836e42..3a48cbd60ad 100644 --- a/idea/idea-completion/testData/handlers/basic/override/Suspend.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/Suspend.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { suspend fun foo() } diff --git a/idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt b/idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt index 94b19bc9acc..58a7596903d 100644 --- a/idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt +++ b/idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON class A { equ } diff --git a/idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt.after b/idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt.after index 8938f4d0427..fb7f12942d5 100644 --- a/idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/TypeFunctionName.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON class A { override fun equals(other: Any?): Boolean { return super.equals(other) diff --git a/idea/idea-completion/testData/handlers/basic/override/TypeNameInConstructorParameter.kt b/idea/idea-completion/testData/handlers/basic/override/TypeNameInConstructorParameter.kt index 3fa47a779d0..58fe09aee1f 100644 --- a/idea/idea-completion/testData/handlers/basic/override/TypeNameInConstructorParameter.kt +++ b/idea/idea-completion/testData/handlers/basic/override/TypeNameInConstructorParameter.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { protected var someVar: java.io.File? } diff --git a/idea/idea-completion/testData/handlers/basic/override/TypeNameInConstructorParameter.kt.after b/idea/idea-completion/testData/handlers/basic/override/TypeNameInConstructorParameter.kt.after index a96ccaed652..cfbec759d9b 100644 --- a/idea/idea-completion/testData/handlers/basic/override/TypeNameInConstructorParameter.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/TypeNameInConstructorParameter.kt.after @@ -1,5 +1,6 @@ import java.io.File +// FIR_COMPARISON interface I { protected var someVar: java.io.File? } diff --git a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter.kt b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter.kt index 8173abf2740..f6e75055a16 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter.kt +++ b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { val someVal: java.io.File? } diff --git a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter.kt.after b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter.kt.after index d341a84ed25..2cff287db24 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter.kt.after @@ -1,5 +1,6 @@ import java.io.File +// FIR_COMPARISON interface I { val someVal: java.io.File? } diff --git a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter2.kt b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter2.kt index 7f176275f90..2726cd8ef61 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter2.kt +++ b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter2.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { val p: Int } diff --git a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter2.kt.after b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter2.kt.after index 7318800fea0..eb86bc30cf9 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter2.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter2.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { val p: Int } diff --git a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter3.kt b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter3.kt index 381c1e1aaf3..26dc7bc262a 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter3.kt +++ b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter3.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { val p: Int } diff --git a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter3.kt.after b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter3.kt.after index dc46698c26e..ad61b02a196 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter3.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter3.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface I { val p: Int } diff --git a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter4.kt b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter4.kt index 65b9af33158..2547bcb1791 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter4.kt +++ b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter4.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON package ppp interface I { diff --git a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter4.kt.after b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter4.kt.after index fd5a7a0325a..5791faa62c8 100644 --- a/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter4.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/ValInConstructorParameter4.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON package ppp interface I { diff --git a/idea/idea-completion/testData/handlers/basic/override/kt25312.kt b/idea/idea-completion/testData/handlers/basic/override/kt25312.kt index e58d60793f7..2a3554b6911 100644 --- a/idea/idea-completion/testData/handlers/basic/override/kt25312.kt +++ b/idea/idea-completion/testData/handlers/basic/override/kt25312.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface Interface { fun funA() } diff --git a/idea/idea-completion/testData/handlers/basic/override/kt25312.kt.after b/idea/idea-completion/testData/handlers/basic/override/kt25312.kt.after index b905107d371..cb6da11e8aa 100644 --- a/idea/idea-completion/testData/handlers/basic/override/kt25312.kt.after +++ b/idea/idea-completion/testData/handlers/basic/override/kt25312.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON interface Interface { fun funA() } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt index 2671c2cb013..413bba77a66 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt @@ -55,21 +55,15 @@ private object KotlinFirCompletionProvider : CompletionProvider with( - KotlinWithNameReferenceCompletionProvider(basicContext, indexHelper) - ) { - addCompletions(positionContext) - } - is FirUnknownPositionContext -> { - // TODO remove when hack when LL API will be able to handle more context for completion - } + FirPositionCompletionContextDetector.analyseInContext(basicContext, positionContext) { + with(keywordContributor) { completeKeywords(positionContext) } + when (positionContext) { + is FirNameReferencePositionContext -> with( + KotlinWithNameReferenceCompletionProvider(basicContext, indexHelper) + ) { + addCompletions(positionContext) + } + is FirUnknownPositionContext -> { } } } @@ -137,7 +131,6 @@ private class KotlinWithNameReferenceCompletionProvider( basicContext: FirBasicCompletionContext, private val indexHelper: IndexHelper ) : FirCompletionContributorBase(basicContext) { - private val lookupElementFactory = KotlinFirLookupElementFactory() private val typeNamesProvider = TypeNamesProvider(indexHelper) private val scopeNameFilter: KtScopeNameFilter = @@ -198,13 +191,13 @@ private class KotlinWithNameReferenceCompletionProvider( .getClassifierSymbols(scopeNameFilter) .filter { visibilityChecker.isVisible(it) } - classesFromScopes.forEach { addSymbolToCompletion(result, expectedType, it) } + classesFromScopes.forEach { addSymbolToCompletion(expectedType, it) } val kotlinClassesFromIndices = indexHelper.getKotlinClasses(scopeNameFilter, psiFilter = { it !is KtEnumEntry }) kotlinClassesFromIndices.asSequence() .map { it.getSymbol() as KtClassifierSymbol } .filter { visibilityChecker.isVisible(it) } - .forEach { addSymbolToCompletion(result, expectedType, it) } + .forEach { addSymbolToCompletion(expectedType, it) } } private fun KtAnalysisSession.collectDotCompletion( @@ -220,11 +213,11 @@ private class KotlinWithNameReferenceCompletionProvider( val nonExtensionMembers = possibleReceiverScope.collectNonExtensions(visibilityChecker) val extensionNonMembers = implicitScopes.collectSuitableExtensions(extensionChecker, visibilityChecker) - nonExtensionMembers.forEach { addSymbolToCompletion(result, expectedType, it) } - extensionNonMembers.forEach { addSymbolToCompletion(result, expectedType, it) } + nonExtensionMembers.forEach { addSymbolToCompletion(expectedType, it) } + extensionNonMembers.forEach { addSymbolToCompletion(expectedType, it) } collectTopLevelExtensionsFromIndices(listOf(typeOfPossibleReceiver), extensionChecker, visibilityChecker) - .forEach { addSymbolToCompletion(result, expectedType, it) } + .forEach { addSymbolToCompletion(expectedType, it) } } private fun KtAnalysisSession.collectDefaultCompletion( @@ -238,19 +231,19 @@ private class KotlinWithNameReferenceCompletionProvider( val availableNonExtensions = implicitScopes.collectNonExtensions(visibilityChecker) val extensionsWhichCanBeCalled = implicitScopes.collectSuitableExtensions(extensionChecker, visibilityChecker) - availableNonExtensions.forEach { addSymbolToCompletion(result, expectedType, it) } - extensionsWhichCanBeCalled.forEach { addSymbolToCompletion(result, expectedType, it) } + availableNonExtensions.forEach { addSymbolToCompletion(expectedType, it) } + extensionsWhichCanBeCalled.forEach { addSymbolToCompletion(expectedType, it) } if (shouldCompleteTopLevelCallablesFromIndex) { val topLevelCallables = indexHelper.getTopLevelCallables(scopeNameFilter) topLevelCallables.asSequence() .map { it.getSymbol() as KtCallableSymbol } .filter { visibilityChecker.isVisible(it) } - .forEach { addSymbolToCompletion(result, expectedType, it) } + .forEach { addSymbolToCompletion(expectedType, it) } } collectTopLevelExtensionsFromIndices(implicitReceiversTypes, extensionChecker, visibilityChecker) - .forEach { addSymbolToCompletion(result, expectedType, it) } + .forEach { addSymbolToCompletion(expectedType, it) } collectTypesCompletion(implicitScopes, expectedType, visibilityChecker) } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirBasicCompletionContext.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirBasicCompletionContext.kt index 40825aee3fe..a2be5b1440e 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirBasicCompletionContext.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirBasicCompletionContext.kt @@ -9,6 +9,7 @@ import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.completion.PrefixMatcher import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.idea.completion.KotlinFirLookupElementFactory import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.psi.KtFile @@ -21,6 +22,7 @@ internal class FirBasicCompletionContext( val fakeKtFile: KtFile, val project: Project, val targetPlatform: TargetPlatform, + val lookupElementFactory: KotlinFirLookupElementFactory = KotlinFirLookupElementFactory(), ) { companion object { fun createFromParameters(parameters: CompletionParameters, result: CompletionResultSet): FirBasicCompletionContext? { diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt index 96624dfee10..46dcbf8ca38 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.completion.context import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.analyse import org.jetbrains.kotlin.idea.frontend.api.analyseInFakeAnalysisSession import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.mainReference @@ -60,7 +61,7 @@ internal object FirPositionCompletionContextDetector { action ) is FirUnknownPositionContext -> { - // TODO + analyse(basicContext.originalKtFile, action) } } } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCompletionContributorBase.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCompletionContributorBase.kt index f93b5209d62..4ae9e89c314 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCompletionContributorBase.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCompletionContributorBase.kt @@ -29,9 +29,7 @@ internal abstract class FirCompletionContributorBase(protected val basicContext: protected val fakeKtFile: KtFile get() = basicContext.fakeKtFile protected val project: Project get() = basicContext.project protected val targetPlatform: TargetPlatform get() = basicContext.targetPlatform - - - protected val lookupElementFactory = KotlinFirLookupElementFactory() + protected val lookupElementFactory: KotlinFirLookupElementFactory get() = basicContext.lookupElementFactory protected fun KtAnalysisSession.addSymbolToCompletion(expectedType: KtType?, symbol: KtSymbol) { if (symbol !is KtNamedSymbol) return diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirKeywordCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirKeywordCompletionContributor.kt index 5dec650da39..9bb8d9aa93f 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirKeywordCompletionContributor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirKeywordCompletionContributor.kt @@ -26,6 +26,8 @@ internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionC override fun getLanguageVersionSetting(module: Module) = LanguageVersionSettingsImpl.DEFAULT // TODO }) + private val resolveDependentCompletionKeywordHandlers = ResolveDependentCompletionKeywordHandlers(basicContext) + fun KtAnalysisSession.completeKeywords( positionContext: FirPositionCompletionContext ) { @@ -43,10 +45,10 @@ internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionC } fun KtAnalysisSession.completeWithResolve(position: PsiElement, expression: KtExpression?) { - complete(position, expression) { lookupElement, keyword -> + complete(position) { lookupElement, keyword -> val lookups = DefaultCompletionKeywordHandlers.defaultHandlers.getHandlerForKeyword(keyword) ?.createLookups(parameters, expression, lookupElement, project) - ?: ResolveDependentCompletionKeywordHandlers.handlers.getHandlerForKeyword(keyword)?.run { + ?: resolveDependentCompletionKeywordHandlers.handlers.getHandlerForKeyword(keyword)?.run { createLookups(parameters, expression, lookupElement, project) } ?: listOf(lookupElement) @@ -54,16 +56,7 @@ internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionC } } - fun completeDefaultKeywordsWithoutResolve(position: PsiElement, expression: KtExpression?) { - complete(position, expression) { lookupElement, keyword -> - val lookups = DefaultCompletionKeywordHandlers.defaultHandlers.getHandlerForKeyword(keyword) - ?.createLookups(parameters, expression, lookupElement, project) - ?: listOf(lookupElement) - result.addAllElements(lookups) - } - } - - private inline fun complete(position: PsiElement, expression: KtExpression?, crossinline complete: (LookupElement, String) -> Unit) { + private inline fun complete(position: PsiElement, crossinline complete: (LookupElement, String) -> Unit) { keywordCompletion.complete(position, prefixMatcher, targetPlatform.isJvm()) { lookupElement -> val keyword = lookupElement.lookupString complete(lookupElement, keyword) @@ -71,10 +64,9 @@ internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionC } } -private object ResolveDependentCompletionKeywordHandlers { +private class ResolveDependentCompletionKeywordHandlers(basicContext: FirBasicCompletionContext) { val handlers = CompletionKeywordHandlers( ReturnKeywordHandler, - OverrideKeywordHandler, + OverrideKeywordHandler(basicContext), ) -} - +} \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/keywords/OverrideKeywordHandler.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/keywords/OverrideKeywordHandler.kt new file mode 100644 index 00000000000..5c2598119e6 --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/keywords/OverrideKeywordHandler.kt @@ -0,0 +1,173 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.completion.contributors.keywords + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.icons.AllIcons +import com.intellij.openapi.project.Project +import com.intellij.ui.RowIcon +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.idea.completion.* +import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext +import org.jetbrains.kotlin.idea.core.overrideImplement.* +import org.jetbrains.kotlin.idea.core.overrideImplement.KtClassMember +import org.jetbrains.kotlin.idea.core.overrideImplement.KtGenerateMembersHandler +import org.jetbrains.kotlin.idea.core.overrideImplement.KtOverrideMembersHandler +import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember +import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.analyse +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithModality +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtIconProvider.getIcon +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.nameOrAnonymous +import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtSymbolPointer +import org.jetbrains.kotlin.idea.frontend.api.tokens.HackToForceAllowRunningAnalyzeOnEDT +import org.jetbrains.kotlin.idea.frontend.api.tokens.hackyAllowRunningOnEdt +import org.jetbrains.kotlin.idea.util.application.runWriteAction + +internal class OverrideKeywordHandler( + private val basicContext: FirBasicCompletionContext +) : CompletionKeywordHandler(KtTokens.OVERRIDE_KEYWORD) { + + @OptIn(ExperimentalStdlibApi::class) + override fun KtAnalysisSession.createLookups( + parameters: CompletionParameters, + expression: KtExpression?, + lookup: LookupElement, + project: Project + ): Collection { + val result = mutableListOf(lookup) + val position = parameters.position + val isConstructorParameter = position.getNonStrictParentOfType() != null + val classOrObject = position.getNonStrictParentOfType() ?: return result + val members = collectMembers(classOrObject, isConstructorParameter) + + for (member in members) { + result += createLookupElementToGenerateSingleOverrideMember(member, classOrObject, isConstructorParameter, project) + } + return result + } + + private fun KtAnalysisSession.collectMembers(classOrObject: KtClassOrObject, isConstructorParameter: Boolean): List { + val allMembers = KtOverrideMembersHandler().collectMembersToGenerate(classOrObject) + return if (isConstructorParameter) { + allMembers.mapNotNull { member -> + if (member.memberInfo.isProperty) { + member.copy(bodyType = BodyType.FROM_TEMPLATE, preferConstructorParameter = true) + } else null + } + } else allMembers.toList() + } + + private fun KtAnalysisSession.createLookupElementToGenerateSingleOverrideMember( + member: KtClassMember, + classOrObject: KtClassOrObject, + isConstructorParameter: Boolean, + project: Project + ): OverridesCompletionLookupElementDecorator { + val memberSymbol = member.symbol + check(memberSymbol is KtNamedSymbol) + + val text = getSymbolTextForLookupElement(memberSymbol) + val baseIcon = getIcon(memberSymbol) + val isImplement = (memberSymbol as? KtSymbolWithModality)?.modality == Modality.ABSTRACT + val additionalIcon = if (isImplement) AllIcons.Gutter.ImplementingMethod else AllIcons.Gutter.OverridingMethod + val icon = RowIcon(baseIcon, additionalIcon) + val baseClass = classOrObject.getClassOrObjectSymbol() + val baseClassIcon = getIcon(baseClass) + val isSuspendFunction = (memberSymbol as? KtFunctionSymbol)?.isSuspend == true + val baseClassName = baseClass.nameOrAnonymous.asString() + + val memberPointer = memberSymbol.createPointer() + + val baseLookupElement = with(basicContext.lookupElementFactory) { createLookupElement(memberSymbol) } + ?: error("Lookup element should be available for override completion") + return OverridesCompletionLookupElementDecorator( + baseLookupElement, + declaration = null, + text, + isImplement, + icon, + baseClassName, + baseClassIcon, + isConstructorParameter, + isSuspendFunction, + generateMember = { + generateMemberInNewAnalysisSession(classOrObject, memberPointer, member, project) + }, + shortenReferences = { element -> + @OptIn(HackToForceAllowRunningAnalyzeOnEDT::class) + val shortenings = hackyAllowRunningOnEdt { + analyse(classOrObject) { + collectPossibleReferenceShortenings(element.containingKtFile, element.textRange) + } + } + runWriteAction { + shortenings.invokeShortening() + } + } + ) + } + + private fun KtAnalysisSession.getSymbolTextForLookupElement(memberSymbol: KtCallableSymbol): String = buildString { + append(KtTokens.OVERRIDE_KEYWORD.value) + .append(" ") + .append(memberSymbol.render(renderingOptionsForLookupElementRendering)) + if (memberSymbol is KtFunctionSymbol) { + append(" {...}") + } + } + + @OptIn(HackToForceAllowRunningAnalyzeOnEDT::class) + private fun generateMemberInNewAnalysisSession( + classOrObject: KtClassOrObject, + memberPointer: KtSymbolPointer, + member: KtClassMember, + project: Project + ) = hackyAllowRunningOnEdt { + analyse(classOrObject) { + val memberInCorrectAnalysisSession = createCopyInCurrentAnalysisSession(memberPointer, member) + generateMember( + project, + memberInCorrectAnalysisSession, + classOrObject, + copyDoc = false, + mode = MemberGenerateMode.OVERRIDE + ) + } + } + + //todo temporary hack until KtSymbolPointer is properly implemented + private fun KtAnalysisSession.createCopyInCurrentAnalysisSession( + memberPointer: KtSymbolPointer, + member: KtClassMember + ) = KtClassMember( + KtClassMemberInfo( + memberPointer.restoreSymbol() + ?: error("Cannot restore symbol from $memberPointer"), + member.memberInfo.memberText, + member.memberInfo.memberIcon, + member.memberInfo.containingSymbolText, + member.memberInfo.containingSymbolIcon, + ), + member.bodyType, + member.preferConstructorParameter, + ) + + companion object { + private val renderingOptionsForLookupElementRendering = + KtGenerateMembersHandler.renderOption.copy( + renderUnitReturnType = false, + renderDeclarationHeader = true + ) + } +} \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtClassMember.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtClassMember.kt index d155a28f750..cbd6d2dc17f 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtClassMember.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtClassMember.kt @@ -43,8 +43,8 @@ internal data class KtClassMemberInfo( val isProperty: Boolean get() = symbol is KtPropertySymbol } -internal class KtClassMember( - private val memberInfo: KtClassMemberInfo, +internal data class KtClassMember( + val memberInfo: KtClassMemberInfo, val bodyType: BodyType, val preferConstructorParameter: Boolean ) : MemberChooserObjectBase( diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtOverrideMembersHandler.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtOverrideMembersHandler.kt index 829465b09f0..84d52005648 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtOverrideMembersHandler.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtOverrideMembersHandler.kt @@ -19,7 +19,7 @@ import org.jetbrains.kotlin.idea.frontend.api.tokens.hackyAllowRunningOnEdt import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.psi.KtClassOrObject -internal class KtOverrideMembersHandler : KtGenerateMembersHandler() { +internal open class KtOverrideMembersHandler : KtGenerateMembersHandler() { @OptIn(HackToForceAllowRunningAnalyzeOnEDT::class) override fun collectMembersToGenerate(classOrObject: KtClassOrObject): Collection { return hackyAllowRunningOnEdt { @@ -29,7 +29,7 @@ internal class KtOverrideMembersHandler : KtGenerateMembersHandler() { } } - private fun KtAnalysisSession.collectMembers(classOrObject: KtClassOrObject): List { + fun KtAnalysisSession.collectMembers(classOrObject: KtClassOrObject): List { val classOrObjectSymbol = classOrObject.getClassOrObjectSymbol() return getOverridableMembers(classOrObjectSymbol).map { (symbol, bodyType, containingSymbol) -> KtClassMember( diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/completion/OverridesCompletionLookupElementDecorator.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/completion/OverridesCompletionLookupElementDecorator.kt index b99787dcfc1..339d8c50a0f 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/completion/OverridesCompletionLookupElementDecorator.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/completion/OverridesCompletionLookupElementDecorator.kt @@ -30,9 +30,8 @@ class OverridesCompletionLookupElementDecorator( private val baseClassName: String, private val baseClassIcon: Icon?, private val isConstructorParameter: Boolean, - private val classOrObject: KtClassOrObject, private val isSuspend: Boolean, - private val generateMember: (targetClass: KtClassOrObject, copyDoc: Boolean) -> KtCallableDeclaration, + private val generateMember: () -> KtCallableDeclaration, private val shortenReferences: (KtElement) -> Unit, ) : LookupElementDecorator(lookupElement) { override fun getLookupString() = @@ -85,7 +84,7 @@ class OverridesCompletionLookupElementDecorator( // keep original modifiers val modifierList = KtPsiFactory(context.project).createModifierList(dummyMember.modifierList!!.text) - val prototype = generateMember(classOrObject, false) + val prototype = generateMember() prototype.modifierList!!.replace(modifierList) val insertedMember = dummyMember.replaced(prototype) if (isSuspend) insertedMember.addModifier(KtTokens.SUSPEND_KEYWORD)