FIR IDE: add packages name completion

This commit is contained in:
Ilya Kirillov
2021-05-17 19:49:33 +02:00
committed by TeamCityServer
parent df93dc91d1
commit e77783a0e5
28 changed files with 180 additions and 32 deletions
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package <caret>
// EXIST: kotlin
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package kotlin.prop<caret>erties.
import kotlin.properties.Delegates
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package testdata.kotlin.data
class TestSample() {
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package kotlin.<caret>
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package Test.MyTest
fun test() {
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package java
annotation class Hello
@@ -1,3 +1,4 @@
// FIR_COMPARISON
val v = 1
fun f() = 2
@@ -1,3 +1,4 @@
// FIR_COMPARISON
fun foo() {
val v = HashMap<String, <caret>>
}
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package kotlin
fun some() {
+1
View File
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package java.util.<caret>
// EXIST: concurrent
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package Tests
class A : java.<caret>
@@ -1,3 +1,4 @@
// FIR_COMPARISON
package java.lang.<caret>
// EXIST: annotation
@@ -86,7 +86,7 @@ class FE10BindingContextImpl(
private val moduleInfo = ktElement.getModuleInfo()
@OptIn(InvalidWayOfUsingAnalysisSession::class)
override val ktAnalysisSessionFacade = KtAnalysisSessionFe10BindingHolder.create(ktElement.getResolveState(), token)
override val ktAnalysisSessionFacade = KtAnalysisSessionFe10BindingHolder.create(ktElement.getResolveState(), token, ktElement)
override val moduleDescriptor: ModuleDescriptor = KtSymbolBasedModuleDescriptorImpl(this, moduleInfo)
@@ -60,20 +60,24 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
val callableContributor = FirCallableCompletionContributor(basicContext)
val classifierContributor = FirClassifierCompletionContributor(basicContext)
val annotationsContributor = FirAnnotationCompletionContributor(basicContext)
val packageCompletionContributor = FirPackageCompletionContributor(basicContext)
when (positionContext) {
is FirExpressionNameReferencePositionContext -> {
complete(keywordContributor, positionContext)
complete(packageCompletionContributor, positionContext)
complete(callableContributor, positionContext)
complete(classifierContributor, positionContext)
}
is FirTypeNameReferencePositionContext -> {
complete(keywordContributor, positionContext)
complete(packageCompletionContributor, positionContext)
complete(classifierContributor, positionContext)
}
is FirAnnotationTypeNameReferencePositionContext -> {
complete(keywordContributor, positionContext)
complete(packageCompletionContributor, positionContext)
complete(annotationsContributor, positionContext)
}
@@ -53,6 +53,16 @@ internal class KotlinFirLookupElementFactory {
.withIcon(KotlinFirIconProvider.getIconFor(symbol))
}
fun createPackageLookupElement(packageFqName: FqName): LookupElement {
return LookupElementBuilder.create(PackageLookupObject(packageFqName), packageFqName.shortName().asString())
.withInsertHandler(QuotedNamesAwareInsertionHandler())
.let {
if (!packageFqName.parent().isRoot) {
it.appendTailText(" (${packageFqName.asString()})", true)
} else it
}
}
fun KtAnalysisSession.createLookupElementForClassLikeSymbol(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElement? {
if (symbol !is KtNamedSymbol) return null
return classLookupElementFactory.createLookup(symbol, insertFqName)
@@ -76,6 +86,13 @@ private interface KotlinLookupObject {
val shortName: Name
}
private data class PackageLookupObject(
val packageFqName: FqName,
) : KotlinLookupObject {
override val shortName: Name = packageFqName.shortName()
}
private data class ClassifierLookupObject(override val shortName: Name, val classId: ClassId?, val insertFqName: Boolean) : KotlinLookupObject
/**
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.completion.KotlinFirLookupElementFactory
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtFile
@@ -27,6 +28,8 @@ internal class FirBasicCompletionContext(
val indexHelper: IndexHelper,
val lookupElementFactory: KotlinFirLookupElementFactory = KotlinFirLookupElementFactory(),
) {
val visibleScope = KotlinSourceFilterScope.projectSourceAndClassFiles(originalKtFile.resolveScope, project)
companion object {
fun createFromParameters(parameters: CompletionParameters, result: CompletionResultSet): FirBasicCompletionContext? {
val prefixMatcher = result.prefixMatcher
@@ -92,4 +92,12 @@ interface KtDeclarationScope<out T : KtSymbolWithDeclarations> : KtScope {
interface KtPackageScope : KtScope {
val fqName: FqName
fun getPackageSymbols(nameFilter: KtScopeNameFilter = { true }): Sequence<KtPackageSymbol>
override fun getAllSymbols(): Sequence<KtSymbol> = withValidityAssertion {
super.getAllSymbols() + getPackageSymbols()
}
override fun getConstructors(): Sequence<KtConstructorSymbol> = withValidityAssertion { emptySequence() }
}
@@ -48,6 +48,9 @@ abstract class KtSymbolProvider : KtAnalysisSessionComponent() {
abstract fun getClassOrObjectSymbolByClassId(classId: ClassId): KtClassOrObjectSymbol?
abstract fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): Sequence<KtSymbol>
@Suppress("PropertyName")
abstract val ROOT_PACKAGE_SYMBOL: KtPackageSymbol
}
interface KtSymbolProviderMixIn : KtAnalysisSessionMixIn {
@@ -111,4 +114,7 @@ interface KtSymbolProviderMixIn : KtAnalysisSessionMixIn {
fun FqName.getContainingCallableSymbolsWithName(name: Name): Sequence<KtSymbol> =
analysisSession.symbolProvider.getTopLevelCallableSymbols(this, name)
@Suppress("PropertyName")
val ROOT_PACKAGE_SYMBOL: KtPackageSymbol
get() = analysisSession.symbolProvider.ROOT_PACKAGE_SYMBOL
}
@@ -6,7 +6,9 @@
package org.jetbrains.kotlin.idea.frontend.api.fir
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.api.*
@@ -19,6 +21,8 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirOverrideInfoProvi
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbolProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.threadLocal
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
@@ -28,6 +32,7 @@ private constructor(
val firResolveState: FirModuleResolveState,
internal val firSymbolBuilder: KtSymbolByFirBuilder,
token: ValidityToken,
element: KtElement,
private val mode: AnalysisSessionMode,
) : KtAnalysisSession(token) {
@@ -90,19 +95,23 @@ private constructor(
contextResolveState,
firSymbolBuilder.createReadOnlyCopy(contextResolveState),
token,
originalKtFile,
AnalysisSessionMode.DEPENDENT_COPY
)
}
val rootModuleSession: FirSession get() = firResolveState.rootModuleSession
val firSymbolProvider: FirSymbolProvider get() = rootModuleSession.symbolProvider
val targetPlatform: TargetPlatform get() = rootModuleSession.moduleData.platform
val searchScope: GlobalSearchScope = KotlinSourceFilterScope.projectSourceAndClassFiles(element.resolveScope, project)
companion object {
@InvalidWayOfUsingAnalysisSession
@Deprecated("Please use org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProviderKt.analyze")
internal fun createAnalysisSessionByResolveState(
firResolveState: FirModuleResolveState,
token: ValidityToken
token: ValidityToken,
element: KtElement,
): KtFirAnalysisSession {
val project = firResolveState.project
val firSymbolBuilder = KtSymbolByFirBuilder(
@@ -115,7 +124,8 @@ private constructor(
firResolveState,
firSymbolBuilder,
token,
AnalysisSessionMode.REGULAR
element,
AnalysisSessionMode.REGULAR,
)
}
}
@@ -31,7 +31,7 @@ class KtFirAnalysisSessionProvider(private val project: Project) : KtAnalysisSes
return cache.getAnalysisSession(resolveState to factory.identifier) {
val validityToken = factory.create(project)
@Suppress("DEPRECATION")
KtFirAnalysisSession.createAnalysisSessionByResolveState(resolveState, validityToken)
KtFirAnalysisSession.createAnalysisSessionByResolveState(resolveState, validityToken, contextElement)
}
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir
import com.google.common.collect.MapMaker
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.*
@@ -112,10 +113,16 @@ internal class KtSymbolByFirBuilder private constructor(
fun createPackageSymbolIfOneExists(packageFqName: FqName): KtFirPackageSymbol? {
val exists = PackageIndexUtil.packageExists(packageFqName, GlobalSearchScope.allScope(project), project)
val exists =
PackageIndexUtil.packageExists(packageFqName, GlobalSearchScope.allScope(project), project)
|| JavaPsiFacade.getInstance(project).findPackage(packageFqName.asString()) != null
if (!exists) {
return null
}
return createPackageSymbol(packageFqName)
}
fun createPackageSymbol(packageFqName: FqName): KtFirPackageSymbol {
return KtFirPackageSymbol(packageFqName, project, token)
}
@@ -107,15 +107,22 @@ internal class KtFirScopeProvider(
override fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope = withValidityAssertion {
packageMemberScopeCache.getOrPut(packageSymbol) {
val firPackageScope =
FirPackageMemberScope(
packageSymbol.fqName,
firResolveState.rootModuleSession/*TODO use correct session here*/
).also(firScopeStorage::register)
KtFirPackageScope(firPackageScope, project, builder, token)
KtFirPackageScope(
packageSymbol.fqName,
project,
builder,
this,
token,
analysisSession.searchScope,
analysisSession.targetPlatform
)
}
}
fun registerScope(scope: FirScope) {
firScopeStorage.register(scope)
}
override fun getCompositeScope(subScopes: List<KtScope>): KtCompositeScope = withValidityAssertion {
KtFirCompositeScope(subScopes, token)
}
@@ -179,7 +186,15 @@ internal class KtFirScopeProvider(
return when (firScope) {
is FirAbstractSimpleImportingScope -> KtFirNonStarImportingScope(firScope, builder, token)
is FirAbstractStarImportingScope -> KtFirStarImportingScope(firScope, builder, project, token)
is FirPackageMemberScope -> KtFirPackageScope(firScope, project, builder, token)
is FirPackageMemberScope -> KtFirPackageScope(
firScope.fqName,
project,
builder,
this,
token,
analysisSession.searchScope,
analysisSession.targetPlatform
)
is FirContainingNamesAwareScope -> KtFirDelegatingScopeImpl(firScope, builder, token)
is FirMemberTypeParameterScope -> KtFirDelegatingScopeImpl(firScope, builder, token)
else -> TODO(firScope::class.toString())
@@ -6,32 +6,45 @@
package org.jetbrains.kotlin.idea.frontend.api.fir.scopes
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
import org.jetbrains.kotlin.idea.fir.low.level.api.api.searchScope
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.idea.frontend.api.fir.components.KtFirScopeProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.lazyThreadUnsafeWeakRef
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtPackageScope
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassifierSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelClassByPackageIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionByPackageIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelPropertyByPackageIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelTypeAliasByPackageIndex
import org.jetbrains.kotlin.idea.search.getKotlinFqName
import org.jetbrains.kotlin.idea.stubindex.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.isJvm
internal class KtFirPackageScope(
firScope: FirPackageMemberScope,
override val fqName: FqName,
private val project: Project,
private val builder: KtSymbolByFirBuilder,
_scopeProvider: KtFirScopeProvider,
override val token: ValidityToken,
private val searchScope: GlobalSearchScope,
private val targetPlatform: TargetPlatform,
) : KtPackageScope {
private val firScope by weakRef(firScope)
override val fqName: FqName get() = firScope.fqName
private val scopeProvider by weakRef(_scopeProvider)
private val firScope: FirPackageMemberScope by lazyThreadUnsafeWeakRef {
val scope = FirPackageMemberScope(fqName, builder.rootSession)
scopeProvider.registerScope(scope)
scope
}
override fun getPossibleCallableNames() = withValidityAssertion {
hashSetOf<Name>().apply {
@@ -58,5 +71,22 @@ internal class KtFirPackageScope(
firScope.getClassifierSymbols(getPossibleClassifierNames().filter(nameFilter), builder)
}
override fun getConstructors(): Sequence<KtConstructorSymbol> = emptySequence()
override fun getPackageSymbols(nameFilter: KtScopeNameFilter): Sequence<KtPackageSymbol> = withValidityAssertion {
sequence {
PackageIndexUtil
.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))
}
}
}
}
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.idea.frontend.api.fir.symbols
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.file.PsiPackageImpl
@@ -131,4 +131,6 @@ internal class KtFirSymbolProvider(
val firs = firSymbolProvider.getTopLevelCallableSymbols(packageFqName, name)
return firs.asSequence().map { firSymbol -> firSymbolBuilder.buildSymbol(firSymbol.fir) }
}
override val ROOT_PACKAGE_SYMBOL: KtPackageSymbol = KtFirPackageSymbol(FqName.ROOT, resolveState.project, token)
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.psi.KtElement
class KtAnalysisSessionFe10BindingHolder private constructor(
@@ -46,8 +47,8 @@ class KtAnalysisSessionFe10BindingHolder private constructor(
companion object {
@InvalidWayOfUsingAnalysisSession
fun create(firResolveState: FirModuleResolveState, token: ValidityToken): KtAnalysisSessionFe10BindingHolder {
val firAnalysisSession = KtFirAnalysisSession.createAnalysisSessionByResolveState(firResolveState, token)
fun create(firResolveState: FirModuleResolveState, token: ValidityToken, ktElement: KtElement): KtAnalysisSessionFe10BindingHolder {
val firAnalysisSession = KtFirAnalysisSession.createAnalysisSessionByResolveState(firResolveState, token, ktElement)
return KtAnalysisSessionFe10BindingHolder(firAnalysisSession)
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2020 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.frontend.api.fir.utils
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner
import java.lang.ref.WeakReference
import kotlin.reflect.KProperty
class ReadOnlyWeakRef<V : Any>
@Deprecated("Consider suing ValidityTokenOwner.weakRef instead")
constructor(value: V, val token: ValidityToken) {
val weakRef = WeakReference(value)
@Suppress("NOTHING_TO_INLINE")
inline operator fun getValue(thisRef: Any, property: KProperty<*>): V =
weakRef.get() ?: if (token.isValid()) {
throw EntityWasGarbageCollectedException(property.toString())
} else {
error("Accessing the invalid value of $property")
}
}
@Suppress("NOTHING_TO_INLINE")
internal inline fun <V : Any> ValidityTokenOwner.weakRef(value: V) = ReadOnlyWeakRef(value, token)
internal inline fun <V : Any> ValidityTokenOwner.weakRef(value: () -> V) = ReadOnlyWeakRef(value(), token)
@@ -10,21 +10,23 @@ import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner
import java.lang.ref.WeakReference
import kotlin.reflect.KProperty
class ReadOnlyWeakRef<V : Any>
@Deprecated("Consider suing ValidityTokenOwner.weakRef instead")
constructor(value: V, val token: ValidityToken) {
val weakRef = WeakReference(value)
internal class LazyThreadUnsafeWeakRef<V : Any>
constructor(_createValue: () -> V, val token: ValidityToken) {
private var createValue: (() -> V)? = _createValue
private var weakRef: WeakReference<V>? = null
@Suppress("NOTHING_TO_INLINE")
inline operator fun getValue(thisRef: Any, property: KProperty<*>): V =
weakRef.get() ?: if (token.isValid()) {
inline operator fun getValue(thisRef: Any, property: KProperty<*>): V {
if (weakRef == null) {
weakRef = WeakReference(createValue!!())
createValue = null
}
return weakRef!!.get() ?: if (token.isValid()) {
throw EntityWasGarbageCollectedException(property.toString())
} else {
error("Accessing the invalid value of $property")
}
}
}
@Suppress("NOTHING_TO_INLINE")
internal inline fun <V : Any> ValidityTokenOwner.weakRef(value: V) = ReadOnlyWeakRef(value, token)
internal inline fun <V : Any> ValidityTokenOwner.weakRef(value: () -> V) = ReadOnlyWeakRef(value(), token)
internal fun <V : Any> ValidityTokenOwner.lazyThreadUnsafeWeakRef(createValue: () -> V) = LazyThreadUnsafeWeakRef(createValue, token)