FIR IDE: introduce import statement completion
This commit is contained in:
committed by
TeamCityServer
parent
c998d0f026
commit
943ae108f5
@@ -8,14 +8,40 @@ package org.jetbrains.kotlin.idea.stubindex
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS
|
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS
|
||||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl
|
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl
|
||||||
|
import com.intellij.psi.JavaPsiFacade
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.stubs.StubIndex
|
import com.intellij.psi.stubs.StubIndex
|
||||||
|
import org.jetbrains.kotlin.idea.search.getKotlinFqName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
|
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
|
|
||||||
object PackageIndexUtil {
|
object PackageIndexUtil {
|
||||||
|
fun getJavaAndKotlinSubPackageFqNames(
|
||||||
|
packageFqName: FqName,
|
||||||
|
scope: GlobalSearchScope,
|
||||||
|
project: Project,
|
||||||
|
targetPlatform: TargetPlatform,
|
||||||
|
nameFilter: (Name) -> Boolean
|
||||||
|
) = sequence {
|
||||||
|
yieldAll(getSubPackageFqNames(packageFqName, scope, project, nameFilter))
|
||||||
|
|
||||||
|
if (targetPlatform.isJvm()) {
|
||||||
|
val javaPackage = JavaPsiFacade.getInstance(project).findPackage(packageFqName.asString())
|
||||||
|
if (javaPackage != null) {
|
||||||
|
for (psiPackage in javaPackage.getSubPackages(scope)) {
|
||||||
|
val fqName = psiPackage.getKotlinFqName() ?: continue
|
||||||
|
if (nameFilter(fqName.shortName())) {
|
||||||
|
yield(fqName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getSubPackageFqNames(
|
fun getSubPackageFqNames(
|
||||||
packageFqName: FqName,
|
packageFqName: FqName,
|
||||||
|
|||||||
+6
-3
@@ -10,8 +10,6 @@ import com.intellij.openapi.components.service
|
|||||||
import com.intellij.patterns.PlatformPatterns
|
import com.intellij.patterns.PlatformPatterns
|
||||||
import com.intellij.patterns.PsiJavaPatterns
|
import com.intellij.patterns.PsiJavaPatterns
|
||||||
import com.intellij.util.ProcessingContext
|
import com.intellij.util.ProcessingContext
|
||||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
|
||||||
import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker
|
|
||||||
import org.jetbrains.kotlin.idea.completion.context.*
|
import org.jetbrains.kotlin.idea.completion.context.*
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirExpressionNameReferencePositionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirExpressionNameReferencePositionContext
|
||||||
@@ -25,7 +23,6 @@ import org.jetbrains.kotlin.idea.completion.contributors.FirClassifierCompletion
|
|||||||
import org.jetbrains.kotlin.idea.completion.contributors.FirKeywordCompletionContributor
|
import org.jetbrains.kotlin.idea.completion.contributors.FirKeywordCompletionContributor
|
||||||
import org.jetbrains.kotlin.idea.completion.contributors.complete
|
import org.jetbrains.kotlin.idea.completion.contributors.complete
|
||||||
import org.jetbrains.kotlin.idea.completion.weighers.Weighers
|
import org.jetbrains.kotlin.idea.completion.weighers.Weighers
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
|
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalKtFile
|
import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalKtFile
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -70,6 +67,7 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
|||||||
val classifierContributor = FirClassifierCompletionContributor(basicContext)
|
val classifierContributor = FirClassifierCompletionContributor(basicContext)
|
||||||
val annotationsContributor = FirAnnotationCompletionContributor(basicContext)
|
val annotationsContributor = FirAnnotationCompletionContributor(basicContext)
|
||||||
val packageCompletionContributor = FirPackageCompletionContributor(basicContext)
|
val packageCompletionContributor = FirPackageCompletionContributor(basicContext)
|
||||||
|
val importDirectivePackageMembersCompletionContributor = FirImportDirectivePackageMembersCompletionContributor(basicContext)
|
||||||
|
|
||||||
when (positionContext) {
|
when (positionContext) {
|
||||||
is FirExpressionNameReferencePositionContext -> {
|
is FirExpressionNameReferencePositionContext -> {
|
||||||
@@ -95,6 +93,11 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
|||||||
complete(FirSuperEntryContributor(basicContext), positionContext)
|
complete(FirSuperEntryContributor(basicContext), positionContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is FirImportDirectivePositionContext -> {
|
||||||
|
complete(packageCompletionContributor, positionContext)
|
||||||
|
complete(importDirectivePackageMembersCompletionContributor, positionContext)
|
||||||
|
}
|
||||||
|
|
||||||
is FirUnknownPositionContext -> {
|
is FirUnknownPositionContext -> {
|
||||||
complete(keywordContributor, positionContext)
|
complete(keywordContributor, positionContext)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.*
|
|||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
internal object KotlinFirIconProvider {
|
internal object KotlinFirIconProvider {
|
||||||
fun getIconFor(symbol: KtNamedSymbol): Icon? {
|
fun getIconFor(symbol: KtSymbol): Icon? {
|
||||||
if (symbol is KtFunctionSymbol) {
|
if (symbol is KtFunctionSymbol) {
|
||||||
val isAbstract = symbol.modality == Modality.ABSTRACT
|
val isAbstract = symbol.modality == Modality.ABSTRACT
|
||||||
|
|
||||||
|
|||||||
+91
-57
@@ -11,10 +11,12 @@ import com.intellij.codeInsight.completion.InsertionContext
|
|||||||
import com.intellij.codeInsight.lookup.Lookup
|
import com.intellij.codeInsight.lookup.Lookup
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
|
import com.intellij.icons.AllIcons
|
||||||
import com.intellij.openapi.diagnostic.ControlFlowException
|
import com.intellij.openapi.diagnostic.ControlFlowException
|
||||||
import com.intellij.openapi.diagnostic.logger
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.idea.completion.contributors.helpers.addDotAndInvokeCompletion
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.isTextAt
|
import org.jetbrains.kotlin.idea.completion.handlers.isTextAt
|
||||||
import org.jetbrains.kotlin.idea.core.asFqNameWithRootPrefixIfNeeded
|
import org.jetbrains.kotlin.idea.core.asFqNameWithRootPrefixIfNeeded
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
@@ -27,6 +29,7 @@ import org.jetbrains.kotlin.idea.frontend.api.tokens.HackToForceAllowRunningAnal
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.tokens.hackyAllowRunningOnEdt
|
import org.jetbrains.kotlin.idea.frontend.api.tokens.hackyAllowRunningOnEdt
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtFunctionalType
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtFunctionalType
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.miniStdLib.letIf
|
||||||
import org.jetbrains.kotlin.name.*
|
import org.jetbrains.kotlin.name.*
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtTypeArgumentList
|
import org.jetbrains.kotlin.psi.KtTypeArgumentList
|
||||||
@@ -40,38 +43,50 @@ internal class KotlinFirLookupElementFactory {
|
|||||||
private val typeParameterLookupElementFactory = TypeParameterLookupElementFactory()
|
private val typeParameterLookupElementFactory = TypeParameterLookupElementFactory()
|
||||||
|
|
||||||
fun KtAnalysisSession.createLookupElement(symbol: KtNamedSymbol): LookupElement? {
|
fun KtAnalysisSession.createLookupElement(symbol: KtNamedSymbol): LookupElement? {
|
||||||
val elementBuilder = when (symbol) {
|
return when (symbol) {
|
||||||
is KtFunctionSymbol -> with(functionLookupElementFactory) { createLookup(symbol) }
|
is KtCallableSymbol -> createCallableLookupElement(symbol, importingStrategy = detectImportStrategy(symbol), CallableInsertionStrategy.AS_CALL)
|
||||||
is KtVariableLikeSymbol -> with(variableLookupElementFactory) { createLookup(symbol) }
|
is KtClassLikeSymbol -> with(classLookupElementFactory) { createLookup(symbol) }
|
||||||
is KtClassLikeSymbol -> classLookupElementFactory.createLookup(symbol)
|
is KtTypeParameterSymbol -> with(typeParameterLookupElementFactory) { createLookup(symbol) }
|
||||||
is KtTypeParameterSymbol -> typeParameterLookupElementFactory.createLookup(symbol)
|
|
||||||
else -> throw IllegalArgumentException("Cannot create a lookup element for $symbol")
|
else -> throw IllegalArgumentException("Cannot create a lookup element for $symbol")
|
||||||
} ?: return null
|
}
|
||||||
|
|
||||||
return elementBuilder
|
|
||||||
.withPsiElement(symbol.psi) // TODO check if it is a heavy operation and should be postponed
|
|
||||||
.withIcon(KotlinFirIconProvider.getIconFor(symbol))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPackageLookupElement(packageFqName: FqName): LookupElement {
|
fun KtAnalysisSession.createCallableLookupElement(
|
||||||
return LookupElementBuilder.create(PackageLookupObject(packageFqName), packageFqName.shortName().asString())
|
symbol: KtCallableSymbol,
|
||||||
.withInsertHandler(QuotedNamesAwareInsertionHandler())
|
importingStrategy: CallableImportStrategy,
|
||||||
.let {
|
insertionStrategy: CallableInsertionStrategy,
|
||||||
if (!packageFqName.parent().isRoot) {
|
): LookupElementBuilder? {
|
||||||
it.appendTailText(" (${packageFqName.asString()})", true)
|
return when (symbol) {
|
||||||
} else it
|
is KtFunctionSymbol -> with(functionLookupElementFactory) { createLookup(symbol, importingStrategy, insertionStrategy) }
|
||||||
|
is KtVariableLikeSymbol -> with(variableLookupElementFactory) { createLookup(symbol, importingStrategy) }
|
||||||
|
else -> throw IllegalArgumentException("Cannot create a lookup element for $symbol")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createPackagePartLookupElement(packagePartFqName: FqName): LookupElement {
|
||||||
|
val shortName = packagePartFqName.shortName()
|
||||||
|
return LookupElementBuilder.create(PackagePartLookupObject(shortName), "${shortName.render()}.")
|
||||||
|
.withInsertHandler(PackagePartInsertionHandler)
|
||||||
|
.withIcon(AllIcons.Nodes.Package)
|
||||||
|
.letIf(!packagePartFqName.parent().isRoot) {
|
||||||
|
it.appendTailText("(${packagePartFqName.asString()})", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtAnalysisSession.createLookupElementForClassLikeSymbol(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElement? {
|
fun KtAnalysisSession.createLookupElementForClassLikeSymbol(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElement? {
|
||||||
if (symbol !is KtNamedSymbol) return null
|
if (symbol !is KtNamedSymbol) return null
|
||||||
return classLookupElementFactory.createLookup(symbol, insertFqName)
|
return with(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 {
|
private fun KtAnalysisSession.withSymbolInfo(
|
||||||
|
symbol: KtSymbol,
|
||||||
|
elementBuilder: LookupElementBuilder
|
||||||
|
): LookupElementBuilder = elementBuilder
|
||||||
|
.withPsiElement(symbol.psi) // TODO check if it is a heavy operation and should be postponed
|
||||||
|
.withIcon(KotlinFirIconProvider.getIconFor(symbol))
|
||||||
|
|
||||||
|
internal sealed class CallableImportStrategy {
|
||||||
object DoNothing : CallableImportStrategy()
|
object DoNothing : CallableImportStrategy()
|
||||||
data class AddImport(val nameToImport: CallableId) : CallableImportStrategy()
|
data class AddImport(val nameToImport: CallableId) : CallableImportStrategy()
|
||||||
data class InsertFqNameAndShorten(val callableId: CallableId) : CallableImportStrategy()
|
data class InsertFqNameAndShorten(val callableId: CallableId) : CallableImportStrategy()
|
||||||
@@ -86,14 +101,12 @@ private interface KotlinLookupObject {
|
|||||||
val shortName: Name
|
val shortName: Name
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class PackageLookupObject(
|
private data class PackagePartLookupObject(
|
||||||
val packageFqName: FqName,
|
override val shortName: Name,
|
||||||
) : KotlinLookupObject {
|
) : KotlinLookupObject
|
||||||
override val shortName: Name = packageFqName.shortName()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private data class ClassifierLookupObject(override val shortName: Name, val classId: ClassId?, val insertFqName: Boolean) :
|
||||||
private data class ClassifierLookupObject(override val shortName: Name, val classId: ClassId?, val insertFqName: Boolean) : KotlinLookupObject
|
KotlinLookupObject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplest lookup object so two lookup elements for the same function will clash.
|
* Simplest lookup object so two lookup elements for the same function will clash.
|
||||||
@@ -116,30 +129,37 @@ private data class VariableLookupObject(
|
|||||||
) : KotlinLookupObject
|
) : KotlinLookupObject
|
||||||
|
|
||||||
class ClassLookupElementFactory {
|
class ClassLookupElementFactory {
|
||||||
fun createLookup(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElementBuilder {
|
fun KtAnalysisSession.createLookup(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElementBuilder {
|
||||||
val name = symbol.nameOrAnonymous
|
val name = symbol.nameOrAnonymous
|
||||||
return LookupElementBuilder.create(ClassifierLookupObject(name, symbol.classIdIfNonLocal, insertFqName), name.asString())
|
return LookupElementBuilder.create(ClassifierLookupObject(name, symbol.classIdIfNonLocal, insertFqName), name.asString())
|
||||||
.withInsertHandler(ClassifierInsertionHandler)
|
.withInsertHandler(ClassifierInsertionHandler)
|
||||||
|
.let { withSymbolInfo(symbol, it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TypeParameterLookupElementFactory {
|
private class TypeParameterLookupElementFactory {
|
||||||
fun createLookup(symbol: KtTypeParameterSymbol): LookupElementBuilder {
|
fun KtAnalysisSession.createLookup(symbol: KtTypeParameterSymbol): LookupElementBuilder {
|
||||||
return LookupElementBuilder.create(UniqueLookupObject(), symbol.name.asString())
|
return LookupElementBuilder
|
||||||
|
.create(UniqueLookupObject(), symbol.name.asString())
|
||||||
|
.let { withSymbolInfo(symbol, it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VariableLookupElementFactory {
|
private class VariableLookupElementFactory {
|
||||||
fun KtAnalysisSession.createLookup(symbol: KtVariableLikeSymbol): LookupElementBuilder {
|
fun KtAnalysisSession.createLookup(
|
||||||
|
symbol: KtVariableLikeSymbol,
|
||||||
|
importStrategy: CallableImportStrategy = detectImportStrategy(symbol)
|
||||||
|
): LookupElementBuilder {
|
||||||
val lookupObject = VariableLookupObject(
|
val lookupObject = VariableLookupObject(
|
||||||
symbol.name,
|
symbol.name,
|
||||||
importStrategy = detectImportStrategy(symbol)
|
importStrategy = importStrategy
|
||||||
)
|
)
|
||||||
|
|
||||||
return LookupElementBuilder.create(lookupObject, symbol.name.asString())
|
return LookupElementBuilder.create(lookupObject, symbol.name.asString())
|
||||||
.withTypeText(symbol.annotatedType.type.render(WITH_TYPE_RENDERING_OPTIONS))
|
.withTypeText(symbol.annotatedType.type.render(WITH_TYPE_RENDERING_OPTIONS))
|
||||||
.markIfSyntheticJavaProperty(symbol)
|
.markIfSyntheticJavaProperty(symbol)
|
||||||
.withInsertHandler(VariableInsertionHandler)
|
.withInsertHandler(VariableInsertionHandler)
|
||||||
|
.let { withSymbolInfo(symbol, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun LookupElementBuilder.markIfSyntheticJavaProperty(symbol: KtVariableLikeSymbol): LookupElementBuilder = when (symbol) {
|
private fun LookupElementBuilder.markIfSyntheticJavaProperty(symbol: KtVariableLikeSymbol): LookupElementBuilder = when (symbol) {
|
||||||
@@ -154,35 +174,50 @@ private class VariableLookupElementFactory {
|
|||||||
|
|
||||||
private fun buildSyntheticPropertyTailText(getterName: String, setterName: String?): String =
|
private fun buildSyntheticPropertyTailText(getterName: String, setterName: String?): String =
|
||||||
if (setterName != null) "$getterName()/$setterName()" else "$getterName()"
|
if (setterName != null) "$getterName()/$setterName()" else "$getterName()"
|
||||||
|
}
|
||||||
|
|
||||||
private fun detectImportStrategy(symbol: KtVariableLikeSymbol): CallableImportStrategy {
|
private fun detectImportStrategy(symbol: KtCallableSymbol): CallableImportStrategy {
|
||||||
if (symbol !is KtKotlinPropertySymbol || symbol.dispatchType != null) return CallableImportStrategy.DoNothing
|
if (symbol !is KtKotlinPropertySymbol || symbol.dispatchType != null) return CallableImportStrategy.DoNothing
|
||||||
|
|
||||||
val propertyId = symbol.callableIdIfNonLocal ?: return CallableImportStrategy.DoNothing
|
val propertyId = symbol.callableIdIfNonLocal ?: return CallableImportStrategy.DoNothing
|
||||||
|
|
||||||
return if (symbol.isExtension) {
|
return if (symbol.isExtension) {
|
||||||
CallableImportStrategy.AddImport(propertyId)
|
CallableImportStrategy.AddImport(propertyId)
|
||||||
} else {
|
} else {
|
||||||
CallableImportStrategy.InsertFqNameAndShorten(propertyId)
|
CallableImportStrategy.InsertFqNameAndShorten(propertyId)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal enum class CallableInsertionStrategy {
|
||||||
|
AS_CALL,
|
||||||
|
AS_IDENTIFIER
|
||||||
|
}
|
||||||
|
|
||||||
private class FunctionLookupElementFactory {
|
private class FunctionLookupElementFactory {
|
||||||
fun KtAnalysisSession.createLookup(symbol: KtFunctionSymbol): LookupElementBuilder? {
|
fun KtAnalysisSession.createLookup(
|
||||||
|
symbol: KtFunctionSymbol,
|
||||||
|
importStrategy: CallableImportStrategy,
|
||||||
|
insertionStrategy: CallableInsertionStrategy
|
||||||
|
): LookupElementBuilder? {
|
||||||
val lookupObject = FunctionLookupObject(
|
val lookupObject = FunctionLookupObject(
|
||||||
symbol.name,
|
symbol.name,
|
||||||
importStrategy = detectImportStrategy(symbol),
|
importStrategy = importStrategy,
|
||||||
inputValueArguments = symbol.valueParameters.isNotEmpty(),
|
inputValueArguments = symbol.valueParameters.isNotEmpty(),
|
||||||
insertEmptyLambda = insertLambdaBraces(symbol),
|
insertEmptyLambda = insertLambdaBraces(symbol),
|
||||||
renderedFunctionParameters = with(ShortNamesRenderer) { renderFunctionParameters(symbol) }
|
renderedFunctionParameters = with(ShortNamesRenderer) { renderFunctionParameters(symbol) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val insertionHandler = when (insertionStrategy) {
|
||||||
|
CallableInsertionStrategy.AS_CALL -> FunctionInsertionHandler
|
||||||
|
CallableInsertionStrategy.AS_IDENTIFIER -> QuotedNamesAwareInsertionHandler()
|
||||||
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
LookupElementBuilder.create(lookupObject, symbol.name.asString())
|
LookupElementBuilder.create(lookupObject, symbol.name.asString())
|
||||||
.withTailText(getTailText(symbol), true)
|
.withTailText(getTailText(symbol), true)
|
||||||
.withTypeText(symbol.annotatedType.type.render(WITH_TYPE_RENDERING_OPTIONS))
|
.withTypeText(symbol.annotatedType.type.render(WITH_TYPE_RENDERING_OPTIONS))
|
||||||
.withInsertHandler(FunctionInsertionHandler)
|
.withInsertHandler(insertionHandler)
|
||||||
|
.let { withSymbolInfo(symbol, it) }
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (e is ControlFlowException) throw e
|
if (e is ControlFlowException) throw e
|
||||||
LOG.error(e)
|
LOG.error(e)
|
||||||
@@ -190,18 +225,6 @@ private class FunctionLookupElementFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun detectImportStrategy(symbol: KtFunctionSymbol): CallableImportStrategy {
|
|
||||||
if (symbol.dispatchType != null) return CallableImportStrategy.DoNothing
|
|
||||||
|
|
||||||
val functionFqName = symbol.callableIdIfNonLocal ?: return CallableImportStrategy.DoNothing
|
|
||||||
|
|
||||||
return if (symbol.isExtension) {
|
|
||||||
CallableImportStrategy.AddImport(functionFqName)
|
|
||||||
} else {
|
|
||||||
CallableImportStrategy.InsertFqNameAndShorten(functionFqName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtAnalysisSession.getTailText(symbol: KtFunctionSymbol): String {
|
private fun KtAnalysisSession.getTailText(symbol: KtFunctionSymbol): String {
|
||||||
return if (insertLambdaBraces(symbol)) " {...}" else with(ShortNamesRenderer) { renderFunctionParameters(symbol) }
|
return if (insertLambdaBraces(symbol)) " {...}" else with(ShortNamesRenderer) { renderFunctionParameters(symbol) }
|
||||||
}
|
}
|
||||||
@@ -371,11 +394,22 @@ private object VariableInsertionHandler : InsertHandler<LookupElement> {
|
|||||||
shortenReferencesForFirCompletion(targetFile, TextRange(context.startOffset, context.tailOffset))
|
shortenReferencesForFirCompletion(targetFile, TextRange(context.startOffset, context.tailOffset))
|
||||||
}
|
}
|
||||||
|
|
||||||
is CallableImportStrategy.DoNothing -> {}
|
is CallableImportStrategy.DoNothing -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object PackagePartInsertionHandler : InsertHandler<LookupElement> {
|
||||||
|
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||||
|
val lookupElement = item.`object` as PackagePartLookupObject
|
||||||
|
val name = lookupElement.shortName.render()
|
||||||
|
context.document.replaceString(context.startOffset, context.tailOffset, name)
|
||||||
|
context.commitDocument()
|
||||||
|
context.addDotAndInvokeCompletion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private open class QuotedNamesAwareInsertionHandler : InsertHandler<LookupElement> {
|
private open class QuotedNamesAwareInsertionHandler : InsertHandler<LookupElement> {
|
||||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||||
val lookupElement = item.`object` as KotlinLookupObject
|
val lookupElement = item.`object` as KotlinLookupObject
|
||||||
|
|||||||
+2
@@ -9,6 +9,7 @@ import com.intellij.codeInsight.completion.CompletionParameters
|
|||||||
import com.intellij.codeInsight.completion.CompletionResultSet
|
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
import com.intellij.codeInsight.completion.PrefixMatcher
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
||||||
import org.jetbrains.kotlin.idea.completion.KotlinFirLookupElementFactory
|
import org.jetbrains.kotlin.idea.completion.KotlinFirLookupElementFactory
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
|
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
|
||||||
@@ -29,6 +30,7 @@ internal class FirBasicCompletionContext(
|
|||||||
val lookupElementFactory: KotlinFirLookupElementFactory = KotlinFirLookupElementFactory(),
|
val lookupElementFactory: KotlinFirLookupElementFactory = KotlinFirLookupElementFactory(),
|
||||||
) {
|
) {
|
||||||
val visibleScope = KotlinSourceFilterScope.projectSourceAndClassFiles(originalKtFile.resolveScope, project)
|
val visibleScope = KotlinSourceFilterScope.projectSourceAndClassFiles(originalKtFile.resolveScope, project)
|
||||||
|
val moduleInfo: IdeaModuleInfo = originalKtFile.getModuleInfo()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun createFromParameters(parameters: CompletionParameters, result: CompletionResultSet): FirBasicCompletionContext? {
|
fun createFromParameters(parameters: CompletionParameters, result: CompletionResultSet): FirBasicCompletionContext? {
|
||||||
|
|||||||
+32
-3
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.idea.completion.context
|
package org.jetbrains.kotlin.idea.completion.context
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.util.parentOfType
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.analyse
|
import org.jetbrains.kotlin.idea.frontend.api.analyse
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.analyseInDependedAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.analyseInDependedAnalysisSession
|
||||||
@@ -24,6 +25,15 @@ internal sealed class FirNameReferencePositionContext : FirRawPositionCompletion
|
|||||||
abstract val explicitReceiver: KtExpression?
|
abstract val explicitReceiver: KtExpression?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class FirImportDirectivePositionContext(
|
||||||
|
override val position: PsiElement,
|
||||||
|
override val reference: KtSimpleNameReference,
|
||||||
|
override val nameExpression: KtSimpleNameExpression,
|
||||||
|
override val explicitReceiver: KtExpression?,
|
||||||
|
val importDirective: KtImportDirective,
|
||||||
|
) : FirNameReferencePositionContext()
|
||||||
|
|
||||||
|
|
||||||
internal class FirTypeNameReferencePositionContext(
|
internal class FirTypeNameReferencePositionContext(
|
||||||
override val position: PsiElement,
|
override val position: PsiElement,
|
||||||
override val reference: KtSimpleNameReference,
|
override val reference: KtSimpleNameReference,
|
||||||
@@ -68,17 +78,36 @@ internal object FirPositionCompletionContextDetector {
|
|||||||
val nameExpression = reference.expression.takeIf { it !is KtLabelReferenceExpression }
|
val nameExpression = reference.expression.takeIf { it !is KtLabelReferenceExpression }
|
||||||
?: return FirUnknownPositionContext(position)
|
?: return FirUnknownPositionContext(position)
|
||||||
val explicitReceiver = nameExpression.getReceiverExpression()
|
val explicitReceiver = nameExpression.getReceiverExpression()
|
||||||
|
val parent = nameExpression.parent
|
||||||
|
|
||||||
return when (val parent = nameExpression.parent) {
|
return when {
|
||||||
is KtUserType -> {
|
parent is KtUserType -> {
|
||||||
detectForTypeContext(parent, position, reference, nameExpression, explicitReceiver)
|
detectForTypeContext(parent, position, reference, nameExpression, explicitReceiver)
|
||||||
}
|
}
|
||||||
|
nameExpression.isReferenceExpressionInImportDirective() -> {
|
||||||
|
FirImportDirectivePositionContext(
|
||||||
|
position,
|
||||||
|
reference,
|
||||||
|
nameExpression,
|
||||||
|
explicitReceiver,
|
||||||
|
parent.parentOfType(withSelf = true)!!
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
FirExpressionNameReferencePositionContext(position, reference, nameExpression, explicitReceiver)
|
FirExpressionNameReferencePositionContext(position, reference, nameExpression, explicitReceiver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KtExpression.isReferenceExpressionInImportDirective() = when (val parent = parent) {
|
||||||
|
is KtImportDirective -> parent.importedReference == this
|
||||||
|
is KtDotQualifiedExpression -> {
|
||||||
|
val importDirective = parent.parent as? KtImportDirective
|
||||||
|
importDirective?.importedReference == parent
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
private fun detectForTypeContext(
|
private fun detectForTypeContext(
|
||||||
userType: KtUserType,
|
userType: KtUserType,
|
||||||
position: PsiElement,
|
position: PsiElement,
|
||||||
@@ -116,7 +145,7 @@ internal object FirPositionCompletionContextDetector {
|
|||||||
positionContext.nameExpression,
|
positionContext.nameExpression,
|
||||||
action
|
action
|
||||||
)
|
)
|
||||||
is FirUnknownPositionContext -> {
|
is FirUnknownPositionContext, is FirImportDirectivePositionContext -> {
|
||||||
analyse(basicContext.originalKtFile, action)
|
analyse(basicContext.originalKtFile, action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-9
@@ -8,13 +8,10 @@ package org.jetbrains.kotlin.idea.completion.contributors
|
|||||||
import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker
|
import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirNameReferenceRawPositionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirNameReferenceRawPositionContext
|
||||||
|
import org.jetbrains.kotlin.idea.completion.contributors.helpers.getStaticScope
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
|
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.symbols.markers.KtSymbolWithMembers
|
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
|
||||||
@@ -42,11 +39,7 @@ internal open class FirClassifierCompletionContributor(
|
|||||||
visibilityChecker: CompletionVisibilityChecker
|
visibilityChecker: CompletionVisibilityChecker
|
||||||
) {
|
) {
|
||||||
val reference = receiver.reference() ?: return
|
val reference = receiver.reference() ?: return
|
||||||
val scope = when (val symbol = reference.resolveToSymbol()) {
|
val scope = getStaticScope(reference) ?: return
|
||||||
is KtSymbolWithMembers -> symbol.getMemberScope()
|
|
||||||
is KtPackageSymbol -> symbol.getPackageScope()
|
|
||||||
else -> return
|
|
||||||
}
|
|
||||||
scope
|
scope
|
||||||
.getClassifierSymbols(scopeNameFilter)
|
.getClassifierSymbols(scopeNameFilter)
|
||||||
.filter { filterClassifiers(it) }
|
.filter { filterClassifiers(it) }
|
||||||
|
|||||||
+14
-1
@@ -10,6 +10,8 @@ import com.intellij.codeInsight.completion.CompletionResultSet
|
|||||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
import com.intellij.codeInsight.completion.PrefixMatcher
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.idea.completion.CallableImportStrategy
|
||||||
|
import org.jetbrains.kotlin.idea.completion.CallableInsertionStrategy
|
||||||
import org.jetbrains.kotlin.idea.completion.KotlinFirLookupElementFactory
|
import org.jetbrains.kotlin.idea.completion.KotlinFirLookupElementFactory
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext
|
||||||
@@ -21,7 +23,6 @@ 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.symbols.markers.KtNamedSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
|
||||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
@@ -64,6 +65,18 @@ internal abstract class FirCompletionContributorBase<C : FirRawPositionCompletio
|
|||||||
result.addElement(lookup)
|
result.addElement(lookup)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun KtAnalysisSession.addCallableSymbolToCompletion(
|
||||||
|
symbol: KtCallableSymbol,
|
||||||
|
importingStrategy: CallableImportStrategy,
|
||||||
|
insertionStrategy: CallableInsertionStrategy,
|
||||||
|
) {
|
||||||
|
if (symbol !is KtNamedSymbol) return
|
||||||
|
val lookup = with(lookupElementFactory) {
|
||||||
|
createCallableLookupElement(symbol, importingStrategy, insertionStrategy)
|
||||||
|
} ?: return
|
||||||
|
result.addElement(lookup)
|
||||||
|
}
|
||||||
|
|
||||||
protected fun KtExpression.reference() = when (this) {
|
protected fun KtExpression.reference() = when (this) {
|
||||||
is KtDotQualifiedExpression -> selectorExpression?.mainReference
|
is KtDotQualifiedExpression -> selectorExpression?.mainReference
|
||||||
else -> mainReference
|
else -> mainReference
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.completion.CallableImportStrategy
|
||||||
|
import org.jetbrains.kotlin.idea.completion.CallableInsertionStrategy
|
||||||
|
import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker
|
||||||
|
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
||||||
|
import org.jetbrains.kotlin.idea.completion.context.FirImportDirectivePositionContext
|
||||||
|
import org.jetbrains.kotlin.idea.completion.contributors.helpers.getStaticScope
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
|
|
||||||
|
internal class FirImportDirectivePackageMembersCompletionContributor(
|
||||||
|
basicContext: FirBasicCompletionContext
|
||||||
|
) : FirCompletionContributorBase<FirImportDirectivePositionContext>(basicContext) {
|
||||||
|
override fun KtAnalysisSession.complete(positionContext: FirImportDirectivePositionContext) {
|
||||||
|
val reference = positionContext.explicitReceiver?.reference() ?: return
|
||||||
|
val scope = getStaticScope(reference) ?: return
|
||||||
|
val visibilityChecker = CompletionVisibilityChecker.create(basicContext, positionContext)
|
||||||
|
|
||||||
|
scope.getClassifierSymbols(scopeNameFilter)
|
||||||
|
.filter { with(visibilityChecker) { isVisible(it) } }
|
||||||
|
.forEach { addClassifierSymbolToCompletion(it, insertFqName = false) }
|
||||||
|
|
||||||
|
scope.getCallableSymbols(scopeNameFilter)
|
||||||
|
.filter { with(visibilityChecker) { isVisible(it) } }
|
||||||
|
.forEach {
|
||||||
|
addCallableSymbolToCompletion(
|
||||||
|
it,
|
||||||
|
importingStrategy = CallableImportStrategy.DoNothing,
|
||||||
|
insertionStrategy = CallableInsertionStrategy.AS_IDENTIFIER
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-8
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion.contributors
|
package org.jetbrains.kotlin.idea.completion.contributors
|
||||||
|
|
||||||
import com.intellij.psi.JavaPsiFacade
|
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirNameReferenceRawPositionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirNameReferenceRawPositionContext
|
||||||
import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext
|
import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext
|
||||||
@@ -13,12 +12,6 @@ import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
|
||||||
import org.jetbrains.kotlin.idea.isExcludedFromAutoImport
|
import org.jetbrains.kotlin.idea.isExcludedFromAutoImport
|
||||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
|
||||||
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
|
||||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
|
||||||
|
|
||||||
internal class FirPackageCompletionContributor(
|
internal class FirPackageCompletionContributor(
|
||||||
basicContext: FirBasicCompletionContext,
|
basicContext: FirBasicCompletionContext,
|
||||||
@@ -36,7 +29,7 @@ internal class FirPackageCompletionContributor(
|
|||||||
packageName.fqName.isExcludedFromAutoImport(project, originalKtFile, originalKtFile.languageVersionSettings)
|
packageName.fqName.isExcludedFromAutoImport(project, originalKtFile, originalKtFile.languageVersionSettings)
|
||||||
}
|
}
|
||||||
.forEach { packageSymbol ->
|
.forEach { packageSymbol ->
|
||||||
result.addElement(lookupElementFactory.createPackageLookupElement(packageSymbol.fqName))
|
result.addElement(lookupElementFactory.createPackagePartLookupElement(packageSymbol.fqName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-16
@@ -37,15 +37,14 @@ internal object SuperCallInsertionHandler : InsertHandler<LookupElement> {
|
|||||||
val lookupObject = item.`object` as SuperCallLookupObject
|
val lookupObject = item.`object` as SuperCallLookupObject
|
||||||
|
|
||||||
replaceWithClassIdAndShorten(lookupObject, context)
|
replaceWithClassIdAndShorten(lookupObject, context)
|
||||||
addDot(context)
|
context.addDotAndInvokeCompletion()
|
||||||
invokeCompletion(context)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun replaceWithClassIdAndShorten(
|
private fun replaceWithClassIdAndShorten(
|
||||||
lookupObject: SuperCallLookupObject,
|
lookupObject: SuperCallLookupObject,
|
||||||
context: InsertionContext
|
context: InsertionContext
|
||||||
) {
|
) {
|
||||||
val replaceTo = lookupObject.replaceTo ?: return
|
val replaceTo = lookupObject.replaceTo ?: return
|
||||||
context.document.replaceString(context.startOffset, context.tailOffset, replaceTo)
|
context.document.replaceString(context.startOffset, context.tailOffset, replaceTo)
|
||||||
context.commitDocument()
|
context.commitDocument()
|
||||||
|
|
||||||
@@ -54,19 +53,6 @@ internal object SuperCallInsertionHandler : InsertHandler<LookupElement> {
|
|||||||
shortenReferencesForFirCompletion(targetFile, TextRange(context.startOffset, context.tailOffset))
|
shortenReferencesForFirCompletion(targetFile, TextRange(context.startOffset, context.tailOffset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invokeCompletion(context: InsertionContext) {
|
|
||||||
ApplicationManager.getApplication().invokeLater {
|
|
||||||
CodeCompletionHandlerBase(CompletionType.BASIC, true, false, true)
|
|
||||||
.invokeCompletion(context.project, context.editor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addDot(context: InsertionContext) {
|
|
||||||
context.document.insertString(context.tailOffset, ".")
|
|
||||||
context.commitDocument()
|
|
||||||
context.editor.caretModel.moveToOffset(context.tailOffset)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface SuperCallLookupObject {
|
internal interface SuperCallLookupObject {
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.helpers
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase
|
||||||
|
import com.intellij.codeInsight.completion.CompletionType
|
||||||
|
import com.intellij.codeInsight.completion.InsertionContext
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
|
||||||
|
internal fun InsertionContext.addDotAndInvokeCompletion() {
|
||||||
|
addDotToCompletion(this)
|
||||||
|
invokeCompletion(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invokeCompletion(context: InsertionContext) {
|
||||||
|
ApplicationManager.getApplication().invokeLater {
|
||||||
|
CodeCompletionHandlerBase(CompletionType.BASIC, true, false, true)
|
||||||
|
.invokeCompletion(context.project, context.editor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addDotToCompletion(context: InsertionContext) {
|
||||||
|
context.document.insertString(context.tailOffset, ".")
|
||||||
|
context.commitDocument()
|
||||||
|
context.editor.caretModel.moveToOffset(context.tailOffset)
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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.helpers
|
||||||
|
|
||||||
|
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.KtPackageSymbol
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithMembers
|
||||||
|
import org.jetbrains.kotlin.idea.references.KtReference
|
||||||
|
|
||||||
|
internal fun KtAnalysisSession.getStaticScope(reference: KtReference): KtScope? =
|
||||||
|
when (val symbol = reference.resolveToSymbol()) {
|
||||||
|
is KtSymbolWithMembers -> symbol.getStaticMemberScope()
|
||||||
|
is KtPackageSymbol -> symbol.getPackageScope()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
+5
@@ -19,6 +19,8 @@ import org.jetbrains.kotlin.psi.KtFile
|
|||||||
|
|
||||||
abstract class KtScopeProvider : KtAnalysisSessionComponent() {
|
abstract class KtScopeProvider : KtAnalysisSessionComponent() {
|
||||||
abstract fun getMemberScope(classSymbol: KtSymbolWithMembers): KtMemberScope
|
abstract fun getMemberScope(classSymbol: KtSymbolWithMembers): KtMemberScope
|
||||||
|
abstract fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope
|
||||||
|
|
||||||
abstract fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtDeclaredMemberScope
|
abstract fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtDeclaredMemberScope
|
||||||
abstract fun getFileScope(fileSymbol: KtFileSymbol): KtDeclarationScope<KtSymbolWithDeclarations>
|
abstract fun getFileScope(fileSymbol: KtFileSymbol): KtDeclarationScope<KtSymbolWithDeclarations>
|
||||||
abstract fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope
|
abstract fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope
|
||||||
@@ -39,6 +41,9 @@ interface KtScopeProviderMixIn : KtAnalysisSessionMixIn {
|
|||||||
fun KtSymbolWithMembers.getDeclaredMemberScope(): KtDeclaredMemberScope =
|
fun KtSymbolWithMembers.getDeclaredMemberScope(): KtDeclaredMemberScope =
|
||||||
analysisSession.scopeProvider.getDeclaredMemberScope(this)
|
analysisSession.scopeProvider.getDeclaredMemberScope(this)
|
||||||
|
|
||||||
|
fun KtSymbolWithMembers.getStaticMemberScope(): KtScope =
|
||||||
|
analysisSession.scopeProvider.getStaticMemberScope(this)
|
||||||
|
|
||||||
fun KtFileSymbol.getFileScope(): KtDeclarationScope<KtSymbolWithDeclarations> =
|
fun KtFileSymbol.getFileScope(): KtDeclarationScope<KtSymbolWithDeclarations> =
|
||||||
analysisSession.scopeProvider.getFileScope(this)
|
analysisSession.scopeProvider.getFileScope(this)
|
||||||
|
|
||||||
|
|||||||
+9
@@ -86,6 +86,15 @@ internal class KtFirScopeProvider(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope {
|
||||||
|
val firScope = symbol.withFirForScope { fir ->
|
||||||
|
fir.scopeProvider.getStaticScope(fir, analysisSession.rootModuleSession, ScopeSession())
|
||||||
|
} ?: return KtFirEmptyMemberScope(symbol)
|
||||||
|
firScopeStorage.register(firScope)
|
||||||
|
check(firScope is FirContainingNamesAwareScope)
|
||||||
|
return KtFirDelegatingScopeImpl(firScope, builder, token)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtDeclaredMemberScope = withValidityAssertion {
|
override fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtDeclaredMemberScope = withValidityAssertion {
|
||||||
declaredMemberScopeCache.getOrPut(classSymbol) {
|
declaredMemberScopeCache.getOrPut(classSymbol) {
|
||||||
val firScope = classSymbol.withFirForScope {
|
val firScope = classSymbol.withFirForScope {
|
||||||
|
|||||||
+7
@@ -79,6 +79,13 @@ internal fun FirScope.getCallableSymbols(callableNames: Collection<Name>, builde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class KtFirDelegatingScopeImpl<S>(
|
||||||
|
override val firScope: S,
|
||||||
|
builder: KtSymbolByFirBuilder,
|
||||||
|
token: ValidityToken
|
||||||
|
) : KtFirDelegatingScope<S>(builder, token) where S : FirContainingNamesAwareScope, S : FirScope
|
||||||
|
|
||||||
|
|
||||||
internal fun FirScope.getClassifierSymbols(classLikeNames: Collection<Name>, builder: KtSymbolByFirBuilder): Sequence<KtClassifierSymbol> =
|
internal fun FirScope.getClassifierSymbols(classLikeNames: Collection<Name>, builder: KtSymbolByFirBuilder): Sequence<KtClassifierSymbol> =
|
||||||
sequence {
|
sequence {
|
||||||
classLikeNames.forEach { name ->
|
classLikeNames.forEach { name ->
|
||||||
|
|||||||
+7
-16
@@ -62,6 +62,11 @@ internal class KtFirPackageScope(
|
|||||||
|
|
||||||
KotlinTopLevelTypeAliasByPackageIndex.getInstance()[fqName.asString(), project, searchScope]
|
KotlinTopLevelTypeAliasByPackageIndex.getInstance()[fqName.asString(), project, searchScope]
|
||||||
.mapNotNullTo(this) { it.nameAsName }
|
.mapNotNullTo(this) { it.nameAsName }
|
||||||
|
|
||||||
|
JavaPsiFacade.getInstance(project)
|
||||||
|
.findPackage(fqName.asString())
|
||||||
|
?.getClasses(searchScope)
|
||||||
|
?.mapNotNullTo(this) { it.name?.let(Name::identifier) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,21 +79,7 @@ internal class KtFirPackageScope(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getPackageSymbols(nameFilter: KtScopeNameFilter): Sequence<KtPackageSymbol> = withValidityAssertion {
|
override fun getPackageSymbols(nameFilter: KtScopeNameFilter): Sequence<KtPackageSymbol> = withValidityAssertion {
|
||||||
sequence {
|
PackageIndexUtil.getJavaAndKotlinSubPackageFqNames(fqName, searchScope, project, targetPlatform, nameFilter)
|
||||||
PackageIndexUtil
|
.map { builder.createPackageSymbol(it) }
|
||||||
.getSubPackageFqNames(fqName, searchScope, project, nameFilter)
|
|
||||||
.forEach {
|
|
||||||
yield(builder.createPackageSymbol(it))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetPlatform.isJvm()) {
|
|
||||||
JavaPsiFacade.getInstance(project).findPackage(fqName.asString())?.getSubPackages(searchScope)?.forEach { psiPackage ->
|
|
||||||
val fqName = psiPackage.getKotlinFqName() ?: return@forEach
|
|
||||||
if (nameFilter(fqName.shortName())) {
|
|
||||||
yield(builder.createPackageSymbol(fqName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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.miniStdLib
|
||||||
|
|
||||||
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
inline fun <T : R, R> T.letIf(condition: Boolean, block: (T) -> R): R {
|
||||||
|
contract {
|
||||||
|
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
return if (condition) block(this) else this
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user