FIR IDE: add type completion with dot
This commit is contained in:
committed by
TeamCityServer
parent
e03916e7fb
commit
bcf7116955
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
class AAA {
|
||||
class Nested
|
||||
inner class Inner
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
class A {
|
||||
class Nested
|
||||
inner class Inner
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
class A {
|
||||
class Nested
|
||||
inner class Inner
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
fun main(args: Array<String>) {
|
||||
println(R.<caret>)
|
||||
}
|
||||
|
||||
+12
-8
@@ -13,15 +13,12 @@ import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.openapi.diagnostic.ControlFlowException
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.isTextAt
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import org.jetbrains.kotlin.idea.core.asFqNameWithRootPrefixIfNeeded
|
||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.idea.frontend.api.analyse
|
||||
import org.jetbrains.kotlin.idea.frontend.api.analyseInDependedAnalysisSession
|
||||
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.addImportToFile
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol
|
||||
@@ -54,6 +51,13 @@ internal class KotlinFirLookupElementFactory {
|
||||
.withPsiElement(symbol.psi) // TODO check if it is a heavy operation and should be postponed
|
||||
.withIcon(KotlinFirIconProvider.getIconFor(symbol))
|
||||
}
|
||||
|
||||
fun KtAnalysisSession.createLookupElementForClassLikeSymbol(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElement? {
|
||||
if (symbol !is KtNamedSymbol) return null
|
||||
return classLookupElementFactory.createLookup(symbol, insertFqName)
|
||||
.withPsiElement(symbol.psi) // TODO check if it is a heavy operation and should be postponed
|
||||
.withIcon(KotlinFirIconProvider.getIconFor(symbol))
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CallableImportStrategy {
|
||||
@@ -71,7 +75,7 @@ private interface KotlinLookupObject {
|
||||
val shortName: Name
|
||||
}
|
||||
|
||||
private data class ClassifierLookupObject(override val shortName: Name, val classId: ClassId?) : KotlinLookupObject
|
||||
private data class ClassifierLookupObject(override val shortName: Name, val classId: ClassId?, val insertFqName: Boolean) : KotlinLookupObject
|
||||
|
||||
/**
|
||||
* Simplest lookup object so two lookup elements for the same function will clash.
|
||||
@@ -93,10 +97,10 @@ private data class VariableLookupObject(
|
||||
val importStrategy: CallableImportStrategy
|
||||
) : KotlinLookupObject
|
||||
|
||||
private class ClassLookupElementFactory {
|
||||
fun createLookup(symbol: KtClassLikeSymbol): LookupElementBuilder {
|
||||
class ClassLookupElementFactory {
|
||||
fun createLookup(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElementBuilder {
|
||||
val name = symbol.nameOrAnonymous
|
||||
return LookupElementBuilder.create(ClassifierLookupObject(name, symbol.classIdIfNonLocal), name.asString())
|
||||
return LookupElementBuilder.create(ClassifierLookupObject(name, symbol.classIdIfNonLocal, insertFqName), name.asString())
|
||||
.withInsertHandler(ClassifierInsertionHandler)
|
||||
}
|
||||
}
|
||||
@@ -202,7 +206,7 @@ private object ClassifierInsertionHandler : InsertHandler<LookupElement> {
|
||||
val targetFile = context.file as? KtFile ?: return
|
||||
val lookupObject = item.`object` as ClassifierLookupObject
|
||||
|
||||
if (lookupObject.classId != null) {
|
||||
if (lookupObject.classId != null && lookupObject.insertFqName) {
|
||||
val fqName = lookupObject.classId.asSingleFqName()
|
||||
|
||||
context.document.replaceString(context.startOffset, context.tailOffset, fqName.render())
|
||||
|
||||
+37
-6
@@ -8,30 +8,61 @@ package org.jetbrains.kotlin.idea.completion.contributors
|
||||
import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker
|
||||
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
||||
import org.jetbrains.kotlin.idea.completion.context.FirNameReferenceRawPositionContext
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
|
||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassifierSymbol
|
||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithMembers
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
internal class FirClassifierCompletionContributor(
|
||||
basicContext: FirBasicCompletionContext,
|
||||
) : FirContextCompletionContributorBase<FirNameReferenceRawPositionContext>(basicContext) {
|
||||
|
||||
override fun KtAnalysisSession.complete(positionContext: FirNameReferenceRawPositionContext) {
|
||||
val implicitScopes = originalKtFile.getScopeContextForPosition(positionContext.nameExpression).scopes
|
||||
val visibilityChecker = CompletionVisibilityChecker.create(basicContext, positionContext)
|
||||
|
||||
when (val receiver = positionContext.explicitReceiver) {
|
||||
null -> {
|
||||
completeWithoutReceiver(positionContext, visibilityChecker)
|
||||
}
|
||||
else -> {
|
||||
completeWithReceiver(receiver, visibilityChecker)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtAnalysisSession.completeWithReceiver(
|
||||
receiver: KtExpression,
|
||||
visibilityChecker: CompletionVisibilityChecker
|
||||
) {
|
||||
val reference = receiver.mainReference ?: return
|
||||
val symbol = reference.resolveToSymbol() as? KtSymbolWithMembers ?: return
|
||||
symbol.getMemberScope()
|
||||
.getClassifierSymbols(scopeNameFilter)
|
||||
.filter { with(visibilityChecker) { isVisible(it) } }
|
||||
.forEach { addClassifierSymbolToCompletion(it, insertFqName = false) }
|
||||
}
|
||||
|
||||
private fun KtAnalysisSession.completeWithoutReceiver(
|
||||
positionContext: FirNameReferenceRawPositionContext,
|
||||
visibilityChecker: CompletionVisibilityChecker
|
||||
) {
|
||||
val implicitScopes = originalKtFile.getScopeContextForPosition(positionContext.nameExpression).scopes
|
||||
val classesFromScopes = implicitScopes
|
||||
.getClassifierSymbols(scopeNameFilter)
|
||||
.filter { with(visibilityChecker) { isVisible(it) } }
|
||||
|
||||
classesFromScopes.forEach { addSymbolToCompletion(expectedType = null, it) }
|
||||
classesFromScopes.forEach { addClassifierSymbolToCompletion(it, insertFqName = true) }
|
||||
|
||||
val kotlinClassesFromIndices = indexHelper.getKotlinClasses(scopeNameFilter, psiFilter = { it !is KtEnumEntry })
|
||||
kotlinClassesFromIndices.asSequence()
|
||||
.map { it.getSymbol() as KtClassifierSymbol }
|
||||
.filter { with(visibilityChecker) { isVisible(it) } }
|
||||
.forEach { addSymbolToCompletion(expectedType = null, it) }
|
||||
.forEach { addClassifierSymbolToCompletion(it, insertFqName = true) }
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionCont
|
||||
import org.jetbrains.kotlin.idea.completion.weighers.Weighers
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
|
||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol
|
||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
@@ -44,6 +44,17 @@ internal abstract class FirCompletionContributorBase<C : FirRawPositionCompletio
|
||||
}
|
||||
}
|
||||
|
||||
protected fun KtAnalysisSession.addClassifierSymbolToCompletion(symbol: KtClassifierSymbol, insertFqName: Boolean) {
|
||||
if (symbol !is KtNamedSymbol) return
|
||||
val lookup = with(lookupElementFactory) {
|
||||
when (symbol) {
|
||||
is KtClassLikeSymbol -> createLookupElementForClassLikeSymbol(symbol, insertFqName)
|
||||
is KtTypeParameterSymbol -> createLookupElement(symbol)
|
||||
}
|
||||
} ?: return
|
||||
result.addElement(lookup)
|
||||
}
|
||||
|
||||
private fun KtAnalysisSession.applyWeighers(
|
||||
lookupElement: LookupElement,
|
||||
symbol: KtSymbol,
|
||||
|
||||
Reference in New Issue
Block a user