FIR UAST: commonize utils from UAST Kotlin
This commit is contained in:
committed by
Ilya Kirillov
parent
f37c722c76
commit
eac875b5d6
@@ -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() }
|
||||
}
|
||||
+32
@@ -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?)
|
||||
@@ -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
|
||||
|
||||
|
||||
+2
-12
@@ -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
|
||||
}
|
||||
|
||||
|
||||
-39
@@ -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
|
||||
}
|
||||
}
|
||||
-24
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user