FIR IDE: add completion for annotations
This commit is contained in:
committed by
TeamCityServer
parent
6b450e6fdf
commit
d76ec9db50
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class AnnType
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class SHello
|
||||
val v = 1
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
val v = 1
|
||||
|
||||
fun foo(@[S<caret>) { }
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
val v = 1
|
||||
|
||||
fun foo(@[volatile S<caret>) { }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_COMPARISON
|
||||
annotation class Hello
|
||||
val v = 1
|
||||
|
||||
|
||||
+9
@@ -17,6 +17,8 @@ import org.jetbrains.kotlin.idea.completion.context.FirExpressionNameReferencePo
|
||||
import org.jetbrains.kotlin.idea.completion.context.FirPositionCompletionContextDetector
|
||||
import org.jetbrains.kotlin.idea.completion.context.FirTypeNameReferencePositionContext
|
||||
import org.jetbrains.kotlin.idea.completion.context.FirUnknownPositionContext
|
||||
import org.jetbrains.kotlin.idea.completion.contributors.*
|
||||
import org.jetbrains.kotlin.idea.completion.contributors.FirAnnotationCompletionContributor
|
||||
import org.jetbrains.kotlin.idea.completion.contributors.FirCallableCompletionContributor
|
||||
import org.jetbrains.kotlin.idea.completion.contributors.FirClassifierCompletionContributor
|
||||
import org.jetbrains.kotlin.idea.completion.contributors.FirKeywordCompletionContributor
|
||||
@@ -57,6 +59,7 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
||||
val keywordContributor = FirKeywordCompletionContributor(basicContext)
|
||||
val callableContributor = FirCallableCompletionContributor(basicContext)
|
||||
val classifierContributor = FirClassifierCompletionContributor(basicContext)
|
||||
val annotationsContributor = FirAnnotationCompletionContributor(basicContext)
|
||||
|
||||
when (positionContext) {
|
||||
is FirExpressionNameReferencePositionContext -> {
|
||||
@@ -68,6 +71,12 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
||||
complete(keywordContributor, positionContext)
|
||||
complete(classifierContributor, positionContext)
|
||||
}
|
||||
|
||||
is FirAnnotationTypeNameReferencePositionContext -> {
|
||||
complete(keywordContributor, positionContext)
|
||||
complete(annotationsContributor, positionContext)
|
||||
}
|
||||
|
||||
is FirUnknownPositionContext -> {
|
||||
complete(keywordContributor, positionContext)
|
||||
}
|
||||
|
||||
+35
-8
@@ -11,10 +11,7 @@ import org.jetbrains.kotlin.idea.frontend.api.analyse
|
||||
import org.jetbrains.kotlin.idea.frontend.api.analyseInDependedAnalysisSession
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.KtUserType
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
|
||||
|
||||
internal sealed class FirRawPositionCompletionContext {
|
||||
@@ -34,6 +31,15 @@ internal class FirTypeNameReferencePositionContext(
|
||||
override val explicitReceiver: KtExpression?
|
||||
) : FirNameReferencePositionContext()
|
||||
|
||||
internal class FirAnnotationTypeNameReferencePositionContext(
|
||||
override val position: PsiElement,
|
||||
override val reference: KtSimpleNameReference,
|
||||
override val nameExpression: KtSimpleNameExpression,
|
||||
override val explicitReceiver: KtExpression?,
|
||||
val annotationEntry: KtAnnotationEntry,
|
||||
) : FirNameReferencePositionContext()
|
||||
|
||||
|
||||
internal class FirExpressionNameReferencePositionContext(
|
||||
override val position: PsiElement,
|
||||
override val reference: KtSimpleNameReference,
|
||||
@@ -55,13 +61,34 @@ internal object FirPositionCompletionContextDetector {
|
||||
?: return FirUnknownPositionContext(position)
|
||||
val explicitReceiver = nameExpression.getReceiverExpression()
|
||||
|
||||
return if (nameExpression.parent is KtUserType) {
|
||||
FirTypeNameReferencePositionContext(position, reference, nameExpression, explicitReceiver)
|
||||
} else {
|
||||
FirExpressionNameReferencePositionContext(position, reference, nameExpression, explicitReceiver)
|
||||
return when (val parent = nameExpression.parent) {
|
||||
is KtUserType -> {
|
||||
detectForTypeContext(parent, position, reference, nameExpression, explicitReceiver)
|
||||
}
|
||||
else -> {
|
||||
FirExpressionNameReferencePositionContext(position, reference, nameExpression, explicitReceiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun detectForTypeContext(
|
||||
userType: KtUserType,
|
||||
position: PsiElement,
|
||||
reference: KtSimpleNameReference,
|
||||
nameExpression: KtSimpleNameExpression,
|
||||
explicitReceiver: KtExpression?
|
||||
): FirNameReferencePositionContext {
|
||||
val annotationEntry = userType.annotationEntry()
|
||||
?: return FirTypeNameReferencePositionContext(position, reference, nameExpression, explicitReceiver)
|
||||
return FirAnnotationTypeNameReferencePositionContext(position, reference, nameExpression, explicitReceiver, annotationEntry)
|
||||
}
|
||||
|
||||
private fun KtUserType.annotationEntry(): KtAnnotationEntry? {
|
||||
val typeReference = (parent as? KtTypeReference)?.takeIf { it.typeElement == this }
|
||||
val constructorCall = (typeReference?.parent as? KtConstructorCalleeExpression)?.takeIf { it.typeReference == typeReference }
|
||||
return (constructorCall?.parent as? KtAnnotationEntry)?.takeIf { it.calleeExpression == constructorCall }
|
||||
}
|
||||
|
||||
inline fun analyseInContext(
|
||||
basicContext: FirBasicCompletionContext,
|
||||
positionContext: FirRawPositionCompletionContext,
|
||||
|
||||
+33
-4
@@ -9,20 +9,21 @@ 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.frontend.api.KtAnalysisSession
|
||||
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.symbols.KtTypeParameterSymbol
|
||||
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.references.mainReference
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
internal class FirClassifierCompletionContributor(
|
||||
internal open class FirClassifierCompletionContributor(
|
||||
basicContext: FirBasicCompletionContext,
|
||||
) : FirContextCompletionContributorBase<FirNameReferenceRawPositionContext>(basicContext) {
|
||||
|
||||
protected open fun KtAnalysisSession.filterClassifiers(classifierSymbol: KtClassifierSymbol): Boolean = true
|
||||
|
||||
override fun KtAnalysisSession.complete(positionContext: FirNameReferenceRawPositionContext) {
|
||||
val visibilityChecker = CompletionVisibilityChecker.create(basicContext, positionContext)
|
||||
|
||||
@@ -44,6 +45,7 @@ internal class FirClassifierCompletionContributor(
|
||||
val symbol = reference.resolveToSymbol() as? KtSymbolWithMembers ?: return
|
||||
symbol.getMemberScope()
|
||||
.getClassifierSymbols(scopeNameFilter)
|
||||
.filter { filterClassifiers(it) }
|
||||
.filter { with(visibilityChecker) { isVisible(it) } }
|
||||
.forEach { addClassifierSymbolToCompletion(it, insertFqName = false) }
|
||||
}
|
||||
@@ -55,6 +57,7 @@ internal class FirClassifierCompletionContributor(
|
||||
val implicitScopes = originalKtFile.getScopeContextForPosition(positionContext.nameExpression).scopes
|
||||
val classesFromScopes = implicitScopes
|
||||
.getClassifierSymbols(scopeNameFilter)
|
||||
.filter { filterClassifiers(it) }
|
||||
.filter { with(visibilityChecker) { isVisible(it) } }
|
||||
|
||||
classesFromScopes.forEach { addClassifierSymbolToCompletion(it, insertFqName = true) }
|
||||
@@ -62,7 +65,33 @@ internal class FirClassifierCompletionContributor(
|
||||
val kotlinClassesFromIndices = indexHelper.getKotlinClasses(scopeNameFilter, psiFilter = { it !is KtEnumEntry })
|
||||
kotlinClassesFromIndices.asSequence()
|
||||
.map { it.getSymbol() as KtClassifierSymbol }
|
||||
.filter { filterClassifiers(it) }
|
||||
.filter { with(visibilityChecker) { isVisible(it) } }
|
||||
.forEach { addClassifierSymbolToCompletion(it, insertFqName = true) }
|
||||
}
|
||||
}
|
||||
|
||||
internal class FirAnnotationCompletionContributor(
|
||||
basicContext: FirBasicCompletionContext
|
||||
) : FirClassifierCompletionContributor(basicContext) {
|
||||
|
||||
override fun KtAnalysisSession.filterClassifiers(classifierSymbol: KtClassifierSymbol): Boolean = when (classifierSymbol) {
|
||||
is KtAnonymousObjectSymbol -> false
|
||||
is KtTypeParameterSymbol -> false
|
||||
is KtNamedClassOrObjectSymbol -> when (classifierSymbol.classKind) {
|
||||
KtClassKind.ANNOTATION_CLASS -> true
|
||||
KtClassKind.ENUM_CLASS -> false
|
||||
KtClassKind.ENUM_ENTRY -> false
|
||||
KtClassKind.ANONYMOUS_OBJECT -> false
|
||||
KtClassKind.CLASS, KtClassKind.OBJECT, KtClassKind.COMPANION_OBJECT, KtClassKind.INTERFACE -> {
|
||||
// TODO show class if nested classifier is annotation class
|
||||
// classifierSymbol.getDeclaredMemberScope().getClassifierSymbols().any { filterClassifiers(it) }
|
||||
false
|
||||
}
|
||||
}
|
||||
is KtTypeAliasSymbol -> {
|
||||
val expendedClass = (classifierSymbol.expandedType as? KtClassType)?.classSymbol
|
||||
expendedClass?.let { filterClassifiers(it) } == true
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -33,10 +33,14 @@ sealed class KtClassLikeSymbol : KtClassifierSymbol(), KtSymbolWithKind {
|
||||
}
|
||||
|
||||
abstract class KtTypeAliasSymbol : KtClassLikeSymbol(), KtNamedSymbol {
|
||||
abstract override val classIdIfNonLocal: ClassId
|
||||
|
||||
final override val symbolKind: KtSymbolKind get() = KtSymbolKind.TOP_LEVEL
|
||||
|
||||
/**
|
||||
* Returns type from right-hand site of type alias
|
||||
* If type alias has type parameters, then those type parameters will be present in result type
|
||||
*/
|
||||
abstract val expandedType: KtType
|
||||
|
||||
abstract override fun createPointer(): KtSymbolPointer<KtTypeAliasSymbol>
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ internal class KtSymbolByFirBuilder private constructor(
|
||||
}
|
||||
|
||||
fun buildTypeAliasSymbol(fir: FirTypeAlias): KtFirTypeAliasSymbol {
|
||||
return symbolsCache.cache(fir) { KtFirTypeAliasSymbol(fir, resolveState, token) }
|
||||
return symbolsCache.cache(fir) { KtFirTypeAliasSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
|
||||
}
|
||||
|
||||
fun buildTypeParameterSymbol(fir: FirTypeParameter): KtFirTypeParameterSymbol {
|
||||
|
||||
+12
-1
@@ -6,27 +6,38 @@
|
||||
package org.jetbrains.kotlin.idea.frontend.api.fir.symbols
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
||||
import org.jetbrains.kotlin.idea.fir.findPsi
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
|
||||
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
|
||||
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.firRef
|
||||
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtPsiBasedSymbolPointer
|
||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtSymbolPointer
|
||||
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
|
||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal class KtFirTypeAliasSymbol(
|
||||
fir: FirTypeAlias,
|
||||
resolveState: FirModuleResolveState,
|
||||
override val token: ValidityToken
|
||||
override val token: ValidityToken,
|
||||
_builder: KtSymbolByFirBuilder,
|
||||
) : KtTypeAliasSymbol(), KtFirSymbol<FirTypeAlias> {
|
||||
private val builder by weakRef(_builder)
|
||||
|
||||
override val firRef = firRef(fir, resolveState)
|
||||
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
|
||||
override val name: Name get() = firRef.withFir { it.name }
|
||||
override val classIdIfNonLocal: ClassId get() = firRef.withFir { it.symbol.classId }
|
||||
|
||||
override val expandedType: KtType by firRef.withFirAndCache(FirResolvePhase.SUPER_TYPES) { fir ->
|
||||
builder.typeBuilder.buildKtType(fir.expandedTypeRef)
|
||||
}
|
||||
|
||||
override fun createPointer(): KtSymbolPointer<KtTypeAliasSymbol> {
|
||||
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
|
||||
TODO("Creating symbols for library typealiases is not supported yet")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
class X<T>
|
||||
|
||||
typealias Y<Z> = X<Z>
|
||||
|
||||
// RESULT
|
||||
/*
|
||||
KtFirTypeParameterSymbol:
|
||||
isReified: false
|
||||
name: T
|
||||
origin: SOURCE
|
||||
upperBounds: [kotlin/Any?]
|
||||
variance: INVARIANT
|
||||
|
||||
KtFirNamedClassOrObjectSymbol:
|
||||
annotationClassIds: []
|
||||
annotations: []
|
||||
classIdIfNonLocal: X
|
||||
classKind: CLASS
|
||||
companionObject: null
|
||||
isData: false
|
||||
isExternal: false
|
||||
isFun: false
|
||||
isInline: false
|
||||
isInner: false
|
||||
modality: FINAL
|
||||
name: X
|
||||
origin: SOURCE
|
||||
superTypes: [[] kotlin/Any]
|
||||
symbolKind: TOP_LEVEL
|
||||
typeParameters: [KtFirTypeParameterSymbol(T)]
|
||||
visibility: Public
|
||||
|
||||
KtFirTypeParameterSymbol:
|
||||
isReified: false
|
||||
name: Z
|
||||
origin: SOURCE
|
||||
upperBounds: [kotlin/Any?]
|
||||
variance: INVARIANT
|
||||
|
||||
KtFirTypeAliasSymbol:
|
||||
classIdIfNonLocal: Y
|
||||
expandedType: X<Z>
|
||||
name: Y
|
||||
origin: SOURCE
|
||||
symbolKind: TOP_LEVEL
|
||||
*/
|
||||
+5
@@ -119,6 +119,11 @@ public class SymbolByPsiTestGenerated extends AbstractSymbolByPsiTest {
|
||||
runTest("idea/idea-frontend-fir/testData/symbols/symbolByPsi/topLevelProperties.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeAlias.kt")
|
||||
public void testTypeAlias() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/testData/symbols/symbolByPsi/typeAlias.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeAnnotations.kt")
|
||||
public void testTypeAnnotations() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/testData/symbols/symbolByPsi/typeAnnotations.kt");
|
||||
|
||||
Reference in New Issue
Block a user