org.jetbrains.kotlin.asJava.classes.implUtils.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2024 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.asJava.classes
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightElement
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.psi.*
fun KtSuperTypeList.findEntry(fqNameToFind: String): KtSuperTypeListEntry? =
entries.find { it.typeAsUserType?.fqName == fqNameToFind }
private val KtUserType.fqName: String?
get() = qualifier?.let { "${it.fqName}.$referencedName" } ?: referencedName
// NOTE: avoid using blocking lazy in light classes, it leads to deadlocks
fun lazyPub(initializer: () -> T) = lazy(LazyThreadSafetyMode.PUBLICATION, initializer)
@Suppress("UnusedReceiverParameter")
fun LightElement.cannotModify(): Nothing {
throw IncorrectOperationException("Modification not implemented.")
}
fun PsiReferenceList.addSuperTypeEntry(
superTypeList: KtSuperTypeList,
entry: KtSuperTypeListEntry,
reference: PsiJavaCodeReferenceElement
) {
// Only classes may be mentioned in 'extends' list, thus create super call instead simple type reference
val entryToAdd =
if ((reference.parent as? PsiReferenceList)?.role == PsiReferenceList.Role.IMPLEMENTS_LIST && role == PsiReferenceList.Role.EXTENDS_LIST) {
KtPsiFactory(project).createSuperTypeCallEntry("${entry.text}()")
} else entry
// TODO: implement KtSuperListEntry qualification/shortening when inserting reference from another context
if (entry.parent != superTypeList) {
superTypeList.addEntry(entryToAdd)
} else {
// Preserve original entry order
entry.replace(entryToAdd)
}
}
fun KtClassOrObject.getExternalDependencies(): List {
return with(KotlinModificationTrackerService.getInstance(project)) {
if ([email protected]) return listOf(outOfBlockModificationTracker)
else when (val file = containingFile) {
is KtFile -> listOf(outOfBlockModificationTracker, fileModificationTracker(file))
else -> listOf(outOfBlockModificationTracker)
}
}
}
// There is no other known way found to make PSI types annotated for now (without creating a new instance).
// It seems we need for platform changes to do it more convenient way (KTIJ-141).
private val setPsiTypeAnnotationProvider: (PsiType, TypeAnnotationProvider) -> Unit by lazyPub {
val klass = PsiType::class.java
val providerField = try {
klass.getDeclaredField("myAnnotationProvider")
.also { it.isAccessible = true }
} catch (e: NoSuchFieldException) {
if (ApplicationManager.getApplication().isInternal) throw e
null
} catch (e: SecurityException) {
if (ApplicationManager.getApplication().isInternal) throw e
null
}
{ psiType, provider ->
providerField?.set(psiType, provider)
}
}
fun PsiType.annotateByTypeAnnotationProvider(
annotations: Sequence>,
): PsiType {
val annotationsIterator = annotations.iterator()
if (!annotationsIterator.hasNext()) return this
if (this is PsiPrimitiveType) {
val typeAnnotation = annotationsIterator.next()
return if (typeAnnotation.isEmpty()) {
this
} else {
val provider = TypeAnnotationProvider.Static.create(typeAnnotation.toTypedArray())
// NB: [PsiType#annotate] makes a clone of the given [PsiType] while manipulating the type annotation provider.
// For simple primitive type, it will be okay and intuitive (than reflection hack).
annotate(provider)
}
}
fun recursiveAnnotator(psiType: PsiType) {
if (!annotationsIterator.hasNext()) return
if (psiType is PsiWildcardType) {
// Wildcard itself cannot have annotations
psiType.bound?.let(::recursiveAnnotator)
return
}
val typeAnnotations = annotationsIterator.next()
when (psiType) {
is PsiPrimitiveType -> return // Primitive type cannot be type parameter so we skip it
is PsiClassType -> {
for (parameterType in psiType.parameters) {
recursiveAnnotator(parameterType)
}
}
is PsiArrayType ->
recursiveAnnotator(psiType.componentType)
else -> {}
}
if (typeAnnotations.isEmpty()) return
val provider = TypeAnnotationProvider.Static.create(typeAnnotations.toTypedArray())
setPsiTypeAnnotationProvider(psiType, provider)
}
recursiveAnnotator(this)
return this
}