FIR UAST: commonize utils from UAST Kotlin

This commit is contained in:
Jinseong Jeon
2021-04-27 00:07:00 -07:00
committed by Ilya Kirillov
parent f37c722c76
commit eac875b5d6
16 changed files with 99 additions and 158 deletions
+18
View File
@@ -0,0 +1,18 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
implementation(kotlinStdlib())
implementation(project(":compiler:psi"))
implementation(project(":compiler:light-classes"))
// BEWARE: Uast should not depend on IDEA.
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "asm-all", rootProject = rootProject) }
compileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") }
}
sourceSets {
"main" { projectDefault() }
}
@@ -0,0 +1,32 @@
/*
* 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.uast.kotlin
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMember
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.uast.UDeclaration
import org.jetbrains.uast.UElement
fun <T> lz(initializer: () -> T) =
lazy(LazyThreadSafetyMode.SYNCHRONIZED, initializer)
inline fun <reified T : UDeclaration, reified P : PsiElement> unwrap(element: P): P {
val unwrapped = if (element is T) element.javaPsi else element
assert(unwrapped !is UElement)
return unwrapped as P
}
fun unwrapFakeFileForLightClass(file: PsiFile): PsiFile = (file as? FakeFileForLightClass)?.ktFile ?: file
fun getKotlinMemberOrigin(element: PsiElement?): KtDeclaration? {
(element as? KtLightMember<*>)?.lightMemberOrigin?.auxiliaryOriginalElement?.let { return it }
(element as? KtLightElement<*, *>)?.kotlinOrigin?.let { return it as? KtDeclaration }
return null
}
@@ -0,0 +1,42 @@
/*
* 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.uast.kotlin
import org.jetbrains.uast.DEFAULT_EXPRESSION_TYPES_LIST
import org.jetbrains.uast.DEFAULT_TYPES_LIST
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
fun expressionTypes(requiredType: Class<out UElement>?) =
requiredType?.let { arrayOf(it) } ?: DEFAULT_EXPRESSION_TYPES_LIST
fun elementTypes(requiredType: Class<out UElement>?) =
requiredType?.let { arrayOf(it) } ?: DEFAULT_TYPES_LIST
fun <T : UElement> Array<out Class<out T>>.nonEmptyOr(default: Array<out Class<out UElement>>) =
takeIf { it.isNotEmpty() } ?: default
inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.el(f: () -> UElement?): UElement? {
return if (isAssignableFrom(ActualT::class.java)) f() else null
}
inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.expr(f: () -> UExpression?): UExpression? {
return if (isAssignableFrom(ActualT::class.java)) f() else null
}
fun Array<out Class<out UElement>>.isAssignableFrom(cls: Class<*>) = any { it.isAssignableFrom(cls) }
fun <U : UElement> Array<out Class<out UElement>>.accommodate(vararg makers: UElementAlternative<out U>): Sequence<UElement> {
val makersSeq = makers.asSequence()
return this.asSequence()
.flatMap { requiredType -> makersSeq.filter { requiredType.isAssignableFrom(it.uType) } }
.distinct()
.mapNotNull { it.make.invoke() }
}
inline fun <reified U : UElement> alternative(noinline make: () -> U?) = UElementAlternative(U::class.java, make)
class UElementAlternative<U : UElement>(val uType: Class<U>, val make: () -> U?)
+1
View File
@@ -7,6 +7,7 @@ dependencies {
implementation(kotlinStdlib())
implementation(project(":compiler:psi"))
implementation(project(":compiler:light-classes"))
implementation(project(":plugins:uast-kotlin-base"))
// BEWARE: Uast should not depend on IDEA.
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "asm-all", rootProject = rootProject) }
@@ -8,11 +8,11 @@ package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiElement
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.kotlin.internal.FirKotlinUElementWithComments
import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments
abstract class FirKotlinAbstractUElement(
private val givenParent: UElement?
) : FirKotlinUElementWithComments {
) : KotlinUElementWithComments {
final override val uastParent: UElement? by lz {
givenParent ?: convertParent()
@@ -213,25 +213,3 @@ internal object FirKotlinConverter {
}
}
}
private inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.el(f: () -> UElement?): UElement? {
return if (isAssignableFrom(ActualT::class.java)) f() else null
}
private inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.expr(f: () -> UExpression?): UExpression? {
return if (isAssignableFrom(ActualT::class.java)) f() else null
}
private fun Array<out Class<out UElement>>.isAssignableFrom(cls: Class<*>) = any { it.isAssignableFrom(cls) }
private fun <U : UElement> Array<out Class<out UElement>>.accommodate(vararg makers: UElementAlternative<out U>): Sequence<UElement> {
val makersSeq = makers.asSequence()
return this.asSequence()
.flatMap { requiredType -> makersSeq.filter { requiredType.isAssignableFrom(it.uType) } }
.distinct()
.mapNotNull { it.make.invoke() }
}
private inline fun <reified U : UElement> alternative(noinline make: () -> U?) = UElementAlternative(U::class.java, make)
private class UElementAlternative<U : UElement>(val uType: Class<U>, val make: () -> U?)
@@ -88,10 +88,3 @@ class FirKotlinUastLanguagePlugin : UastLanguagePlugin {
TODO("Not yet implemented")
}
}
private fun elementTypes(requiredType: Class<out UElement>?) =
requiredType?.let { arrayOf(it) } ?: DEFAULT_TYPES_LIST
private fun <T : UElement> Array<out Class<out T>>.nonEmptyOr(default: Array<out Class<out UElement>>) =
takeIf { it.isNotEmpty() } ?: default
@@ -7,7 +7,6 @@ package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.PsiParameter
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.psi.*
@@ -46,21 +45,12 @@ open class FirKotlinUMethod(
}
override val uastParameters: List<UParameter> by lz {
fun parameterOrigin(psiParameter: PsiParameter?): KtElement? {
return when (psiParameter) {
is KtLightElement<*, *> -> psiParameter.kotlinOrigin
// TODO: UastKotlinPsiParameter?
else -> null
}
}
val lightParams = psi.parameterList.parameters
val receiverTypeReference =
receiverTypeReference ?: return@lz lightParams.map { FirKotlinUParameter(it, parameterOrigin(it), this) }
receiverTypeReference ?: return@lz lightParams.map { FirKotlinUParameter(it, getKotlinMemberOrigin(it), this) }
val lightReceiver = lightParams.firstOrNull() ?: return@lz emptyList<UParameter>()
val uParameters = SmartList<UParameter>(FirKotlinReceiverUParameter(lightReceiver, receiverTypeReference, this))
lightParams.drop(1).mapTo(uParameters) { FirKotlinUParameter(it, parameterOrigin(it), this) }
lightParams.drop(1).mapTo(uParameters) { FirKotlinUParameter(it, getKotlinMemberOrigin(it), this) }
uParameters
}
@@ -1,39 +0,0 @@
/*
* 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.uast.kotlin.internal
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.uast.UComment
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
interface FirKotlinUElementWithComments : UElement {
override val comments: List<UComment>
get() {
val psi = sourcePsi ?: return emptyList()
val childrenComments = psi.children.filterIsInstance<PsiComment>().map { UComment(it, this) }
if (this !is UExpression) return childrenComments
val childrenAndSiblingComments = childrenComments +
psi.nearestCommentSibling(forward = true)?.let { listOf(UComment(it, this)) }.orEmpty() +
psi.nearestCommentSibling(forward = false)?.let { listOf(UComment(it, this)) }.orEmpty()
val parent = psi.parent as? KtValueArgument ?: return childrenAndSiblingComments
return childrenAndSiblingComments +
parent.nearestCommentSibling(forward = true)?.let { listOf(UComment(it, this)) }.orEmpty() +
parent.nearestCommentSibling(forward = false)?.let { listOf(UComment(it, this)) }.orEmpty()
}
private fun PsiElement.nearestCommentSibling(forward: Boolean): PsiComment? {
var sibling = if (forward) nextSibling else prevSibling
while (sibling is PsiWhiteSpace && !sibling.text.contains('\n')) {
sibling = if (forward) sibling.nextSibling else sibling.prevSibling
}
return sibling as? PsiComment
}
}
@@ -7,27 +7,9 @@ package org.jetbrains.uast.kotlin
import com.intellij.openapi.components.ServiceManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMember
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.uast.UDeclaration
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UastLanguagePlugin
internal fun <T> lz(initializer: () -> T) =
lazy(LazyThreadSafetyMode.SYNCHRONIZED, initializer)
internal inline fun <reified T : UDeclaration, reified P : PsiElement> unwrap(element: P): P {
val unwrapped = if (element is T) element.javaPsi else element
assert(unwrapped !is UElement)
return unwrapped as P
}
internal fun unwrapFakeFileForLightClass(file: PsiFile): PsiFile = (file as? FakeFileForLightClass)?.ktFile ?: file
val firKotlinUastPlugin: UastLanguagePlugin by lz {
UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE }
?: FirKotlinUastLanguagePlugin()
@@ -37,9 +19,3 @@ internal val PsiElement.service: FirKotlinUastResolveProviderService
get() {
return ServiceManager.getService(project, FirKotlinUastResolveProviderService::class.java)
}
internal fun getKotlinMemberOrigin(element: PsiElement?): KtDeclaration? {
(element as? KtLightMember<*>)?.lightMemberOrigin?.auxiliaryOriginalElement?.let { return it }
(element as? KtLightElement<*, *>)?.kotlinOrigin?.let { return it as? KtDeclaration }
return null
}
+1
View File
@@ -11,6 +11,7 @@ dependencies {
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:light-classes"))
compile(project(":plugins:uast-kotlin-base"))
// BEWARE: Uast should not depend on IDEA.
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "asm-all", rootProject = rootProject) }
@@ -169,22 +169,6 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
}
}
internal inline fun <reified ActualT : UElement> Class<*>?.el(f: () -> UElement?): UElement? {
return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null
}
internal inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.el(f: () -> UElement?): UElement? {
return if (isAssignableFrom(ActualT::class.java)) f() else null
}
internal inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.expr(f: () -> UExpression?): UExpression? {
return if (isAssignableFrom(ActualT::class.java)) f() else null
}
internal fun Array<out Class<out UElement>>.isAssignableFrom(cls: Class<*>) = any { it.isAssignableFrom(cls) }
internal object KotlinConverter {
internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
is KtValueArgumentList -> unwrapElements(element.parent)
@@ -743,22 +727,3 @@ val kotlinUastPlugin: UastLanguagePlugin by lz {
UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE }
?: KotlinUastLanguagePlugin()
}
private fun expressionTypes(requiredType: Class<out UElement>?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_EXPRESSION_TYPES_LIST
private fun elementTypes(requiredType: Class<out UElement>?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_TYPES_LIST
private fun <T : UElement> Array<out Class<out T>>.nonEmptyOr(default: Array<out Class<out UElement>>) = takeIf { it.isNotEmpty() }
?: default
private fun <U : UElement> Array<out Class<out UElement>>.accommodate(vararg makers: UElementAlternative<out U>): Sequence<UElement> {
val makersSeq = makers.asSequence()
return this.asSequence()
.flatMap { requiredType -> makersSeq.filter { requiredType.isAssignableFrom(it.uType) } }
.distinct()
.mapNotNull { it.make.invoke() }
}
private inline fun <reified U : UElement> alternative(noinline make: () -> U?) = UElementAlternative(U::class.java, make)
private class UElementAlternative<U : UElement>(val uType: Class<U>, val make: () -> U?)
@@ -126,12 +126,6 @@ open class KotlinUMethod(
override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi
companion object {
private fun getKotlinMemberOrigin(element: PsiElement?): KtDeclaration? {
(element as? KtLightMember<*>)?.lightMemberOrigin?.auxiliaryOriginalElement?.let { return it }
(element as? KtLightElement<*, *>)?.kotlinOrigin?.let { return it as? KtDeclaration }
return null
}
fun create(psi: KtLightMethod, containingElement: UElement?): KotlinUMethod {
val kotlinOrigin = psi.kotlinOrigin
return if (kotlinOrigin is KtConstructor<*>) {
@@ -28,7 +28,6 @@ import com.intellij.psi.impl.compiled.StubBuildingVisitor
import com.intellij.psi.util.PsiTypesUtil
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.descriptors.*
@@ -87,8 +86,6 @@ internal val KOTLIN_CACHED_UELEMENT_KEY = Key.create<WeakReference<UElement>>("c
@Suppress("NOTHING_TO_INLINE")
internal inline fun String?.orAnonymous(kind: String = ""): String = this ?: "<anonymous" + (if (kind.isNotBlank()) " $kind" else "") + ">"
internal fun <T> lz(initializer: () -> T) = lazy(LazyThreadSafetyMode.SYNCHRONIZED, initializer)
internal fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
val innerExpression = KtPsiUtil.safeDeparenthesize(this)
if (innerExpression is KtBlockExpression) {
@@ -98,17 +95,9 @@ internal fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
return innerExpression
}
internal inline fun <reified T : UDeclaration, reified P : PsiElement> unwrap(element: P): P {
val unwrapped = if (element is T) element.javaPsi else element
assert(unwrapped !is UElement)
return unwrapped as P
}
internal fun getContainingLightClass(original: KtDeclaration): KtLightClass? =
(original.containingClassOrObject?.toLightClass() ?: original.containingKtFile.findFacadeClass())
internal fun unwrapFakeFileForLightClass(file: PsiFile): PsiFile = (file as? FakeFileForLightClass)?.ktFile ?: file
// mb merge with org.jetbrains.kotlin.idea.references.ReferenceAccess ?
internal enum class ReferenceAccess(val isRead: Boolean, val isWrite: Boolean) {
READ(true, false), WRITE(false, true), READ_WRITE(true, true)
+1
View File
@@ -211,6 +211,7 @@ include ":benchmarks",
":sam-with-receiver-ide-plugin",
":kotlin-imports-dumper-compiler-plugin",
":plugins:uast-kotlin",
":plugins:uast-kotlin-base",
":plugins:uast-kotlin-fir",
":plugins:uast-kotlin-idea",
":plugins:annotation-based-compiler-plugins-ide-support",